ADA Notes


TABLE OF CONTENTS

Arrays

An array type can be declared which is an array of arrays:

        type week is array (1..7) of integer;
        type month is array (1..5) of week;
        may : month;
      
in which case we would refer to the second week, seventh day of may as
        may(2)(7);
     

Assignment

The simplest assignment statement has the form

        variable := constant;
      
For instance, we might have
        N := 1;
      
We can also have
        variable := expression;
      
And in a declaration statement, we can include an initialization assignment:
        variable : type := expression;
      
In particular, note the following assignment of a logical variable:
        LOG1 := LOG2 and not LOG3;
      

Note that complex, derived datatypes can be copied wholesale. As long as A, B, and TEMP have the same type, the following code swaps them:

        temp := a;
        a := b;
        b := temp;
      

Attributes

It's best to think of attributes as properties of a type, not of an individual value of that type.

For instance, given that we are working with the type INTEGER, it makes sense to ask what the largest and smallest integers are, the number of bits used to store an integer, the maximum number of characters it takes to print an integer, and so on.

The sort of attributes you can ask for depends on the kind of type - scalar or array, discrete or continuous, enumeration, and so on.

For an array type, such as

        type MYARRAY is array (1..10) of REAL;
      
we can request the following attributes:

Here are some of the things we can ask for the INTEGER type, or for any of its subtypes or for any ENUMERATION type (which the integer essentially is):

For a string, declared, for instance, as

        MYSTRING : STRING(1..80);
      
we essentially regard the name "MYSTRING" as a type. We can ask for the values of:
character := MYSTRING'FIRST;
returns the first character.
character := MYSTRING'LAST;
returns the last character.
integer := MYSTRING'LENGTH;
returns the number of characters in the string.
integer := MYSTRING'SIZE;
returns the number of bits used to represent the string.

The CASE Statement

The CASE statement allows the programmer to select a set of statements to execute, based on the value of a variable which must be of enumeration type.

A set of statements may be selected by specifying a single value of the variable, a range, a set of values (separated by |), or the final choice of "others" representing all values not so far specified.

        case TODAY is

          when MON..THU => 
            Work;
          when FRI | SAT => 
            Work; 
            Party;
          when others => 
            null;
        end case;
      

The CONSTANT Property

A constant is a data item which is given an initial value that cannot be changed. Here are some sample declarations:

        hundred : constant INTEGER := 100;
        SQRT2 : CONSTANT FLOAT := 1.414;
        PI : CONSTANT := 3.14159265;
      
The arithmetic type of PI is not declared, so it is taken as a universal real based on the literal value it is assigned.

The value of a constant can never be changed. An attempt to do so will cause a run time error.

Here is another constant declaration, which declares the type of the variable DISC, and uses a formula rather than a literal for the value:

        procedure roots(a : in REAL; b : in REAL; c : in REAL; 
          root1 : out REAL; root2 : out REAL) is

        disc : constant real := b**2 - 4.0*a*c;

        begin

        end roots;
      

Here, DISC is a "constant" in the sense that it resides in a procedure which has input values of A, B, and C. DISC is evaluated at the time that the procedure itself is "elaborated", and is assigned a "constant" value at that time.

Data Declarations

Simple declarations:

        threats : array(1..10) of integer;
        falling : boolean;
        twenty : constant integer := 20;
        hundred : constant integer := 5*twenty;
        fifty : constant := 50;
      
More complex declarations:
        type weekday_type is (Sunday, Monday, Tuesday, Wednesday, Thursday,
          Friday, Saturday);
        day : weekday_type;

        type quadrant_type is ( front_left, front_right, back_left, back_right);
        onoff lights is array(quadrant_type) of boolean;
      

Enumerated Data

The user can specify the actual internal codes used to represent the literals of the enumeration type, using an enumeration representation clause:

        FOR enumeration_type USE aggregate;
      

For example,

        type SUITS is (Hearts, Clubs, Diamonds, Spades);

        for SUITS use (Hearts=>1, Clubs=>2, Diamonds=>3, Spades=>99);
      
The integer codes must be distinct, and must satisfy any predefined ordering relations for the type.

The EXIT Statement

An EXIT statement can be used to jump out of a plain loop, a FOR loop, or a WHILE loop.

        loop
          n := n+1;
          if n > 44 then
            exit;
          end if;
        end loop;

        ...the EXIT statement jumps here.
      

You can also put a condition on the EXIT statement:

        loop
          n := n+1;
          exit when n > 44;
        end loop;

        ...the EXIT statement jumps here.
      

When loops are nested, an EXIT statement may use a loop label to specify which loop or set of loops is to be escaped:

        harold: loop
          george: loop
            n := n+1;
            exit harold when n > 44;
          end loop george;
        end loop harold;

        ...the EXIT statement jumps here.
      

For completeness, you can also exit a particular loop:

        harold: loop

          george: loop
            n := n+1;
            exit george;
          end loop george;

          ...the EXIT statement jumps here.

        end loop harold;
      

Note that the EXIT statement terminates the loop, not just the particular iteration during which it occurs.

The FOR Statement

The ADA FOR loop carries out one or more statements a given number of times.

        for i in 1..10 loop
          n := n+1;
        end loop;
      
A FOR loop can be traversed in reverse order:
        for i in reverse 1..10 loop
          n := n+1;
        end loop;
      
but (PECULIARITY) you cannot specify an arbitrary increment.

Moreover, apparently, the FOR loop index cannot take on negative values. The following loop will not compile:

        for i in -10..10 loop
          n := n+1;
        end loop;
      

The "in" in the loop declaration is a test for membership. The FOR loop index consists of all the elements of a set. The set need not be a count from 1 to 10. It can be of any enumeration type:

        type color is (VIOLET, INDIGO, BLUE, GREEN, YELLOW, ORANGE, RED);

        i : color;

        for i in VIOLET..RED
          n := n+1;
        end loop;
      

Functions

A typical function might be declared as

        function fred ( I : in INTEGER; X : inout REAL; Z : out CHARACTER) 
        return BOOLEAN;
      

The GOTO Statement

The GOTO statement has the form

        goto LABEL;
      
The goto statement transfers control to the statement following the given label.

For instance, the following code

        for i in 1..N
          if x(i) = 1 then
            goto FOUNDIT;
          end if;
        end loop;

        <> 
      

Input/Output

To print out integers, you will need, in your specification area:

        with text_io; use text_io;
        package int_io is new integer_io(integer);
      

INT_IO is a temporary local name you are making up. INTEGER_IO is the name of a generic package inside of TEXT_IO, which can accept INTEGER (or reasonable variations) arguments for the kind of quantity to be printed.

To print floating point values also, add

        package real_io is new float_io(float);
      
Then, to print stuff, try things like:
        angle : float = 3.14159265;
        iangle : int = 180;

        text_io.put("Angle (radians) = ");
        real_io.put(angle);
        text_io.put(", while rounded angle in degrees is ");
        int_io.put(iangle);
        text_io.new_line;
      

Similarly, for an enumeration data type, try:

        type suits is (HEARTS, CLUBS, DIAMONDS, SPADES);

        package suits_io is new enumeration_io(suits);
      

Now the statements

        mysuit := CLUBS;
        suits_io.put(mysuit);
      
will actually result in the desired output
        CLUBS
      
rather than some sad numeric obfuscation.

The IF Statement

The simplest IF statement:

        if n < 1 then
          n := 1;
        end if;
      

The second simplest IF statement includes an ELSE:

        if n <= 1 then
          n :=1;
        else
          n := n+1;
        end if;
      

Compound IF statements require the ELSE and the (PECULIARITY) misspelled ELSIF statements:

        if a >= 0 then
          c := b / a;
        elsif b /= 0 then
          c := 0;
        else
          c := 1;
        end if;
      

PECULIARITY: "end if" cannot be written as "endif".

Literal Values

Literal values are representations of particular numbers, vectors, strings, or other items.

Array Literals

An array or vector value can be represented by the component values, separated by commas, and delimited by parentheses.

        a := (1, 2, 3);
      
To represent a vector of all zeroes, write:
        a := ( others=>0 );
      
A single vector entry is a scalar:
        a(1) := 7;
      

A matrix must be thought of as an array of rows. Thus, a matrix value can be represented as:

        a := ( (1,2,3), (4,5,6), (7,8,9) );
      
You may indicate the individual rows in a literal, in which case the rows may be listed in any order:
        a := ( 1=>(1,2,3), 3=>(7,8,9), 2=>(4,5,6) );
      
or you may list rows and columns. Here is one possibility:
        a := ( 1=> ( 1=>1, 2=>2, 3=>3 ), 
               2=> ( 1=>4, 2=>5, 3=>6 ), 
               3=> ( 1=>7, 2=>8, 3=>9 ) );
      
To represent a matrix all of whose entries are 17, write
        a := ( others => ( others => 17 ) );
      
A single matrix entry is a scalar:
        a(1,2) := 17;
      

Boolean Literals

The tokens TRUE and FALSE are reserved words, and are the two legal values for a BOOLEAN quantity.

Character Literals

The alphabet is 'a' through 'z', and so on. Other printable characters are also themselves, in single quotes. Non-printable characters have special names.

        char1 := 'a';
        char2 := ASCII.ESC;
      

Enumeration Literals

The values assignable to an enumeration variable are exactly those listed in the type statement. Thus, if the type statement is

        type suits is ( Hearts, Clubs, Diamonds, Spades);
      
and the variable MYSUIT is declared as
        mysuit : suit;
      
then a legal assignment of MYSUIT is
        mysuit := Clubs;
      

If an enumeration type SUITS is declared in package FRED, then you can use that enumeration type in another package, such as GEORGE, by prefixing the package name to the enumeration type. For instance, you might declare

        mysuit := FRED.SUIT;
      
and assign
        mysuit := FRED.CLUBS;
      

Fixed and Floating Point Literals

Fixed point and floating point literals are called "decimal literals", and require a decimal point. They may include an exponent, with the marker "E" written in upper or lower case. Underscores may be inserted to group digits for readability:

        12.0, 0.0, 0.456, 3.14159_26, 1.34E-12, 1.0E+6.  
      

Integer Literals

At least for integer literals, there's not much to say. Seventeen is just plain old '17'. Note, however, that you can specify a base, so that #2#101# means 101 base 2, that is, '5'.

Record Literals

A "record" is a datatype with "parts". Presumably, we know how to specify literal values for each of the parts, so the main question is how we put those values together to specify a literal record value.

Supposing that we have defined:

        type FREDTYPE is record
          temp : FLOAT;
          age : INTEGER;
          name : STRING(20);
        end record;

        FRED : FREDTYPE;
      
then a literal value for FRED could be specified as:
      FRED := ( 98.6, 23, "Fred Smith" );
      
where order is important, or
        FRED := ( name => "Fred Smith", age=>23, temp=>98.6 );
      
where order is not important, since the record component names are used as keywords to label each value.

String Literals

A string literal is simply text delimited by double quotes. If a double quote should actually appear as part of the string, then it must be doubled in the literal.

        s1 := "alligator";
        s2 := "Contains a "" double quote!";
        s3 := "c";
        s4 := "";       -- A null string is allowed.
      

A string must fit on one line, or be patched together from smaller strings using the "&" operator:

      e := "A really....long " &
        "string that goes over two lines."
      

Unprintable characters have symbolic names defined in the package ASCII:

        f := "String that includes the " & ASCII.ACK & " control character."
      

ADA has a very stupid attitude toward strings. Strings can not have individual elements altered. ALL elements must be set. And you can't do the following:

        fred : string(80);
        fred := "Hello!";
      
because you are saying that an 80 character string equals a 6 character string. You have to do something more complicated and unnatural. If you are lucky enought that FRED is a constant, then you can get away with:
        fred : string(1:6) := "Hello!";
      
or
        fred : constant string := "Hello!";
      
Or, if only a few characters of fred have to be set:
        fred := ( 1..6 => '*', others=> ' ');
      
But in general, the handling of strings in ADA is a real LOONEY TUNE!

Loops

The simplest loop has no control:

        loop
          n := n+1;
        end loop;
      

An EXIT statement might be very useful here:

        loop
          n := n+1;
          if n > 44 then
            exit;
          end if;
        end loop;
      

You can also put a condition on the EXIT statement:

        loop
          n := n+1;
          exit when n > 44;
        end loop;
      

A loop can be labeled:

        harold: loop
          n := n+1;
        end loop harold;
      

When loops are nested, an EXIT statement may use a loop label to specify which loop or set of loops is to be escaped:

        harold: loop
          george: loop
            n := n+1;
            exit harold when n > 44;
          end loop george;
        end loop harold;
      

Names

Variables, procedures, functions, and other entities must be named. Names must begin with a letter, and may contain letters, numbers, and underscores.

Names are not case sensitive.

The NULL Statement

The NULL statement can be used as a filler for otherwise-empty IF/THEN/ELSE statements, CASE statements, package and procedure bodies, and so on, where it's actually illegal, or merely confusing, to leave a null body.

        if n < 1 then
          null;
        else
          n := n+1;
        end if;
      

Operators

Logical Operators

All data types have the logical equality and nonequality operators:

        if n = 1 then...

        if n /= 1 then...
      

Numeric or enumeration or character or string or boolean data has ordering relations as well:

        if n >  1 then...
        if n >= 1 then...
        if n <  1 then...
        if n <= 1 then...
      

A variable that is of enumeration type can have the membership operator:

        if n in a then
        if n not in a then
      

A variable of logical type can be used in Boolean operations:

        if a and b then
        if a or b then
        if a xor b then
        if not a then
      

There are also "SHORT CIRCUIT" forms:

if a AND THEN b then
Check condition A. Only if A is true should you then go on and check condition B.
if a OR ELSE b then
Check condition A. Only if A is false should you then go on and check condition B.
You might use such a form to avoid dividing by zero:
        if x /= 0.0 AND THEN sin ( 1.0 / x ) == 1.0 then
      

String Operators

        string := string1 & string2   -- String concatenation.
        string :=   char1 & string1   -- Prefix string with given character.
        string := string1 & char1     -- Append character to string.
        string :=   char1 & char2     -- Create string from characters.
      

Array Operators

        array := array1 & array2;  <-- concatenate two arrays.
        array := entry1 & array1;  <-- preprend an entry to an array.
        array := array1 & entry1;  <-- append an entry to an array.
        array := entry1 & entry2;  <-- construct an array from two entries.
      

Arithmetic Operators

        a+b;
        a-b;
         -b;
        a*b;
        a/b;
        a**b;     b must be an integer.
        a mod b;  has the sign of b and absolute value less than abs(b);
                  a and b must be integers.
        a rem b;  has the sign of a and absolute value less than abs(b);
                  a and b must be integers.
        abs(a);
      

PECULIARITY: No square root function!

Packages

Consider the following package:

        package fred is
          procedure bob;
        end fred;

        package body fred is
          procedure bob is
          begin
          end bob;
        begin
          text_io.put("Hi there mom!");
        end fred;
      

The "executable" code portion of fred will actually be invoked each time that a package or procedure containg the statement with fred is elaborated. So you can use this chunk to do initializations, to call other procedures, print out titles, whatever you wish.

Representation Clauses

Representation clauses specify how the types of the language are to be mapped onto the underlying machine.

A representation clause has the form:

        representation_clause ::= type_representation_clause OR address_clause
      

A type representation clause has the form:

        type_representation_clause ::= length_clause OR
          enumeration_representation_clause OR record_representation_clause
      

A length clause specifies an amount of storage associated with a type:

        length_clause ::= FOR attribute USE simple_expression;
      
The only allowed attributes are SIZE, STORAGE_SIZE and SMALL, prefixed by the name of the type or subtype.

An enumeration representation clause has the form:

        FOR type_simple_name USE aggregate;
      
The aggregate used to specify this mapping is written as a one dimensional aggregate, for which the index subtype is the enumeration type.

A record representation clause has the form:

        record_representation_clause ::=
          FOR type_simple_name USE
            RECORD [alignment_clause]
              {component_clause}
            END RECORD;
      

An address clause specifies a required address in storage for an entity:

        address_clause ::= FOR simple_name USE AT simple_expression;
      
The expression given after AT must be of the type ADDRESS defined in the package SYSTEM, and SYSTEM must be named by a WITH clause.

A representation clause is used to impose certain characteristics of the mapping of an entity onto the underlying machine, pragmas can be used to provide an implementation with criteria for its selection of such a mapping. In particular, the pragma PACK specifies that storage minimization should be the main criterion when selecting the representation of a record or array type:

        pragma PACK(type_simple_name);
      

Reserved Words

A reserved word must not be used as an identifier. Note that when a reserved word is used for an identifier name, the compiler may not be able to clearly report the error.

        abort
        abs
        accept
        access
        all
        and
        array
        at       <-- used in certain representation clauses.
        begin
        body
        case
        constant
        declare
        delay
        delta
        digits
        do
        else
        elsif
        end
        entry
        exception
        exit
        for
        function
        generic
        goto          <-- Cannot be spelled "GO TO" with a space!
        if
        in
        is
        limited
        loop
        mod
        new
        not
        null
        of
        or
        others
        out
        package
        pragma
        private
        procedure
        raise
        range
        record
        rem
        renames
        return
        reverse
        select
        separate
        subtype
        task
        terminate
        then
        type
        use
        when
        while
        with
        xor
      

The RETURN Statement

A RETURN statement completes the execution of a function or procedure (or ACCEPT statement). A RETURN statement in a procedure must not include an expression, and hence simply has the form:

        return;
      
A RETURN statement in a function must include an expression, specifying the value computed by the function, for instance:
        return x+y;
      

Statement Labels

Statements may be labeled. It is possible for a labeled statement to consist of a label and nothing else. More typically, a labeled statement consists of a label and an associated executable statement. A label is an identifier enclosed in double angle brackets.

A labeled statement may be the target of an EXIT or GOTO statement.

        <>
          if A(I) < ELEMENT then
            if LEFT(I) /= 0 then
              I := LEFT(I);
              goto COMPARE;
            end if;
 
            ...more statements...

          end if;
      

Types

  • access
  • array
  • boolean The BOOLEAN type is an example of the ENUMERATION type. The two legal values are FALSE and TRUE.
  • character The CHARACTER type can hold the value of any single ASCII character. CHARACTER is an example of the ENUMERATION type.
  • enumeration The legal values of an ENUMERATION type are specified in the declaration. For instance type suit_type is ( Hearts, Clubs, Diamonds, Spades); mysuit : suit_type;
  • float
  • integer
  • private
  • record
  • strings The STRING type is defined as an array of characters. A string declaration may be: mystring : string(1..10); yourstring : constant string := "No size declaration!"; Special string operators include "&", which concatenates.
  • Type Conversion

    The names of the predefined types can be used, in most cases, to convert data from other types, if it is a sensible operation. Thus,

            x : float;
            i : integer;
    
            x := 3.14159265;
            i := integer(x);
          
    Note, in particular, that the INTEGER conversion operator rounds to nearest, rather than truncating to -infinity or to zero.

    The WHILE Statement

    A WHILE loop is easy to fashion:

            while angle < 0.0 loop
              angle := angle + 360.0
            end loop;
          
    If the test condition holds, then the body of the loop will be executed. If the "bottom" of the loop is reached, that is, the end loop, then execution will return to the WHILE, where the condition will be checked again, for a possible repeat of the loop.

    The WITH and USE Statements

    If ADA routines in a file FILE1 refer to routines or datatypes or other quantities defined in file FILE2, then in the specifications part of the program there should be at least the statement:

            with file2;
          
    In that case, when a quantity from FILE2 is referenced in FILE1, its name must be preceded by "FILE2.". However, (assuming there will be no ambiguity) this prefix can be dropped by adding the USE statement:
            with file2; use file2;
          

    You can return to the HTML web page.


    Last revised on 12 September 2005.