Copyright 1984 by ABComputing May 15, 1984 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» º The Ada Tutorial - Part I º º º º by º º º º George Gordon Noel º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Introduction ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ In the last issue we looked at Ada through a wide-angle lens, examining the history and key features of the language. It is time to zoom-in for a closer look. This article is the first in a series of Ada tutorials, and if you follow along closely, and practice what you learn with an "Ada compiler," before long you will be writing Ada programs. By the time this series concludes, you will be privy to some of the most advanced programming concepts in the history of computers. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ The Program AVERAGE ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ If you are not firmly grounded in the basics of Ada, the more esoteric parts of the language (and there are lots of them) will leave you bewildered. Therefore, this first installment is devoted to the simple, rock-bottom details that appear in every Ada program. We investigate some of these details through a program that finds the average of two integers. with TEXT_IO; use TEXT_IO; procedure AVERAGE is package INT_IO is new TEXT_IO.INTEGER_IO (integer); use INT_IO; FIRST_NUMBER: integer; SECOND_NUMBER: integer; AVG: integer; begin put ("Enter a number: "); NEW_LINE; get (FIRST_NUMBER); put ("And another number: "); NEW_LINE; get (SECOND_NUMBER); AVG := (FIRST_NUMBER + SECOND_NUMBER) / 2; put ("The average is: "); NEW_LINE; put (AVG); end AVERAGE; This program prompts the user for a number, reads an integer from the standard input device into the variable FIRST_NUMBER, repeats this process for SECOND_NUMBER, sums, divides, and places the result in the variable AVG, which is printed along with a final message. Aside from the curious first, third, and fourth lines of this program, you might think that we are working in Pascal or some other familiar language. We won't examine the details of these three lines until later in this series, except to say that any program that performs input/output operations involving integer numbers, must contain these three lines of code. Now, let's examine the features of this program that are similar to features in existing, better known languages. Our AVERAGE program is an example of a "procedure," a program unit familiar from PL/1 and other languages. A procedure is a convenient way of grouping together data and commands for implementing some specific job. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ The Declaritive Portion ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ AVERAGE is divided into a "declarative part," which is the first indented region of the program, and a series of statements in the second indented region. (According to the formal rules of Ada, there are actually four distinct sections in this program. We won't be meeting the remaining two for quite some time.) The declarative part is where you establish the existence of data objects (and other items, as we will see), and will be covered in my next installment. For now, just observe that the last three lines in the declarative part create three integer variables. The statements grouped between the words begin and end are commands that implement the code of AVERAGE. The get statement receives information from the standard input device (presumably a keyboard), and the put statement transmits information to the standard output device (presumably a display screen.) ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ NEW_LINE and := ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ The NEW_LINE command sends a carriage return and line feed to the screen. The final kind of statement in this example is the familiar assignment statement in line 15. The assignment operator is the := symbol, which Ada shares with Pascal, Algol, and Modula II. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Use of Semicolons ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Notice that most lines in the example end in semicolons. The use of semicolons is more consistent in Ada than in Pascal. Semicolons "terminate" statements in Ada rather than "separate" them as in Pascal. Semicolons only come after statements and declarations. The word begin is not a statement, nor is the second line (called the "procedure specification") that ends with the word is. The program as a whole ends with a semicolon rather than a period, as it would in Pascal. In our example program, the procedure name, AVERAGE, is repeated before the final semicolon. This is not required, but it is almost universal practice among Ada programmers. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Reserved Words ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Like many other languages, Ada has "reserved words" or "keywords" that have a fixed meaning which the programmer can not modify. In the examples in this article, reserved words appear in lower case to distinguish them from the "user defined identifiers," or symbols created by the programmer, which are in upper case. (The I/O procedures get and put are library routines, as in C, meaning that the words get and put are not reserved. They occur so often, however, that programmers usually write them in lower case to avoid constantly banging the shift key.) If you attempt to redefine a keyword - for instance, if you tried to declare an integer variable called "procedure" - an error message would be issued. Keywords, however, may be imbedded in larger identifiers. This means that you could have an integer variable called DOLLARS even though the word "do" is a keyword in Ada. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Identifiers ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Ada identifiers can consist of letters of the alphabet, numbers, and the underscore character. You can make them as long as you like (indeed, Ada identifiers tend to be wordy) but they must start with a letter. X2 is a legal Ada identifier but 2X is not. Use underscore characters for readability, but remember they can not be the first or last character in an identifier, and they can not appear consecutively. FIRST_NUMBER and TEXT_IO are fine but _OUCH, WRONG_, and OH___MY are illegal. Also, Ada does not distinguish between upper and lower case; the identifiers Harold, HAROLD, harold, and hArOlD are identical in Ada. We will, however, use the convention of writing all user defined identifiers in upper case. Aside from identifiers, the most common symbols in an Ada program are numbers and punctuation. Let's look at numbers. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Ada Data Types ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ One of the most imposing things about Ada is the huge number of data types. Although other languages have integer and floating-point numbers, characters, and Boolean (true/false) data types, Ada goes all out with a vast supermarket of data types, both ordinary and exotic. (Ada is sometimes criticized as a "kitchen sink" language that attempts to be all things to all people.) Since data types will be the topic of my next two columns, we only briefly look at numbers now, mostly just to see how they are written. Like other languages, numbers in Ada are divided into two categories - integers, or whole numbers, and reals, or numbers with a fractional part. You can distinguish between them because reals have a decimal point and integers don't, just like in FORTRAN. 0, 12, -99, 32767 -- integers 0.0, 3.14, -0.025 -- reals Both kinds of numbers can be preceded by a minus sign to indicate that the number is negative or by an optional plus sign if it is positive. Multi-digit numbers of both varieties can be made easier to read by using the underscore character; the number 1000000 is the same as the number 1_000_000. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Based Numbers ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Ada allows you to write numbers in bases other than ten by using a special "based number" notation. The base of the number system is written, followed by a # symbol, the number in question, and another #. For example, 8#32# is a number in base 8 which equals (3 * 8) + (2 * 1) or 26 in base 10. The number 2#1010# is a binary (base 2) number equal to 10 in decimal. Ada lets you use any number system from base 2 to base 16. In bases 11 through 16, Ada employs the "superdigits" A, B, C, D, E, and F to represent the numbers 10 through 15. For instance, the based number 16#1A# equals (1 * 16) + (10 * 1), or 26 in base 10. Based numbers are mostly used in programs that interact very closely with the underlying hardware. This means that the number systems commonly associated with computers - binary, octal (base 8), and hexadecimal (base 16) - will be used most often. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Arithmetic Operators ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Ada has a number of "operators" for performing calculations: The arithmetic operators, +, -, *, and /, are the same as in other languages. There is also a ** operator for exponentiation, an abs operator for taking the absolute value of a number, a rem operator for computing the remainder after division, and a mod operator for modular arithmetic. 2 ** 3 -- equals 8 abs -60 -- equals 60 12 mod -5 -- equals -3 12 rem -5 -- equals 2 The differences between the mod and rem operators are too subtle to explain here. If you are interested, see the Ada Language Reference Manual or ALM (reviewed in this issue of PCFL/PCUG.) Like other languages, numeric expressions can be arbitrarily complicated, and can include variables like FIRST_NUMBER and numeric "literals" like 5 or 29.7. Expressions are evaluated according to the precedence of the operators, which is similar to other languages, and parentheses may be used to change the order of evaluation. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Ada's Strong Typing ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Numeric expressions should only involve one kind of number - integers should be kept with integers and reals with reals. This is because Ada is a "strongly typed" language, or one that does not allow mixing of data types. (In this respect, Ada is like Pascal and unlike C, FORTRAN, and PL/1.) Thus, it is acceptable to write 1 + 2, but (1 + 2.0) is not acceptable because an integer and a real number are mixed. Strong typing has effects throughout Ada. You must be certain that the data type of the expression on the right-hand side of an assignment statement matches the data type of the target variable on the left side: AVG := 2; -- okay since AVG is an integer AVG := 2.0; -- gives an error message As another example, the NEW_LINE command appearing in our first example program may be supplied with an optional "parameter," in parentheses, to indicate how many blank lines are to be printed. The statement NEW_LINE prints one blank line, while NEW_LINE(3) prints three blank lines. Since it would be meaningless to print a fractional number of blank lines, NEW_LINE expects an integer parameter. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Relaxing Strong Typing ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ It is not always possible to live by Ada's strict rules regarding data types. On occasion, you may not be able to avoid adding integers and real numbers. To help out in these times of need, Ada has limited facilities for "type conversion" - changing a value of one type to another type. This is done by writing the value to be converted in parentheses, preceded by the name of the desired type. The following statement converts a floating-point number to type integer, adds the new integer value to two other integers, and assigns the result to an integer variable. AVG := AVG + 15 + integer (30.9); The effect of type conversion, along with other features of numbers in Ada, is demonstrated in the next example. procedure PLAY_WITH_NUMBERS is X: integer; begin -- the first two statements in this program -- demonstrate how different numeric notations -- can be combined in one expression X := 10000 + 10_000; -- X equals 20000 X := 5 + 8#24#; -- X equals 25 -- the next statement demonstrates integer division X := 5 / 2; -- X equals 2 -- now let's see some type conversion X := 2 * integer (2.7); -- X equals 6 end PLAY_WITH_NUMBERS; First, notice that this program does not do any input/output. The lack of I/O eliminates the need for the TEXT_IO facilities that made the last program look so mysterious. This program also includes comments. Recall that comments begin with a double dash and extend to the end of the line. A comment must either occupy an entire line or come at the end of the line. The first two assignments show that Ada does not care how integer numbers are written - you can mix ordinary integers with based numbers and numbers including the underscore character. The third assignment demonstrates that if the quotient of two integers is not an integer, Ada lops off the fractional part to produce an integer result. The opposite happens with type conversion. When you change a real number to an integer, Ada rounds up or down, as indicated. The expression "integer (1.1)" equals 1 while "integer (1.7)" equals 2. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Conclusions ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ The parts of Ada that we met in this installment were not flashy or even that different from other, more familiar languages. They are, however, important building blocks that will act as a foundation for our coming work. The flashier parts of Ada will start appearing in the next issue when we begin our discussion of data types. (A more complex example - the famous Byte magazine prime number benchmark - appears in the "Ada Programs" section of this column.) As always, your questions about Ada and critical comments on these articles are welcome. Send them to the author care of PCFL/PCUG. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ File Name: ÛÛ ada1.txt ÛÛ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ