The Programming Language EFL Stuart I. Feldman Bell Laboratories Murray Hill, New Jersey 07974 _A_B_S_T_R_A_C_T EFL is a clean, general purpose computer language intended to encourage portable program- ming. It has a uniform and readable syntax and good data and control flow structuring. EFL pro- grams can be translated into efficient Fortran code, so the EFL programmer can take advantage of the ubiquity of Fortran, the valuable libraries of software written in that language, and the porta- bility that comes with the use of a standardized language, without suffering from Fortran's many failings as a language. It is especially useful for numeric programs. The EFL language permits the programmer to express complicated ideas in a comprehensible way, while permitting access to the power of the Fortran environment. EFL can be viewed as a descendant of B. W. Kernighan's Ratfor [1]; the name originally stood for `Extended For- tran Language'. The current version of the EFL compiler is written in portable C. _1. _I_N_T_R_O_D_U_C_T_I_O_N _1._1. _P_u_r_p_o_s_e EFL is a clean, general purpose computer language intended to encourage portable programming. It has a uni- form and readable syntax and good data and control flow structuring. EFL programs can be translated into efficient Fortran code, so the EFL programmer can take advantage of - 2 - the ubiquity of Fortran, the valuable libraries of software written in that language, and the portability that comes with the use of a standardized language, without suffering from Fortran's many failings as a language. It is espe- cially useful for numeric programs. Thus, the EFL language permits the programmer to express complicated ideas in a comprehensible way, while permitting access to the power of the Fortran environment. _1._2. _H_i_s_t_o_r_y EFL can be viewed as a descendant of B. W. Kernighan's Ratfor [1]; the name originally stood for `Extended Fortran Language'. A. D. Hall designed the initial version of the language and wrote a preliminary version of a compiler. I extended and modified the language and wrote a full compiler (in C) for it. The current compiler is much more than a simple preprocessor: it attempts to diagnose all syntax errors, to provide readable Fortran output, and to avoid a number of niggling restrictions. To achieve this goal, a sizable two-pass translator is needed. _1._3. _N_o_t_a_t_i_o_n In examples and syntax specifications, _b_o_l_d_f_a_c_e type is used to indicate literal words and punctuation, such as while. Words in _i_t_a_l_i_c type indicate an item in a category, such as an _e_x_p_r_e_s_s_i_o_n. A construct surrounded by double brackets represents a list of one or more of those items, - 3 - separated by commas. Thus, the notation _i_t_e_m . could refer to any of the following: _i_t_e_m _i_t_e_m, _i_t_e_m _i_t_e_m, _i_t_e_m, _i_t_e_m The reader should have a fair degree of familiarity with some procedural language. There will be occasional references to Ratfor and to Fortran which may be ignored if the reader is unfamiliar with those languages. - 4 - _2. _L_E_X_I_C_A_L _F_O_R_M _2._1. _C_h_a_r_a_c_t_e_r _S_e_t The following characters are legal in an EFL program: _l_e_t_t_e_r_s a b c d e f g h i j k l m n o p q r s t u v w x y z _d_i_g_i_t_s 0 1 2 3 4 5 6 7 8 9 _w_h_i_t_e _s_p_a_c_e _b_l_a_n_k _t_a_b _q_u_o_t_e_s ' " _s_h_a_r_p # _c_o_n_t_i_n_u_a_t_i_o_n _ _b_r_a_c_e_s { } _p_a_r_e_n_t_h_e_s_e_s ( ) _o_t_h_e_r , ; : . + - * / = < > & ~ | $ Letter case (upper or lower) is ignored except within strings, so `a' and `A' are treated as the same character. All of the examples below are printed in lower case. An exclamation mark (`!') may be used in place of a tilde (`~'). Square brackets (`[' and `]') may be used in place of braces (`{' and `}'). _2._2. _L_i_n_e_s EFL is a line-oriented language. Except in special cases (discussed below), the end of a line marks the end of a token and the end of a statement. The trailing portion of a line may be used for a comment. There is a mechanism for diverting input from one source file to another, so a single line in the program may be replaced by a number of lines from the other file. Diagnostic messages are labeled with the line number of the file on which they are detected. - 5 - _2._2._1. _W_h_i_t_e _S_p_a_c_e Outside of a character string or comment, any sequence of one or more spaces or tab characters acts as a single space. Such a space terminates a token. _2._2._2. _C_o_m_m_e_n_t_s A comment may appear at the end of any line. It is introduced by a sharp (#) character, and continues to the end of the line. (A sharp inside of a quoted string does not mark a comment.) The sharp and succeeding characters on the line are discarded. A blank line is also a comment. Comments have no effect on execution. _2._2._3. _I_n_c_l_u_d_e _F_i_l_e_s It is possible to insert the contents of a file at a point in the source text, by referencing it in a line like _i_n_c_l_u_d_e _j_o_e No statement or comment may follow an _i_n_c_l_u_d_e on a line. In effect, the _i_n_c_l_u_d_e line is replaced by the lines in the named file, but diagnostics refer to the line number in the included file. Includes may be nested at least ten deep. _2._2._4. _C_o_n_t_i_n_u_a_t_i_o_n Lines may be continued explicitly by using the under- score (_) character. If the last character of a line (after comments and trailing white space have been stripped) is an - 6 - underscore, the end of line and the initial blanks on the next line are ignored. Underscores are ignored in other contexts (except inside of quoted strings). Thus 1_000_000_ 000 equals 10789999. There are also rules for continuing lines automati- cally: the end of line is ignored whenever it is obvious that the statement is not complete. To be specific, a statement is continued if the last token on a line is an operator, comma, left brace, or left parenthesis. (A state- ment is not continued just because of unbalanced braces or parentheses.) Some compound statements are also continued automatically; these points are noted in the sections on executable statements. _2._2._5. _M_u_l_t_i_p_l_e _S_t_a_t_e_m_e_n_t_s _o_n _a _L_i_n_e A semicolon terminates the current statement. Thus, it is possible to write more than one statement on a line. A line consisting only of a semicolon, or a semicolon follow- ing a semicolon, forms a null statement. _2._3. _T_o_k_e_n_s A program is made up of a sequence of tokens. Each token is a sequence of characters. A blank terminates any token other than a quoted string. End of line also ter- minates a token unless explicit continuation (see above) is - 7 - signaled by an underscore. _2._3._1. _I_d_e_n_t_i_f_i_e_r_s An identifier is a letter or a letter followed by letters or digits. The following is a list of the reserved words that have special meaning in EFL. They will be dis- cussed later. _a_r_r_a_y _e_x_i_t _p_r_e_c_i_s_i_o_n _a_u_t_o_m_a_t_i_c _e_x_t_e_r_n_a_l _p_r_o_c_e_d_u_r_e _b_r_e_a_k _f_a_l_s_e _r_e_a_d _c_a_l_l _f_i_e_l_d _r_e_a_d_b_i_n _c_a_s_e _f_o_r _r_e_a_l _c_h_a_r_a_c_t_e_r _f_u_n_c_t_i_o_n _r_e_p_e_a_t _c_o_m_m_o_n _g_o _r_e_t_u_r_n _c_o_m_p_l_e_x _g_o_t_o _s_e_l_e_c_t _c_o_n_t_i_n_u_e _i_f _s_h_o_r_t _d_e_b_u_g _i_m_p_l_i_c_i_t _s_i_z_e_o_f _d_e_f_a_u_l_t _i_n_c_l_u_d_e _s_t_a_t_i_c _d_e_f_i_n_e _i_n_i_t_i_a_l _s_t_r_u_c_t _d_i_m_e_n_s_i_o_n _i_n_t_e_g_e_r _s_u_b_r_o_u_t_i_n_e _d_o _i_n_t_e_r_n_a_l _t_r_u_e _d_o_u_b_l_e _l_e_n_g_t_h_o_f _u_n_t_i_l _d_o_u_b_l_e_p_r_e_c_i_s_i_o_n _l_o_g_i_c_a_l _v_a_l_u_e _e_l_s_e _l_o_n_g _w_h_i_l_e _e_n_d _n_e_x_t _w_r_i_t_e _e_q_u_i_v_a_l_e_n_c_e _o_p_t_i_o_n _w_r_i_t_e_b_i_n The use of these words is discussed below. These words may not be used for any other purpose. _2._3._2. _S_t_r_i_n_g_s A character string is a sequence of characters sur- rounded by quotation marks. If the string is bounded by single-quote marks ( ' ), it may contain double quote marks ( " ), and vice versa. A quoted string may not be broken across a line boundary. - 8 - '_h_e_l_l_o _t_h_e_r_e' "_a_i_n'_t _m_i_s_b_e_h_a_v_i_n'" _2._3._3. _I_n_t_e_g_e_r _C_o_n_s_t_a_n_t_s An integer constant is a sequence of one or more digits. _0 _5_7 _1_2_3_4_5_6 _2._3._4. _F_l_o_a_t_i_n_g _P_o_i_n_t _C_o_n_s_t_a_n_t_s A floating point constant contains a dot and/or an exponent field. An _e_x_p_o_n_e_n_t _f_i_e_l_d is a letter _d or _e fol- lowed by an optionally signed integer constant. If _I and _J are integer constants and _E is an exponent field, then a floating constant has one of the following forms: ._I _I. _I._J _I_E _I._E ._I_E _I._J_E _2._3._5. _P_u_n_c_t_u_a_t_i_o_n Certain characters are used to group or separate objects in the language. These are parentheses ( ) braces { } comma , - 9 - semicolon ; colon : end-of-line The end-of-line is a token (statement separator) when the line is neither blank nor continued. _2._3._6. _O_p_e_r_a_t_o_r_s The EFL operators are written as sequences of one or more non-alphanumeric characters. + - * / ** < <= > >= == ~= && || & | += -= /= **= &&= ||= &= |= -> . $ A dot (`.') is an operator when it qualifies a structure element name, but not when it acts as a decimal point in a numeric constant. There is a special mode (see the Atavisms section) in which some of the operators may be represented by a string consisting of a dot, an identifier, and a dot (_e._g., .lt. ). _2._4. _M_a_c_r_o_s EFL has a simple macro substitution facility. An iden- tifier may be defined to be equal to a string of tokens; whenever that name appears as a token in the program, the string replaces it. A macro name is given a value in a _d_e_f_i_n_e statement like - 10 - define count n += 1 Any time the name _c_o_u_n_t appears in the program, it is replaced by the statement _n += _1 A _d_e_f_i_n_e statement must appear alone on a line; the form is define _n_a_m_e _r_e_s_t-_o_f-_l_i_n_e Trailing comments are part of the string. _3. _P_R_O_G_R_A_M _F_O_R_M _3._1. _F_i_l_e_s A _f_i_l_e is a sequence of lines. A file is compiled as a single unit. It may contain one or more procedures. Declarations and options that appear outside of a procedure affect the succeeding procedures on that file. _3._2. _P_r_o_c_e_d_u_r_e_s Procedures are the largest grouping of statements in EFL. Each procedure has a name by which it is invoked. (The first procedure invoked during execution, known as the _m_a_i_n procedure, has the null name.) Procedure calls and argument passing are discussed in Section 8. _3._3. _B_l_o_c_k_s Statements may be formed into groups inside of a pro- cedure. To describe the scope of names, it is convenient to - 11 - introduce the ideas of _b_l_o_c_k and of _n_e_s_t_i_n_g _l_e_v_e_l. The beginning of a program file is at nesting level zero. Any options, macro definitions, or variable declarations there are also at level zero. The text immediately following a _p_r_o_c_e_d_u_r_e statement is at level 1. After the declarations, a left brace marks the beginning of a new block and increases the nesting level by 1; a right brace drops the level by 1. (Braces inside declarations do not mark blocks.) (See Section 7.2). An _e_n_d statement marks the end of the procedure, level 1, and the return to level 0. A name (variable or macro) that is defined at level _k is defined throughout that block and in all deeper nested lev- els in which that name is not redefined or redeclared. Thus, a procedure might look like the following: # _b_l_o_c_k _0 _p_r_o_c_e_d_u_r_e _g_e_o_r_g_e _r_e_a_l _x _x = _2 . . . _i_f(_x > _2) { # _n_e_w _b_l_o_c_k _i_n_t_e_g_e_r _x # _a _d_i_f_f_e_r_e_n_t _v_a_r_i_a_b_l_e _d_o _x = _1,_7 _w_r_i_t_e(,_x) . . . } # _e_n_d _o_f _b_l_o_c_k _e_n_d # _e_n_d _o_f _p_r_o_c_e_d_u_r_e, _r_e_t_u_r_n _t_o _b_l_o_c_k _0 _3._4. _S_t_a_t_e_m_e_n_t_s A statement is terminated by end of line or by a semi- colon. Statements are of the following types: - 12 - Option Include Define 9 Procedure End 9 Declarative Executable The _o_p_t_i_o_n statement is described in Section 10. The _i_n_c_l_u_d_e, _d_e_f_i_n_e, and _e_n_d statements have been described above; they may not be followed by another statement on a line. Each procedure begins with a _p_r_o_c_e_d_u_r_e statements and finishes with an _e_n_d statement; these are discussed in Sec- tion 8. Declarations describe types and values of variables and procedures. Executable statements cause specific actions to be taken. A block is an example of an executable statement; it is made up of declarative and executable statements. _3._5. _L_a_b_e_l_s An executable statement may have a _l_a_b_e_l which may be used in a branch statement. A label is an identifier fol- lowed by a colon, as in read(, x) if(x < 3) goto error . . . error: fatal("bad input") _4. _D_A_T_A _T_Y_P_E_S _A_N_D _V_A_R_I_A_B_L_E_S EFL supports a small number of basic (scalar) types. The programmer may define objects made up of variables of - 13 - basic type; other aggregates may then be defined in terms of previously defined aggregates. _4._1. _B_a_s_i_c _T_y_p_e_s The basic types are logical integer field(_m:_n) real complex long real long complex character(_n) A logical quantity may take on the two values true and false. An integer may take on any whole number value in some machine-dependent range. A field quantity is an integer restricted to a particular closed interval ([_m:_n]). A `real' quantity is a floating point approximation to a real or rational number. A long real is a more precise approximation to a rational. (Real quantities are represented as single precision floating point numbers; long reals are double precision floating point numbers.) A com- plex quantity is an approximation to a complex number, and is represented as a pair of reals. A character quantity is a fixed-length string of _n characters. _4._2. _C_o_n_s_t_a_n_t_s There is a notation for a constant of each basic type. A logical may take on the two values - 14 - _t_r_u_e _f_a_l_s_e An integer or field constant is a fixed point constant, optionally preceded by a plus or minus sign, as in _1_7 -_9_4 +_6 _0 A long real (`double precision') constant is a floating point constant containing an exponent field that begins with the letter _d. A real (`single precision') constant is any other floating point constant. A real or long real constant may be preceded by a plus or minus sign. The following are valid _r_e_a_l constants: _1_7._3 -._4 _7._9_e-_6 ( = 7.9x1078-6999) _1_4_e_9 ( = 1.4x107810999) The following are valid _l_o_n_g _r_e_a_l constants _7._9_d-_6 ( = 7.9x1078-6999) _5_d_3 A character constant is a quoted string. _4._3. _V_a_r_i_a_b_l_e_s A variable is a quantity with a name and a location. At any particular time the variable may also have a value. (A variable is said to be _u_n_d_e_f_i_n_e_d before it is initialized or assigned its first value, and after certain indefinite operations are performed.) Each variable has certain - 15 - attributes: _4._3._1. _S_t_o_r_a_g_e _C_l_a_s_s The association of a name and a location is either transitory or permanent. Transitory association is achieved when arguments are passed to procedures. Other associations are permanent (static). (A future extension of EFL may include dynamically allocated variables.) _4._3._2. _S_c_o_p_e _o_f _N_a_m_e_s The names of common areas are global, as are procedure names: these names may be used anywhere in the program. All other names are local to the block in which they are declared. _4._3._3. _P_r_e_c_i_s_i_o_n Floating point variables are either of normal or _l_o_n_g precision. This attribute may be stated independently of the basic type. _4._4. _A_r_r_a_y_s It is possible to declare rectangular arrays (of any dimension) of values of the same type. The index set is always a cross-product of intervals of integers. The lower and upper bounds of the intervals must be constants for arrays that are local or _c_o_m_m_o_n. A formal argument array may have intervals that are of length equal to one of the - 16 - other formal arguments. An element of an array is denoted by the array name followed by a parenthesized comma- separated list of integer values, each of which must lie within the corresponding interval. (The intervals may include negative numbers.) Entire arrays may be passed as procedure arguments or in input/output lists, or they may be initialized; all other array references must be to indivi- dual elements. _4._5. _S_t_r_u_c_t_u_r_e_s It is possible to define new types which are made up of elements of other types. The compound object is known as a _s_t_r_u_c_t_u_r_e; its constituents are called _m_e_m_b_e_r_s of the struc- ture. The structure may be given a name, which acts as a type name in the remaining statements within the scope of its declaration. The elements of a structure may be of any type (including previously defined structures), or they may be arrays of such objects. Entire structures may be passed to procedures or be used in input/output lists; individual elements of structures may be referenced. The uses of structures will be detailed below. The following structure might represent a symbol table: _s_t_r_u_c_t _t_a_b_l_e_e_n_t_r_y { _c_h_a_r_a_c_t_e_r(_8) _n_a_m_e _i_n_t_e_g_e_r _h_a_s_h_v_a_l_u_e _i_n_t_e_g_e_r _n_u_m_b_e_r_o_f_e_l_e_m_e_n_t_s _f_i_e_l_d(_0:_1) _i_n_i_t_i_a_l_i_z_e_d, _u_s_e_d, _s_e_t _f_i_e_l_d(_0:_1_0) _t_y_p_e } - 17 - _5. _E_X_P_R_E_S_S_I_O_N_S Expressions are syntactic forms that yield a value. An expression may have any of the following forms, recursively applied: primary ( _e_x_p_r_e_s_s_i_o_n ) _u_n_a_r_y-_o_p_e_r_a_t_o_r _e_x_p_r_e_s_s_i_o_n _e_x_p_r_e_s_s_i_o_n _b_i_n_a_r_y-_o_p_e_r_a_t_o_r _e_x_p_r_e_s_s_i_o_n In the following table of operators, all operators on a line have equal precedence and have higher precedence than opera- tors on later lines. The meanings of these operators are described in sections 5.3 and 5.4. -> . ** * / _u_n_a_r_y + - ++ -- + - < <= > >= == ~= & && | || $ = += -= *= /= **= &= |= &&= ||= Examples of expressions are _a<_b && _b<_c -(_a + _s_i_n(_x)) / (_5+_c_o_s(_x))**_2 _5._1. _P_r_i_m_a_r_i_e_s Primaries are the basic elements of expressions, as follows: _5._1._1. _C_o_n_s_t_a_n_t_s Constants are described in Section 4.2. - 18 - _5._1._2. _V_a_r_i_a_b_l_e_s Scalar variable names are primaries. They may appear on the left or the right side of an assignment. Unqualified names of aggregates (structures or arrays) may only appear as procedure arguments and in input/output lists. _5._1._3. _A_r_r_a_y _E_l_e_m_e_n_t_s An element of an array is denoted by the array name followed by a parenthesized list of subscripts, one integer value for each declared dimension: _a(_5) _b(_6,-_3,_4) _5._1._4. _S_t_r_u_c_t_u_r_e _M_e_m_b_e_r_s A structure name followed by a dot followed by the name of a member of that structure constitutes a reference to that element. If that element is itself a structure, the reference may be further qualified. _a._b _x(_3)._y(_4)._z(_5) _5._1._5. _P_r_o_c_e_d_u_r_e _I_n_v_o_c_a_t_i_o_n_s A procedure is invoked by an expression of one of the forms _p_r_o_c_e_d_u_r_e_n_a_m_e ( ) _p_r_o_c_e_d_u_r_e_n_a_m_e ( _e_x_p_r_e_s_s_i_o_n ) _p_r_o_c_e_d_u_r_e_n_a_m_e ( _e_x_p_r_e_s_s_i_o_n-_1, ..., _e_x_p_r_e_s_s_i_o_n-_n ) - 19 - The _p_r_o_c_e_d_u_r_e_n_a_m_e is either the name of a variable declared _e_x_t_e_r_n_a_l or it is the name of a function known to the EFL compiler (see Section 8.5), or it is the actual name of a procedure, as it appears in a _p_r_o_c_e_d_u_r_e statement. If a _p_r_o_c_e_d_u_r_e_n_a_m_e is declared _e_x_t_e_r_n_a_l and is an argument of the current procedure, it is associated with the procedure name passed as actual argument; otherwise it is the actual name of a procedure. Each _e_x_p_r_e_s_s_i_o_n in the above is called an _a_c_t_u_a_l _a_r_g_u_m_e_n_t. Examples of procedure invocations are _f(_x) _w_o_r_k() _g(_x, _y+_3, '_x_x') When one of these procedure invocations is to be performed, each of the actual argument expressions is first evaluated. The types, precisions, and bounds of actual and formal argu- ments should agree. If an actual argument is a variable name, array element, or structure member, the called pro- cedure is permitted to use the corresponding formal argument as the left side of an assignment or in an input list; oth- erwise it may only use the value. After the formal and actual arguments are associated, control is passed to the first executable statement of the procedure. When a _r_e_t_u_r_n statement is executed in that procedure, or when control reaches the _e_n_d statement of that procedure, the function value is made available as the value of the procedure invo- cation. The type of the value is determined by the attri- butes of the _p_r_o_c_e_d_u_r_e_n_a_m_e that are declared or implied in the calling procedure, which must agree with the attributes - 20 - declared for the function in its procedure. In the special case of a generic function, the type of the result is also affected by the type of the argument. See Chapter 8 for details. _5._1._6. _I_n_p_u_t/_O_u_t_p_u_t _E_x_p_r_e_s_s_i_o_n_s The EFL input/output syntactic forms may be used as integer primaries that have a non-zero value if an error occurs during the input or output. See Section 7.7. _5._1._7. _C_o_e_r_c_i_o_n_s An expression of one precision or type may be converted to another by an expression of the form _a_t_t_r_i_b_u_t_e_s ( _e_x_p_r_e_s_s_i_o_n ) At present, the only _a_t_t_r_i_b_u_t_e_s permitted are precision and basic types. Attributes are separated by white space. An arithmetic value of one type may be coerced to any other arithmetic type; a character expression of one length may be coerced to a character expression of another length; logical expressions may not be coerced to a nonlogical type. As a special case, a quantity of _c_o_m_p_l_e_x or _l_o_n_g _c_o_m_p_l_e_x type may be constructed from two integer or real quantities by pass- ing two expressions (separated by a comma) in the coercion. Examples and equivalent values are _i_n_t_e_g_e_r(_5._3) = _5 _l_o_n_g _r_e_a_l(_5) = _5._0_d_0 _c_o_m_p_l_e_x(_5,_3) = 5+3_i - 21 - Most conversions are done implicitly, since most binary operators permit operands of different arithmetic types. Explicit coercions are of most use when it is necessary to convert the type of an actual argument to match that of the corresponding formal parameter in a procedure call. _5._1._8. _S_i_z_e_s There is a notation which yields the amount of memory required to store a datum or an item of specified type: sizeof ( _l_e_f_t_s_i_d_e ) sizeof ( _a_t_t_r_i_b_u_t_e_s ) In the first case, _l_e_f_t_s_i_d_e can denote a variable, array, array element, or structure member. The value of _s_i_z_e_o_f is an integer, which gives the size in arbitrary units. If the size is needed in terms of the size of some specific unit, this can be computed by division: _s_i_z_e_o_f(_x) / _s_i_z_e_o_f(_i_n_t_e_g_e_r) yields the size of the variable _x in integer words. The distance between consecutive elements of an array may not equal _s_i_z_e_o_f because certain data types require final padding on some machines. The _l_e_n_g_t_h_o_f operator gives this larger value, again in arbitrary units. The syntax is lengthof ( _l_e_f_t_s_i_d_e ) lengthof ( _a_t_t_r_i_b_u_t_e_s ) - 22 - _5._2. _P_a_r_e_n_t_h_e_s_e_s An expression surrounded by parentheses is itself an expression. A parenthesized expression must be evaluated before an expression of which it is a part is evaluated. _5._3. _U_n_a_r_y _O_p_e_r_a_t_o_r_s All of the unary operators in EFL are prefix operators. The result of a unary operator has the same type as its operand. _5._3._1. _A_r_i_t_h_m_e_t_i_c Unary + has no effect. A unary - yields the negative of its operand. The prefix operator ++ adds one to its operand. The prefix operator -- subtracts one from its operand. The value of either expression is the result of the addition or subtraction. For these two operators, the operand must be a scalar, array element, or structure member of arithmetic type. (As a side effect, the operand value is changed.) _5._3._2. _L_o_g_i_c_a_l The only logical unary operator is complement (~). This operator is defined by the equations ~ _t_r_u_e = _f_a_l_s_e ~ _f_a_l_s_e = _t_r_u_e - 23 - _5._4. _B_i_n_a_r_y _O_p_e_r_a_t_o_r_s Most EFL operators have two operands, separated by the operator. Because the character set must be limited, some of the operators are denoted by strings of two or three spe- cial characters. All binary operators except exponentiation are left associative. _5._4._1. _A_r_i_t_h_m_e_t_i_c The binary arithmetic operators are + addition - subtraction * multiplication / division ** exponentiation Exponentiation is right associative: a**b**c = a**(b**c) = 9_a78(_b7_c99)999 The operations have the conventional meanings: 8+2 = 10, 8-2 = 6, 8*2 = 16, 8/2 = 4, 8**2 = 8782999 = 64. The type of the result of a binary operation _A _o_p _B is determined by the types of its operands: Type of B 9Type of A integer real long real complex long complex 8_______________________________________________________________________________________ integer integer real long real complex long complex real real real long real complex long complex long real long real long real long real long complex long complex complex complex complex long complex complex long complex long complex long complex long complex long complex long complex long complex 7 |7|7|7|7|7|7|7| If the type of an operand differs from the type of the result, the calculation is done as if the operand were first coerced to the type of the result. If both operands are integers, the result is of type integer, and is computed 9 - 24 - exactly. (Quotients are truncated toward zero, so 8/3=2.) _5._4._2. _L_o_g_i_c_a_l The two binary logical operations in EFL, _a_n_d and _o_r, are defined by the truth tables: A B A and B A or B 8 ____________________________________ false false false false false true false true true false false true true true true true Each of these operators comes in two forms. In one form, the order of evaluation is specified. The expression _a && _b is evaluated by first evaluating _a; if it is false then the expression is false and _b is not evaluated; otherwise the expression has the value of _b. The expression _a || _b is evaluated by first evaluating _a; if it is true then the expression is true and _b is not evaluated; otherwise the expression has the value of _b. The other forms of the operators (& for and and | for or) do not imply an order of evaluation. With the latter operators, the compiler may speed up the code by evaluating the operands in any order. _5._4._3. _R_e_l_a_t_i_o_n_a_l _O_p_e_r_a_t_o_r_s There are six relations between arithmetic quantities. These operators are not associative. 9 - 25 - EFL Operator Meaning 8 ________________________________________ < < less than <= <_ less than or equal to == = equal to ~= =/ not equal to > > greater than >= >_ greater than or equal Since the complex numbers are not ordered, the only rela- tional operators that may take complex operands are == and ~= . The character collating sequence is not defined. _5._4._4. _A_s_s_i_g_n_m_e_n_t _O_p_e_r_a_t_o_r_s All of the assignment operators are right associative. The simple form of assignment is _b_a_s_i_c-_l_e_f_t-_s_i_d_e = _e_x_p_r_e_s_s_i_o_n A _b_a_s_i_c-_l_e_f_t-_s_i_d_e is a scalar variable name, array element, or structure member of basic type. This statement computes the expression on the right side, and stores that value (possibly after coercing the value to the type of the left side) in the location named by the left side. The value of the assignment expression is the value assigned to the left side after coercion. There is also an assignment operator corresponding to each binary arithmetic and logical operator. In each case, _a _o_p= _b is equivalent to _a = _a _o_p _b. (The operator and equal sign must not be separated by blanks.) Thus, _n+=_2 adds 2 to n. The location of the left side is evaluated only once. 9 - 26 - _5._5. _D_y_n_a_m_i_c _S_t_r_u_c_t_u_r_e_s EFL does not have an address (pointer, reference) type. However, there is a notation for dynamic structures, _l_e_f_t_s_i_d_e -> _s_t_r_u_c_t_u_r_e_n_a_m_e This expression is a structure with the shape implied by _s_t_r_u_c_t_u_r_e_n_a_m_e but starting at the location of _l_e_f_t_s_i_d_e. In effect, this overlays the structure template at the speci- fied location. The _l_e_f_t_s_i_d_e must be a variable, array, array element, or structure member. The type of the _l_e_f_t_- _s_i_d_e must be one of the types in the structure declaration. An element of such a structure is denoted in the usual way using the dot operator. Thus, _p_l_a_c_e(_i) -> _s_t._e_l_t refers to the _e_l_t member of the _s_t structure starting at the _i78_t_h999 element of the array _p_l_a_c_e. _5._6. _R_e_p_e_t_i_t_i_o_n _O_p_e_r_a_t_o_r Inside of a list, an element of the form _i_n_t_e_g_e_r-_c_o_n_s_t_a_n_t-_e_x_p_r_e_s_s_i_o_n $ _c_o_n_s_t_a_n_t-_e_x_p_r_e_s_s_i_o_n is equivalent to the appearance of the _e_x_p_r_e_s_s_i_o_n a number of times equal to the first expression. Thus, (_3, _3$_4, _5) is equivalent to (_3, _4, _4, _4, _5) - 27 - _5._7. _C_o_n_s_t_a_n_t _E_x_p_r_e_s_s_i_o_n_s If an expression is built up out of operators (other than functions) and constants, the value of the expression is a constant, and may be used anywhere a constant is required. _6. _D_E_C_L_A_R_A_T_I_O_N_S Declarations statement describe the meaning, shape, and size of named objects in the EFL language. _6._1. _S_y_n_t_a_x A declaration statement is made up of attributes and variables. Declaration statements are of two form: _a_t_t_r_i_b_u_t_e_s _v_a_r_i_a_b_l_e-_l_i_s_t _a_t_t_r_i_b_u_t_e_s { _d_e_c_l_a_r_a_t_i_o_n_s } In the first case, each name in the _v_a_r_i_a_b_l_e-_l_i_s_t has the specified attributes. In the second, each name in the declarations also has the specified attributes. A variable name may appear in more than one variable list, so long as the attributes are not contradictory. Each name of a nonar- gument variable may be accompanied by an initial value specification. The _d_e_c_l_a_r_a_t_i_o_n_s inside the braces are one or more declaration statements. Examples of declarations are - 28 - _i_n_t_e_g_e_r _k=_2 9 _l_o_n_g _r_e_a_l _b(_7,_3) 9 _c_o_m_m_o_n(_c_n_a_m_e) { _i_n_t_e_g_e_r _i _l_o_n_g _r_e_a_l _a_r_r_a_y(_5,_0:_3) _x, _y _c_h_a_r_a_c_t_e_r(_7) _c_h } _6._2. _A_t_t_r_i_b_u_t_e_s _6._2._1. _B_a_s_i_c _T_y_p_e_s The following are basic types in declarations _l_o_g_i_c_a_l _i_n_t_e_g_e_r _f_i_e_l_d(_m:_n) _c_h_a_r_a_c_t_e_r(_k) _r_e_a_l _c_o_m_p_l_e_x In the above, the quantities _k, _m, and _n denote integer con- stant expressions with the properties _k>0 and _n>_m. _6._2._2. _A_r_r_a_y_s The dimensionality may be declared by an _a_r_r_a_y attri- bute array(_b918,_._._.,_b9_n8) Each of the _b9_i8 may either be a single integer expression or a pair of integer expressions separated by a colon. The pair of expressions form a lower and an upper bound; the single expression is an upper bound with an implied lower bound of 1. The number of dimensions is equal to _n, the number of bounds. All of the integer expressions must be - 29 - constants. An exception is permitted only if all of the variables associated with an array declarator are formal arguments of the procedure; in this case, each bound must have the property that _u_p_p_e_r-_l_o_w_e_r+1 is equal to a formal argument of the procedure. (The compiler has limited abil- ity to simplify expressions, but it will recognize important cases such as (_0:_n-_1). The upper bound for the last dimen- sion (_b9_n8) may be marked by an asterisk ( * ) if the size of the array is not known. The following are legal array attributes: _a_r_r_a_y(_5) _a_r_r_a_y(_5, _1:_5, -_3:_0) _a_r_r_a_y(_5, *) _a_r_r_a_y(_0:_m-_1, _m) _6._2._3. _S_t_r_u_c_t_u_r_e_s A structure declaration is of the form struct _s_t_r_u_c_t_n_a_m_e { _d_e_c_l_a_r_a_t_i_o_n _s_t_a_t_e_m_e_n_t_s } The _s_t_r_u_c_t_n_a_m_e is optional; if it is present, it acts as if it were the name of a type in the rest of its scope. Each name that appears inside the _d_e_c_l_a_r_a_t_i_o_n_s is a _m_e_m_b_e_r of the structure, and has a special meaning when used to qualify any variable declared with the structure type. A name may appear as a member of any number of structures, and may also be the name of an ordinary variable, since a structure member name is used only in contexts where the parent type is known. The following are valid structure attributes - 30 - _s_t_r_u_c_t _x_x { _i_n_t_e_g_e_r _a, _b _r_e_a_l _x(_5) } _s_t_r_u_c_t { _x_x _z(_3); _c_h_a_r_a_c_t_e_r(_5) _y } The last line defines a structure containing an array of three xx'_s and a character string. _6._2._4. _P_r_e_c_i_s_i_o_n Variables of floating point (real or complex) type may be declared to be long to ensure they have higher precision than ordinary floating point variables. The default preci- sion is short. _6._2._5. _C_o_m_m_o_n Certain objects called _c_o_m_m_o_n _a_r_e_a_s have external scope, and may be referenced by any procedure that has a declaration for the name using a common ( _c_o_m_m_o_n_a_r_e_a_n_a_m_e ) attribute. All of the variables declared with a particular common attribute are in the same block; the order in which they are declared is significant. Declarations for the same block in differing procedures must have the variables in the same order and with the same types, precision, and shapes, though not necessarily with the same names. - 31 - _6._2._6. _E_x_t_e_r_n_a_l If a name is used as the procedure name in a procedure invocation, it is implicitly declared to have the _e_x_t_e_r_n_a_l attribute. If a procedure name is to be passed as an argu- ment, it is necessary to declare it in a statement of the form external _n_a_m_e . If a name has the external attribute and it is a formal argument of the procedure, then it is associated with a pro- cedure identifier passed as an actual argument at each call. If the name is not a formal argument, then that name is the actual name of a procedure, as it appears in the correspond- ing _p_r_o_c_e_d_u_r_e statement. _6._3. _V_a_r_i_a_b_l_e _L_i_s_t The elements of a variable list in a declaration con- sist of a name, an optional dimension specification, and an optional initial value specification. The name follows the usual rules. The dimension specification is the same form and meaning as the parenthesized list in an _a_r_r_a_y attribute. The initial value specification is an equal sign (=) fol- lowed by a constant expression. If the name is an array, the right side of the equal sign may be a parenthesized list of constant expressions, or repeated elements or lists; the total number of elements in the list must not exceed the number of elements of the array, which are filled in - 32 - column-major order. _6._4. _T_h_e _I_n_i_t_i_a_l _S_t_a_t_e_m_e_n_t An initial value may also be specified for a simple variable, array, array element, or member of a structure using a statement of the form initial _v_a_r = _v_a_l . The _v_a_r may be a variable name, array element specification, or member of structure. The right side follows the same rules as for an initial value specification in other declaration statements. _7. _E_X_E_C_U_T_A_B_L_E _S_T_A_T_E_M_E_N_T_S Every useful EFL program contains executable statements - otherwise it would not do anything and would not need to be run. Statements are frequently made up of other state- ments. Blocks are the most obvious case, but many other forms contain statements as constituents. To increase the legibility of EFL programs, some of the statement forms can be broken without an explicit continua- tion. A square ([]) in the syntax represents a point where the end of a line will be ignored. _7._1. _E_x_p_r_e_s_s_i_o_n _S_t_a_t_e_m_e_n_t_s - 33 - _7._1._1. _S_u_b_r_o_u_t_i_n_e _C_a_l_l A procedure invocation that returns no value is known as a subroutine call. Such an invocation is a statement. Examples are _w_o_r_k(_i_n, _o_u_t) _r_u_n() Input/output statements (see Section 7.7) resemble pro- cedure invocations but do not yield a value. If an error occurs the program stops. _7._1._2. _A_s_s_i_g_n_m_e_n_t _S_t_a_t_e_m_e_n_t_s An expression that is a simple assignment (=) or a com- pound assignment (+= etc.) is a statement: _a = _b _a = _s_i_n(_x)/_6 _x *= _y _7._2. _B_l_o_c_k_s A block is a compound statement that acts as a state- ment. A block begins with a left brace, optionally followed by declarations, optionally followed by executable state- ments, followed by a right brace. A block may be used any- where a statement is permitted. A block is not an expres- sion and does not have a value. An example of a block is - 34 - { _i_n_t_e_g_e_r _i # _t_h_i_s _v_a_r_i_a_b_l_e _i_s _u_n_k_n_o_w_n _o_u_t_s_i_d_e _t_h_e _b_r_a_c_e_s 9 _b_i_g = _0 _d_o _i = _1,_n _i_f(_b_i_g < _a(_i)) _b_i_g = _a(_i) } _7._3. _T_e_s_t _S_t_a_t_e_m_e_n_t_s Test statements permit execution of certain statements conditional on the truth of a predicate. _7._3._1. _I_f _S_t_a_t_e_m_e_n_t The simplest of the test statements is the _i_f state- ment, of form if ( _l_o_g_i_c_a_l-_e_x_p_r_e_s_s_i_o_n ) [] _s_t_a_t_e_m_e_n_t The logical expression is evaluated; if it is true, then the _s_t_a_t_e_m_e_n_t is executed. _7._3._2. _I_f-_E_l_s_e A more general statement is of the form if ( _l_o_g_i_c_a_l-_e_x_p_r_e_s_s_i_o_n ) [] _s_t_a_t_e_m_e_n_t-_1 [] else [] _s_t_a_t_e_m_e_n_t-_2 If the expression is _t_r_u_e then _s_t_a_t_e_m_e_n_t-_1 is executed, oth- erwise _s_t_a_t_e_m_e_n_t-_2 is executed. Either of the consequent statements may itself be an _i_f-_e_l_s_e so a completely nested test sequence is possible: 9 - 35 - _i_f(_x<_y) _i_f(_a<_b) _k = _1 _e_l_s_e _k = _2 _e_l_s_e _i_f(_a<_b) _m = _1 _e_l_s_e _m = _2 An _e_l_s_e applies to the nearest preceding un-elsed if. A more common use is as a sequential test: _i_f(_x==_1) _k = _1 _e_l_s_e _i_f(_x==_3 | _x==_5) _k = _2 _e_l_s_e _k = _3 _7._3._3. _S_e_l_e_c_t _S_t_a_t_e_m_e_n_t A multiway test on the value of a quantity is suc- cinctly stated as a _s_e_l_e_c_t statement, which has the general form select( _e_x_p_r_e_s_s_i_o_n ) [] _b_l_o_c_k Inside the block two special types of labels are recognized. A prefix of the form case _c_o_n_s_t_a_n_t . : marks the statement to which control is passed if the expression in the select has a value equal to one of the case constants. If the expression equals none of these con- stants, but there is a label _d_e_f_a_u_l_t inside the select, a branch is taken to that point; otherwise the statement - 36 - following the right brace is executed. Once execution begins at a _c_a_s_e or _d_e_f_a_u_l_t label, it continues until the next _c_a_s_e or _d_e_f_a_u_l_t is encountered. The _e_l_s_e-_i_f example above is better written as _s_e_l_e_c_t(_x) { _c_a_s_e _1: _k = _1 _c_a_s_e _3,_5: _k = _2 _d_e_f_a_u_l_t: _k = _3 } Note that control does not `fall through' to the next case. _7._4. _L_o_o_p_s The loop forms provide the best way of repeating a statement or sequence of operations. The simplest (while) form is theoretically sufficient, but it is very convenient to have the more general loops available, since each expresses a mode of control that arises frequently in prac- tice. _7._4._1. _W_h_i_l_e _S_t_a_t_e_m_e_n_t This construct has the form while ( _l_o_g_i_c_a_l-_e_x_p_r_e_s_s_i_o_n ) [] _s_t_a_t_e_m_e_n_t The expression is evaluated; if it is true, the statement is executed, and then the test is performed again. If the expression is false, execution proceeds to the next state- ment. - 37 - _7._5. _F_o_r _S_t_a_t_e_m_e_n_t The _f_o_r statement is a more elaborate looping con- struct. It has the form for ( _i_n_i_t_i_a_l-_s_t_a_t_e_m_e_n_t , [] _l_o_g_i_c_a_l-_e_x_p_r_e_s_s_i_o_n , [] _i_t_e_r_a_t_i_o_n-_s_t_a_t_e_m_e_n_t ) [] _b_o_d_y-_s_t_a_t_e_m_e_n_t Except for the behavior of the _n_e_x_t statement (see Section 7.6.3), this construct is equivalent to _i_n_i_t_i_a_l-_s_t_a_t_e_m_e_n_t while ( _l_o_g_i_c_a_l-_e_x_p_r_e_s_s_i_o_n ) { _b_o_d_y-_s_t_a_t_e_m_e_n_t _i_t_e_r_a_t_i_o_n-_s_t_a_t_e_m_e_n_t } This form is useful for general arithmetic iterations, and for various pointer-type operations. The sum of the integers from 1 to 100 can be computed by the fragment _n = _0 _f_o_r(_i = _1, _i <= _1_0_0, _i += _1) _n += _i Alternatively, the computation could be done by the single statement _f_o_r( { _n = _0 ; _i = _1 } , _i<=_1_0_0 , { _n += _i ; ++_i } ) ; Note that the body of the _f_o_r loop is a null statement in this case. An example of following a linked list will be given later. _7._5._1. _R_e_p_e_a_t _S_t_a_t_e_m_e_n_t The statement - 38 - repeat [] _s_t_a_t_e_m_e_n_t executes the statement, then does it again, without any ter- mination test. Obviously, a test inside the _s_t_a_t_e_m_e_n_t is needed to stop the loop. _7._5._2. _R_e_p_e_a_t..._U_n_t_i_l _S_t_a_t_e_m_e_n_t The _w_h_i_l_e loop performs a test before each iteration. The statement repeat [] _s_t_a_t_e_m_e_n_t [] until ( _l_o_g_i_c_a_l-_e_x_p_r_e_s_s_i_o_n ) executes the _s_t_a_t_e_m_e_n_t, then evaluates the logical; if the logical is true the loop is complete; otherwise control returns to the _s_t_a_t_e_m_e_n_t. Thus, the body is always executed at least once. The _u_n_t_i_l refers to the nearest preceding _r_e_p_e_a_t that has not been paired with an _u_n_t_i_l. In practice, this appears to be the least frequently used looping con- struct. _7._5._3. _D_o _L_o_o_p_s The simple arithmetic progression is a very common one in numerical applications. EFL has a special loop form for ranging over an ascending arithmetic sequence do _v_a_r_i_a_b_l_e = _e_x_p_r_e_s_s_i_o_n-_1, _e_x_p_r_e_s_s_i_o_n-_2, _e_x_p_r_e_s_s_i_o_n-_3 _s_t_a_t_e_m_e_n_t The variable is first given the value _e_x_p_r_e_s_s_i_o_n-_1. The statement is executed, then _e_x_p_r_e_s_s_i_o_n-_3 is added to the variable. The loop is repeated until the variable exceeds - 39 - _e_x_p_r_e_s_s_i_o_n-_2. If _e_x_p_r_e_s_s_i_o_n-_3 and the preceding comma are omitted, the increment is taken to be 1. The loop above is equivalent to t2 = expression-2 t3 = expression-3 for(variable = expression-1 , variable <= t2 , variable += t3) statement (The compiler translates EFL _d_o statements into Fortran DO statements, which are in turn usually compiled into excel- lent code.) The _d_o _v_a_r_i_a_b_l_e may not be changed inside of the loop, and _e_x_p_r_e_s_s_i_o_n-_1 must not exceed _e_x_p_r_e_s_s_i_o_n-_2. The sum of the first hundred positive integers could be computed by _n = _0 _d_o _i = _1, _1_0_0 _n += _i _7._6. _B_r_a_n_c_h _S_t_a_t_e_m_e_n_t_s Most of the need for branch statements in programs can be averted by using the loop and test constructs, but there are programs where they are very useful. _7._6._1. _G_o_t_o _S_t_a_t_e_m_e_n_t The most general, and most dangerous, branching state- ment is the simple unconditional goto _l_a_b_e_l After executing this statement, the next statement performed is the one following the given label. Inside of a _s_e_l_e_c_t - 40 - the case labels of that block may be used as labels, as in the following example: select(k) { case 1: error(7) case 2: k = 2 goto case 4 case 3: k = 5 goto case 4 case 4: fixup(k) goto default default: prmsg("ouch") } (If two _s_e_l_e_c_t statements are nested, the case labels of the outer _s_e_l_e_c_t are not accessible from the inner one.) _7._6._2. _B_r_e_a_k _S_t_a_t_e_m_e_n_t A safer statement is one which transfers control to the statement following the current _s_e_l_e_c_t or loop form. A statement of this sort is almost always needed in a _r_e_p_e_a_t loop: _r_e_p_e_a_t { _d_o _a _c_o_m_p_u_t_a_t_i_o_n _i_f( _f_i_n_i_s_h_e_d ) break } More general forms permit controlling a branch out of more than one construct. - 41 - _b_r_e_a_k _3 transfers control to the statement following the third loop and/or _s_e_l_e_c_t surrounding the statement. It is possible to specify which type of construct (for, while, repeat, do, or select) is to be counted. The statement _b_r_e_a_k _w_h_i_l_e breaks out of the first surrounding _w_h_i_l_e statement. Either of the statements _b_r_e_a_k _3 _f_o_r _b_r_e_a_k _f_o_r _3 will transfer to the statement after the third enclosing _f_o_r loop. _7._6._3. _N_e_x_t _S_t_a_t_e_m_e_n_t The _n_e_x_t statement causes the first surrounding loop statement to go on to the next iteration: the next operation performed is the test of a _w_h_i_l_e, the _i_t_e_r_a_t_i_o_n-_s_t_a_t_e_m_e_n_t of a _f_o_r, the body of a _r_e_p_e_a_t, the test of a _r_e_p_e_a_t..._u_n_t_i_l, or the increment of a _d_o. Elaborations similar to those for _b_r_e_a_k are available: _n_e_x_t _n_e_x_t _3 _n_e_x_t _3 _f_o_r _n_e_x_t _f_o_r _3 A _n_e_x_t statement ignores _s_e_l_e_c_t statements. - 42 - _7._6._4. _R_e_t_u_r_n The last statement of a procedure is followed by a return of control to the caller. If it is desired to effect such a return from any other point in the procedure, a return statement may be executed. Inside a function procedure, the function value is specified as an argument of the statement: return ( _e_x_p_r_e_s_s_i_o_n ) _7._7. _I_n_p_u_t/_O_u_t_p_u_t _S_t_a_t_e_m_e_n_t_s EFL has two input statements (read and readbin), two output statements (write and writebin), and three control statements (endfile, rewind, and backspace). These forms may be used either as a primary with a _i_n_t_e_g_e_r value or as a statement. If an exception occurs when one of these forms is used as a statement, the result is undefined but will probably be treated as a fatal error. If they are used in a context where they return a value, they return zero if no exception occurs. For the input forms, a negative value indicates end-of-file and a positive value an error. The input/output part of EFL very strongly reflects the facili- ties of Fortran. _7._7._1. _I_n_p_u_t/_O_u_t_p_u_t _U_n_i_t_s Each I/O statement refers to a `unit', identified by a small positive integer. Two special units are defined by - 43 - EFL, the _s_t_a_n_d_a_r_d _i_n_p_u_t _u_n_i_t and the _s_t_a_n_d_a_r_d _o_u_t_p_u_t _u_n_i_t. These particular units are assumed if no unit is specified in an I/O transmission statement. The data on the unit are organized into _r_e_c_o_r_d_s. These records may be read or written in a fixed sequence, and each transmission moves an integral number of records. Transmis- sion proceeds from the first record until the _e_n_d _o_f _f_i_l_e. _7._7._2. _B_i_n_a_r_y _I_n_p_u_t/_O_u_t_p_u_t The _r_e_a_d_b_i_n and _w_r_i_t_e_b_i_n statements transmit data in a machine-dependent but swift manner. The statements are of the form writebin( _u_n_i_t , _b_i_n_a_r_y-_o_u_t_p_u_t-_l_i_s_t ) readbin( _u_n_i_t , _b_i_n_a_r_y-_i_n_p_u_t-_l_i_s_t ) Each statement moves one unformatted record between storage and the device. The _u_n_i_t is an integer expression. A _b_i_n_a_r_y-_o_u_t_p_u_t-_l_i_s_t is an _i_o_l_i_s_t (see below) without any for- mat specifiers. A _b_i_n_a_r_y-_i_n_p_u_t-_l_i_s_t is an _i_o_l_i_s_t without format specifiers in which each of the expressions is a variable name, array element, or structure member. _7._7._3. _F_o_r_m_a_t_t_e_d _I_n_p_u_t/_O_u_t_p_u_t The _r_e_a_d and _w_r_i_t_e statements transmit data in the form of lines of characters. Each statement moves one or more records (lines). Numbers are translated into decimal nota- tion. The exact form of the lines is determined by format specifications, whether provided explicitly in the statement - 44 - or implicitly. The syntax of the statements is write( _u_n_i_t , _f_o_r_m_a_t_t_e_d-_o_u_t_p_u_t-_l_i_s_t ) read( _u_n_i_t , _f_o_r_m_a_t_t_e_d-_i_n_p_u_t-_l_i_s_t ) The lists are of the same form as for binary I/O, except that the lists may include format specifications. If the _u_n_i_t is omitted, the standard input or output unit is used. _7._7._4. _I_o_l_i_s_t_s An _i_o_l_i_s_t specifies a set of values to be written or a set of variables into which values are to be read. An _i_o_l_- _i_s_t is a list of one or more _i_o_e_x_p_r_e_s_s_i_o_n_s of the form _e_x_p_r_e_s_s_i_o_n { _i_o_l_i_s_t } _d_o-_s_p_e_c_i_f_i_c_a_t_i_o_n { _i_o_l_i_s_t } For formatted I/O, an _i_o_e_x_p_r_e_s_s_i_o_n may also have the forms _i_o_e_x_p_r_e_s_s_i_o_n : _f_o_r_m_a_t-_s_p_e_c_i_f_i_e_r : _f_o_r_m_a_t-_s_p_e_c_i_f_i_e_r A _d_o-_s_p_e_c_i_f_i_c_a_t_i_o_n looks just like a _d_o statement, and has a similar effect: the values in the braces are transmitted repeatedly until the _d_o execution is complete. _7._7._5. _F_o_r_m_a_t_s The following are permissible _f_o_r_m_a_t-_s_p_e_c_i_f_i_e_r_s. The quantities _w, _d, and _k must be integer constant expressions. - 45 - i(_w) integer with _w digits f(_w,_d) floating point number of _w characters, _d of them to the right of the decimal point. e(_w,_d) floating point number of _w characters, _d of them to the right of the decimal point, with the exponent field marked with the letter e l(_w) logical field of width _w characters, the first of which is t or f (the rest are blank on output, ignored on input) standing for true and false respectively c character string of width equal to the length of the datum c(_w) character string of width _w s(_k) skip _k lines x(_k) skip _k spaces " ... " use the characters inside the string as a Fortran format If no format is specified for an item in a formatted input/output statement, a default form is chosen. If an item in a list is an array name, then the entire array is transmitted as a sequence of elements, each with its own format. The elements are transmitted in column- major order, the same order used for array initializations. _7._7._6. _M_a_n_i_p_u_l_a_t_i_o_n _s_t_a_t_e_m_e_n_t_s The three input/output statements _b_a_c_k_s_p_a_c_e(_u_n_i_t) _r_e_w_i_n_d(_u_n_i_t) _e_n_d_f_i_l_e(_u_n_i_t) look like ordinary procedure calls, but may be used either as statements or as integer expressions which yield non-zero if an error is detected. _b_a_c_k_s_p_a_c_e causes the specified unit to back up, so that the next read will re-read the pre- vious record, and the next write will over-write it. _r_e_w_i_n_d moves the device to its beginning, so that the next input statement will read the first record. _e_n_d_f_i_l_e causes the - 46 - file to be marked so that the record most recently written will be the last record on the file, and any attempt to read past is an error. _8. _P_R_O_C_E_D_U_R_E_S Procedures are the basic unit of an EFL program, and provide the means of segmenting a program into separately compilable and named parts. _8._1. _P_r_o_c_e_d_u_r_e _S_t_a_t_e_m_e_n_t Each procedure begins with a statement of one of the forms procedure _a_t_t_r_i_b_u_t_e_s procedure _p_r_o_c_e_d_u_r_e_n_a_m_e _a_t_t_r_i_b_u_t_e_s procedure _p_r_o_c_e_d_u_r_e_n_a_m_e ( ) _a_t_t_r_i_b_u_t_e_s procedure _p_r_o_c_e_d_u_r_e_n_a_m_e ( _n_a_m_e . ) The first case specifies the main procedure, where execution begins. In the two other cases, the _a_t_t_r_i_b_u_t_e_s may specify precision and type, or they may be omitted entirely. The precision and type of the procedure may be declared in an ordinary declaration statement. If no type is declared, then the procedure is called a _s_u_b_r_o_u_t_i_n_e and no value may be returned for it. Otherwise, the procedure is a function and a value of the declared type is returned for each call. Each _n_a_m_e inside the parentheses in the last form above is called a _f_o_r_m_a_l _a_r_g_u_m_e_n_t of the procedure. - 47 - _8._2. _E_n_d _S_t_a_t_e_m_e_n_t Each procedure terminates with a statement _e_n_d _8._3. _A_r_g_u_m_e_n_t _A_s_s_o_c_i_a_t_i_o_n When a procedure is invoked, the actual arguments are evaluated. If an actual argument is the name of a variable, an array element, or a structure member, that entity becomes associated with the formal argument, and the procedure may reference the values in the object, and assign to it. Oth- erwise, the value of the actual is associated with the for- mal argument, but the procedure may not attempt to change the value of that formal argument. If the value of one of the arguments is changed in the procedure, it is not permitted that the corresponding actual argument be associated with another formal argument or with a _c_o_m_m_o_n element that is referenced in the procedure. _8._4. _E_x_e_c_u_t_i_o_n _a_n_d _R_e_t_u_r_n _V_a_l_u_e_s After actual and formal arguments have been associated, control passes to the first executable statement of the pro- cedure. Control returns to the invoker either when the _e_n_d statement of the procedure is reached or when a _r_e_t_u_r_n statement is executed. If the procedure is a function (has a declared type), and a return(_v_a_l_u_e) is executed, the value is coerced to the correct type and precision and returned. - 48 - _8._5. _K_n_o_w_n _F_u_n_c_t_i_o_n_s A number of functions are known to EFL, and need not be declared. The compiler knows the types of these functions. Some of them are _g_e_n_e_r_i_c; i.e., they name a family of func- tions that differ in the types of their arguments and return values. The compiler chooses which element of the set to invoke based upon the attributes of the actual arguments. _8._5._1. _M_i_n_i_m_u_m _a_n_d _M_a_x_i_m_u_m _F_u_n_c_t_i_o_n_s The generic functions are _m_i_n and _m_a_x. The _m_i_n calls return the value of their smallest argument; the _m_a_x calls return the value of their largest argument. These are the only functions that may take different numbers of arguments in different calls. If any of the arguments are _l_o_n_g _r_e_a_l then the result is _l_o_n_g _r_e_a_l. Otherwise, if any of the arguments are _r_e_a_l then the result is _r_e_a_l; otherwise all the arguments and the result must be _i_n_t_e_g_e_r. Examples are _m_i_n(_5, _x, -_3._2_0) _m_a_x(_i, _z) _8._5._2. _A_b_s_o_l_u_t_e _V_a_l_u_e The _a_b_s function is a generic function that returns the magnitude of its argument. For integer and real arguments the type of the result is identical to the type of the argu- ment; for complex arguments the type of the result is the real of the same precision. - 49 - _8._5._3. _E_l_e_m_e_n_t_a_r_y _F_u_n_c_t_i_o_n_s The following generic functions take arguments of real, long real, or complex type and return a result of the same type: