Eiffel: The Syntax |
The annotated Eiffel syntax described here is aimed at writers of Eiffel tools such as compilers, interpreters, syntax checkers, short and flat tools, pretty-printers, etc., who want to benefit from some tips and tricks. Although this is not the official Eiffel syntax specification provided by the Nonprofit International Consortium for Eiffel (NICE), it departs from it in only two or three well documented occassions. In particular, it explains where, and sometimes why, existing compilers have extended the Eiffel syntax.
The Eiffel syntax constructs are listed into groups, starting with high-level constructs such as Class_declaration down to lexical components such as Identifier. Alternatively, these constructs are also given in alphabetical order. The notation used to describe the Eiffel syntax is specified elsewhere. A possible implementation of the Eiffel syntax in yacc- and lex-like format is also provided as an example.
This page is also available in Portuguese (translated by Artur Weber for homeyou), in Spanish (translated by Lera Domartina), in Albanian (translated by Ermira Beqiri of NPI Number Lookup), and in Azerbaijani (translated by Qalina Najafova).
Note: Most Eiffel compilers do not check the validity of the optional comment after the keyword end. SmallEiffel emits a warning though.
Note: A file may contain more than one class declaration. However most Eiffel compilers have a limitation of one class per file.
Note: The keyword separate is not part of the Eiffel standard. It has been introduced in ISE Eiffel to support the SCOOP mechanism. Read Object-Oriented Software Construction, second edition, for details.
Note: The list of formal generics may be empty. As a consequence, FOO[] is valid and means the same as FOO. However, this is not the recommended style.
Note: Because of this construct, the Eiffel grammar is not LR(1). This occurs in the following situation:
class FOO inherit BAR endThe keyword end will be considered as part of the optional Feature_adaptation instead of as part of the Class_declaration construct.
A way to solve this problem would be to allow the keyword end in the Feature_adaptation only when at least one of the optional constructs making up the Feature_adaptation is present.
Note: The standard syntax requires a Feature_list instead of a Procedure_list but the Creation_clause actually lists creation procedure names (see validity rule VGCP-2).
Note: Prefix and Infix are function names, not procedure names. It is not clear to me whether a Prefix could be an attribute name, but it is definitely not a procedure name (see validity rule VFFD-5).
Note: All Eiffel compilers accept the prefix and infix operators regardless of the letter case, such as prefix "NOT" or infix "AnD".
Note: No intervening character is allowed after the first or before the last double quote. However it is not clear what kind of break should be used between the two keywords in and then or or else. SmallEiffel accepts any number of blanks and tab characters, whereas the other compilers require a single blank.
Note: The list of entity declarations may be empty. As a consequence, foo() is valid and means the same as foo. However, this is not recommended style.
Note: Most Eiffel compilers do not check the validity of the optional comment after the keyword end. It is not in the style guidelines to put this comment anymore.
Note: Each Eiffel compiler supports its own mini-syntax in the language name and external name strings to describe their interface with other programming languages. See the documentation which comes with the different compilers for details.
Note: Although comments such as header comments are expected in some constructs such as Routine or Features, this is the only place where ignoring a comment results in a syntax error or an incorrect syntax tree. This occurs in the following situations:
require tag: -- Syntax error when ignored! doand
require tag: -- If this comment is ignored, -- tag will be erroneously -- associated with foo.is_valid! foo.is_validSee the second note in Comment for more details.
Note: The validity rule VXRT states that the Retry instruction is only valid in a rescue clause. This could eventually be enforced by the syntax.
Note: The standard Eiffel syntax also lists Formal_generic_name as a possible alternative for Type. However it introduced an ambiguity in the syntax since an identifier could be recognized both as a Formal_generic_name and a Class_type with no actual generics.
Note: The list of types may be empty. As a consequence, FOO[] is valid and means the same as FOO. However, this is not the recommended style.
Note: Class_type_separate is not part of the Eiffel standard. It has been introduced in ISE Eiffel to support the SCOOP mechanism. Read Object-Oriented Software Construction, second edition, for details.
Note: In the standard syntax, Constant appears instead of Bit_length. However the validity rule VTBT states that a Bit_type declaration is valid if and only if its Constant is of type INTEGER, which means that the constant is either a manifest integer constant or an attribute constant.
Note: If the type is absent, the two exclamation marks may be written with or without intervening break. In the style standard, the recommended form is the one without breaks, which makes !! appear as a single lexical symbol.
Note: In the standard Eiffel syntax, the Creation_call is made of an Unqualified_call. But the validity rule VGCC-6 states that if f is the feature of the Creation_call, the f is a procedure.
Note: The list of choices may be empty. As a consequence,
inspect expr when then do_something ...although meaningless, is syntactically correct. It can be thought of as
if False then do_something ...However, this is not part of the recommended style.
Note: The standard syntax specifies Constant instead of Choice_constant. However the validity rule VOMB-1-2 states that the Constant in Choice and Interval is only of type INTEGER or CHARACTER.
Note: The lexical analyzer has to be smart enough in the following example:
inspect expr when 1..2 then ...Indeed, '1..2' should be recognized as the two integer constants '1' and '2' separated by the Eiffel symbol '..', instead of as two consecutive real constants '1.' and '.2'. Visual Eiffel erroneously emits a syntax error when parsing the example above.
Note: TowerEiffel accepts "remote constant" in Choice and Interval, such as in:
foo: FOO inspect i when foo.const then do_something endwhere const is declared as constant in class FOO. This is not standard Eiffel syntax.
Note: The validity rule VAVE states that Expression must be of type INTEGER. This could eventually be partially enforced in the syntax by discarding Equality, Manifest_array, Strip and all non-integer Manifest_constants.
Note: The validity rule VXRT states that the Retry instruction is only valid in a Rescue clause. This could eventually be enforced by the syntax.
Note: This instruction has a purely syntactical role: making sure that extra semicolons added by oversight to a Compound are harmless, as in
if c then ; i1;;; i2; else ;; endTowerEiffel does not support extra semicolons other than terminators. All other compilers work as expected. SmallEiffel emits a warning when parsing extra semicolons.
Note: This specification of Call is slightly different from the version supplied in the standard. However the standard syntax accepts constructs which are not correct Eiffel such as:
foo.Result Current (5)whereas the specification given above does not.
Note: In TowerEiffel, features may be called directly on a Manifest_constant without placing parentheses around the constant, such as in:
str := 'a'.outwhich should be, using the standard syntax:
str := ('a').outThere is a slight lexical problem with Integer_constant though, since
123.outis recognized as
123. out'123.' being a Real_constant. The programmer has to add an extra Break between the integer constant and the dot to work around this problem.
Note: The Precursor construct is not part of the standard Eiffel syntax. It has been introduced in Object-Oriented Software Construction, second edition, and a proposal for its standardization has been submitted to NICE. ISE Eiffel and Halstenbach will most likely support this construct in their next release.
Note: In Object-Oriented Software Construction, second edition, the class name in Parent_qualification is enclosed between double braces: {{Class_name}}. However the proposal submitted to NICE uses the syntax specified above.
Note: According to validity rule VFFD-5, an Attribute can also be a Prefix.
Note: The Entity syntax group from the standard syntax specification has been very much simplified to resolved many ambiguities. For example, should:
foobe recognized as an Attribute, a Local or a Formal? Only a semantic analysis can give the answer.
Note: The list of actuals may be empty. As a consequence, foo() is valid and means the same as foo. However, this is not recommended style.
Note: TowerEiffel treats Address as a normal expression (i.e. as an alternative in the Expression construct). As a consequence, an address does not need to occur only in actual lists.
Note: This specification of Expression is slightly different from the version supplied in the standard. First, Current and Result have been added as a consequence of new specification for Call. Then, Manifest_constant has been replaced with the list of its alternatives. This is to resolve an ambiguity in the standard syntax. In the following piece of code:
foo := - 2should the Expression on the right hand side of the assignment be recognized as an Integer_constant or as an Unary_expression whose Prefix_operator is '-' and whose Expression is an (unsigned) Integer? Replacing Integer_constant and Real_constant by Integer and Real solves the problem.
Note: Wide_character_constant, Wide_manifest_string and Hexadecimal_constant are not part of the standard. They have been introduced in TowerEiffel to support wide characters and string, and hexadecimal integers.
Note: The validity rule VWBE states that a boolean expression must be of type BOOLEAN. This could eventually be partially enforced in the syntax by discarding Manifest_array, Strip and all non-boolean Manifest_constants.
Note: See Operator for operator precedence and associativity.
Note: See Operator for operator precedence and associativity.
Note: Wide_character_constant, Wide_manifest_string and Hexadecimal_constant are not part of the standard. They have been introduced in TowerEiffel to support wide characters and string, and hexadecimal integers.
Note: There is an ambiguity in the standard syntax here. In the following piece of code:
foo := - 2should the Expression on the right hand side of the assignment be recognized as an Integer_constant or as an Unary_expression whose Prefix_operator is '-' and whose Expression is an (unsigned) Integer? This has been resolved in the current syntax description by rewriting the specification for Expression.
Note: Same ambiguity as for Integer_constant above.
Note: Wide_character_constant is not part of the standard. It has been introduced in TowerEiffel to support wide characters.
Note: No intervening character is allowed between the dollar sign and the Character_constant.
Note: Wide_manifest_string is not part of the standard. It has been introduced in TowerEiffel to support wide character in strings.
Note: No intervening character is allowed between the dollar sign and the Manifest_string.
Note: The validity rule VAOL-1 states that the Old expression is only valid in a Postcondition. This could eventually be enforced by the syntax.
Note: Unfortunately, SmallEiffel is case-sensitive. (Surprisingly, it is not case-sensitive for Reserved_words.)
Note: An identifier is valid if and only if it is not one of the Reserved_words.
Note: TowerEiffel cannot handle contiguous underscores in feature names and class names.
Note: The last two constraints concerning underscores might be removed in the future, allowing groups of any number of digits.
Note: Contrary to Integer_constant, Integer has no sign.
Note: Be aware of the minimum integer value problem! For example, on platforms where integers are stored on 32 bits, the following Eiffel code is valid:
Minimum_integer: INTEGER is - 2_147_483_648 -- Smallest supported value of type INTEGERbut the parser should be smart enough otherwise it will read an unary minus followed by the integer 2147483648, which does not fit in 32 bits and hence triggers an overflow.
Note: Hexadecimal_constant is not part of the standard. It has been introduced in TowerEiffel to support hexadecimal integers.
Note: It is not clear whether underscores are allowed in hexadecimal constants.
Note: The recommended style is to use E rather than e.
Note: Contrary to Real_constant, Real has no sign.
Note: The constraint stating that the integral and fractional parts may not both be absent is lexically important. Otherwise the following piece of code
a.e1could be scanned as
a .e1instead of
a . e1'.e1' being recognized as a real.
Note: Printable characters include, in this case, blanks and tab characters, but not new lines. Compare that to Free_operator.
Note: Printable characters include, in this case, blanks and tab characters, but not new lines. Compare that to Free_operator.
Note: The recommended style is to use B rather than b.
Note: Printable characters do not include, in this case, characters allowed in Breaks. Compare that to Character_constant.
Note: The following code
a@1is scanned as
a @1which is not syntactically correct. See Eiffel gotchas for details.
Note: Eiffel: The Language, second printing, allows Special_characters (although printable) in free operators. No Eiffel compiler supports that.
Note: SmallEiffel and Visual Eiffel are case-sensitive for free operators.
Note: This is not the official description of Comment. However I couldn't see why the percent character (%) was not allowed in its bare form (i.e. not part of a Special_character) in a comment.
Note: There are two kinds of comments: free comments and expected comments. Free comments can be discarded by some tools. However expected comments appear as part of four constructs: Routine, Assertion_clause, Creation_clause and Feature_clause, and should be processed by tools such as the short utility. Although, in Routine, Creation_clause and Feature_clause, the header comment is optional and may be ignored without too much harm, it is compulsory in Assertion_clause and ignoring it would be a syntax error. A solution to implement these expected comments could be to use lexical tie-ins.
Note: TowerEiffel erroneously emits a syntax error when a comment appears between the feature keyword and the optional Clients in the Features construct. This is probably a secondary effect of the use of lexical tie-ins suggested above.
Note: In the following Routine declaration:
foo is -- This is the first comment. -- This is the second comment. -- This is the third comment. do ... endit is not clear which one of the three comments is the expected Header_comment and what are the two other free comments. TowerEiffel chose the first comment to be the header comment. Some other compilers, such as ISE Eiffel, Halstenbach and Visual Eiffel, actually merge the three comments into one which becomes the header comment.
Note: Some Eiffel compilers ignore any line starting with '--|' instead of just '--' in header comments.
Note: Some platforms such as Windows put a carriage return character before the new line. In such cases, it is easier to consider the carriage return as a fourth possible character making up a break.
Character | Code | Mnemonic name |
@ | %A | At-sign |
BS | %B | Backspace |
^ | %C | Circumflex |
$ | %D | Dollar |
FF | %F | Form feed |
\ | %H | backslasH |
~ | %L | tiLda |
NL (LF) | %N | Newline |
` | %Q | back Quote |
CR | %R | carriage Return |
# | %S | Sharp |
HT | %T | horizontal Tab |
NUL | %U | nUll character |
| | %V | Vertical bar |
% | %% | percent |
' | %' | single quote |
" | %" | double quote |
[ | %( | opening bracket |
] | %) | closing bracket |
{ | %< | opening brace |
} | %> | closing brace |
Note: Most Eiffel compilers emit a syntax error when the sequence %K is not listed in the table above. However, Visual Eiffel considers that the sequence %K represents the character K when the sequence is not listed in the table above. As a consequence %P stands for character P and %D stands for character $.
Note: All Eiffel compilers that I have tested (i.e. ISE Eiffel, Halstenbach, SmallEiffel, Visual Eiffel, TowerEiffel) expect the letter K in %K to be in upper case to be recognized as a special character from the table above. As a consequence %d and %D are not considered the same.
Note: It is not clear to me whether underscores are allowed in the code integer (specially when it is the code of a wide character).
Note: The official syntax specification lists the following class names as reserved words: BOOLEAN, CHARACTER, DOUBLE, INTEGER, NONE, POINTER, REAL, STRING. I understand that these classes have to be known by Eiffel compilers, but I don't see why they should be reserved words. Note that ANY, GENERAL, PLATFORM and many other class names from the Kernel Library Standard are not listed either! Moreover, these class names appear nowhere in the syntax constructs. Finally, only Visual Eiffel considers these class names as reserved words.
Note: In Eiffel: The Language, second printing, False, Strip, True and Unique are considered to be keywords. I do not share this point of view.
Note: Although SmallEiffel is case-sensitive with respect to Identifier, it considers letter case not being significant for reserved words!
Note: Precursor is not part of the standard syntax. It has been introduced to support the Precursor mechanism.
Symbol | Associativity |
. | left |
old not unary + unary - All free unary operators |
|
All free binary operators | |
^ | right |
* / // \\ |
left left left left |
binary + binay - |
left left |
= /= < > <= >= |
left left left left left left |
and and then |
left left |
or or else xor |
left left left |
implies | left |
Note: The reason why Eiffel compilers reject the following piece of code:
foo := 1 < 2 < 3is not because the comparison operators are non-associative. These operators really are left associative. The above code is syntactically correct but is simply rejected because '1 < 2' is of type BOOLEAN and there is no feature such as:
infix "<" (i: INTEGER): SOME_TYPEin class BOOLEAN.
foo (expr).bar
Note: For some constructs, some Eiffel compilers will consider semicolons as terminators, consider them compulsory, or just emit a warning if they are missing.
Copyright © 1999-2024, Eric
Bezault mailto:ericb@gobosoft.com http://www.gobosoft.com Last Updated: 24 March 2024 |