[Next] [Up] [Previous]

Type Declaration

This section deals primarily with non-executable statements. These statements are processed during compilation to determine how the rest of the program is to operate, but do not specify an action to be done when the program is running. Non-executable statements may not have statement numbers, except for the FORMAT statement, which, being concerned with input/output, not type declaration, is not discussed in this section.

It may also be noted that, as expressions are only permitted to appear in type declaration statements under various restrictions, some operator symbols (such as * and /) have roles in the syntax of type declaration statements which are normally reserved for separators.

A normal type declaration statement has the form

       type  variable,variable,...

where each variable may optionally be followed by a subscript list indicating that it is an array, and by an initial value or a series of initial values within slashes (/).

This is the same appearance as in FORTRAN.

Expressions which can be evaluated before the program starts (that is, expressions not containing any variables or user-defined functions) in parentheses preceded by a percent sign may be used whenever a numeric constant is required, as array dimensions:

       REAL X(%(4*5))

or even as line numbers!

In the initialization portion of a type declaration statement, the percent sign is not required. For example, a REAL array could be initialized to pi with the following statement:

       REAL X(20)/20*%(4*_ATN(1))/

The asterisk (*) before the percent sign is a repeat specification, not a multiplication sign.

In addition to allowing the use of constant expressions where the use of a 'naked' expression might confuse the compiler, several statements allow the construct %(...) to enclose a non-constant expression (or one containing dummy variables) to allow it to be placed within an area which uses symbols found in expressions (such as parentheses, or the asterisk as above) for other syntactic purposes. The ALIAS statement, discussed below, makes use of that construct extensively.

Normally, arrays are stored in memory with the first subscript varying the least rapidly. This is the opposite of the order usually employed in FORTRAN. However, row-major ordering can be specified by placing a period between the variable name and the subscript list. Thus, the statement

     REAL A(2,3),B.(2,3)

places the elements of A in memory in the order

A(1,1),A(1,2),A(1,3),A(2,1),A(2,2),A(2,3)

but the elements of B in memory in the order

B(1,1),B(2,1),B(1,2),B(2,2),B(1,3),B(2,3).

As this illustrates, each array subscript begins with the value 1. This default can be overriden:

       REAL A(0:5)

creates a linear array with elements A(0) to A(5). This syntax, instead of A(%(_R(0:5))), is possible because array subscripts may only be separated by commas or stronger separators, not weaker ones. (However, A(%(_R(0:5))), and, indeed, A(_R(0:5)), are also allowed, and mean the same thing.)

It is also possible to create an array with a subscript of a denumerable type other than one of the integer types by naming that type in parentheses; for example,

       REAL Y((CHAR*1)'A':'Z')

causes Y to be an array with a position for every character whose internal code goes from that for A to that for Z, inclusive. (If your computer uses ASCII, this will indeed be a 26 element array.)

If the typename is used alone, the array will have a position corresponding to every possible value in that type.

Using sets, other than contiguous simple ranges, to indicate subscripts that may have scattered possible values may be permitted, but will be inefficient. However,

       REAL A(0:10:2)

indicating that there is an element of A corresponding only to every even number from 0 to 10 inclusive is permitted.

This may also be done with non-numeric subscripts; the last item, indicating the increment, will still be a number in that case.

If the type specification is preceded by a period, then it must be followed by a single value for the subscript, and that value must be a power of two, and in that case the type need no longer be denumerable. An example of that kind of declaration would be:

       CHARACTER*10 LBB(.(CHARACTER*25)4096)

Here, what is being declared is a 4,096 element hash table whose elements are strings ten characters long, indexed by strings twenty-five characters long. An array can be a hash table along one dimension, and a conventional array along another dimension, and, as well, if memory permits, it can be a hash table along more than one dimension. When this is done, the hash table entries point to entire rows, columns, or planes of the array; that is, there is only one hash table to find items along one subscript, independent of the values in the other subscripts.

Note that an array so declared, if passed to a subprogram, will appear to have the standard subscript type of numeric subscripts increasing by one, unless also declared the same way in the subprogram. Except in EASY mode, when an array of an ordinary type is passed to a subprogram, all that subprogram receives is the starting address of the array; declarations within the subprogram must be correct for it to be looking at the right data. Even when array bounds checking is enabled, that checking is relative to bounds declared in the subprogram, not necessarily the actual bounds of the array as determined in the program that produced it.

The available types, which are also names of statements, are

     REAL           (R, SINGLE_PRECISION, SINGLE, SNGL, SP)
     DOUBLE         (D, DBL, DOUBLE, DOUBLE_PRECISION, DP)
     QUAD           (Q, QUAD, QUADRUPLE, QUADRUPLE_PRECISION, QP)

     COMPLEX        (C, CMPLX, SNGL_COMPLEX, SINGLE_COMPLEX, SINGLE_PRECISION_COMPLEX, SPC)
     DCX            (CD, DBL_CMPLX, DBL_COMPLEX, DOUBLE_COMPLEX, DOUBLE_PRECISION_COMPLEX, DPC)
     QCX            (CQ, QUAD_CMPLX, QUAD_COMPLEX, QUADRUPLE_COMPLEX, QUADRUPLE_PRECISION_COMPLEX, QPC)

     QUATERNION     (QT, SNGL_QUATERNION, SINGLE_QUATERNION, SINGLE_PRECISION_QUATERNION, SPQ)
     DQT            (QD, DBL_QUATERNION, DOUBLE_QUATERNION, DOUBLE_PRECISION_QUATERNION, DPQ)
     QQT            (QQ, QUAD_QUATERNION, QUADRUPLE_QUATERNION, QUADRUPLE_PRECISION_QUATERNION, QPQ)

     BYTE           (B)
     UNH            (UH, UNSIGNED_HALFWORD)
     UNSIGNED       (U)
     UNL            (UL, UNSIGNED_LONG, UNSIGNED_LONG_INTEGER, LONG_UNSIGNED)

     SBY            (SB, SIGNED_BYTE)
     HALF           (H, HALFWORD)
     INT            (I, INTEGER)
     LONG           (LI, LONG_INTEGER)

     DECIMAL        (D, BCD, PACKED_DECIMAL)
     NUMERIC        (N, UNPACKED_DECIMAL)

     LOG            (L, LOGICAL, BOOLEAN, BOOL)

     CHAR           (C, CHARACTER)

     FIXED_STRING   (FS)

     STRING         (S)
     MUTABLE        (M)

     TVAL           (T, TYPE_VALUE)

     VLIST

As well, there are compound types; types which involve other types:

     SET
     GROUP
     LIST
     PATH
     SUBPROGRAM

and one type which may be either simple or compound:

     ADDRESS        (A)

A variable of type CHAR reserves space for exactly one printing character. 'Higher precision' character type constants can be specified by adding a length specification in this form:

       CHARACTER*80 RECORD

causes the variable RECORD to have room for 80 characters. RECORD will always have length 80, unlike a STRING, which can change its length. Where a shorter string or character expression is assigned to RECORD, it will be padded on the right. The blank is the default padding character, but this can be reset.

In addition to type declaration statements, which must appear at the beginning of a program (before any executable statements), when a type name appears as a statement keyword without any text following, it indicates that that type is to be the default interpretation for constants of the appropriate type in the program until further notice. Such statements may appear anywhere in the program.

DECIMAL, HALFWORD, LONG, NUMERIC and INTEGER only apply to numeric constants without decimal points; REAL, DOUBLE_PRECISION, and QUADRUPLE_PRECISION to numeric constants with decimal points. STRING and FIXED_STRING (see below) apply to text strings in double quotes. MUTABLE is allowed, and can be in effect at the same time as any of the other specifications: it applies only to the arguments of undeclared functions, whereas the other declarations may also apply at other points where context is weak. (Refer to the precise description of implicit type conversion rules for further detail.)

While the internal form of DECIMAL and NUMERIC quantities is guaranteed, and these types may be unavailable in implementations on machines on which these types are not useful, it is not guaranteed that INTEGER constants will be implemented in binary form. Instead, the INTEGER type is to use whatever internal representation is most efficient for integer calculation on the target machine, which may, for example, be decimal on a machine internally wired only for decimal arithmetic.

In general, EXALT data items should have the same format as FORTRAN data items with the same type. As far as possible, EXALT should be implemented so as to support externally compiled procedures with an upwards-compatible extension of the FORTRAN IV calling sequence. Since CHARACTER variables are treated as having no length information, this provides compatiblity with such variables in extended versions of FORTRAN IV. STRING variables, which do have intrinsic length information, are expected to be implemented in a storage pool, like strings in many BASIC interpreters. Since CHARACTER variables in FORTRAN 77 do have intrinsic length, they may be implemented in a manner suitable for EXALT STRING variables, or they may be allocated fixed storage while still posessing intrinsic length. The type FIXED_STRING would, in that case, be made to correspond with CHARACTER within FORTRAN 77, and installation-specific documentation would need to indicate this to programmers.

The fact that arrays in EXALT are stored with the last subscript varying the most quickly is a more serious incompatibility with all versions of FORTRAN, and must be kept in mind when writing applications to call or be called by FORTRAN programs.

The types INT, UNSIGNED, REAL, COMPLEX, and QUATERNION can also have length specifications added. This may cause them to indicate that variables are to belong to related types: thus, these type names, in addition to referring to a specific type, also act as general names for a class of types. Thus, on typical 8-bit byte oriented architectures, the following equivalencies might exist:

REAL          REAL*4                     
DOUBLE        REAL*8
QUAD          REAL*16

COMPLEX       COMPLEX*8
DCX           COMPLEX*16
QCX           COMPLEX*32

QUATERNION    QUATERNION*16
DQT           QUATERNION*32
QQT           QUATERNION*64

BYTE          UNSIGNED*1
UNH           UNSIGNED*2
UNSIGNED      UNSIGNED*4
UNL           UNSIGNED*8

SBY           INT*1
HALF          INT*2
INT           INT*4
LONG          INT*8

However, as this refers to the actual length occupied by variables, this is system-dependent.

Note that the default length for REAL and INTEGER numbers is the same. This is in fact required by some FORTRAN standards. It is NOT required by the definition of the EXALT language, and may not be assumed by programmers wishing to write system-independent code. On a machine with a 24-bit word length, for example, the default length of a floating-point value may be 48 bits, while the default length for an integer may be 24 bits.

In addition, length specifications may be allowed with DECIMAL and NUMERIC types; if so, it is possible that they will be almost as flexible as CHARACTER length specifications; for example, DECIMAL*1 through DECIMAL*8 might all refer to distinct types, for eight possibilities.

If a length specification is permitted with STRING variables, it refers to the number of character positions of memory used to indicate the length of the string; a system could allow STRING*1, STRING*2, and STRING*4, although most systems will allow only one STRING type.

Alternate forms of the length specification are also available in EXALT.

       CHARACTER*10/12 W

specifies that W contains ten 12-bit characters. Systems with 24-bit word lengths might support 6, 8, and 12 bit long characters, and systems with 36-bit word lengths might support 6 and 9 bit long characters with machine instructions.

       REAL.10 X

specifies that X is a real variable with at least 10 decimal digits of precision, if possible: that is, X belongs to whichever one of the types REAL, DOUBLE_PRECISION, or QUADRUPLE_PRECISION is the lowest-precision type to have at least 10 digits of significance. Note that this form of length specification is useful for writing system-independent code.

       INTEGER.(-100:100) I

specifies that I belongs to whichever one of the types SIGNED_BYTE, HALFWORD, INTEGER, or LONG that has the capability of representing integer values ranging from -100 to 100. (The types BYTE, UNSIGNED_HALFWORD, UNSIGNED, and UNSIGNED_LONG would also be considered had the range not included negative numbers.)

This is another place where expressions enclosed in parentheses preceded by a percent sign may be used.

In programs, numbers undergo operations with other numbers, producing numeric results. There are many different 'types' in EXALT for numbers, but all represent numbers. To avoid the programmer having to explicitly specify many type conversions, EXALT automatically performs necessary type conversions within programs.

Each numeric type has three priority levels, an 'order' level, an 'implementation' level, and a 'length' level, as follows:

NUMERIC      2  1  3               REAL         3  3 10
BCD          2  2  3               DOUBLE       3  3 11
                                   QUAD         3  3 12
BYTE         1  3  1               
UNH          1  3  2               COMPLEX      4  3 10
UNSIGNED     1  3  3               DCX          4  3 11
UNL          1  3  4               QCX          4  3 12

SBY          2  3  1               QUATERNION   5  3 10
HALFWORD     2  3  2               DQT          5  3 11
INTEGER      2  3  3               QQT          5  3 12
LONG         2  3  4

For a two-argument numeric operator, applicable to all types, the result is in the first type in the list (running down the columns) which is greater than or equal to the types of both arguments in all three priority levels. Both arguments are converted to that type before the operation takes place, except where this is not useful (i.e. a real number may be taken to an integer power, or an integer root taken of a real number).

For a function with some restriction on the type of its arguments, the given argument is converted to the first type in the list which is acceptable and which exceeds that argument in all three priority areas.

Note that loss of significance in conversion from integer to real types is deliberately ignored. This is partly because their relative precisions are implementation-dependent, and partly because of the way variables tend to be used: conversion to any floating-point type, even one of high precision, will destroy the assurance of absolute accuracy given by integer numbers. Note also that the length priority of 3 given to BCD and NUMERIC types allows for fixed-point overflow in some cases, again to avoid implementation dependency. Note, however, that if an integer type number and a high-precision real number are the two arguments of an operand, conversion is directly to the high-precision real type, so that all precision of the integer number that the real type can represent is retained: all this restriction means is that integer numbers, however high their precision, cannot force the use of a higher-precision form of floating-point number than is already in use.


[Next] [Up] [Previous]