Modula-3: Syntax

# Syntax

> Care should be taken, when using colons and semicolons in the same sentence, that the reader understands how far the force of each sign carries. ---Robert Graves and Alan Hodge

## Keywords

    AND       DO          FROM        NOT         REPEAT     UNTIL
    ANY       ELSE        GENERIC     OBJECT      RETURN     UNTRACED
    ARRAY     ELSIF       IF          OF          REVEAL     VALUE
    AS        END         IMPORT      OR          ROOT       VAR
    BEGIN     EVAL        IN          OVERRIDES   SET        WHILE
    BITS      EXCEPT      INTERFACE   PROCEDURE   THEN       WITH
    BRANDED   EXCEPTION   LOCK        RAISE       TO
    BY        EXIT        LOOP        RAISES      TRY
    CASE      EXPORTS     METHODS     READONLY    TYPE
    CONST     FINALLY     MOD         RECORD      TYPECASE
    DIV       FOR         MODULE      REF         UNSAFE

## Reserved identifiers

    ABS       BYTESIZE   EXTENDED  INTEGER    MIN     NUMBER    TEXT
    ADDRESS   CARDINAL   FALSE     ISTYPE     MUTEX   ORD       TRUE
    ADR       CEILING    FIRST     LAST       NARROW  REAL      TRUNC
    ADRSIZE   CHAR       FLOAT     LONGREAL   NEW     REFANY    TYPECODE
    BITSIZE   DEC        FLOOR     LOOPHOLE   NIL     ROUND     VAL
    BOOLEAN   DISPOSE    INC       MAX        NULL    SUBARRAY

## Operators

    +        <         #        =        ;        ..       :
    -        >         {        }        |        :=       <:
    *        <=        (        )        ^        ,        =>
    /        >=        [        ]        .        &

## Comments

A comment is an arbitrary character sequence opened by `(*` and closed by `*)`. Comments can be nested and can extend over more than one line.

## Pragmas

A pragma is an arbitrary character sequence opened by `<*` and closed by `*>`. Pragmas can be nested and can extend over more than one line. Pragmas are hints to the implementation; they do not affect the language semantics.

We recommend supporting the two pragmas `<*INLINE*>` and `<*EXTERNAL*>`. The pragma `<*INLINE*>` precedes a procedure declaration to indicate that the procedure should be expanded at the point of call. The pragma `<* EXTERNAL N:L *>` precedes an interface or a declaration in an interface to indicate that the entity it precedes is implemented by the language `L`, where it has the name `N`. If "`:L`" is omitted, then the implementation's default external language is assumed. If "`N`" is omitted, then the external name is determined from the Modula-3 name in some implementation-dependent way.

## Conventions for syntax

We use the following notation for defining syntax:

        X Y      X followed by Y
        X|Y      X or Y.
        [X]      X or empty
        {X}      A possibly empty sequence of X's
        X&Y      X or Y or X Y

"Followed by" has greater binding power than `|` or `&`; parentheses are used to override this precedence rule. Non-terminals begin with an upper-case letter. Terminals are either keywords or quoted operators. The symbols `Ident`, `Number`, `TextLiteral`, and `CharLiteral` are defined in the token grammar. Each production is terminated by a period. The syntax does not reflect the restrictions that revelations and exceptions can be declared only at the top level; nor does it include explicit productions for `NEW`, `INC`, and `DEC`, which parse like procedure calls.

## Compilation unit productions

    Compilation = [UNSAFE] (Interface | Module) | GenInf | GenMod.

    Interface   = INTERFACE Id ";" {Import} {Decl} END Id "."
                | INTERFACE Id "=" Id GenActls END Id ".".
    Module      = MODULE Id [EXPORTS IdList] ";" {Import} Block Id "."
                | MODULE Id [EXPORTS IdList] "=" Id GenActls END Id ".".

    GenInf = GENERIC INTERFACE Id GenFmls ";" {Import} {Decl} END Id ".".
    GenMod = GENERIC MODULE Id GenFmls ";" {Import} Block Id ".".

    Import      = AsImport | FromImport.
    AsImport    = IMPORT ImportItem {"," ImportItem} ";".
    FromImport  = FROM Id IMPORT IdList ";".
    Block       = {Decl} BEGIN S END.
    Decl = CONST {ConstDecl ";"}
         | TYPE {TypeDecl ";"}
         | EXCEPTION {ExceptionDecl ";"}
         | VAR {VariableDecl ";"}
         | ProcedureHead ["=" Block Id] ";"
         | REVEAL {QualId ("=" | "<:") Type ";"}.

    GenFmls        = "(" [IdList] ")".
    GenActls       = "(" [IdList] ")".
    ImportItem     = Id | Id AS Id.
    ConstDecl      = Id [":" Type] "=" ConstExpr.
    TypeDecl       = Id ("=" | "<:") Type.
    ExceptionDecl  = Id ["(" Type ")"].
    VariableDecl   = IdList (":" Type & ":=" Expr).
    ProcedureHead  = PROCEDURE Id Signature.

    Signature      = "(" Formals ")" [":" Type] [RAISES Raises].
    Formals        = [ Formal {";" Formal} [";"] ].
    Formal         = [Mode] IdList (":" Type & ":=" ConstExpr).
    Mode           = VALUE | VAR | READONLY.
    Raises         = "{" [ QualId {"," QualId} ] "}" | ANY.

## Statement productions

    Stmt = AssignSt | Block | CallSt | CaseSt | ExitSt | EvalSt | ForSt
         | IfSt | LockSt | LoopSt | RaiseSt | RepeatSt | ReturnSt
         | TCaseSt | TryXptSt | TryFinSt | WhileSt | WithSt.

    S =  [ Stmt {";" Stmt} [";"] ].

    AssignSt = Expr ":=" Expr.
    CallSt   = Expr "(" [Actual {"," Actual}] ")".
    CaseSt   = CASE Expr OF [Case] {"|" Case} [ELSE S] END.
    ExitSt   = EXIT.
    EvalSt   = EVAL Expr.
    ForSt    = FOR Id ":=" Expr TO Expr [BY Expr] DO S END.
    IfSt     = IF Expr THEN S {ELSIF Expr THEN S} [ELSE S] END.
    LockSt   = LOCK Expr DO S END.
    LoopSt   = LOOP S END.
    RaiseSt  = RAISE QualId ["(" Expr ")"].
    RepeatSt = REPEAT S UNTIL Expr.
    ReturnSt = RETURN [Expr].
    TCaseSt  = TYPECASE Expr OF [TCase] {"|" TCase} [ELSE S] END.
    TryXptSt = TRY S EXCEPT [Handler] {"|" Handler} [ELSE S] END.
    TryFinSt = TRY S FINALLY S END.
    WhileSt  = WHILE Expr DO S END.
    WithSt   = WITH Binding {"," Binding} DO S END.

    Case    = Labels {"," Labels} "=>" S.
    Labels  = ConstExpr [".." ConstExpr].
    Handler = QualId {"," QualId} ["(" Id ")"] "=>" S.
    TCase   = Type {"," Type} ["(" Id ")"] "=>" S.
    Binding = Id "=" Expr.
    Actual  = Type | [Id ":="] Expr .

## Type productions

    Type = TypeName | ArrayType | PackedType | EnumType | ObjectType
         | ProcedureType | RecordType | RefType | SetType | SubrangeType
         | "(" Type ")".

    ArrayType     = ARRAY [Type {"," Type}] OF Type.
    PackedType    = BITS ConstExpr FOR Type.
    EnumType      = "{" [IdList] "}".
    ObjectType    = [TypeName | ObjectType] [Brand] OBJECT Fields
                     [METHODS Methods] [OVERRIDES Overrides] END.
    ProcedureType = PROCEDURE Signature.
    RecordType    = RECORD Fields END.
    RefType       = [UNTRACED] [Brand] REF Type.
    SetType       = SET OF Type.
    SubrangeType  = "[" ConstExpr ".." ConstExpr "]".

    Brand     = BRANDED [ConstExpr].
    Fields    = [ Field {";" Field} [";"] ].
    Field     = IdList (":" Type & ":=" ConstExpr).
    Methods   = [ Method {";" Method} [";"] ].
    Method    = Id Signature [":=" ConstExpr].
    Overrides = [ Override {";" Override} [";"] ].
    Override  = Id ":=" ConstExpr .

## Expression productions

    ConstExpr = Expr.

    Expr = E1 {OR E1}.
      E1 = E2 {AND E2}.
      E2 = {NOT} E3.
      E3 = E4 {Relop E4}.
      E4 = E5 {Addop E5}.
      E5 = E6 {Mulop E6}.
      E6 = {"+" | "-"} E7.
      E7 = E8 {Selector}.
      E8 = Id | Number | CharLiteral | TextLiteral
         | Constructor | "(" Expr ")".

    Relop =  "=" | "#" | "<"  | "<=" | ">" | ">=" | IN.
    Addop =  "+" | "-" | "&".
    Mulop =  "*" | "/" | DIV | MOD.

    Selector = "^"  |  "." Id  |  "[" Expr {"," Expr} "]"
             | "(" [ Actual {"," Actual} ] ")".

    Constructor = Type "{" [ SetCons | RecordCons | ArrayCons ] "}".

    SetCons = SetElt {"," SetElt}.
    SetElt = Expr [".." Expr].
    RecordCons = RecordElt {"," RecordElt}.
    RecordElt = [Id ":="] Expr.
    ArrayCons =  Expr {"," Expr} ["," ".."].

## Miscellaneous productions

    IdList      =  Id {"," Id}.
    QualId      =  Id ["." Id].
    TypeName    =  QualId | ROOT | UNTRACED ROOT.

## Token productions

To read a token, first skip all blanks, tabs, newlines, carriage returns, vertical tabs, form feeds, comments, and pragmas. Then read the longest sequence of characters that forms an operator or an `Id` or `Literal`.

An `Id` is a case-significant sequence of letters, digits, and underscores that begins with a letter. An `Id` is a keyword if it appears in the list of keywords, a reserved identifier if it appears in the list of reserved identifiers, and an ordinary identifier otherwise.

In the following grammar, terminals are characters surrounded by double-quotes and the special terminal `DQUOTE` represents double-quote itself.

    Id = Letter {Letter | Digit | "_"}.

    Literal = Number | CharLiteral | TextLiteral.

    CharLiteral = "'"  (PrintingChar | Escape | DQUOTE) "'".

    TextLiteral = DQUOTE {PrintingChar | Escape | "'"} DQUOTE.

    Escape = "\" "n"   | "\" "t"     | "\" "r"     | "\" "f"
           | "\" "\"   | "\" "'"     | "\" DQUOTE
           | "\" OctalDigit OctalDigit OctalDigit.

    Number = Digit {Digit}
           | Digit {Digit} "_" HexDigit {HexDigit}
           | Digit {Digit} "." Digit {Digit} [Exp].

    Exp = ("E" | "e" | "D" | "d" | "X" | "x") ["+" | "-"] Digit {Digit}.

    PrintingChar = Letter | Digit | OtherChar.

    HexDigit = Digit | "A" | "B" | "C" | "D" | "E" | "F"
                     | "a" | "b" | "c" | "d" | "e" | "f".

    Digit = "0" | "1" | ... | "9".

    OctalDigit = "0" | "1" | ... | "7".

    Letter = "A"  | "B"  | ... | "Z"  | "a"  | "b"  | ... | "z".

    OtherChar = " " | "!" | "#" | "$" | "%" | "&" | "(" | ")"
              | "*" | "+" | "," | "-" | "." | "/" | ":" | ";"
              | "<" | "=" | ">" | "?" | "@" | "[" | "]" | "^"
              | "_" | "`" | "{" | "|" | "}" | "~"
              | ExtendedChar

    ExtendedChar = any char with ISO-Latin-1 code in [8_ 240..8_ 377].

    Last modified on Wed Apr  3 09:38:55 PST 1996 by heydon
         modified on Mon Dec 19 08:18:35 PST 1994 by kalsow