Forráskód Böngészése

Pascal + TurboPascal3 validator pilots (grammars, builds, tests)

Eric Streit 3 napja
szülő
commit
259f259ba8

+ 30 - 0
grammars/Pascal/README.md

@@ -0,0 +1,30 @@
+# Standard Pascal validator pilot
+
+`pascal.atg` is the installed J&W standard-Pascal grammar with one fix:
+`IGNORE CASE` moved right after `COMPILER` (this Coco/R version rejects
+it anywhere later, and silently scans case-sensitively). The grammar is
+otherwise strict ISO 7185: no `ELSE` in `CASE` (fpc `-Miso` accepts it,
+but standard Pascal has none), no `$` hex, `END.` without module name.
+
+## Build
+
+```sh
+./build.sh        # -> build/PStd (build/ is git-ignored)
+```
+
+Needs `CR` (Coco/R), `gm2 -fiso`, the `parser.frm`/`scanner.frm`
+frames and `FileIO.def/.mod` — all resolved from the environment with
+sensible defaults (`CRFRAMES`, `M2LIB`, `CR`, `GM2`). Note: link via
+the two-step module list (`-fgen-module-list` then `-fuse-list`); a
+single-step link trips over pre-existing errors in this gm2 build's
+own ISO library `.def` files (`RndFile`/`TermFile`/`ChanConsts`
+set-constructor complaints).
+
+## Differential results (PStd vs `fpc -Miso`)
+
+Accept battery + `tests/deep.pas` (const/type/var, records, enums,
+sets, subranges, nested functions, labels/goto, all statements,
+hex-free literals): **0 false positives**. Broken mutants: **0
+missed**, positions close. `fpc` leniencies correctly not followed:
+missing/trailing `;`, unary `+`, which the strict grammar rejects
+(documented, fpc accepts).

+ 29 - 0
grammars/Pascal/build.sh

@@ -0,0 +1,29 @@
+#!/bin/bash
+# Build the FILEBASE syntax validator from FILEBASE.atg.
+# Needs: CR (Coco/R V1.53), gm2 -fiso, parser/scanner frames, FileIO.
+# Note: link via the two-step module list; a single-step link trips
+# over pre-existing errors in this gm2 build's own ISO library .defs.
+set -e
+CR="${CR:-/home/eric/Projets/Projets-Modula2/MyWork/CocoGm2/CR}"
+GM2="${GM2:-/home/eric/bin/Modula2/Gm2/bin/gm2}"
+FRAMES="${CRFRAMES:-/home/eric/Projets/Projets-Modula2/MyWork/Theia/GNU-grammar/build}"
+M2LIB="${M2LIB:-/home/eric/Projets/Projets-Modula2/MyWork/Theia/GNU-grammar/build}"
+HERE="$(dirname "$0")"
+B="$HERE/build"
+rm -rf "$B"
+mkdir -p "$B"
+cp "$HERE"/*.atg "$B/"
+cp "$M2LIB/FileIO.def" "$M2LIB/FileIO.mod" "$B/"
+cd "$B"
+echo "=== CR ==="; CRFRAMES="$FRAMES" "$CR" -m -C *.atg
+echo "=== compile ==="
+for m in FileIO PascalS PascalP; do "$GM2" -fiso -I . -c "$m.mod"; done
+echo "=== link ==="
+# NOTE: the gen step exits 1 on pre-existing errors in gm2's own
+# ISO library .defs, but still writes a usable modules.lst.
+"$GM2" -fiso -I . -fgen-module-list=modules.lst -o /dev/null FileIO.o PascalS.o PascalP.o Pascal.mod || true
+"$GM2" -fiso -I . -fuse-list=modules.lst -o PStd FileIO.o PascalS.o PascalP.o Pascal.mod
+echo "=== smoke ==="
+printf 'PROGRAM Hello;\nBEGIN\n  WriteLn('"'"'hi'"'"');\nEND.\n' > Hello.pas
+./PStd Hello.pas
+rm -f Hello.pas Hello.LST

+ 233 - 0
grammars/Pascal/pascal.atg

@@ -0,0 +1,233 @@
+COMPILER Pascal
+IGNORE CASE
+(* J & W Pascal - not Turbo Pascal *)
+(* This grammar is not LL(1) *)
+
+CHARACTERS
+  eol      = CHR(13) .
+  letter   = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" .
+  digit    = "0123456789".
+  noQuote1 = ANY - "'" - eol .
+
+IGNORE CHR(9) .. CHR(13)
+
+COMMENTS FROM "(*" TO "*)"
+COMMENTS FROM "{" TO "}"
+
+TOKENS
+  identifier  =  letter { letter | digit } .
+  integer     =  digit { digit } | digit { digit }  CONTEXT ("..") .
+  real        =  digit { digit } "." digit { digit }
+                 [ "E" ["+" | "-"] digit { digit } ]
+                 |  digit { digit } "E" ["+" | "-"] digit { digit }  .
+  string      = "'" { noQuote1 | "''" } "'" .
+
+PRODUCTIONS
+
+  Pascal            = "program"  NewIdent [ ExternalFiles ] ";"
+                      Block "." .
+
+  ExternalFiles     = "(" NewIdentList ")" .
+
+  Block             =  DeclarationPart StatementPart .
+
+  DeclarationPart   = LabelDeclarations ConstDefinitions
+                      TypeDefinitions VarDeclarations
+                      { ProcDeclarations } .
+
+(* -------------------------------------------------------------------- *)
+
+  LabelDeclarations = [ "label" Labels ";" ] .
+
+  Labels            = Label { "," Label } .
+
+  Label             = UnsignedInt .
+
+(* -------------------------------------------------------------------- *)
+
+  ConstDefinitions  = [ "const" ConstDef { ConstDef } ] .
+
+  ConstDef          = NewIdent "=" Constant ";" .
+
+  Constant          = [ "+" | "-" ] ( UnsignedNumber | ConstIdent ) | String .
+
+  UnsignedNumber    = UnsignedInt | UnsignedReal .
+
+  ConstIdent        = identifier .
+
+(* -------------------------------------------------------------------- *)
+
+  TypeDefinitions   = [ "type" TypeDef { TypeDef } ] .
+
+  TypeDef           = NewIdent "=" Type ";" .
+
+  Type              = SimpleType | [ "packed" ] StructType | "^" TypeIdent .
+
+  SimpleType        = TypeIdent | EnumerationType | SubrangeType .
+
+  TypeIdent         = identifier .
+
+  EnumerationType   = "(" NewIdentList ")" .
+
+  SubrangeType      = Constant ".." Constant .
+
+  StructType        = ArrayType | RecordType | SetType | FileType .
+
+  ArrayType         = "array" "[" IndexList "]" "of" Type .
+
+  IndexList         = SimpleType { "," SimpleType } .
+
+  RecordType        = "record" FieldList "end" .
+
+  SetType           = "set" "of" SimpleType .
+
+  FileType          = "file" "of" Type .
+
+  FieldList         = [ ( fixedPart [ ";" VariantPart ] | VariantPart ) [ ";" ] ] .
+
+  fixedPart         = RecordSection { ";" RecordSection } .
+
+  RecordSection     = NewIdentList ":" Type .
+
+  VariantPart       = "case" VariantSelector "of" Variant { ";" Variant } .
+
+  VariantSelector   = [ NewIdent ":" ] TypeIdent .
+
+  Variant           = CaseLabelList ":" "(" FieldList ")" .
+
+(* -------------------------------------------------------------------- *)
+
+  VarDeclarations   = [ "var" VarDecl { VarDecl } ] .
+
+  VarDecl           = NewIdentList ":" Type ";" .
+
+(* -------------------------------------------------------------------- *)
+
+  ProcDeclarations  = ( ProcHeading | FuncHeading ) ";" Body ";" .
+
+  ProcHeading       = "procedure" NewIdent [ FormalParams ] .
+
+  FuncHeading       = "function" NewIdent [ FormalParams ] ReturnType .
+
+  ReturnType        = [ (* empty if forward referenced *) ":" TypeIdent ] .
+
+  Body              = Block | "forward" .
+
+  FormalParams      = "(" FormalSection { ";" FormalSection } ")"  .
+
+  FormalSection     = [ "var" ] ParamGroup | ProcHeading | FuncHeading .
+
+  ParamGroup        = NewIdentList ":" ParamType .
+
+  ParamType         =   TypeIdent
+                      | "array" "[" IndexSpecList "]" "of" ParamType
+                      | "packed" "array" "[" IndexSpec "]" "of" TypeIdent .
+
+  IndexSpecList     = IndexSpec { ";" IndexSpec } .
+
+  IndexSpec         = NewIdent ".." NewIdent ":" TypeIdent .
+
+(* -------------------------------------------------------------------- *)
+
+  StatementPart     = CompoundStatement .
+
+  CompoundStatement = "begin" StatementSequence "end" .
+
+  StatementSequence = Statement { ";" Statement } .
+
+  Statement         = [ Label ":" ]
+                      [   AssignmentOrCall
+                        | CompoundStatement
+                        | GotoStatement
+                        | WhileStatement
+                        | RepeatStatement
+                        | IfStatement
+                        | CaseStatement
+                        | ForStatement
+                        | WithStatement ] .
+
+  AssignmentOrCall  = Designator ( ":=" Expression | [ ActualParams ] ) .
+
+  ActualParams      = "(" ActualParameter { "," ActualParameter } ")" .
+
+  ActualParameter   = Expression [ FieldWidth (* only in i/o *) ] .
+
+  FieldWidth        = ":" IntegerExpression [ ":" IntegerExpression ] .
+
+  GotoStatement     = "goto" Label .
+
+  WhileStatement    = "while" BooleanExpression "do" Statement .
+
+  RepeatStatement   = "repeat" StatementSequence "until" BooleanExpression .
+
+  IfStatement       = "if" BooleanExpression "then" Statement
+                      [ "else" Statement ] .
+
+  CaseStatement     = "case" OrdinalExpression "of" CaseList "end" .
+
+  CaseList          = OneCase { ";" OneCase } [ ";" ] .
+
+  OneCase           = CaseLabelList ":" Statement .
+
+  CaseLabelList     = CaseLabel { "," CaseLabel } .
+
+  CaseLabel         = Constant .
+
+  ForStatement      = "for" ControlVariable ":=" OrdinalExpression
+                      ( "to" | "downto" ) OrdinalExpression "do" Statement .
+
+  ControlVariable   = identifier .
+
+  WithStatement     = "with" RecVarList "do" Statement .
+
+  RecVarList        = Designator { "," Designator } .
+
+(* -------------------------------------------------------------------- *)
+
+  IntegerExpression = Expression .
+
+  BooleanExpression = Expression .
+
+  OrdinalExpression = Expression .
+
+  Expression        = SimpleExpression [ RelOp SimpleExpression ] .
+
+  RelOp             = "=" | "<" | ">" | "<=" | ">=" | "<>" | "in" .
+
+  SimpleExpression  = ( "+" Term | "-" Term | Term ) { AddOp Term } .
+
+  AddOp             = "+" | "-" | "or" .
+
+  Term              = Factor { MulOp Factor } .
+
+  MulOp             = "*" | "/" | "div" | "mod" | "and" .
+
+  Factor            =   Designator [ ActualParams ]
+                      | UnsignedLiteral
+                      | SetConstructor
+                      | "(" Expression ")"
+                      | "not" Factor .
+
+  Designator        = identifier { "." identifier | "[" ExpList "]" | "^" } .
+
+  ExpList           = Expression { "," Expression } .
+
+  UnsignedLiteral   = UnsignedNumber | "nil" | String .
+
+  SetConstructor    = "[" Member { "," Member } "]" .
+
+  Member            = Expression [ ".." Expression ] .
+
+(* -------------------------------------------------------------------- *)
+
+  NewIdentList      = NewIdent { "," NewIdent } .
+
+  NewIdent          = identifier .
+
+  UnsignedInt       = integer .
+
+  UnsignedReal      = real .
+
+  String            = string .
+
+END Pascal.

+ 43 - 0
grammars/Pascal/tests/deep.pas

@@ -0,0 +1,43 @@
+PROGRAM Deep;
+LABEL 10;
+CONST N = 10;
+TYPE
+  IntArr = ARRAY [1..10] OF INTEGER;
+  Point = RECORD x, y: INTEGER END;
+  Color = (red, green, blue);
+VAR
+  i, j: INTEGER;
+  ch: CHAR;
+  b: BOOLEAN;
+  r: REAL;
+  a: IntArr;
+  pt: Point;
+  col: Color;
+  s: SET OF CHAR;
+FUNCTION Sum(a, b: INTEGER): INTEGER;
+BEGIN
+  Sum := a + b
+END;
+FUNCTION Odd(n: INTEGER): BOOLEAN;
+BEGIN
+  Odd := ODD(n)
+END;
+{ program comment }
+BEGIN
+  FOR i := 1 TO N DO a[i] := i;
+  WHILE i < N DO i := i + 1;
+  REPEAT
+    CASE i OF
+      1: Write(1);
+      2, 3: Write(2)
+    END;
+  UNTIL i > N;
+  col := red;
+  s := ['a', 'b'];
+  b := 'x' IN s;
+  10: pt.x := Sum(1, 2);
+  IF Odd(i) THEN GOTO 10;
+  r := 1.5E-3;
+  b := (i = 1) AND (j <> 2) OR NOT b;
+  WriteLn('done')
+END.

+ 33 - 0
grammars/TurboPascal3/README.md

@@ -0,0 +1,33 @@
+# Turbo Pascal 3 validator pilot
+
+`turbo_pascal3.atg` is byte-identical to the standard-Pascal grammar
+apart from its tag line, so it starts from the same base plus three
+Turbo extensions (all diagnosed against `fpc -Mtp` as oracle):
+
+1. `IGNORE CASE` moved right after `COMPILER` (same toolchain
+   requirement as the standard grammar).
+2. `$` hexadecimal literals (`$FF`): new `hexDigit` set plus a
+   `"$" hexDigit { hexDigit }` integer alternative.
+3. `ELSE` in `CASE`: `CaseList` gains `[ "ELSE" Statement ]`
+   (standard Pascal has none; Turbo and `fpc -Mtp` accept it).
+
+Two benign LL(1) warnings remain (dangling-`ELSE` family).
+
+## Build
+
+```sh
+./build.sh        # -> build/TP3 (build/ is git-ignored)
+```
+
+Needs `CR` (Coco/R), `gm2 -fiso`, the `parser.frm`/`scanner.frm`
+frames and `FileIO.def/.mod` — all resolved from the environment with
+sensible defaults (`CRFRAMES`, `M2LIB`, `CR`, `GM2`). Note: link via
+the two-step module list (`-fgen-module-list` then `-fuse-list`); a
+single-step link trips over pre-existing errors in this gm2 build's
+own ISO library `.def` files.
+
+## Differential results (TP3 vs `fpc -Mtp`)
+
+Accept battery + `tests/deep.pas` (adds `STRING`, `+` concat, `$`
+hex, `CASE..ELSE` over the standard set): **0 false positives**.
+Broken mutants: **0 missed**, positions close.

+ 29 - 0
grammars/TurboPascal3/build.sh

@@ -0,0 +1,29 @@
+#!/bin/bash
+# Build the FILEBASE syntax validator from FILEBASE.atg.
+# Needs: CR (Coco/R V1.53), gm2 -fiso, parser/scanner frames, FileIO.
+# Note: link via the two-step module list; a single-step link trips
+# over pre-existing errors in this gm2 build's own ISO library .defs.
+set -e
+CR="${CR:-/home/eric/Projets/Projets-Modula2/MyWork/CocoGm2/CR}"
+GM2="${GM2:-/home/eric/bin/Modula2/Gm2/bin/gm2}"
+FRAMES="${CRFRAMES:-/home/eric/Projets/Projets-Modula2/MyWork/Theia/GNU-grammar/build}"
+M2LIB="${M2LIB:-/home/eric/Projets/Projets-Modula2/MyWork/Theia/GNU-grammar/build}"
+HERE="$(dirname "$0")"
+B="$HERE/build"
+rm -rf "$B"
+mkdir -p "$B"
+cp "$HERE"/*.atg "$B/"
+cp "$M2LIB/FileIO.def" "$M2LIB/FileIO.mod" "$B/"
+cd "$B"
+echo "=== CR ==="; CRFRAMES="$FRAMES" "$CR" -m -C *.atg
+echo "=== compile ==="
+for m in FileIO PascalS PascalP; do "$GM2" -fiso -I . -c "$m.mod"; done
+echo "=== link ==="
+# NOTE: the gen step exits 1 on pre-existing errors in gm2's own
+# ISO library .defs, but still writes a usable modules.lst.
+"$GM2" -fiso -I . -fgen-module-list=modules.lst -o /dev/null FileIO.o PascalS.o PascalP.o Pascal.mod || true
+"$GM2" -fiso -I . -fuse-list=modules.lst -o TP3 FileIO.o PascalS.o PascalP.o Pascal.mod
+echo "=== smoke ==="
+printf 'PROGRAM Hello;\nBEGIN\n  WriteLn('"'"'hi'"'"');\nEND.\n' > Hello.pas
+./TP3 Hello.pas
+rm -f Hello.pas Hello.LST

+ 34 - 0
grammars/TurboPascal3/tests/deep.pas

@@ -0,0 +1,34 @@
+PROGRAM DeepTP;
+LABEL 10;
+CONST N = 10;
+TYPE
+  IntArr = ARRAY [1..10] OF INTEGER;
+  Str = STRING;
+VAR
+  i, j: INTEGER;
+  ch: CHAR;
+  b: BOOLEAN;
+  r: REAL;
+  a: IntArr;
+  s: STRING;
+FUNCTION Sum(a, b: INTEGER): INTEGER;
+BEGIN
+  Sum := a + b
+END;
+BEGIN
+  i := $FF;
+  s := 'hello' + '!';
+  FOR i := 1 TO N DO a[i] := i;
+  WHILE i < N DO i := i + 1;
+  REPEAT
+    CASE ch OF
+      'a': Write(1)
+    ELSE
+      Write(2)
+    END;
+  UNTIL i > N;
+  10: j := Sum(1, 2);
+  IF j > 0 THEN GOTO 10;
+  r := 1.5E-3;
+  WriteLn('done')
+END.

+ 236 - 0
grammars/TurboPascal3/turbo_pascal3.atg

@@ -0,0 +1,236 @@
+(* Tags: TURBO3, TURBOPASCAL, TP3, BORLAND *)
+COMPILER Pascal
+IGNORE CASE
+(* J & W Pascal - not Turbo Pascal *)
+(* This grammar is not LL(1) *)
+
+CHARACTERS
+  eol      = CHR(13) .
+  letter   = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" .
+  digit    = "0123456789".
+  hexDigit = digit + "ABCDEF" .
+  noQuote1 = ANY - "'" - eol .
+
+IGNORE CHR(9) .. CHR(13)
+
+COMMENTS FROM "(*" TO "*)"
+COMMENTS FROM "{" TO "}"
+
+TOKENS
+  identifier  =  letter { letter | digit } .
+  integer     =  digit { digit } | digit { digit }  CONTEXT ("..")
+              | "$" hexDigit { hexDigit } .
+  real        =  digit { digit } "." digit { digit }
+                 [ "E" ["+" | "-"] digit { digit } ]
+                 |  digit { digit } "E" ["+" | "-"] digit { digit }  .
+  string      = "'" { noQuote1 | "''" } "'" .
+
+PRODUCTIONS
+
+  Pascal            = "program"  NewIdent [ ExternalFiles ] ";"
+                      Block "." .
+
+  ExternalFiles     = "(" NewIdentList ")" .
+
+  Block             =  DeclarationPart StatementPart .
+
+  DeclarationPart   = LabelDeclarations ConstDefinitions
+                      TypeDefinitions VarDeclarations
+                      { ProcDeclarations } .
+
+(* -------------------------------------------------------------------- *)
+
+  LabelDeclarations = [ "label" Labels ";" ] .
+
+  Labels            = Label { "," Label } .
+
+  Label             = UnsignedInt .
+
+(* -------------------------------------------------------------------- *)
+
+  ConstDefinitions  = [ "const" ConstDef { ConstDef } ] .
+
+  ConstDef          = NewIdent "=" Constant ";" .
+
+  Constant          = [ "+" | "-" ] ( UnsignedNumber | ConstIdent ) | String .
+
+  UnsignedNumber    = UnsignedInt | UnsignedReal .
+
+  ConstIdent        = identifier .
+
+(* -------------------------------------------------------------------- *)
+
+  TypeDefinitions   = [ "type" TypeDef { TypeDef } ] .
+
+  TypeDef           = NewIdent "=" Type ";" .
+
+  Type              = SimpleType | [ "packed" ] StructType | "^" TypeIdent .
+
+  SimpleType        = TypeIdent | EnumerationType | SubrangeType .
+
+  TypeIdent         = identifier .
+
+  EnumerationType   = "(" NewIdentList ")" .
+
+  SubrangeType      = Constant ".." Constant .
+
+  StructType        = ArrayType | RecordType | SetType | FileType .
+
+  ArrayType         = "array" "[" IndexList "]" "of" Type .
+
+  IndexList         = SimpleType { "," SimpleType } .
+
+  RecordType        = "record" FieldList "end" .
+
+  SetType           = "set" "of" SimpleType .
+
+  FileType          = "file" "of" Type .
+
+  FieldList         = [ ( fixedPart [ ";" VariantPart ] | VariantPart ) [ ";" ] ] .
+
+  fixedPart         = RecordSection { ";" RecordSection } .
+
+  RecordSection     = NewIdentList ":" Type .
+
+  VariantPart       = "case" VariantSelector "of" Variant { ";" Variant } .
+
+  VariantSelector   = [ NewIdent ":" ] TypeIdent .
+
+  Variant           = CaseLabelList ":" "(" FieldList ")" .
+
+(* -------------------------------------------------------------------- *)
+
+  VarDeclarations   = [ "var" VarDecl { VarDecl } ] .
+
+  VarDecl           = NewIdentList ":" Type ";" .
+
+(* -------------------------------------------------------------------- *)
+
+  ProcDeclarations  = ( ProcHeading | FuncHeading ) ";" Body ";" .
+
+  ProcHeading       = "procedure" NewIdent [ FormalParams ] .
+
+  FuncHeading       = "function" NewIdent [ FormalParams ] ReturnType .
+
+  ReturnType        = [ (* empty if forward referenced *) ":" TypeIdent ] .
+
+  Body              = Block | "forward" .
+
+  FormalParams      = "(" FormalSection { ";" FormalSection } ")"  .
+
+  FormalSection     = [ "var" ] ParamGroup | ProcHeading | FuncHeading .
+
+  ParamGroup        = NewIdentList ":" ParamType .
+
+  ParamType         =   TypeIdent
+                      | "array" "[" IndexSpecList "]" "of" ParamType
+                      | "packed" "array" "[" IndexSpec "]" "of" TypeIdent .
+
+  IndexSpecList     = IndexSpec { ";" IndexSpec } .
+
+  IndexSpec         = NewIdent ".." NewIdent ":" TypeIdent .
+
+(* -------------------------------------------------------------------- *)
+
+  StatementPart     = CompoundStatement .
+
+  CompoundStatement = "begin" StatementSequence "end" .
+
+  StatementSequence = Statement { ";" Statement } .
+
+  Statement         = [ Label ":" ]
+                      [   AssignmentOrCall
+                        | CompoundStatement
+                        | GotoStatement
+                        | WhileStatement
+                        | RepeatStatement
+                        | IfStatement
+                        | CaseStatement
+                        | ForStatement
+                        | WithStatement ] .
+
+  AssignmentOrCall  = Designator ( ":=" Expression | [ ActualParams ] ) .
+
+  ActualParams      = "(" ActualParameter { "," ActualParameter } ")" .
+
+  ActualParameter   = Expression [ FieldWidth (* only in i/o *) ] .
+
+  FieldWidth        = ":" IntegerExpression [ ":" IntegerExpression ] .
+
+  GotoStatement     = "goto" Label .
+
+  WhileStatement    = "while" BooleanExpression "do" Statement .
+
+  RepeatStatement   = "repeat" StatementSequence "until" BooleanExpression .
+
+  IfStatement       = "if" BooleanExpression "then" Statement
+                      [ "else" Statement ] .
+
+  CaseStatement     = "case" OrdinalExpression "of" CaseList "end" .
+
+  CaseList          = OneCase { ";" OneCase } [ ";" ] [ "ELSE" Statement ] .
+
+  OneCase           = CaseLabelList ":" Statement .
+
+  CaseLabelList     = CaseLabel { "," CaseLabel } .
+
+  CaseLabel         = Constant .
+
+  ForStatement      = "for" ControlVariable ":=" OrdinalExpression
+                      ( "to" | "downto" ) OrdinalExpression "do" Statement .
+
+  ControlVariable   = identifier .
+
+  WithStatement     = "with" RecVarList "do" Statement .
+
+  RecVarList        = Designator { "," Designator } .
+
+(* -------------------------------------------------------------------- *)
+
+  IntegerExpression = Expression .
+
+  BooleanExpression = Expression .
+
+  OrdinalExpression = Expression .
+
+  Expression        = SimpleExpression [ RelOp SimpleExpression ] .
+
+  RelOp             = "=" | "<" | ">" | "<=" | ">=" | "<>" | "in" .
+
+  SimpleExpression  = ( "+" Term | "-" Term | Term ) { AddOp Term } .
+
+  AddOp             = "+" | "-" | "or" .
+
+  Term              = Factor { MulOp Factor } .
+
+  MulOp             = "*" | "/" | "div" | "mod" | "and" .
+
+  Factor            =   Designator [ ActualParams ]
+                      | UnsignedLiteral
+                      | SetConstructor
+                      | "(" Expression ")"
+                      | "not" Factor .
+
+  Designator        = identifier { "." identifier | "[" ExpList "]" | "^" } .
+
+  ExpList           = Expression { "," Expression } .
+
+  UnsignedLiteral   = UnsignedNumber | "nil" | String .
+
+  SetConstructor    = "[" Member { "," Member } "]" .
+
+  Member            = Expression [ ".." Expression ] .
+
+(* -------------------------------------------------------------------- *)
+
+  NewIdentList      = NewIdent { "," NewIdent } .
+
+  NewIdent          = identifier .
+
+  UnsignedInt       = integer .
+
+  UnsignedReal      = real .
+
+  String            = string .
+
+END Pascal.