| William.Waite@Colorado.edu |
The specification was originally developed as a class project at the University of Colorado by J. Amundsen, B. D. Basham, S-C. Chiang, D. A. Ence, R. K. Hill, J. E. Kvamme, O. Lokkebo, H. Ma, R. S. Matthieu, M. T. Rupawalla and W. Wang. It was put into its present form while the author was a Visiting Fellow at Australian National University.
From this specification module, the Eli system can generate an executable program that checks its input to verify conformance to the rules of ALGOL 60. This specification module can also be combined with other specification modules to define additional analysis of the input program and/or translation of the algorithm embodied in that program to another language.
This specification defines a hardware language that differs from the reference language of the Revised Report in some of the symbols used to represent objects. These differences will be pointed out in the appropriate sections of this document.
We have also restricted the language in two ways: unsigned integers cannot
be used as labels, and type specifications must be given for all procedure
parameters.
The former restriction avoids a known ambiguity, and the latter is
necessary for compile-time determination of the types of expressions.
Both are common in ALGOL 60 implementations (Randell, B., Russell, L. J.
``ALGOL 60 Implementation'').
1.1 Formalism for Syntactic Description
We have used a more modern form of BNF notation in which the quoting
conventions are reversed:
The Revised Report uses angle brackets to quote nonterminal symbols, and
leaves terminal symbols unquoted;
we leave nonterminal symbols unquoted and use apostrophes to quote terminal
symbols.
One consequence of this quoting strategy is that spaces are not allowed within nonterminal names. In order to preserve the understandability of the nonterminal names used in the Revised Report, we have adopted the convention of running the words together and capitalizing the first letter of every word. Thus we render the Revised Report's nonterminal <simple variable> as SimpleVariable.
Definition:
The null string of symbols[1]==The Revised Report uses a combination of BNF and English to describe the complete syntax of the language. Because this is an executable specification, we follow standard compiler practice, using BNF to describe the phrase structure and using a combination of regular expressions and C code to describe the basic symbols and comments.This macro is invoked in definition 2.Empty ::= .
algol60.con[2]==This macro is attached to a product file.The null string of symbols[1] Logical Values[22] Numbers[38] Variables[48] Function Designators[53] Expressions[47] Compound Statements and Blocks[84] Assignment Statements[86] Go To Statements[90] Dummy Statements[93] Conditional Statements[94] For Statements[95] Procedure Statements[97] Declarations[103]
In a definition, the regular expression defines a sequence of characters that identifies the particular basic symbol or comment. If this character sequence does not constitute the complete basic symbol or comment, then an auxiliary scanner that obtains the complete sequence is specified. Finally, if an internal representation of the basic symbol or comment is required, then a token processor that builds the desired internal representation is specified.
For example, consider an ALGOL 60 string. This basic symbol is identified by the opening string quote `. A single opening string quote does not constitute the complete string, so we specify an auxiliary scanner called Algol60String to obtain the complete sequence. An internal representation of the string is required, so we specify the token processor mkidn to build that representation.
Auxiliary scanners and token processors for common situations can be found in the Eli library, or they can be written in C or C++ and provided with the specification. This document includes two C-coded auxiliary scanners, Algol60Comment and Algol60String, and uses one, Ctext, from the Eli library. Both of the token processors, mkidn and mkstr, are taken from the Eli library.
All auxiliary scanners obey the following interface specification:
Define an Auxiliary Scanner[3](¶1)==A type-gla file provides the definitions of the basic symbols to be recognized by the lexical analyzer. These definitions specify not only the form of the basic symbol, but also the mechanism by which its internal representation (if any) will be constructed.This macro is invoked in definitions 25 and 41.char * #if defined(__cplusplus) || defined(__STDC__) ¶1(char *start, int length) #else ¶1(start, length) char *start; int length; #endif /* Standard interface for an auxiliary scanner * On entry- * start points to the first character of the scanned string * length=length of the scanned string * On exit- * The function returns a pointer to the first character * beyond the scanned string ***/
algol60.gla[4]==A type-c file provides auxiliary routines to handle tasks that must be defined operationally.This macro is attached to a product file.Delimiters[23] Unsigned Numbers[37] Identifiers[28] Strings[40] Parameter Delimiter Letter String[54] Code as Procedure Body[121]
algol60.c[5]==This macro is attached to a product file.#include <stdio.h> #include <string.h> #include <ctype.h> #include "err.h" #include "gla.h" #include "source.h" #include "tabsize.h" Comment Scanner[25] String Scanner[41]
algol60.map[6]==Our specifications of equivalence classes have replaced the examples of ALGOL 60 code that appear in the Revised Report. Where no equivalence classes are defined, we have inserted an empty section in order to keep the section numbering parallel to that of the Revised Report.This macro is attached to a product file.MAPSYM Equivalences[49]
Relationships among computations are embodied in attributes, which constitute pre- and post-conditions for computations. An attribute may have a value, and that value may be of any type. Types are often defined by external modules that export a set of appropriate operations for use in computation. The pre- and post-conditions may relate computations locally, or remotely along root-to-leaf or depth-first, left-to-right paths.
Eli's attribute grammar notation is LIDO. A LIDO specification consists of a set of symbol and rule computations, with additional definitions of the types of attributes. All computations must be expressed as function application. (Non-strict functions are available for dealing with conditional computation.) Computations may be associated with specific contexts in the tree (rule computations), or with every context in which a particular symbol appears (symbol computations).
algol60.lido[7]==This macro is attached to a product file.Internal representation of an identifier[29] Subscripts[52] Scope Attributes[45] Scope Violation Rules[30] Statement Scope Rules[9] Establish operator indications for source symbols[67] Identify an operator from its context[13] Balance the operands of a conditional[14] Semantics[44] Verify type consistency of a left-part list[89] The for List Elements[96] Actual-Formal Correspondence[99] Restrictions[100] Specifications[118]
Identifiers are freely chosen by the programmer and given meaning through specific language constructs. The general strategy is to bind the definition of an identifier and all of its uses to the same definition table key. When processing a construct that gives meaning to an identifier, properties characterizing that meaning are associated with the definition table key to which the definition is bound, and when processing a construct that uses an identifier those properties are accessed.
Eli provides modules for establishing these bindings. Each module implements a specific set of rules governing the binding process, and any number of copies of any of the available modules can be instantiated in a given specification.
Instantiate the ALGOL 60 consistent renaming module[8]==This module exports a set of computational roles defining the behavior of the relevant constructs:This macro is invoked in definition 18.$/Name/AlgScope.gnrc :inst
Statement Scope Rules[9]==This macro is invoked in definition 7.SYMBOL Program INHERITS RootScope END;
Operator indications are established for each operator's source language symbol by computations described in LIDO:
Set a monadic operator indication[10](¶2)==This macro is invoked in definitions 67 and 78.RULE: Uniop ::= '¶1' COMPUTE Uniop.indication=OilOp¶2; END;
Set a dyadic operator indication[11](¶2)==Signatures for the operators are described, and operators associated with indications, by descriptions written in OIL:This macro is invoked in definitions 67, 69, 71, 78, and 80.RULE: Binop ::= '¶1' COMPUTE Binop.indication=OilOp¶2; END;
algol60.oil[12]==OIL describes a set of constraints that the operators and expressions must satisfy. Those constraints must be verified by tree computations that use operations exported by the OIL library:This macro is attached to a product file.Define operators and associate them with indications[59] Define an operator to be applied when needed[73] Define operators to establish types without values[92]
Identify an operator from its context[13]==The constraint on a conditional expression is that the type of the result must not depend on the (run-time) outcome of the condition:This macro is invoked in definition 7.ATTR type: tOilType; ATTR indication, operator: tOilOp; RULE: Expression ::= Uniop Expression COMPUTE Expression[1].type=OilGetArgType(Uniop.operator,0); Uniop.operator=OilIdOp1(Uniop.indication,Expression[2].type); END; SYMBOL Uniop COMPUTE IF(NOT(OilIsValidOp(THIS.operator)), message(ERROR, "Illegal operation", 0, COORDREF)); END; RULE: Expression ::= Expression Binop Expression COMPUTE Expression[1].type=OilGetArgType(Binop.operator,0); Binop.operator= OilIdOp2(Binop.indication,Expression[2].type,Expression[3].type); END; SYMBOL Binop COMPUTE IF(NOT(OilIsValidOp(THIS.operator)), message(ERROR, "Illegal operation", 0, COORDREF)); END;
Balance the operands of a conditional[14]==This macro is invoked in definition 7.RULE: Expression ::= IfClause Expression 'else' Expression COMPUTE Expression[1].type= OilBalance( OilTypeToSet(Expression[2].type), OilTypeToSet(Expression[3].type)); END;
algol60.pdl[15]==The declaration of a property specifies the type of value that property can hold. All C basic types, plus the type DefTableKey (the type of a definition table key) can be used without further specification; any other types must be specified by some type-h file whose name is given in the type-pdl file.This macro is attached to a product file."algol60.h" "keyarray.h" Properties characterizing all quantities[43] Properties characterizing arrays[110] Properties characterizing procedures[119] Properties characterizing formal parameters[120] Properties of standard functions[60] Arity of transfer functions[63]
algol60.h[16]==Because type-h files may be included by several different specifications, they must be protected against multiple inclusion. Eli's convention is to use a symbol consisting of the file name rendered in upper case, with periods replaced by underscores.This macro is attached to a product file.#ifndef ALGOL60_H #define ALGOL60_H Kinds of quantities[42] #endif
The definitions must be made available to the routines that implement the computations, by including them in a type-HEAD.phi file:
algol60.HEAD.phi[17]==This macro is attached to a product file.#include "algol60.h"
algol60.specs[18]==The predefinition module requires that the specifications of predefined identifiers be supplied in a file whose name is passed as the referto parameter of the module's instantiation. This file is defined above as the result of the Eli request ALGOL60.fw:fwGen/algol60.d:This macro is attached to a product file.Instantiate the ALGOL 60 consistent renaming module[8] $/Prop/Unique.gnrc :inst $/Tech/Strings.specs $/pdl/keyarray.specs $/Name/PreDefine.gnrc +referto=Identifier :inst $/Name/PreDefId.gnrc +referto=(algol60.d) :inst
algol60.d[19]==Eli attaches no particular significance to the d suffix. It was chosen specifically for this reason, to avoid any unintended processing by Eli.This macro is attached to a product file.Standard Functions[58] Transfer Functions[61]
Basic symbols are recognized by a finite-state machine, and therefore the definitions of the basic symbols are stated as regular expressions rather than productions of a context-free grammar. This means that all recursive definitions given in the Revised Report must be replaced by the equivalent iterative formulations. We have kept the regular expression notation as close to the form of the context-free grammar as possible to ease verification, except that we have replaced alternations with a more compact representation when describing sets of characters: [a-d] means a|b|c|d and [^;] means ``any character other than semicolon'', for example.
The scanner that recognizes basic symbols attaches source text coordinates
(the line number and column number of the first character) to each basic
symbol.
This requires that the scanner keep track of the coordinates as it is
scanning.
Coordinate tracking is handled automatically for most basic symbols, but
must be provided explicitly for basic symbols that may contain horizontal
tab or newline characters.
These cases are noted below when they occur.
2.1 Letters
letter[20]==Letters are used only as components of other basic symbols.This macro is invoked in definition 28.[a-zA-Z]
digit[21]==Digits are used only as components of other basic symbols.This macro is invoked in definitions 28 and 31.[0-9]
Logical Values[22]==The logical values are denoted by keywords of the language.This macro is invoked in definition 2.LogicalValue ::= 'true' / 'false' .
Delimiters[23]==(\040 must be used to represent a space within a regular expression because any white space terminates the expression.)This macro is defined in definitions 23 and 24.Semi: $;([\040\t\n]*comment[^;]*;)? (coordAdjust) begin: $begin([\040\t\n]+comment[^;]*;)? (coordAdjust)
This macro is invoked in definition 4.
Both Semi and begin are easy to define with regular expressions because they are self-delimiting. The regular expression accepts horizontal tabs and newlines, and therefore the auxiliary scanner coordAdjust must be used to adjust the coordinates appropriately.
Comments following end are much harder to deal with because they can not contain certain strings. It would be possible to write a regular expression that matched strings ending in end or ; or else, and then use an auxiliary scanner to accept everything up to but not including that symbol. The problem is that the scanner would then find the longest such string, and we need the shortest such string.
Thus we need to use an auxiliary scanner to pick up the comment string following an end:
Delimiters[24]==An auxiliary scanner is invoked after the associated regular expression has been accepted. In this case, Algol60Comment will be invoked after the normal scanner has accepted the symbol end.This macro is defined in definitions 23 and 24.end: $end (Algol60Comment)
This macro is invoked in definition 4.
The auxiliary scanner is called with a pointer to the first character matched by the regular expression and the length of the string matching the regular expression; it should return a pointer to the first character that does not belong to the basic symbol being recognized. Thus start should point to the e of end, length should be 3, and Algol60Comment should return a pointer to the next end, ; or else.
The regular expression will match the characters e, n and d in that order. Since the scanner finds the longest match, the character following the d cannot be a letter or a digit. If it were, the scanner would combine it with the first three characters in searching for an identifier. The variable p is set to point to the character following the d, so after fetching that character to c and incrementing p the stated loop invariant holds:
Comment Scanner[25]==If c is ;, then the scan should be terminated and the position of the semicolon returned. Otherwise, any necessary adjustment of the coordinates to reflect a tab or newline character must be made.This macro is defined in definitions 25.Define an Auxiliary Scanner[3] (`Algol60Comment') { char *p = start + length; char c = *p++; for (;;) { /* Invariant: * c is neither a letter nor a digit && * p points to the first unexamined character * Bound: Number of characters left in the file ***/ if (c == ';') return p - 1; Adjust coordinates if necessary[26] (`') if (*p == 'e') { if (strncmp(p, "end", 3) == 0 && !isalnum(p[3]) || strncmp(p, "else", 4) == 0 && !isalnum(p[4])) return p; } while (isalnum(c = *p++)) ; } }
This macro is invoked in definition 5.
The first unexamined character, pointed to by p, could be anything. If it is an e, then the routine checks for the presence of one of the two keywords that can follow the comment. Each of the specified character sequences must be followed by a character other than a letter or digit if it is to be recognized as a keyword. When either of those keywords is found, the routine returns the position of that keyword. (Thus terminating the comment with the character preceding the keyword.)
Finally, the routine re-establishes the invariant of the outer loop.
The generated scanner keeps track of the line and column number of each basic symbol, so that the processor can report errors at the appropriate position in the source program. Tab and newline characters require special action to maintain these values:
Adjust coordinates if necessary[26](¶1)==Character position within a line is the difference between the current character index and the character index StartLine. A tab character occupies one character position, but it may represent a longer sequence, depending upon it's position in the line. This additional white space is taken into account by moving StartLine backwards.This macro is invoked in definitions 25 and 41.if (c == '\t') StartLine -= TABSIZE(p - StartLine); else if (c == '\n') { Refill the source buffer if necessary[27] (`¶1') LineNum++; StartLine = p - 1; }
The coordinate adjustment code is needed for processing strings (Section 2.6) as well. These two cases differ in that it is an error for the file to end within a string, but no error if the file ends within a comment. If an end-of-file is an error, code to report that error must be introduced. That code is introduced through the parameter to the coordinate adjustment description.
Source text is stored as a sequence of characters in memory, and the last character of that sequence is guaranteed to be a newline. If the character following a newline is the ASCII NUL character, then there are no more characters in the sequence; otherwise, this newline is not the last newline of the sequence. Thus when the scanner reaches a newline, it must check whether that newline is the last of the sequence in memory:
Refill the source buffer if necessary[27](¶1)==Recall that p points to the character following the newline. If it is the ASCII NUL character, then there are no more characters of the file stored in memory. By calling refillBuf with start as an argument, the scanner extends the character sequence that begins at the location pointed to by start. Because of the way storage is allocated by the source text input module, it may be necessary to move the sequence to another location. Thus TokenStart (the starting location of the basic symbol), start, and p must all be adjusted. Finally, a check is made to see whether the character sequence was, in fact, extended. If it was not, then end-of-file has been reached, the comment string has ended, and the scanner terminates.This macro is invoked in definition 26.if (*p == '\0') { size_t pSave = p - start, sSave = p - StartLine; refillBuf(start); TokenStart = start = TEXTSTART; p = start + pSave; StartLine = start + sSave; if (*p == '\0') { ¶1 return p - 1; } }
Identifiers[28]==This regular expression is equivalent to the definition given in the Revised Report.This macro is invoked in definition 4.Identifier: $letter[20](letter[20]|digit[21])* [mkidn]
Distinct identifiers must be distinguishable from one another. The token processor mkidn assigns a unique integer value to each distinct identifier. This integer value can also be used to access the string representing the identifier, and is stored as the value of the Sym attribute of symbols representing identifier occurrences:
Internal representation of an identifier[29]==The same identifier cannot be used to denote two different quantities except when these quantities have disjoint scopes as defined by the declarations of the program:This macro is invoked in definition 7.ATTR Sym: int;
Scope Violation Rules[30]==This macro is defined in definitions 30, 46, and 102.SYMBOL MultDefChk INHERITS Unique COMPUTE IF(NOT(THIS.Unique), message( ERROR, CatStrInd("Identifier is multiply defined: ", THIS.Sym), 0, COORDREF)); END;
This macro is invoked in definition 7.
unsigned integer[31]==This regular expression is equivalent to the definition given in the Revised Report.This macro is invoked in definitions 32, 33, 35, and 37.digit[21]+
integer[32]==The + must be escaped because it is a regular expression operator.This macro is invoked in definition 34.(unsigned integer[31]|\+unsigned integer[31]|-unsigned integer[31])
decimal fraction[33]==The . must be escaped because it is a regular expression operator.This macro is invoked in definition 35.\.unsigned integer[31]
Following standard practice, we represent the subscript 10 of the reference language by the letter E:
exponent part[34]==By requiring a decimal number to contain a decimal fraction, we obtain distinct representations for integer and real constants:This macro is invoked in definitions 36 and 37.(E|e)integer[32]
decimal number[35]==We cannot allow an unsigned number consisting of only an exponent part, because there would be no way for the scanner to distinguish it from an identifier (this is a consequence of our representing the subscript 10 of the reference language by the letter E):This macro is invoked in definition 36.(decimal fraction[33]|unsigned integer[31]decimal fraction[33])
unsigned number[36]==We express the distinction between integer and real constants by introducing the new basic symbol UnsignedReal, which does not appear in the Revised Report:This macro is invoked in definition 37.(decimal number[35]|decimal number[35]exponent part[34])
Unsigned Numbers[37]==The token processor mkidn assigns a unique integer value to each distinct numeric denotation. (Note that distinct denotations may represent the same numeric value: 001 has the same value as 1 and 1.23E1 has the same value as 12.3.) This integer value can be used to access the denoting string.This macro is invoked in definition 4.UnsignedInteger: $unsigned integer[31] [mkidn] UnsignedReal: $unsigned number[36]|unsigned integer[31]exponent part[34] [mkidn]
An unsigned integer followed by an exponent part is legal according to the Revised Report. Because of the need to exclude unsigned integer from the definition of decimal number, however, this case has to be treated specially.
Numbers[38]==The symbol number does not appear elsewhere in the Revised Report, so it is not defined here.This macro is invoked in definition 2.UnsignedNumber: UnsignedInteger / UnsignedReal .
Denotation types[39]==This macro is invoked in definition 66.RULE: Expression ::= UnsignedInteger COMPUTE Expression.type=OilTypeIntegerKey; END; RULE: Expression ::= UnsignedReal COMPUTE Expression.type=OilTypeRealKey; END;
Strings[40]==Algol60String will be invoked after the normal scanner has accepted the character `.This macro is invoked in definition 4.String: $` (Algol60String) [mkidn]
String Scanner[41]==This macro is invoked in definition 5.Define an Auxiliary Scanner[3] (`Algol60String') { char *p = start + length; int counter = 1; /* Invariant: * counter = number of unmatched open quotes * p points to the first unexamined character * Bound: Number of characters left in the file ***/ while (counter) { char c = *p++; Adjust coordinates if necessary[26] (`message(ERROR,"End-of-file in string",0,&curpos);') if (c == '\'') counter--; else if (c == '`') counter++; } return p; }
Kinds of quantities[42]==UndefinedIdn is used to distinguish identifiers that are used but not declared. Every declared quantity is represented internally by a definition table key under which the kind is stored as a property:This macro is invoked in definition 16.typedef enum { UndefinedIdn, VariableIdn, ArrayIdn, LabelIdn, SwitchIdn, ProcedureIdn } KindOfQuantity;
Properties characterizing all quantities[43]==The kind of quantity may also be stored as an attribute of certain nodes, and a dependence must be used to guarantee that all quantities have their Kind properties set before any are queried:This macro is defined in definitions 43 and 51.Kind: KindOfQuantity;
This macro is invoked in definition 15.
Semantics[44]==The scope of a quantity is the set of statements and expressions in which the declaration of the identifier associated with that quantity is valid. A scope is represented internally by an environment, which is stored as the Env attribute of symbols representing certain sets of statements and expressions. A quantity is represented internally by a definition table key, which is stored as the Key attribute of symbols representing occurrences of identifiers:This macro is defined in definitions 44, 50, 57, 66, 77, 83, 85, 87, 91, 98, 106, 109, 112, and 117.ATTR kind: KindOfQuantity; SYMBOL Program COMPUTE SYNT.GotAllProperties= CONSTITUENTS ( VarIdDef.GotProperties,ArraySegment.GotProperties, ProcedureDeclaration.GotProperties,Label.GotProperties); END;
This macro is invoked in definition 7.
Scope Attributes[45]==This macro is invoked in definition 7.ATTR Env: Environment; ATTR Key: DefTableKey;
Scope Violation Rules[46]==This macro is defined in definitions 30, 46, and 102.SYMBOL VarIdDef INHERITS MultDefChk END; SYMBOL FormalParameter INHERITS MultDefChk END; SYMBOL Program INHERITS RangeUnique END;
This macro is invoked in definition 7.
The Revised Report does not consider that labels and strings have values, but this position is inconsistent with the fact that labels and strings can be passed as parameters. For uniformity, therefore, we specify operators for labels and strings as well as for integer, real and Boolean values. These specifications result in the values OilTypeLabelKey and OilTypeStringKey, which we use to represent the ``types'' of labels and strings.
Parameter-passing and assignment operations do not yield results, but
rather have side effects on the state of the computation.
Our specifications of these operations result in the value
OilTypeVoidKey, and we use that value to represent situations in which
no value may occur.
3 Expressions
The grammar given in the Revised Report is ambiguous.
Several changes were needed to eliminate the ambiguity; these will be
pointed out in the appropriate sections.
Because type information is required to distinguish arithmetic, Boolean and designational expressions, we have merged the grammars for these three kinds of expression. Wherever possible, however, we have retained the nonterminal symbols used in the Revised Report.
The Revised Report distinguishes various classes of identifier: variable identifier, array identifier, switch identifier and procedure identifier. Without information about how an identifier was declared, it is impossible to make this distinction in all contexts. We have therefore replaced every occurrence of the nonterminals variable identifier, array identifier, switch identifier and procedure identifier with the terminal Identifier and eliminated the rules defining those nonterminals.
Expressions[47]==This macro is invoked in definition 2.Arithmetic Expressions[64] Boolean Expressions[75] Designational Expressions[82]
Variables[48]==This macro is invoked in definition 2.SimpleVariable ::= Identifier . SubscriptExpression ::= Expression . SubscriptList ::= SubscriptExpression / SubscriptList ',' SubscriptExpression . SubscriptedVariable ::= Identifier '[' SubscriptList ']' . Variable ::= SimpleVariable / SubscriptedVariable .
Equivalences[49]==This macro is defined in definitions 49, 65, 76, and 105.Variable ::= SimpleVariable SubscriptedVariable .
This macro is invoked in definition 6.
Semantics[50]==This macro is defined in definitions 44, 50, 57, 66, 77, 83, 85, 87, 91, 98, 106, 109, 112, and 117.SYMBOL Variable INHERITS IdUseEnv COMPUTE SYNT.Sym=TERM; SYNT.type= GetType(THIS.Key,OilErrorType()) DEPENDS_ON INCLUDING Program.GotAllProperties; END;
This macro is invoked in definition 7.
Properties characterizing all quantities[51]==This macro is defined in definitions 43 and 51.Type: tOilType;
This macro is invoked in definition 15.
Subscripts[52]==This macro is invoked in definition 7.ATTR dim, sub: int; RULE: Variable ::= Identifier '[' SubscriptList ']' COMPUTE .kind= GetKind(Variable.Key,UndefinedIdn) DEPENDS_ON INCLUDING Program.GotAllProperties; .dim=GetDim(Variable.Key,0) DEPENDS_ON INCLUDING Program.GotAllProperties; .sub= CONSTITUENTS SubscriptExpression.operator SHIELD SubscriptExpression WITH (int, ADD, ARGTOONE, ZERO); IF(AND(AND(NE(.kind,ArrayIdn),NE(.kind,UndefinedIdn)),NE(.kind,SwitchIdn)), message(ERROR,"Array or switch identifier required",0,COORDREF)); IF(AND(NE(.dim,0),NE(.dim,.sub)), message(ERROR,"Number of indices differs from dimension",0,COORDREF)); END; RULE: SubscriptExpression ::= Expression COMPUTE SubscriptExpression.operator= OilIdOp2(OilOpColonEqual,OilTypeIntegerKey,Expression.type); IF(EQ(SubscriptExpression.operator,OilErrorOp()), message(ERROR,"Invalid type for subscript",0,COORDREF)); END;
Function Designators[53]==The complex parameter delimiter must be treated as a basic symbol in order to distinguish the letter string it contains from an identifier:This macro is defined in definitions 53, 55, and 56.ActualParameter ::= String / Expression . ParameterDelimiter ::= ',' / PDLetterString .
This macro is invoked in definition 2.
Parameter Delimiter Letter String[54]==This macro is invoked in definition 4.PDLetterString : $\)[a-zA-Z]+:\(
Function Designators[55]==A FunctionDesignator with an empty ActualParameterPart cannot be distinguished from a Variable in the absence of type information, so we have eliminated the empty alternative of the ActualParameterPart:This macro is defined in definitions 53, 55, and 56.ActualParameterList ::= ActualParameter / ActualParameterList ParameterDelimiter ActualParameter .
This macro is invoked in definition 2.
Function Designators[56]==This macro is defined in definitions 53, 55, and 56.FunctionDesignator ::= Identifier '(' ActualParameterList ')' .
This macro is invoked in definition 2.
Semantics[57]==This macro is defined in definitions 44, 50, 57, 66, 77, 83, 85, 87, 91, 98, 106, 109, 112, and 117.SYMBOL FunctionDesignator INHERITS IdUseEnv, ActualFormalCorrespondence COMPUTE SYNT.Sym=TERM; END; RULE: FunctionDesignator ::= Identifier '(' ActualParameterList ')' COMPUTE .kind= GetKind(FunctionDesignator.Key,UndefinedIdn) DEPENDS_ON INCLUDING Program.GotAllProperties; IF(AND(NE(.kind,ProcedureIdn),NE(.kind,UndefinedIdn)), message(ERROR, "Not a procedure identifier", 0, COORDREF)); END;
This macro is invoked in definition 7.
Standard Functions[58]==These functions are understood to operate indifferently on arguments both of type real and integer. They will all yield values of type real, except for sign(E) which will have values of type integer.This macro is invoked in definition 19.PreDefKey("abs", absKey) PreDefKey("sign", signKey) PreDefKey("sqrt", sqrtKey) PreDefKey("sin", sinKey) PreDefKey("cos", cosKey) PreDefKey("arctan",arctanKey) PreDefKey("ln", lnKey) PreDefKey("exp", expKey)
Define operators and associate them with indications[59]==This macro is defined in definitions 59, 62, 68, 70, 72, 74, 79, 81, and 88.OPER absKey(RealKey): RealKey; signKey(RealKey): IntegerKey; sqrtKey, sinKey, cosKey, arctanKey, lnKey, expKey(RealKey): RealKey; INDICATION absKey: absKey; signKey: signKey; sqrtKey: sqrtKey; sinKey: sinKey; cosKey: cosKey; arctanKey: arctanKey; lnKey: lnKey; expKey: expKey;
This macro is invoked in definition 12.
Properties of standard functions[60]==This macro is invoked in definition 15.absKey -> Arity={1}, Operator={OilOpabsKey}; signKey -> Arity={1}, Operator={OilOpsignKey}; sqrtKey -> Arity={1}, Operator={OilOpsqrtKey}; sinKey -> Arity={1}, Operator={OilOpsinKey}; cosKey -> Arity={1}, Operator={OilOpcosKey}; arctanKey -> Arity={1}, Operator={OilOparctanKey}; lnKey -> Arity={1}, Operator={OilOplnKey}; expKey -> Arity={1}, Operator={OilOpexpKey};
Transfer Functions[61]==This macro is invoked in definition 19.PreDefKey("entier",entierKey)
Define operators and associate them with indications[62]==This macro is defined in definitions 59, 62, 68, 70, 72, 74, 79, 81, and 88.OPER entierKey(RealKey): IntegerKey; INDICATION entierKey: entierKey;
This macro is invoked in definition 12.
Arity of transfer functions[63]==This macro is invoked in definition 15.entierKey -> Arity={1}, Operator={OilOpentierKey};
Arithmetic Expressions[64]==The Revised Report makes no syntactic distinction between the monadic and dyadic versions of + and -. Because this distinction is important for the semantics of the language, we have made it by using literals for the monadic versions.This macro is defined in definitions 64.AddingOperator ::= '+' / '-' . MultiplyingOperator ::= '*' / '/' / 'div' . Primary ::= UnsignedNumber / Variable / FunctionDesignator / '(' Expression ')' . Factor ::= Primary / Factor '^' Primary . Term ::= Factor / Term MultiplyingOperator Factor . SimpleArithmeticExpression ::= Term / '+' Term / '-' Term / SimpleArithmeticExpression AddingOperator Term . IfClause ::= 'if' Expression 'then' .
This macro is invoked in definition 47.
Equivalences[65]==This macro is defined in definitions 49, 65, 76, and 105.Binop ::= AddingOperator MultiplyingOperator . Expression ::= SimpleArithmeticExpression Term Factor Primary UnsignedNumber .
This macro is invoked in definition 6.
Semantics[66]==This macro is defined in definitions 44, 50, 57, 66, 77, 83, 85, 87, 91, 98, 106, 109, 112, and 117.RULE: ArithmeticExpression ::= Expression COMPUTE IF( AND(AND( NE(Expression.type,OilErrorType()), NE(Expression.type,OilTypeIntegerKey)), NE(Expression.type,OilTypeRealKey)), message(ERROR,"Expression must be arithmetic",0,COORDREF)); END; RULE: IfClause ::= 'if' BooleanExpression 'then' END; Denotation types[39] RULE: Expression ::= Variable COMPUTE Expression.type = Variable.type; END; RULE: Expression ::= FunctionDesignator COMPUTE Expression.type = FunctionDesignator.type; END;
This macro is invoked in definition 7.
The operators +, - and * have the conventional meaning (addition, subtraction and multiplication). The type of the expression will be integer if both of the operands are of integer type, otherwise real:
Establish operator indications for source symbols[67]==This macro is defined in definitions 67, 69, 71, 78, and 80.Set a monadic operator indication[10] (`+', `Nop') Set a dyadic operator indication[11] (`+', `Plus') Set a monadic operator indication[10] (`-', `Neg') Set a dyadic operator indication[11] (`-', `Minus') Set a dyadic operator indication[11] (`*', `Star')
This macro is invoked in definition 7.
Define operators and associate them with indications[68]==It is unnecessary to provide operators for all combinations of integer and real operands because Section 5.1.3 implies that the compiler is allowed to convert an integer value to a real value in an arithmetic expression wherever the context requires it.This macro is defined in definitions 59, 62, 68, 70, 72, 74, 79, 81, and 88.OPER iNop, iNeg(IntegerKey): IntegerKey; iiAdd, iiSubtract, iiMultiply(IntegerKey, IntegerKey): IntegerKey; rNop, rNeg(RealKey): RealKey; rrAdd, rrSubtract, rrMultiply(RealKey, RealKey): RealKey; INDICATION Nop: iNop, rNop; Plus: iiAdd, rrAdd; Neg: iNeg, rNeg; Minus: iiSubtract, rrSubtract; Star: iiMultiply, rrMultiply;
This macro is invoked in definition 12.
The source language operator symbols / and div both denote division, to be understood as a multiplication of the left operand by the reciprocal of the right operand.
/ is defined for all four combinations of types real and integer and will yield results of type real in any case. The operator div is defined only for two operands both of type integer and will yield a result of type integer:
Establish operator indications for source symbols[69]==This macro is defined in definitions 67, 69, 71, 78, and 80.Set a dyadic operator indication[11] (`/', `Slash') Set a dyadic operator indication[11] (`div', `Div')
This macro is invoked in definition 7.
Define operators and associate them with indications[70]==The source language operator symbols ^ denotes exponentiation:This macro is defined in definitions 59, 62, 68, 70, 72, 74, 79, 81, and 88.OPER rrDiv(RealKey, RealKey): RealKey; iiDiv(IntegerKey, IntegerKey): IntegerKey; INDICATION Slash: rrDiv; Div: iiDiv;
This macro is invoked in definition 12.
Establish operator indications for source symbols[71]==This macro is defined in definitions 67, 69, 71, 78, and 80.Set a dyadic operator indication[11] (`^', `UpArrow')
This macro is invoked in definition 7.
Define operators and associate them with indications[72]==The fact that the type of the result of an exponentiation depends on the value of one of the operands is a problem, because type is considered to be a static property of the program in this specification. A new arithmetic type is defined to handle this situation.This macro is defined in definitions 59, 62, 68, 70, 72, 74, 79, 81, and 88.OPER iiExp(IntegerKey, IntegerKey): ArithKey; riExp(RealKey, IntegerKey): RealKey; rrExp(RealKey, RealKey): RealKey; INDICATION UpArrow: iiExp, riExp, rrExp;
This macro is invoked in definition 12.
A value of arithmetic type will have to carry an indication of its type with it. It can be used as either a value of type integer or a value of type real, subject to appropriate run-time checks and/or conversions:
Define an operator to be applied when needed[73]==Unfortunately, it must be possible to perform all arithmetic operations on values of arithmetic type if those operations can be performed on values of either type real or type integer:This macro is defined in definitions 73 and 107.COERCION aiConvert(ArithKey): IntegerKey; arConvert(ArithKey): RealKey;
This macro is invoked in definition 12.
Define operators and associate them with indications[74]==This macro is defined in definitions 59, 62, 68, 70, 72, 74, 79, 81, and 88.OPER aNop, aNeg(ArithKey): ArithKey; aiAdd, aiSubtract, aiMultiply(ArithKey, IntegerKey): ArithKey; iaAdd, iaSubtract, iaMultiply(IntegerKey, ArithKey): ArithKey; aaAdd, aaSubtract, aaMultiply(ArithKey, ArithKey): ArithKey; aiExp(ArithKey, IntegerKey): ArithKey; iaExp(IntegerKey, ArithKey): ArithKey; arExp(ArithKey, RealKey): RealKey; raExp(RealKey, ArithKey): RealKey; aaExp(ArithKey, ArithKey): ArithKey; INDICATION Nop: aNop; Plus: aiAdd, iaAdd, aaAdd; Neg: aNeg; Minus: aiSubtract, iaSubtract, aaSubtract; Star: aiMultiply, iaMultiply, aaMultiply; UpArrow: aiExp, iaExp, arExp, raExp, aaExp;
This macro is invoked in definition 12.
Boolean Expressions[75]==This macro is invoked in definition 47.RelationalOperator ::= '<' / '<=' / '=' / '>=' / '>' / '!=' . Relation ::= SimpleArithmeticExpression RelationalOperator SimpleArithmeticExpression . BooleanPrimary ::= SimpleArithmeticExpression / LogicalValue / Relation . BooleanSecondary ::= BooleanPrimary / 'not' BooleanPrimary . BooleanFactor ::= BooleanSecondary / BooleanFactor 'and' BooleanSecondary . BooleanTerm ::= BooleanFactor / BooleanTerm 'or' BooleanFactor . Implication ::= BooleanTerm / Implication '->' BooleanTerm . SimpleBoolean ::= Implication / SimpleBoolean '==' Implication . Expression ::= SimpleBoolean / IfClause SimpleBoolean 'else' Expression .
Equivalences[76]==This macro is defined in definitions 49, 65, 76, and 105.Binop ::= RelationalOperator . Expression ::= SimpleBoolean Implication BooleanTerm BooleanFactor BooleanSecondary BooleanPrimary Relation LogicalValue.
This macro is invoked in definition 6.
Semantics[77]==This macro is defined in definitions 44, 50, 57, 66, 77, 83, 85, 87, 91, 98, 106, 109, 112, and 117.RULE: BooleanExpression ::= Expression COMPUTE IF( AND( NE(Expression.type,OilErrorType()), NE(Expression.type,OilTypeBooleanKey)), message(ERROR,"Expression must be Boolean",0,COORDREF)); END; RULE: Expression ::= 'true' COMPUTE Expression.type=OilTypeBooleanKey; END; RULE: Expression ::= 'false' COMPUTE Expression.type=OilTypeBooleanKey; END;
This macro is invoked in definition 7.
Establish operator indications for source symbols[78]==This macro is defined in definitions 67, 69, 71, 78, and 80.Set a monadic operator indication[10] (`not', `Not') Set a dyadic operator indication[11] (`<', `Lt') Set a dyadic operator indication[11] (`<=', `Le') Set a dyadic operator indication[11] (`=', `Eq') Set a dyadic operator indication[11] (`!=', `Ne') Set a dyadic operator indication[11] (`>=', `Ge') Set a dyadic operator indication[11] (`>', `Gt')
This macro is invoked in definition 7.
Define operators and associate them with indications[79]==The logical operators always take values of type Boolean as operands and yield values of type Boolean as results.This macro is defined in definitions 59, 62, 68, 70, 72, 74, 79, 81, and 88.OPER iiLT, iiLE, iiEQ, iiGE, iiGT, iiNE(IntegerKey, IntegerKey): BooleanKey; rrLT, rrLE, rrEQ, rrGE, rrGT, rrNE(RealKey, RealKey): BooleanKey; INDICATION Lt: iiLT, rrLT; Le: iiLE, rrLE; Eq: iiEQ, rrEQ; Ge: iiGE, rrGE; Gt: iiGT, rrGT; Ne: iiNE, rrNE;
This macro is invoked in definition 12.
Establish operator indications for source symbols[80]==This macro is defined in definitions 67, 69, 71, 78, and 80.Set a dyadic operator indication[11] (`and', `And') Set a dyadic operator indication[11] (`or', `Or') Set a dyadic operator indication[11] (`->', `Implies') Set a dyadic operator indication[11] (`==', `Equiv')
This macro is invoked in definition 7.
Define operators and associate them with indications[81]==This macro is defined in definitions 59, 62, 68, 70, 72, 74, 79, 81, and 88.OPER bNot(BooleanKey): BooleanKey; bAnd, bOr, bImplies, bEquiv(BooleanKey, BooleanKey): BooleanKey; INDICATION Not: bNot; And: bAnd; Or: bOr; Implies: bImplies; Equiv: bEquiv;
This macro is invoked in definition 12.
Designational Expressions[82]==Designational expressions do not appear in the grammar because their phrase structure is already covered by other forms of expression, and they cannot be distinguished without type information.This macro is invoked in definition 47.Label ::= Identifier .
Semantics[83]==This macro is defined in definitions 44, 50, 57, 66, 77, 83, 85, 87, 91, 98, 106, 109, 112, and 117.SYMBOL Label INHERITS IdDefScope COMPUTE SYNT.Sym=TERM; SYNT.GotProperties= ORDER(ResetType(THIS.Key,OilTypeLabelKey),ResetKind(THIS.Key,LabelIdn)); END; RULE: DesignationalExpression ::= Expression COMPUTE IF( AND( NE(Expression.type,OilErrorType()), NE(Expression.type,OilTypeLabelKey)), message(ERROR,"Label expected",0,COORDREF)); END;
This macro is invoked in definition 7.
Compound Statements and Blocks[84]==This macro is invoked in definition 2.UnlabelledBasicStatement ::= AssignmentStatement / GoToStatement / DummyStatement / ProcedureStatement . BasicStatement ::= UnlabelledBasicStatement / Label ':' BasicStatement. UnconditionalStatement ::= BasicStatement / CompoundStatement / Block . Statement ::= UnconditionalStatement / ConditionalStatement / ForStatement . CompoundTail ::= Statement end / Statement Semi CompoundTail . BlockHead ::= begin Declaration / BlockHead Semi Declaration . UnlabelledCompound ::= begin CompoundTail . UnlabelledBlock ::= BlockHead Semi CompoundTail . CompoundStatement ::= UnlabelledCompound / Label ':' CompoundStatement . Block ::= UnlabelledBlock / Label ':' Block . Program ::= Block / CompoundStatement .
Semantics[85]==This macro is defined in definitions 44, 50, 57, 66, 77, 83, 85, 87, 91, 98, 106, 109, 112, and 117.SYMBOL Block INHERITS RangeScope END;
This macro is invoked in definition 7.
Assignment Statements[86]==This macro is invoked in definition 2.LeftPart ::= Variable ':=' . LeftPartList ::= LeftPart / LeftPartList LeftPart . AssignmentStatement ::= LeftPartList Expression .
Semantics[87]==This macro is defined in definitions 44, 50, 57, 66, 77, 83, 85, 87, 91, 98, 106, 109, 112, and 117.ATTR Key: DefTableKey; SYMBOL Program COMPUTE THIS.Key = NoKey; END; RULE: LeftPart ::= Variable ':=' COMPUTE LeftPart.kind= GetKind(Variable.Key,UndefinedIdn) DEPENDS_ON INCLUDING Program.GotAllProperties; IF( AND(AND( NE(LeftPart.kind,VariableIdn), NE(LeftPart.kind,ArrayIdn)), NE(LeftPart.kind,ProcedureIdn)), message(ERROR,"Illegal left of :=",0,COORDREF)); IF( AND( EQ(LeftPart.kind,ProcedureIdn), NE(INCLUDING (ProcedureDeclaration.Key,Program.Key),Variable.Key)), message(ERROR,"Illegal use of procedure id",0,COORDREF)); END;
This macro is invoked in definition 7.
Define operators and associate them with indications[88]==This macro is defined in definitions 59, 62, 68, 70, 72, 74, 79, 81, and 88.OPER bAssign(BooleanKey,BooleanKey):VoidKey; iiAssign(IntegerKey,IntegerKey):VoidKey; irAssign(IntegerKey,RealKey): VoidKey; rrAssign(RealKey,RealKey): VoidKey; INDICATION ColonEqual: bAssign, iiAssign, irAssign, rrAssign;
This macro is invoked in definition 12.
Verify type consistency of a left-part list[89]==This macro is invoked in definition 7.CHAIN LeftPartType: tOilType; RULE: AssignmentStatement ::= LeftPartList Expression COMPUTE .operator=OilIdOp2(OilOpColonEqual,AssignmentStatement.type,Expression.type); CHAINSTART LeftPartList.LeftPartType=OilErrorType(); AssignmentStatement.type=LeftPartList.LeftPartType; IF(NOT(OilIsValidOp(.operator)), message(ERROR, "Illegal assignment", 0, COORDREF)); END; RULE: LeftPart ::= Variable ':=' COMPUTE LeftPart.LeftPartType= IF(EQ(LeftPart.LeftPartType,OilErrorType()), Variable.type, ORDER( IF(NE(Variable.type,LeftPart.LeftPartType), message(ERROR,"Type differs from earlier left part",0,COORDREF)), LeftPart.LeftPartType)); END;
Go To Statements[90]==This macro is invoked in definition 2.GoToStatement ::= 'go' 'to' Expression .
Semantics[91]==This macro is defined in definitions 44, 50, 57, 66, 77, 83, 85, 87, 91, 98, 106, 109, 112, and 117.RULE: GoToStatement ::= 'go' 'to' DesignationalExpression END;
This macro is invoked in definition 7.
Define operators to establish types without values[92]==This macro is defined in definitions 92 and 101.OPER jump(LabelKey):VoidKey;
This macro is invoked in definition 12.
Dummy Statements[93]==This macro is invoked in definition 2.DummyStatement ::= Empty .
Conditional Statements[94]==This macro is invoked in definition 2.IfStatement ::= IfClause UnconditionalStatement . ConditionalStatement ::= IfStatement / IfStatement 'else' Statement / IfClause ForStatement / Label ':' ConditionalStatement .
For Statements[95]==This macro is invoked in definition 2.ForListElement ::= Expression / Expression 'step' Expression 'until' Expression / Expression 'while' Expression . ForList ::= ForListElement / ForList ',' ForListElement . ForClause ::= 'for' Variable ':=' ForList 'do' . ForStatement ::= ForClause Statement / Label ':' ForStatement .
The for List Elements[96]==This macro is invoked in definition 7.RULE: ForListElement ::= ArithmeticExpression END; RULE: ForListElement ::= ArithmeticExpression 'step' ArithmeticExpression 'until' ArithmeticExpression END; RULE: ForListElement ::= ArithmeticExpression 'while' BooleanExpression END;
Procedure Statements[97]==This macro is invoked in definition 2.ActualParameterPart ::= Empty / '(' ActualParameterList ')' . ProcedureStatement ::= Identifier ActualParameterPart .
Semantics[98]==This macro is defined in definitions 44, 50, 57, 66, 77, 83, 85, 87, 91, 98, 106, 109, 112, and 117.SYMBOL ProcedureStatement INHERITS IdUseEnv, ActualFormalCorrespondence COMPUTE SYNT.Sym=TERM; IF(NE(THIS.Key,NoKey), IF(NE(GetKind(THIS.Key,UndefinedIdn),ProcedureIdn), message(ERROR,CatStrInd("Not a procedure: ",TERM),0,COORDREF), IF(NE(THIS.type,OilTypeVoidKey), message(ERROR,"Type procedure illegal here",0,COORDREF)))) DEPENDS_ON INCLUDING Program.GotAllProperties; END;
This macro is invoked in definition 7.
Actual-Formal Correspondence[99]==This macro is invoked in definition 7.CHAIN cnt: int; ATTR Arity: int; SYMBOL ActualFormalCorrespondence COMPUTE CHAINSTART HEAD.cnt = 0; SYNT.Arity= GetArity(THIS.Key,SUB(0,1)) DEPENDS_ON INCLUDING Program.GotAllProperties; IF(NE(THIS.Arity,TAIL.cnt), message(ERROR, "Number of parameters mismatch", 0, COORDREF)); END; SYMBOL ActualParameter COMPUTE THIS.cnt=ADD(THIS.cnt,1); END;
Restrictions[100]==This macro is invoked in definition 7.ATTR Arguments, TrailArgs: tOilSetSig; SYMBOL ActualFormalCorrespondence COMPUTE SYNT.operator= IF(EQ(THIS.Arity,TAIL.cnt), OilIdOpTSn( GetOperator(THIS.Key,OilErrorOp()), THIS.Arguments, OilErrorType()), OilErrorOp()) DEPENDS_ON INCLUDING Program.GotAllProperties; SYNT.type=OilGetArgType(THIS.operator,0); IF(NOT(OilIsValidOp(THIS.operator)), message(ERROR,"Argument type mismatch",0,COORDREF)); END; RULE: ProcedureStatement ::= Identifier ActualParameterPart COMPUTE ProcedureStatement.Arguments=ActualParameterPart.Arguments; END; RULE: ActualParameterPart ::= Empty COMPUTE ActualParameterPart.Arguments=OilNewSetSig(); END; RULE: ActualParameterPart ::= '(' ActualParameterList ')' COMPUTE ActualParameterPart.Arguments=ActualParameterList.Arguments; ActualParameterList.TrailArgs=OilNewSetSig(); END; RULE: FunctionDesignator ::= Identifier '(' ActualParameterList ')' COMPUTE FunctionDesignator.Arguments=ActualParameterList.Arguments; ActualParameterList.TrailArgs=OilNewSetSig(); END; RULE: ActualParameterList ::= ActualParameterList ParameterDelimiter ActualParameter COMPUTE ActualParameterList[1].Arguments=ActualParameterList[2].Arguments; ActualParameterList[2].TrailArgs= OilAddSetSig( OilTypeToSet(ActualParameter.type), ActualParameterList[1].TrailArgs); END; RULE: ActualParameterList ::= ActualParameter COMPUTE ActualParameterList.Arguments= OilAddSetSig( OilTypeToSet(ActualParameter.type), ActualParameterList.TrailArgs); END; RULE: ActualParameter ::= String COMPUTE ActualParameter.type=OilTypeStringKey; END; RULE: ActualParameter ::= Expression COMPUTE ActualParameter.type=Expression.type; END;
Define operators to establish types without values[101]==This macro is defined in definitions 92 and 101.OPER pass(StringKey):VoidKey;
This macro is invoked in definition 12.
Scope Violation Rules[102]==This macro is defined in definitions 30, 46, and 102.SYMBOL IdUseEnv COMPUTE IF( EQ(THIS.Key, NoKey), message(ERROR, CatStrInd("Unknown identifier: ", THIS.Sym), 0, COORDREF)); END;
This macro is invoked in definition 7.
Declarations[103]==This macro is invoked in definition 2.Declaration ::= TypeDeclaration / ArrayDeclaration / SwitchDeclaration / ProcedureDeclaration . Type Declarations[104] Array Declarations[108] Switch Declarations[111] Procedure Declarations[113]
Type Declarations[104]==This macro is invoked in definition 103.TypeList ::= VarIdDef / VarIdDef ',' TypeList . VarIdDef ::= Identifier . Type ::= 'real' / 'integer' / 'Boolean' . LocalOrOwnType ::= Type / 'own' Type . TypeDeclaration ::= LocalOrOwnType TypeList .
Equivalences[105]==This macro is defined in definitions 49, 65, 76, and 105.Type ::= LocalOrOwnType .
This macro is invoked in definition 6.
Semantics[106]==In arithmetic expressions any position which can be occupied by a real declared variable may be occupied by an integer declared variable.This macro is defined in definitions 44, 50, 57, 66, 77, 83, 85, 87, 91, 98, 106, 109, 112, and 117.SYMBOL VarIdDef INHERITS IdDefScope COMPUTE SYNT.Sym=TERM; SYNT.GotProperties= ORDER( ResetKind(THIS.Key,VariableIdn), ResetType(THIS.Key,INCLUDING TypeDeclaration.type)); END; RULE: Type ::= 'real' COMPUTE Type.type=OilTypeRealKey; END; RULE: Type ::= 'integer' COMPUTE Type.type=OilTypeIntegerKey; END; RULE: Type ::= 'Boolean' COMPUTE Type.type=OilTypeBooleanKey; END; SYMBOL TypeDeclaration COMPUTE SYNT.type=CONSTITUENT Type.type; END;
This macro is invoked in definition 7.
Define an operator to be applied when needed[107]==This macro is defined in definitions 73 and 107.COERCION irConvert(IntegerKey): RealKey;
This macro is invoked in definition 12.
Array Declarations[108]==This macro is invoked in definition 103.LowerBound ::= Expression . UpperBound ::= Expression . BoundPair ::= LowerBound ':' UpperBound . BoundPairList ::= BoundPair / BoundPairList ',' BoundPair . ArraySegment ::= Identifier '[' BoundPairList ']' / Identifier ',' ArraySegment . ArrayList ::= ArraySegment / ArrayList ',' ArraySegment . ArrayDeclaration ::= 'array' ArrayList / LocalOrOwnType 'array' ArrayList .
Semantics[109]==This macro is defined in definitions 44, 50, 57, 66, 77, 83, 85, 87, 91, 98, 106, 109, 112, and 117.ATTR Dimension: int; SYMBOL ArraySegment INHERITS IdDefScope COMPUTE SYNT.Sym=TERM; SYNT.GotProperties= ORDER( ResetKind(THIS.Key,ArrayIdn), ResetType(THIS.Key,INCLUDING ArrayDeclaration.type), ResetDim(THIS.Key,THIS.Dimension)); END; RULE: BoundPairList ::= BoundPair COMPUTE BoundPairList.Dimension=1; END; RULE: BoundPairList ::= BoundPairList ',' BoundPair COMPUTE BoundPairList[1].Dimension=ADD(BoundPairList[2].Dimension,1); END; RULE: ArraySegment ::= Identifier '[' BoundPairList ']' COMPUTE ArraySegment.Dimension=BoundPairList.Dimension; END; RULE: ArraySegment ::= Identifier ',' ArraySegment COMPUTE ArraySegment[1].Dimension=ArraySegment[2].Dimension; END; RULE: ArrayDeclaration ::= Type 'array' ArrayList COMPUTE ArrayDeclaration.type=Type.type; END; RULE: ArrayDeclaration ::= 'array' ArrayList COMPUTE ArrayDeclaration.type=OilTypeRealKey; END;
This macro is invoked in definition 7.
Properties characterizing arrays[110]==This macro is invoked in definition 15.Dim: int;
Switch Declarations[111]==This macro is invoked in definition 103.SwitchList ::= Expression / SwitchList ',' Expression . SwitchDeclaration ::= 'switch' Identifier ':=' SwitchList .
Semantics[112]==This macro is defined in definitions 44, 50, 57, 66, 77, 83, 85, 87, 91, 98, 106, 109, 112, and 117.SYMBOL SwitchDeclaration INHERITS IdDefScope COMPUTE SYNT.Sym=TERM; SYNT.GotProperties= ORDER( ResetKind(THIS.Key,SwitchIdn), ResetType(THIS.Key,OilTypeLabelKey), ResetDim(THIS.Key,1)); END; RULE: SwitchList ::= DesignationalExpression END; RULE: SwitchList ::= SwitchList ',' DesignationalExpression END;
This macro is invoked in definition 7.
Procedure Declarations[113]==The Revised Report uses the nonterminal <identifier list> to represent uses of formal parameter identifiers in both the value part and the specification part. The semantics of these two contexts are quite different, so we defined another nonterminal, ValueParameterList to represent the former context.This macro is defined in definitions 113, 114, 115, and 116.FormalParameter ::= Identifier . FormalParameterList ::= FormalParameter / FormalParameterList ParameterDelimiter FormalParameter . FormalParameterPart ::= '(' FormalParameterList ')' . IdentifierList ::= Identifier / IdentifierList ',' Identifier .
This macro is invoked in definition 103.
Procedure Declarations[114]==The Revised Report does not require type information for formal parameters. If no type information is available, however, it may be impossible for the compiler to determine the type of an expression. Thus we require that all formal parameters have specifications, which means that a SpecificationPart can be empty only if there are no formal parameters. That constraint is verified by the definition of the ProcedureHeading:This macro is defined in definitions 113, 114, 115, and 116.ValueParameterList ::= ValueParameter / ValueParameterList ',' ValueParameter . ValueParameter ::= Identifier . ValuePart ::= 'value' ValueParameterList Semi / Empty . Specifier ::= 'string' / Type / 'array' / Type 'array' / 'label' / 'switch' / 'procedure' / Type 'procedure' .
This macro is invoked in definition 103.
Procedure Declarations[115]==The grammar given in the Revised Report does not reflect the scope rules of the language: A procedure identifier is declared in the enclosing scope, and the formal parameters are declared in the procedure body, but the grammar places both in the <procedure heading> phrase. We have therefore moved the procedure identifier to the procedure declaration and defined a new nonterminal, ProcedureRange, that is exactly the scope of the formal parameters described by Section 5.4.3 of the Revised Report:This macro is defined in definitions 113, 114, 115, and 116.SpecificationPart ::= Specifier IdentifierList Semi / SpecificationPart Specifier IdentifierList Semi .
This macro is invoked in definition 103.
Procedure Declarations[116]==This macro is defined in definitions 113, 114, 115, and 116.ProcedureHeading ::= FormalParameterPart Semi ValuePart SpecificationPart / Semi . ProcedureBody ::= Statement / Code . ProcedureRange ::= ProcedureHeading ProcedureBody . ProcedureDeclaration ::= 'procedure' Identifier ProcedureRange / Type 'procedure' Identifier ProcedureRange .
This macro is invoked in definition 103.
Semantics[117]==This macro is defined in definitions 44, 50, 57, 66, 77, 83, 85, 87, 91, 98, 106, 109, 112, and 117.SYMBOL ProcedureDeclaration INHERITS IdDefScope COMPUTE SYNT.Sym=TERM; SYNT.GotProperties= ORDER( ResetKind(THIS.Key,ProcedureIdn), ResetArity(THIS.Key,THIS.Arity), ResetType(THIS.Key,THIS.type)); END; RULE: ProcedureDeclaration ::= 'procedure' Identifier ProcedureRange COMPUTE ProcedureDeclaration.type=OilTypeVoidKey; END; RULE: ProcedureDeclaration ::= Type 'procedure' Identifier ProcedureRange COMPUTE ProcedureDeclaration.type=Type.type; END;
This macro is invoked in definition 7.
Specifications[118]==This macro is invoked in definition 7.SYMBOL ProcedureDeclaration COMPUTE SYNT.GotFormalTypes=CONSTITUENTS IdentifierList.GotType; SYNT.Arity=CONSTITUENTS FormalParameter.Key WITH (int,ADD,ARGTOONE,ZERO); END; SYMBOL ProcedureRange INHERITS RangeScope END; SYMBOL FormalParameter INHERITS IdDefScope COMPUTE SYNT.Sym=TERM; END; SYMBOL ValueParameter INHERITS IdUseScope COMPUTE SYNT.Sym=TERM; SYNT.GotProperties=ResetIsValue(THIS.Key, 1); END; SYMBOL SpecificationPart COMPUTE SYNT.kind=CONSTITUENT Specifier.kind; SYNT.type=CONSTITUENT Specifier.type; END; SYMBOL IdentifierList INHERITS IdUseScope COMPUTE SYNT.Sym=TERM; SYNT.GotType= ResetType(THIS.Key,INCLUDING SpecificationPart.type); SYNT.GotProperties= ResetKind(THIS.Key,INCLUDING SpecificationPart.kind) DEPENDS_ON THIS.GotType; END; RULE: Specifier ::= 'string' COMPUTE Specifier.type=OilTypeStringKey; Specifier.kind=VariableIdn; END; RULE: Specifier ::= Type COMPUTE Specifier.type=Type.type; Specifier.kind=VariableIdn; END; RULE: Specifier ::= 'array' COMPUTE Specifier.type=OilTypeRealKey; Specifier.kind=ArrayIdn; END; RULE: Specifier ::= Type 'array' COMPUTE Specifier.type=Type.type; Specifier.kind = ArrayIdn; END; RULE: Specifier ::= 'label' COMPUTE Specifier.type=OilTypeLabelKey; Specifier.kind=LabelIdn; END; RULE: Specifier ::= 'switch' COMPUTE Specifier.type=OilTypeLabelKey; Specifier.kind=SwitchIdn; END; RULE: Specifier ::= 'procedure' COMPUTE Specifier.type=OilTypeRealKey; Specifier.kind=ProcedureIdn; END; RULE: Specifier ::= Type 'procedure' COMPUTE Specifier.type=Type.type; Specifier.kind = ProcedureIdn; END; ATTR Signature, Trailing: tOilArgSig; RULE: FormalParameterPart ::= '(' FormalParameterList ')' COMPUTE FormalParameterPart.operator= OilNewOp( INCLUDING ProcedureDeclaration.Key, OilAddArgSig( INCLUDING ProcedureDeclaration.type, FormalParameterList.Signature), 1); FormalParameterPart.GotProperties= ORDER( ResetOperator( INCLUDING ProcedureDeclaration.Key, FormalParameterPart.operator), OilAddIdentification( FormalParameterPart.operator, FormalParameterPart.operator)); FormalParameterList.Trailing=OilNewArgSig(); END; RULE: FormalParameterList ::= FormalParameterList ParameterDelimiter FormalParameter COMPUTE FormalParameterList[1].Signature=FormalParameterList[2].Signature; FormalParameterList[2].Trailing= OilAddArgSig( GetType(FormalParameter.Key,OilErrorType()), FormalParameterList[1].Trailing) DEPENDS_ON INCLUDING ProcedureDeclaration.GotFormalTypes; END; RULE: FormalParameterList ::= FormalParameter COMPUTE FormalParameterList.Signature= OilAddArgSig( GetType(FormalParameter.Key,OilErrorType()), FormalParameterList.Trailing) DEPENDS_ON INCLUDING ProcedureDeclaration.GotFormalTypes; END;
Properties characterizing procedures[119]==This macro is invoked in definition 15.Operator: tOilOp; Arity: int;
Properties characterizing formal parameters[120]==This macro is invoked in definition 15.IsValue: int;
We have chosen to define Code as a body of text enclosed in braces, possibly with nested text of the same form. A C procedure body or compound statement takes this form, which is recognized by the Ctext auxiliary scanner:
Code as Procedure Body[121]==The { must be escaped because it is a regular expression operator.This macro is invoked in definition 4.Code: $\{ (Ctext) [mkstr]
The token processor mkstr assigns a unique integer value to each code body regardless of its content. This integer value can be used to access the code body.