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.

Note:
All Eiffel compilers accept the prefix and infix
operators regardless of the letter case, such asprefix
"NOT"orinfix
"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 inand thenoror else. SmallEiffel accepts any number
of blanks and tab characters, whereas the other compilers
require a single blank.

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!
do

and

require
tag: -- If this comment is ignored,
-- tag will be erroneously
-- associated with foo.is_valid!
foo.is_valid

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:
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:
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:
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 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:
This specification of Expressionis 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 := - 2

should the Expression on the right hand side of the
assignment be recognized as an Integer_constant or as an Unary_expression whose Prefix_operatoris '-' 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: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 := - 2

should the Expression on the right hand side of the
assignment be recognized as an Integer_constant or as an Unary_expression whose Prefix_operatoris '-' and whose Expression is an (unsigned) Integer? This has been resolved in the
current syntax description by rewriting the specification
for Expression.

An identifier is a sequence of one or more characters, of
which the first is a letter (a
to z and A
to Z) and each of the
subsequent ones, if any, is a letter, a decimal digit (0
to 9) or an underscore
character (_).
Letter case is not significant for letters: the two
identifiers lInKeD_liST and LINKED_LIST
are considered the same.

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.

An hexadecimal constant is a sequence of two
or more characters, whose first character is a decimal
digit (0 to 9),
whose subsequent characters but the last are decimal
digits or letters a to f
or A to F,
and followed by x or X,
with no other intervening characters.

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.

an optional Integer,
giving the integral part (If this is absent, the
integral part is 0.)

a required dot (.)

an optional Integer
written backwards, which gives the fractional
part (if this is absent, the fractional part is
0.)

an optional exponent, which is the letter e
or E followed by an
optional Sign (+
or -) and an Integer. The integer
is required if the e or
E is present. This
indicates that the value appearing before the e
or E must be scaled by
10^n, where n is the given integer.

No intervening character (blank or otherwise) is
permitted between these elements. The integral and
fractional parts may not both be absent. If underscores
are used in the integral or the fractional part, they
must also appear in the other part, unless it has three
digits or less.

An extended form allows one to write a manifest string on
two or more lines. Every line but the last must end with
a percent (%)
and every line but the first must begin with a percent (%) possibly
preceded by blanks () and tab characters.

Note:
Printable characters include, in this case, blanks and
tab characters, but not new lines. Compare that to Free_operator.

A free operator is a sequence of one or
more characters, whose first character is any one of@
# | & and whose
subsequent characters, if any, may be any printable
characters. Letter case is not significant for letters in
free operators.

Note:
Printable characters do not include, in this case,
characters allowed in Breaks. Compare that to Character_constant.

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.

foois
-- This is the first comment.
-- This is the second comment.
-- This is the third comment.
do
...
end

it 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.

a sequence %/code/
where code is an
unsigned integer representing the character of ASCII code code
in decimal value

a sequence %K
used to represent the following special
characters:

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).

The letter case is not significant for
reserved words: the two words Result and rEsUlT are considered the same.

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.

The operators in the following table are
grouped by precedence level, starting with the highest
precedence group. Operators within each group have the
same precedence. For two or more consecutive occurrences
of binary operators with the same precedence level, the
associativity column specifies the order of evaluation.

Symbol

Associativity

.

left

oldnot
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

andand then

left
left

oror elsexor

left
left
left

implies

left

Note:
The reason why Eiffel compilers reject the following
piece of code:

foo := 1 < 2 < 3

is 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:

Semicolons are used as separators in lists such as Index_list or Compound. Semicolons are
optional in most places. However they are required in
some cases to remove ambiguities in Assertion
and Compound. The ambiguity appears in the following piece
of code:

foo (expr).bar

where this could be recognized as "bar applied to the result of function foo with argument expr" or as "a call to foo followed by bar applied to expr". The rule to resolve this ambiguity is to
put a semicolon between 'foo' and '(expr).bar' to get the second interpretation, or to leave
it as it is to get the first one.

Note:
For some constructs, some Eiffel compilers will consider
semicolons as terminators, consider them compulsory, or
just emit a warning if they are missing.