(root)/
gcc-13.2.0/
gcc/
m2/
mc/
mcp5.bnf
--
-- mc-5.bnf grammar and associated actions for mcp5.
--
-- Copyright (C) 2016-2023 Free Software Foundation, Inc.
-- Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
--
-- This file is part of GNU Modula-2.
--
-- GNU Modula-2 is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 3, or (at your option)
-- any later version.
--
-- GNU Modula-2 is distributed in the hope that it will be useful, but
-- WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-- General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with GNU Modula-2; see the file COPYING3.  If not see
-- <http://www.gnu.org/licenses/>.
% module mcp5 begin

(* output from mc-5.bnf, automatically generated do not edit.

Copyright (C) 2016-2023 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.

This file is part of GNU Modula-2.

GNU Modula-2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GNU Modula-2 is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Modula-2; see the file COPYING.  If not,
see <https://www.gnu.org/licenses/>.  *)

IMPLEMENTATION MODULE mcp5 ;

FROM DynamicStrings IMPORT String, InitString, KillString, Mark,
                           ConCat, ConCatChar ;

FROM mcError IMPORT errorStringAt, flushErrors ;
FROM nameKey IMPORT NulName, Name, makekey ;
FROM mcPrintf IMPORT printf0, printf1 ;
FROM mcDebug IMPORT assert ;
FROM mcReserved IMPORT toktype ;
FROM mcComment IMPORT setProcedureComment ;
FROM mcMetaError IMPORT metaError1, metaError2 ;
FROM mcStack IMPORT stack ;

IMPORT mcStack ;

FROM mcLexBuf IMPORT currentstring, currenttoken, getToken, insertToken,
                     insertTokenAndRewind, getTokenNo, lastcomment,
                     getBodyComment, getAfterComment ;

FROM decl IMPORT node, lookupDef, lookupImp, lookupModule, getSymName,
		 enterScope, leaveScope,
		 makeEnum, makeEnumField, putType, lookupSym, isDef, makeSubrange,
                 makeSet, makePointer,
		 addParameter,
		 makeVarargs, makeVarParameter, makeNonVarParameter,
		 putSubrangeType, putConst, getType, skipType,
		 makeArray, putUnbounded, getCardinal, makeBinaryTok, makeUnaryTok,
		 makeRecord, isRecord, isRecordField, isVarientField, makeVarient,
		 addFieldsToRecord, isVarient, buildVarientSelector,
 		 buildVarientFieldRecord, paramEnter, paramLeave,
		 makeIdentList, putIdent, addVarParameters, addNonVarParameters,
		 lookupInScope, import, lookupExported, isImp, isModule, isConst,
		 makeLiteralInt, makeLiteralReal, makeString, getBuiltinConst,
		 getNextEnum, makeComponentRef, makeArrayRef, makeDeRef,
		 makePointerRef,
		 makeExpList, putExpList, isExpList, isArray, isPointer, isVar,
		 isConst, isParameter,
		 makeStatementSequence, addStatement, putBegin, putFinally,
		 makeReturn, putReturn, makeExit, makeComment,
		 isStatementSequence, isWhile, makeWhile, putWhile,
		 makeAssignment, makeFuncCall, isReturn,
		 makeIf, makeElsif, putElse, isIf,
		 makeFor, putFor, isFor,
		 makeRepeat, putRepeat,
		 resetConstExpPos, getNextConstExp,
		 makeSetValue, putSetValue, includeSetValue,
		 makeCase, putCaseExpression, putCaseElse,
		 putCaseStatement, makeCaseList, putCaseRange,
		 dupExpr, makeLoop, putLoop, isLoop,
		 addCommentBody, addCommentAfter, addIfComments,
		 addElseComments, addIfEndComments,
		 addWhileDoComment, addWhileEndComment,
                 addRepeatComment, addUntilComment,
		 makeCommentS ;


CONST
   Pass1     = FALSE ;
   Debugging = FALSE ;

VAR
   WasNoError : BOOLEAN ;
   curstring,
   curident   : Name ;
   curproc,
   frommodule,
   qualid,
   typeDes,
   typeExp,
   curmodule  : node ;
   loopNo     : CARDINAL ;
   loopStk,
   stmtStk,
   withStk,
   stk        : stack ;


(*
   followNode -
*)

PROCEDURE followNode (n: node) ;
BEGIN
   IF isVar (n)
   THEN
      printf0 ("variable: ")
   ELSIF isParameter (n)
   THEN
      printf0 ("parameter: ")
   END ;
   n := skipType (getType (n)) ;
   IF isArray (n)
   THEN
      printf0 ("array\n")
   ELSIF isPointer (n)
   THEN
      printf0 ("pointer\n")
   ELSIF isRecord (n)
   THEN
      printf0 ("record\n")
   ELSE
      printf0 ("other\n")
   END
END followNode ;


(*
   push -
*)

PROCEDURE push (n: node) : node ;
BEGIN
   RETURN mcStack.push (stk, n)
END push ;


(*
   pop -
*)

PROCEDURE pop () : node ;
BEGIN
   RETURN mcStack.pop (stk)
END pop ;


(*
   replace -
*)

PROCEDURE replace (n: node) : node ;
BEGIN
   RETURN mcStack.replace (stk, n)
END replace ;


(*
   peep - returns the top node on the stack without removing it.
*)

PROCEDURE peep () : node ;
BEGIN
   RETURN push (pop ())
END peep ;


(*
   depth - returns the depth of the stack.
*)

PROCEDURE depth () : CARDINAL ;
BEGIN
   RETURN mcStack.depth (stk)
END depth ;


(*
   checkDuplicate -
*)

PROCEDURE checkDuplicate (b: BOOLEAN) ;
BEGIN

END checkDuplicate ;


(*
   isQualident - returns TRUE if, n, is a qualident.
*)

PROCEDURE isQualident (n: node) : BOOLEAN ;
VAR
   type: node ;
BEGIN
   IF isDef (n)
   THEN
      RETURN TRUE
   ELSE
      type := skipType (getType (n)) ;
      RETURN (type # NIL) AND isRecord (type)
   END ;
   RETURN FALSE
END isQualident ;



(*
   startWith -
*)

PROCEDURE startWith (n: node) ;
BEGIN
   n := mcStack.push (withStk, n)
END startWith ;


(*
   endWith -
*)

PROCEDURE endWith ;
VAR
   n: node ;
BEGIN
   n := mcStack.pop (withStk)
END endWith ;


(*
   lookupWithSym -
*)

PROCEDURE lookupWithSym (i: Name) : node ;
VAR
   d      : CARDINAL ;
   n, m, t: node ;
BEGIN
   d := mcStack.depth (withStk) ;
   WHILE d # 0 DO
      n := mcStack.access (withStk, d) ;
      t := skipType (getType (n)) ;
      m := lookupInScope (t, i) ;
      IF m # NIL
      THEN
         n := dupExpr (n) ;
         RETURN makeComponentRef (n, m)
      END ;
      DEC (d)
   END ;
   RETURN lookupSym (i)
END lookupWithSym ;


(*
   pushStmt - push a node, n, to the statement stack and return node, n.
*)

PROCEDURE pushStmt (n: node) : node ;
BEGIN
   RETURN mcStack.push (stmtStk, n)
END pushStmt ;


(*
   popStmt - pop the top node from the statement stack.
*)

PROCEDURE popStmt () : node ;
BEGIN
   RETURN mcStack.pop (stmtStk)
END popStmt ;


(*
   peepStmt - return the top node from the statement stack,
              but leave the stack unchanged.
*)

PROCEDURE peepStmt () : node ;
BEGIN
   RETURN pushStmt (popStmt ())
END peepStmt ;


(*
   pushLoop - push a node, n, to the loop stack and return node, n.
*)

PROCEDURE pushLoop (n: node) : node ;
BEGIN
   RETURN mcStack.push (loopStk, n)
END pushLoop ;


(*
   popLoop - pop the top node from the loop stack.
*)

PROCEDURE popLoop () : node ;
BEGIN
   RETURN mcStack.pop (loopStk)
END popLoop ;


(*
   peepLoop - return the top node from the loop stack,
              but leave the stack unchanged.
*)

PROCEDURE peepLoop () : node ;
BEGIN
   RETURN pushLoop (popLoop ())
END peepLoop ;


PROCEDURE ErrorString (s: String) ;
BEGIN
   errorStringAt (s, getTokenNo ()) ;
   WasNoError := FALSE
END ErrorString ;


PROCEDURE ErrorArray (a: ARRAY OF CHAR) ;
BEGIN
   ErrorString (InitString (a))
END ErrorArray ;


(*
   pushNunbounded -
*)

PROCEDURE pushNunbounded (c: CARDINAL) ;
VAR
   type,
   array,
   subrange: node ;
BEGIN
   WHILE c#0 DO
      type := pop () ;
      subrange := makeSubrange (NIL, NIL) ;
      putSubrangeType (subrange, getCardinal ()) ;

      array := makeArray (subrange, type) ;
      putUnbounded (array) ;
      type := push (array) ;
      DEC (c)
   END
END pushNunbounded ;


(*
   makeIndexedArray - builds and returns an array of type, t, with, c, indices.
*)

PROCEDURE makeIndexedArray (c: CARDINAL; t: node) : node ;
VAR
   i: node ;
BEGIN
   WHILE c>0 DO
      t := makeArray (pop (), t) ;
      DEC (c)
   END ;
   RETURN t
END makeIndexedArray ;


(*
   importInto - from, m, import, name, into module, current.
                It checks to see if curident is an enumeration type
                and if so automatically includes all enumeration fields
                as well.
*)

PROCEDURE importInto (m: node; name: Name; current: node) ;
VAR
   s, o: node ;
BEGIN
   assert (isDef (m)) ;
   assert (isDef (current) OR isModule (current) OR isImp (current)) ;
   s := lookupExported (m, name) ;
   IF s=NIL
   THEN
      metaError2 ('{%1k} was not exported from definition module {%2a}', name, m)
   ELSE
      o := import (current, s) ;
      IF s#o
      THEN
         metaError2 ('{%1ad} cannot be imported into the current module as it causes a name clash with {%2ad}',
                     s, o)
      END
   END
END importInto ;


(*
   checkEndName - if module does not have, name, then issue an error containing, desc.
*)

PROCEDURE checkEndName (module: node; name: Name; desc: ARRAY OF CHAR) ;
VAR
   s: String ;
BEGIN
   IF getSymName (module)#name
   THEN
      s := InitString ('inconsistent module name found with this ') ;
      s := ConCat (s, Mark (InitString (desc))) ;
      ErrorString (s)
   END
END checkEndName ;

% declaration mcp5 begin


(*
   SyntaxError - after a syntax error we skip all tokens up until we reach
                 a stop symbol.
*)

PROCEDURE SyntaxError (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ;
BEGIN
   DescribeError ;
   IF Debugging
   THEN
      printf0('\nskipping token *** ')
   END ;
   (*
      yes the ORD(currenttoken) looks ugly, but it is *much* safer than
      using currenttoken<sometok as a change to the ordering of the
      token declarations below would cause this to break. Using ORD() we are
      immune from such changes
   *)
   WHILE NOT (((ORD(currenttoken)<32)  AND (currenttoken IN stopset0)) OR
              ((ORD(currenttoken)>=32) AND (ORD(currenttoken)<64) AND (currenttoken IN stopset1)) OR
              ((ORD(currenttoken)>=64) AND (currenttoken IN stopset2)))
   DO
      getToken
   END ;
   IF Debugging
   THEN
      printf0(' ***\n')
   END
END SyntaxError ;


(*
   SyntaxCheck -
*)

PROCEDURE SyntaxCheck (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ;
BEGIN
   (* and again (see above re: ORD)
    *)
   IF NOT (((ORD(currenttoken)<32)  AND (currenttoken IN stopset0)) OR
     	   ((ORD(currenttoken)>=32) AND (ORD(currenttoken)<64) AND (currenttoken IN stopset1)) OR
           ((ORD(currenttoken)>=64) AND (currenttoken IN stopset2)))
   THEN
      SyntaxError (stopset0, stopset1, stopset2)
   END
END SyntaxCheck ;


(*
   WarnMissingToken - generates a warning message about a missing token, t.
*)

PROCEDURE WarnMissingToken (t: toktype) ;
VAR
   s0 : SetOfStop0 ;
   s1 : SetOfStop1 ;
   s2 : SetOfStop2 ;
   str: String ;
BEGIN
   s0 := SetOfStop0{} ;
   s1 := SetOfStop1{} ;
   s2 := SetOfStop2{} ;
   IF ORD(t)<32
   THEN
      s0 := SetOfStop0{t}
   ELSIF ORD(t)<64
   THEN
      s1 := SetOfStop1{t}
   ELSE
      s2 := SetOfStop2{t}
   END ;
   str := DescribeStop (s0, s1, s2) ;

   str := ConCat (InitString ('syntax error,'), Mark (str)) ;
   errorStringAt (str, getTokenNo ())
END WarnMissingToken ;


(*
   MissingToken - generates a warning message about a missing token, t.
*)

PROCEDURE MissingToken (t: toktype) ;
BEGIN
   WarnMissingToken (t) ;
   IF (t#identtok) AND (t#integertok) AND (t#realtok) AND (t#stringtok)
   THEN
      IF Debugging
      THEN
         printf0 ('inserting token\n')
      END ;
      insertToken (t)
   END
END MissingToken ;


(*
   CheckAndInsert -
*)

PROCEDURE CheckAndInsert (t: toktype; stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) : BOOLEAN ;
BEGIN
   IF ((ORD(t)<32) AND (t IN stopset0)) OR
      ((ORD(t)>=32) AND (ORD(t)<64) AND (t IN stopset1)) OR
      ((ORD(t)>=64) AND (t IN stopset2))
   THEN
      WarnMissingToken (t) ;
      insertTokenAndRewind (t) ;
      RETURN( TRUE )
   ELSE
      RETURN( FALSE )
   END
END CheckAndInsert ;


(*
   InStopSet
*)

PROCEDURE InStopSet (t: toktype; stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) : BOOLEAN ;
BEGIN
   IF ((ORD(t)<32) AND (t IN stopset0)) OR
      ((ORD(t)>=32) AND (ORD(t)<64) AND (t IN stopset1)) OR
      ((ORD(t)>=64) AND (t IN stopset2))
   THEN
      RETURN( TRUE )
   ELSE
      RETURN( FALSE )
   END
END InStopSet ;


(*
   PeepToken - peep token checks to see whether the stopset is satisfied by currenttoken
               If it is not then it will insert a token providing the token
               is one of ; ] ) } . OF END ,

               if the stopset contains <identtok> then we do not insert a token
*)

PROCEDURE PeepToken (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ;
BEGIN
   (* and again (see above re: ORD)
    *)
   IF (NOT (((ORD(currenttoken)<32)  AND (currenttoken IN stopset0)) OR
     	    ((ORD(currenttoken)>=32) AND (ORD(currenttoken)<64) AND (currenttoken IN stopset1)) OR
            ((ORD(currenttoken)>=64) AND (currenttoken IN stopset2)))) AND
      (NOT InStopSet(identtok, stopset0, stopset1, stopset2))
   THEN
      (* SyntaxCheck would fail since currentoken is not part of the stopset
         we check to see whether any of currenttoken might be a commonly omitted token *)
      IF CheckAndInsert(semicolontok, stopset0, stopset1, stopset2) OR
         CheckAndInsert(rsbratok, stopset0, stopset1, stopset2) OR
         CheckAndInsert(rparatok, stopset0, stopset1, stopset2) OR
         CheckAndInsert(rcbratok, stopset0, stopset1, stopset2) OR
         CheckAndInsert(periodtok, stopset0, stopset1, stopset2) OR
         CheckAndInsert(oftok, stopset0, stopset1, stopset2) OR
         CheckAndInsert(endtok, stopset0, stopset1, stopset2) OR
         CheckAndInsert(commatok, stopset0, stopset1, stopset2)
      THEN
      END
   END
END PeepToken ;


(*
   Expect -
*)

PROCEDURE Expect (t: toktype; stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ;
BEGIN
   IF currenttoken=t
   THEN
      getToken ;
      IF Pass1
      THEN
         PeepToken(stopset0, stopset1, stopset2)
      END
   ELSE
      MissingToken(t)
   END ;
   SyntaxCheck(stopset0, stopset1, stopset2)
END Expect ;


(*
   CompilationUnit - returns TRUE if the input was correct enough to parse
                     in future passes.
*)

PROCEDURE CompilationUnit () : BOOLEAN ;
BEGIN
   stk := mcStack.init () ;
   withStk := mcStack.init () ;
   stmtStk := mcStack.init () ;
   loopStk := mcStack.init () ;
   loopNo := 0 ;
   WasNoError := TRUE ;
   FileUnit(SetOfStop0{eoftok}, SetOfStop1{}, SetOfStop2{}) ;
   mcStack.kill (stk) ;
   mcStack.kill (withStk) ;
   mcStack.kill (stmtStk) ;
   mcStack.kill (loopStk) ;
   RETURN WasNoError
END CompilationUnit ;


(*
   Ident - error checking varient of Ident
*)

PROCEDURE Ident (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ;
BEGIN
   curident := makekey (currentstring) ;
   Expect(identtok, stopset0, stopset1, stopset2)
END Ident ;


(*
   string -
*)

PROCEDURE string (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ;
BEGIN
   curstring := makekey (currentstring) ;
   Expect(stringtok, stopset0, stopset1, stopset2)
END string ;


(*
   Integer -
*)

PROCEDURE Integer (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ;
VAR
   n: node ;
BEGIN
   n := push (makeLiteralInt (makekey (currentstring))) ;
   Expect(integertok, stopset0, stopset1, stopset2)
END Integer ;


(*
   Real -
*)

PROCEDURE Real (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ;
VAR
   n: node ;
BEGIN
   n := push (makeLiteralReal (makekey (currentstring))) ;
   Expect(realtok, stopset0, stopset1, stopset2)
END Real ;

% module mcp5 end
END mcp5.
% rules
error       'ErrorArray' 'ErrorString'
tokenfunc   'currenttoken'

token   ''                eoftok      -- internal token
token   '+'               plustok
token   '-'               minustok
token   '*'               timestok
token   '/'               dividetok
token   ':='              becomestok
token   '&'               ambersandtok
token   "."               periodtok
token   ","               commatok
token   ";"               semicolontok
token   '('               lparatok
token   ')'               rparatok
token   '['               lsbratok   -- left  square brackets
token   ']'               rsbratok   -- right square brackets
token   '{'               lcbratok   -- left  curly brackets
token   '}'               rcbratok   -- right curly brackets
token   '^'               uparrowtok
token   "'"               singlequotetok
token   '='               equaltok
token   '#'               hashtok
token   '<'               lesstok
token   '>'               greatertok
token   '<>'              lessgreatertok
token   '<='              lessequaltok
token   '>='              greaterequaltok
token   '<*'              ldirectivetok
token   '*>'              rdirectivetok
token   '..'              periodperiodtok
token   ':'               colontok
token   '"'               doublequotestok
token   '|'               bartok
token   'AND'             andtok
token   'ARRAY'           arraytok
token   'BEGIN'           begintok
token   'BY'              bytok
token   'CASE'            casetok
token   'CONST'           consttok
token   'DEFINITION'      definitiontok
token   'DIV'             divtok
token   'DO'              dotok
token   'ELSE'            elsetok
token   'ELSIF'           elsiftok
token   'END'             endtok
token   'EXCEPT'          excepttok
token   'EXIT'            exittok
token   'EXPORT'          exporttok
token   'FINALLY'         finallytok
token   'FOR'             fortok
token   'FROM'            fromtok
token   'IF'              iftok
token   'IMPLEMENTATION'  implementationtok
token   'IMPORT'          importtok
token   'IN'              intok
token   'LOOP'            looptok
token   'MOD'             modtok
token   'MODULE'          moduletok
token   'NOT'             nottok
token   'OF'              oftok
token   'OR'              ortok
token   'PACKEDSET'       packedsettok
token   'POINTER'         pointertok
token   'PROCEDURE'       proceduretok
token   'QUALIFIED'       qualifiedtok
token   'UNQUALIFIED'     unqualifiedtok
token   'RECORD'          recordtok
token   'REM'             remtok
token   'REPEAT'          repeattok
token   'RETRY'           retrytok
token   'RETURN'          returntok
token   'SET'             settok
token   'THEN'            thentok
token   'TO'              totok
token   'TYPE'            typetok
token   'UNTIL'           untiltok
token   'VAR'             vartok
token   'WHILE'           whiletok
token   'WITH'            withtok
token   'ASM'             asmtok
token   'VOLATILE'        volatiletok
token   '...'             periodperiodperiodtok
token   '__DATE__'        datetok
token   '__LINE__'        linetok
token   '__FILE__'        filetok
token   '__ATTRIBUTE__'   attributetok
token   '__BUILTIN__'     builtintok
token   '__INLINE__'      inlinetok
token   'integer number'  integertok
token   'identifier'      identtok
token   'real number'     realtok
token   'string'          stringtok

special Ident             first { < identtok > } follow { }
special Integer           first { < integertok > } follow { }
special Real              first { < realtok > } follow { }
special string            first { < stringtok > } follow { }

BNF

-- the following are provided by the module m2flex and also handbuild procedures below
-- Ident := Letter { ( Letter | Digit ) } =:
-- Integer := Digit { Digit } | OctalDigit { OctalDigit } ( " B " | " C " ) |
--           Digit { HexDigit } " H " =:
-- Real := Digit { Digit } " . " { Digit } [ ScaleFactor ] =:
-- ScaleFactor := " E " [ ( " + " | " - " ) ] Digit { Digit } =:
-- HexDigit := Digit | " A " | " B " | " C " | " D " | " E " | " F " =:
-- Digit := OctalDigit | " 8 " | " 9 " =:
-- OctalDigit := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" =:
-- String

FileUnit := DefinitionModule | ImplementationOrProgramModule
          =:

ProgramModule := "MODULE"
                  Ident                                                % curmodule := lookupModule (curident) %
                                                                       % addCommentBody (curmodule) %
		                                                       % enterScope (curmodule) %
								       % resetConstExpPos (curmodule) %
                  [ Priority ] ";"
                  { Import }
                  Block
                  Ident                                                % checkEndName (curmodule, curident, 'program module') %
		                                                       % leaveScope %

                  "."
                  =:

ImplementationModule := "IMPLEMENTATION" "MODULE"
                         Ident                                         % curmodule := lookupImp (curident) %
                                                                       % addCommentBody (curmodule) %
			                                               % enterScope (lookupDef (curident)) %
                                                                       % enterScope (curmodule) %
                                                                       % resetConstExpPos (curmodule) %
                         [ Priority ] ";"
                         { Import }
                         Block
                         Ident                                         % checkEndName (curmodule, curident, 'implementation module') %
                                                                       % leaveScope ; leaveScope %
                         "."
                      =:

ImplementationOrProgramModule := ImplementationModule | ProgramModule =:

ConstInteger := Integer                                                % VAR i: node ; %
                                                                       % i := pop () %
	      =:

ConstReal := Real                                                      % VAR r: node ; %
                                                                       % r := pop () %
	      =:

ConstNumber := ConstInteger | ConstReal =:

Number := Integer | Real =:

Qualident := Ident { "." Ident } =:

ConstantDeclaration := Ident "=" ConstExpressionNop =:

ConstExpressionNop :=                                                  % VAR c: node ; %
                                                                       % c := getNextConstExp () %
                      SimpleConstExpr [ Relation SimpleConstExpr ] =:

ConstExpression :=                                                     % VAR c: node ; %
                                                                       % c := push (getNextConstExp ()) %
                   SimpleConstExpr [ Relation SimpleConstExpr ] =:

Relation := "="
            | "#"
            | "<>"
            | "<"
            | "<="
            | ">"
            | ">="
            | "IN"
         =:

SimpleConstExpr := UnaryOrConstTerm { AddOperator ConstTerm } =:

UnaryOrConstTerm :=
                    "+"
                    ConstTerm
                    |
                    "-"
                    ConstTerm
                    |
                    ConstTerm
		  =:

AddOperator :=   "+"
               | "-"
               | "OR"
             =:

ConstTerm := ConstFactor { MulOperator ConstFactor } =:

MulOperator := "*"
               | "/"
               | "DIV"
               | "MOD"
               | "REM"
               | "AND"
               | "&"
            =:

NotConstFactor := "NOT" ConstFactor                                     % VAR n: node ; %
                                                                        % n := push (makeUnaryTok (nottok, pop ())) %
                =:

ConstFactor := ConstNumber | ConstString | ConstSetOrQualidentOrFunction |
               "(" ConstExpressionNop ")" | NotConstFactor
               | ConstAttribute =:

-- to help satisfy LL1

ConstString := string =:

ConstComponentElement := ConstExpressionNop [ ".." ConstExpressionNop ]
                  =:

ConstComponentValue := ConstComponentElement [ 'BY' ConstExpressionNop ]
                     =:

ConstArraySetRecordValue := ConstComponentValue { ',' ConstComponentValue }
                          =:

ConstConstructor := '{'
                       [ ConstArraySetRecordValue ]
                    '}' =:

ConstSetOrQualidentOrFunction := Qualident
                                 [ ConstConstructor | ConstActualParameters ]
                                   |
                                     ConstConstructor =:

ConstActualParameters := "(" [ ConstExpList ] ")" =:

ConstExpList := ConstExpressionNop { "," ConstExpressionNop }
              =:

ConstAttribute := "__ATTRIBUTE__" "__BUILTIN__" "(" "("
                  ConstAttributeExpression
                  ")" ")" =:

ConstAttributeExpression := Ident | "<" Qualident ',' Ident ">" =:

ByteAlignment := '<*' AttributeExpression '*>'
               =:

OptAlignmentExpression := [ AlignmentExpression ] =:

AlignmentExpression := "(" ConstExpressionNop ")" =:

Alignment := [ ByteAlignment ] =:

IdentList := Ident { "," Ident }
           =:

SubrangeType := "[" ConstExpressionNop ".." ConstExpressionNop "]" =:

ArrayType := "ARRAY" SimpleType { "," SimpleType } "OF" Type =:

RecordType := "RECORD" [ DefaultRecordAttributes ]
		       FieldListSequence
	      "END" =:

DefaultRecordAttributes := '<*' AttributeExpression '*>' =:

RecordFieldPragma := [ '<*' FieldPragmaExpression
                            { ',' FieldPragmaExpression } '*>' ] =:

FieldPragmaExpression := Ident PragmaConstExpression =:

PragmaConstExpression := [ '(' ConstExpressionNop ')' ] =:

AttributeExpression := Ident '(' ConstExpressionNop ')' =:

FieldListSequence := FieldListStatement { ";" FieldListStatement } =:

FieldListStatement := [ FieldList ] =:

FieldList := IdentList ":" Type RecordFieldPragma
             | "CASE" CaseTag "OF" Varient { "|" Varient }
              [ "ELSE"
                      FieldListSequence
              ] "END"
           =:

TagIdent :=  Ident |                                                    % curident := NulName %
          =:

CaseTag := TagIdent [ ":" Qualident ]
         =:

Varient :=  [ VarientCaseLabelList ":" FieldListSequence ] =:

VarientCaseLabelList := VarientCaseLabels { "," VarientCaseLabels } =:

VarientCaseLabels := ConstExpressionNop [ ".." ConstExpressionNop ]
                   =:

SetType := ( "SET" | "PACKEDSET" ) "OF" SimpleType =:

PointerType := "POINTER" "TO" Type =:

ProcedureType := "PROCEDURE" [ FormalTypeList ] =:

FormalTypeList := "(" ( ")" FormalReturn |
                        ProcedureParameters ")" FormalReturn ) =:

FormalReturn := [ ":" OptReturnType ] =:

OptReturnType := "[" Qualident "]" | Qualident
	       =:

ProcedureParameters := ProcedureParameter
                       { "," ProcedureParameter } =:

ProcedureParameter := "..." | "VAR" FormalType | FormalType =:


VarIdent := Ident [ "[" ConstExpressionNop "]" ]
          =:

VarIdentList := VarIdent { "," VarIdent }  =:

VariableDeclaration :=  VarIdentList ":" Type Alignment
                     =:

Designator := PushQualident { SubDesignator } =:

SubDesignator :=                                                        % VAR n, field, type: node ; %
                                                                        % n := peep () %
                                                                        % IF n = NIL
                                                                          THEN
									     ErrorArray ('no expression found') ;
                                                                             flushErrors ;
                                                                             RETURN
                                                                          END %
									% type := skipType (getType (n)) %
                 ( "."
                   Ident                                                % IF isRecord (type)
                                                                          THEN
                                                                             field := lookupInScope (type, curident) ;
                                                                             IF field = NIL
                                                                             THEN
                                                                                metaError2 ('field {%1k} cannot be found in record {%2ad}', curident, type)
                                                                             ELSE
                                                                                n := replace (makeComponentRef (n, field))
                                                                             END
                                                                          ELSE
                                                                             metaError2 ('attempting to access a field {%1k} from {%2ad} which does not have a record type', curident, type)
                                                                          END %

                   | "[" ArrayExpList                                   % IF isArray (type)
                                                                          THEN
                                                                             n := replace (makeArrayRef (n, pop ()))
                                                                          ELSE
                                                                             metaError1 ('attempting to access an array but the expression is not an array but a {%1d}', type)
                                                                          END %
                     "]"
                   | SubPointer
                 )
               =:

SubPointer :=                                                           % VAR n, field, type: node ; %
                                                                        % n := peep () %
									% type := skipType (getType (n)) %
              "^" ( "." Ident                                           % IF isPointer (type)
                                                                          THEN
									     type := skipType (getType (type)) ;
									     IF isRecord (type)
                                                                             THEN
                                                                                field := lookupInScope (type, curident) ;
                                                                                IF field = NIL
                                                                                THEN
                                                                                   metaError2 ('field {%1k} cannot be found in record {%2ad}', curident, type)
                                                                                ELSE
                                                                                   n := replace (makePointerRef (n, field))
                                                                                END
                                                                             ELSE
                                                                                metaError2 ('attempting to access a field {%1k} from {%2ad} which does not have a record type', curident, type)
                                                                             END
                                                                          ELSE
                                                                             metaError2 ('trying to dereference {%1k} which was not declared as a pointer but a {%2tad}', n, n)
                                                                          END %

                                   |                                    % IF isPointer (type)
                                                                          THEN
                                                                             n := replace (makeDeRef (n))
                                                                          ELSE
                                                                             metaError1 ('attempting to dereference a pointer but the expression is not a pointer but a {%1d}', type)
                                                                          END %
                                      )
            =:



ArrayExpList :=                                                         % VAR l: node ; %
                                                                        % l := push (makeExpList ()) %
                Expression                                              % putExpList (l, pop ()) %
                                                                        % assert (isExpList (peep ())) %
                { ","
                   Expression                                           % putExpList (l, pop ()) %
                                                                        % assert (isExpList (peep ())) %
                }
              =:

ExpList :=                                                              % VAR p, n: node ; %
                                                                        % p := peep () %
									% assert (isExpList (p)) %
                Expression                                              % putExpList (p, pop ()) %
                                                                        % assert (isExpList (peep ())) %
                           { "," Expression                             % putExpList (p, pop ()) %
                                                                        % assert (isExpList (peep ())) %
			                    }
         =:


Expression :=                                                           % VAR c, l, r: node ; op: toktype ; %
              SimpleExpression                                          % op := currenttoken %
	                       [ Relation                               % l := pop () %
			                  SimpleExpression              % r := pop () %
					                                % r := push (makeBinaryTok (op, l, r)) %
					                   ]
           =:

SimpleExpression :=                                                     % VAR op: toktype ; n: node ; %
                    UnaryOrTerm {                                       % op := currenttoken %
		                                                        % n := pop () %
				  AddOperator Term                      % n := push (makeBinaryTok (op, n, pop ())) %
					           }
						     =:

UnaryOrTerm :=                                                          % VAR n: node ; %
               "+" Term                                                 % n := push (makeUnaryTok (plustok, pop ())) %
               | "-" Term                                               % n := push (makeUnaryTok (minustok, pop ())) %
               | Term
	     =:

Term :=                                                                 % VAR op: toktype ; n: node ; %
        Factor {                                                        % op := currenttoken %
	         MulOperator                                            % n := pop () %
		             Factor                                     % n := push (makeBinaryTok (op, n, pop ())) %
                                    } =:

PushString := string                                                    % VAR n: node ; %
                                                                        % n := push (makeString (curstring)) %
            =:

Factor := Number | PushString | SetOrDesignatorOrFunction |
          "(" Expression ")" | "NOT" ( Factor                           % VAR n: node ; %
                                                                        % n := push (makeUnaryTok (nottok, pop ())) %
          | ConstAttribute
                                                                        % n := push (makeUnaryTok (nottok, pop ())) %
                                ) =:

ComponentElement := Expression                                          % VAR l, h, n: node ; %
                                                                        % l := pop () %
									% h := NIL %
                                         [ ".." Expression              % h := pop () %
					                                % ErrorArray ('implementation restriction range is not allowed') %
					                   ]            % n := push (includeSetValue (pop (), l, h)) %
                       =:

ComponentValue := ComponentElement [ 'BY'                               % ErrorArray ('implementation restriction BY not allowed') %
                                          Expression ]
                =:

ArraySetRecordValue := ComponentValue { ',' ComponentValue }
                     =:

Constructor := '{'                                                      % VAR n: node ; %
                                                                        % n := push (makeSetValue ()) %
                        [ ArraySetRecordValue ]
               '}' =:

SetOrDesignatorOrFunction := PushQualident                               % VAR q, p, n: node ; %
                              [ Constructor                              % p := pop () %
				                                         % q := pop () %
					                                 % n := push (putSetValue (p, q)) %
                                            |
                                SimpleDes
				          [                              % q := pop () %
					    ActualParameters             % p := pop () %
					                                 % p := push (makeFuncCall (q, p)) %
					                     ]
                              ]                                |
                              Constructor =:

-- SimpleDes := { "." Ident | "[" ExpList "]" | "^" } =:
SimpleDes := { SubDesignator } =:

ActualParameters := "("                                                  % VAR n: node ; %
                                                                         % n := push (makeExpList ()) %
                        [ ExpList ] ")"                                  % assert (isExpList (peep ())) %
		  =:


ExitStatement :=                                                         % VAR n: node ; %
                 "EXIT"
                                                                         % IF loopNo = 0
                                                                           THEN
                                                                              ErrorArray ('EXIT can only be used inside a LOOP statement')
                                                                           ELSE
                                                                              n := pushStmt (makeExit (peepLoop (), loopNo))
                                                                           END %
               =:

ReturnStatement :=                                                       % VAR n: node ; %
                                                                         % n := pushStmt (makeReturn ()) %
                   "RETURN" [ Expression                                 % putReturn (n, pop ()) %
		                         ]                               % addCommentBody (peepStmt ()) %
                                                                         % addCommentAfter (peepStmt ()) %
					                                 % assert (isReturn (peepStmt ())) %
                 =:

Statement := ( AssignmentOrProcedureCall | IfStatement | CaseStatement |
               WhileStatement | RepeatStatement | LoopStatement |
               ForStatement | WithStatement | AsmStatement |
               ExitStatement | ReturnStatement | RetryStatement |        % VAR s: node ; %
                                                                         % s := pushStmt (NIL) %
             )
           =:

RetryStatement :=                                                        % VAR s: node ; %
                                                                         % s := pushStmt (makeComment ("retry")) %
                  "RETRY"
                =:

AssignmentOrProcedureCall :=                                             % VAR d, a, p: node ; %
                             Designator                                  % d := pop () %
                             ( ":=" Expression                           % a := pushStmt (makeAssignment (d, pop ())) %
                                |
                                  ActualParameters                       % a := pushStmt (makeFuncCall (d, pop ())) %
				                   |                     % a := pushStmt (makeFuncCall (d, NIL)) %
                             )
                                                                         % addCommentBody (peepStmt ()) %
                                                                         % addCommentAfter (peepStmt ()) %
                           =:

-- these two break LL1 as both start with a Designator
-- ProcedureCall := Designator [ ActualParameters ] =:
-- Assignment := Designator ":=" Expression =:

StatementSequence :=                                                     % VAR s, t: node ; %
                                                                         % s := pushStmt (makeStatementSequence ()) %
		                                                         % assert (isStatementSequence (peepStmt ())) %
                     Statement		                                 % addStatement (s, popStmt ()) %
		                                                         % assert (isStatementSequence (peepStmt ())) %
		               { ";" Statement		                 % addStatement (s, popStmt ()) %
		                                                         % assert (isStatementSequence (peepStmt ())) %
				               }
                  =:

IfStatement :=                                                           % VAR i, a, b: node ; %
                "IF"                                                     % b := makeCommentS (getBodyComment ()) %
                     Expression                                          % a := makeCommentS (getAfterComment ()) %
                                "THEN" StatementSequence                 % i := pushStmt (makeIf (pop (), popStmt ())) %
                                                                         % addIfComments (i, b, a) %
              { "ELSIF"                                                  % b := makeCommentS (getBodyComment ()) %
                        Expression                                       % a := makeCommentS (getAfterComment ()) %
			           "THEN"                                % addElseComments (peepStmt (), b, a) %
                                          StatementSequence              % i := makeElsif (i, pop (), popStmt ()) %
              }
              [ "ELSE"
                      StatementSequence                                  % putElse (i, popStmt ()) %
		                        ] "END"                          % b := makeCommentS (getBodyComment ()) %
                                                                         % a := makeCommentS (getAfterComment ()) %
					                                 % assert (isIf (peepStmt ())) %
                                                                         % addIfEndComments (peepStmt (), b, a) %
            =:

CaseStatement :=                                                         % VAR s, e: node ; %
                                                                         % s := pushStmt (makeCase ()) %
                 "CASE"
                        Expression                                       % s := putCaseExpression (s, pop ()) %
                                   "OF" Case { "|" Case }
                 CaseEndStatement
               =:

CaseEndStatement :=                                                      % VAR c: node ; %
                    "END"
                      | "ELSE"
                                                                         % c := peepStmt () %
                             StatementSequence                           % c := putCaseElse (c, popStmt ()) %
                                               "END"
                 =:

Case := [ CaseLabelList ":"                                              % VAR l, c: node ; %
                                                                         % l := pop () %
									 % c := peepStmt () %
                            StatementSequence                            % c := putCaseStatement (c, l, popStmt ()) %
			                      ]
      =:

CaseLabelList :=                                                         % VAR l: node ; %
                                                                         % l := push (makeCaseList ()) %
                 CaseLabels { "," CaseLabels } =:

CaseLabels :=                                                            % VAR lo, hi, l: node ; %
                                                                         % lo := NIL ; hi := NIL %
									 % l := peep () %
              ConstExpression                                            % lo := pop () %
	                      [ ".." ConstExpression                     % hi := pop () %
			                             ]                   % l := putCaseRange (l, lo, hi) %
            =:

WhileStatement :=                                                        % VAR s, w, e, a, b: node ; %
                                                                         % w := pushStmt (makeWhile ()) %
                  "WHILE" Expression "DO"                                % b := makeCommentS (getBodyComment ()) %
                                                                         % a := makeCommentS (getAfterComment ()) %
									 % addWhileDoComment (w, b, a) %
                                                                         % e := pop () %
                      StatementSequence                                  % s := popStmt () %
		  "END"                                                  % (* assert (isStatementSequence (peepStmt ())) *) %
		                                                         % putWhile (w, e, s) %
                                                                         % b := makeCommentS (getBodyComment ()) %
                                                                         % a := makeCommentS (getAfterComment ()) %
									 % addWhileEndComment (w, b, a) %
                =:

RepeatStatement :=                                                       % VAR r, s, a, b: node ; %
                                                                         % r := pushStmt (makeRepeat ()) %
                   "REPEAT"
                                                                         % b := makeCommentS (getBodyComment ()) %
                                                                         % a := makeCommentS (getAfterComment ()) %
									 % addRepeatComment (r, b, a) %
                       StatementSequence                                 % s := popStmt () %
	           "UNTIL" Expression                                    % putRepeat (r, s, pop ()) %
                                                                         % b := makeCommentS (getBodyComment ()) %
                                                                         % a := makeCommentS (getAfterComment ()) %
									 % addUntilComment (r, b, a) %
                 =:

ForStatement :=                                                          % VAR f, i, s, e, b: node ; %
                                                                         % b := NIL %
                                                                         % f := pushStmt (makeFor ()) %
                "FOR" Ident                                              % i := lookupWithSym (curident) %
		            ":=" Expression                              % s := pop () %
			                    "TO" Expression              % e := pop () %
		    [ "BY" ConstExpression                               % b := pop () %
		                           ] "DO"
                    StatementSequence                                    % putFor (f, i, s, e, b, popStmt ()) %
                "END"
              =:

LoopStatement :=                                                         % VAR l, s: node ; %
                 "LOOP"                                                  % l := pushStmt (pushLoop (makeLoop ())) %
		                                                         % INC (loopNo) %
                      StatementSequence                                  % s := popStmt () %
		                                                         % putLoop (l, s) %
		                                                         % DEC (loopNo) %
                 "END"                                                   % l := popLoop () %
		                                                         % assert (isLoop (peepStmt ())) %
               =:

WithStatement := "WITH" Designator "DO"                                  % startWith (pop ()) %
                     StatementSequence
                 "END"                                                   % endWith %
               =:

ProcedureDeclaration := ProcedureHeading ";" ProcedureBlock
                        Ident                                            % leaveScope %
                      =:

ProcedureIdent := Ident                                                  % curproc := lookupSym (curident) %
                                                                         % enterScope (curproc) %
                                                                         % setProcedureComment (lastcomment, curident) %

                =:

DefProcedureIdent := Ident                                               % curproc := lookupSym (curident) %
                   =:

DefineBuiltinProcedure := [ "__ATTRIBUTE__" "__BUILTIN__" "(" "(" Ident ")" ")" | "__INLINE__" ]
                      =:

ProcedureHeading := "PROCEDURE" DefineBuiltinProcedure ( ProcedureIdent
                                                         [ FormalParameters ]
                                                         AttributeNoReturn )
                  =:

Builtin := [ "__BUILTIN__" | "__INLINE__" ] =:

DefProcedureHeading := "PROCEDURE" Builtin ( DefProcedureIdent
                                             [ DefFormalParameters ]
                                             AttributeNoReturn )
                     =:

-- introduced procedure block so we can produce more informative
-- error messages

ProcedureBlock := { Declaration } [ "BEGIN" ProcedureBlockBody ] "END"
                =:

Block := { Declaration } InitialBlock FinalBlock "END"
       =:

InitialBlock := [ "BEGIN" InitialBlockBody ] =:

FinalBlock := [ "FINALLY" FinalBlockBody ] =:

InitialBlockBody := NormalPart                                         % putBegin (curmodule, popStmt ()) %
                               [ "EXCEPT" ExceptionalPart ] =:

FinalBlockBody := NormalPart                                           % putFinally (curmodule, popStmt ()) %
                             [ "EXCEPT" ExceptionalPart ] =:

ProcedureBlockBody := ProcedureNormalPart
                      [ "EXCEPT" ExceptionalPart ] =:

ProcedureNormalPart := StatementSequence                               % putBegin (curproc, popStmt ()) %
                     =:

NormalPart := StatementSequence
            =:

ExceptionalPart := StatementSequence
                 =:

Declaration := "CONST" { ConstantDeclaration ";" } |
               "TYPE" { TypeDeclaration } |
               "VAR" { VariableDeclaration ";" } |
               ProcedureDeclaration ";" |
               ModuleDeclaration ";" =:

DefFormalParameters := "("                                             % paramEnter (curproc) %
                           [ DefMultiFPSection ] ")"                   % paramLeave (curproc) %
			                             FormalReturn =:

AttributeNoReturn := [ "<*" Ident "*>" ] =:

AttributeUnused := [ "<*" Ident "*>" ] =:

DefMultiFPSection := DefExtendedFP | FPSection [ ";" DefMultiFPSection ] =:

FormalParameters := "("                                                % paramEnter (curproc) %
                        [ MultiFPSection ] ")"                         % paramLeave (curproc) %
			                       FormalReturn =:

MultiFPSection := ExtendedFP | FPSection [ ";" MultiFPSection ] =:

FPSection := NonVarFPSection | VarFPSection =:

DefExtendedFP := DefOptArg | "..." =:

ExtendedFP := OptArg | "..." =:

VarFPSection := "VAR" IdentList ":" FormalType [ AttributeUnused ]
              =:

NonVarFPSection := IdentList ":" FormalType [ AttributeUnused ]
                 =:

OptArg := "[" Ident ":" FormalType [ "=" ConstExpressionNop ] "]" =:

DefOptArg := "[" Ident ":" FormalType "=" ConstExpressionNop "]" =:

FormalType := { "ARRAY" "OF" } Qualident =:

ModuleDeclaration := "MODULE" Ident [ Priority ] ";"
                        { Import } [ Export ]
                        Block Ident
                   =:

Priority := "[" ConstExpressionNop "]" =:

Export := "EXPORT" ( "QUALIFIED"
                                 IdentList |
                     "UNQUALIFIED"
                                 IdentList |
                     IdentList ) ";" =:

FromIdentList := Ident { "," Ident } =:

FromImport := "FROM" Ident "IMPORT" FromIdentList ";"
            =:

ImportModuleList := Ident { "," Ident } =:

WithoutFromImport := "IMPORT" ImportModuleList ";"
                   =:

Import := FromImport | WithoutFromImport =:

DefinitionModule := "DEFINITION" "MODULE" [ "FOR" string ] Ident ";"    % curmodule := lookupDef (curident) %
     		                                                        % enterScope (curmodule) %
                      { Import } [ Export ]
                      { Definition }
                    "END" Ident "."                                     % checkEndName (curmodule, curident, 'definition module') %
                                                                        % leaveScope %
                  =:

PushQualident :=                                                        % VAR type, field: node ; %
                 Ident                                                  % qualid := push (lookupWithSym (curident)) %
		                                                        % IF qualid = NIL
                                                                          THEN
                                                                             metaError1 ('the symbol {%1k} is not visible in this scope (or any other nested scope)', curident)
                                                                          END %
		      [ "."
		                                                        % IF NOT isQualident (qualid)
                                                                          THEN
                                                                             ErrorArray ('the first component of this qualident must be a definition module or a parameter/variable/constant which has record type')
                                                                          END %
		            Ident                                       % IF isDef (qualid)
                                                                          THEN
                                                                             qualid := replace (lookupInScope (qualid, curident))
                                                                          ELSE
                                                                             type := skipType (getType (qualid)) ;
                                                                             field := lookupInScope (type, curident) ;
									     IF field = NIL
                                                                             THEN
                                                                                metaError2 ('field {%1k} cannot be found in {%2ad}', curident, qualid)
                                                                             ELSE
                                                                                qualid := replace (makeComponentRef (qualid, field))
                                                                             END
                                                                          END ;
                                                                          IF qualid = NIL
                                                                          THEN
                                                                             metaError1 ('qualified component of the identifier {%1k} cannot be found', curident)
                                                                          END %
			          ]
              =:

OptSubrange := [ SubrangeType ]  =:

TypeEquiv := Qualident OptSubrange =:

EnumIdentList := Ident { "," Ident } =:

Enumeration := "(" EnumIdentList ")" =:

SimpleType := TypeEquiv | Enumeration | SubrangeType =:

Type := SimpleType | ArrayType | RecordType | SetType |
        PointerType | ProcedureType
      =:

TypeDeclaration := { Ident ( ";" | "=" Type    Alignment ";" ) }
		    =:

Definition := "CONST" { ConstantDeclaration ";" } |
              "TYPE" { TypeDeclaration } |
              "VAR" { VariableDeclaration ";" } |
              DefProcedureHeading ";" =:

AsmStatement :=                                                      % VAR s: node ; %
                                                                     % s := pushStmt (makeComment ("asm")) %
                'ASM' [ 'VOLATILE' ] '(' AsmOperands ')' =:

AsmOperands := string [ AsmOperandSpec ]
             =:

AsmOperandSpec := [ ':' AsmList [ ':' AsmList [ ':' TrashList ] ] ]
                =:

AsmList := [ AsmElement ] { ',' AsmElement } =:

NamedOperand := '[' Ident ']' =:

AsmOperandName := [ NamedOperand ]
                =:

AsmElement := AsmOperandName string '(' Expression ')'
            =:

TrashList := [ string ] { ',' string } =:

FNB