Two adjacent grammars live in compiler/src:
| file | scope |
|---|---|
M2.atg |
the modern m2compiler-V3 subset (locked step-1 rules) |
TopSpeed-V3-M2.atg |
the complete historical TopSpeed/Dos Modula-2 V3 dialect, reconstructed from the real JPI/Clarion V3 corpus |
This page documents TopSpeed-V3-M2.atg (the deliverable of the "complete V3
grammar" work item). The bare EBNF below is its PRODUCTIONS section with the
semantic actions ((. .)) and attributes (<...>) stripped; terminals in
quotes are literals, lowercase names are tokens (ident, integer, real, string).
.mod/.def files of the original TS-V3
distribution (/home/eric/bin/Dos/M2/TS-V3: EXAMPLES, MODBASE, REP16, SRC,
INCLUDE, GRAPHIX, SAVE). 0 syntax errors; the only rows left are
semantic not a type messages (parse-clean), e.g. GWINC2M/GRAPH/WINDOW/DEF.CR) reports 25 benign LL(1) advisories ("X is the start &
successor of a deletable structure", plus a few "start of several
alternatives"); attribute and undefined-nonterminal checks are clean._ and @ (Graph._VGA, ct__@Fssssi)& = AND, ~ = NOT, <> = # (all accepted)H (hex), C (char), B (octal), plus 0x/0X hex forms::= constant alias form (GCoord::=INTEGER){}, shifts >>, parameterless
procedure-call statementsCLASS ... IMPLEMENTATION and two-parent CLAUSEThe scanner treats (*%F flag*) ... (*%E*) regions as disabled in the
default (flags-off) build: the region body (declarations, whole procedures,
even a full VAR ... BEGIN ... END alternate module body) is skipped as a
comment, nesting level-matched (nested (*%T/E*) markers balance). (*%T
flag*) markers are whitespace: the region content is real code and is
compiled (thread/_fdata-variant shipping, e.g. LIB.MOD's IsOfClass
Far/Near WHILE pairs where only the %F twin is dropped). Standalone
(*%E*) is an ordinary empty comment.
This behaviour is a manual patch to the generated M2S.mod Comment()
routine and must be re-applied after every CR regeneration (see the note
below). It is required to parse the shipped corpus: DEMO/OMAIN/COMPDEMO doc
banners, WINDOW.MOD's OS/2 alternate body, LIB.MOD's variant blocks.
CR -m TopSpeed-V3-M2.atg produces M2S/M2P/M2(.mod/.def).CR garbles M2S.def; restore it from compiler/src/M2S.def (the
pristine copy in this repo).%F-skip fence patch to M2S.mod (the Comment() routine;
keep (*/% out of patch comments - gm2 nested comment parsing).Neither :the: M2S.def nor M2S.mod carry v3-specific tokens; the token
tables are regenerated from the .atg. M2
= Unit "." .
Unit
= DefUnit | ImplUnit | ProgModule .
DefUnit
= "DEFINITION" "MODULE" GetIdent ";" { Import }
{ ConstBlock | TypeBlock | VarBlock | ProcHeading ";" }
"END" GetIdent .
ImplUnit
= "IMPLEMENTATION" "MODULE" GetIdent ";" { Import }
DeclSeq [ "BEGIN" [ StatSeq ] ] "END" GetIdent .
ProgModule
= "MODULE" GetIdent [ Priority ] ";" { Import }
DeclSeq [ "BEGIN" [ StatSeq ] ] "END" GetIdent .
DeclSeq
= { ConstBlock | TypeBlock | VarBlock | [ "INLINE" ] ProcDecl ";"
| NestedModule ";" | ClassItem ";"
| "LABEL" LabelList ";" } .
LabelList
= GetIdent { "," GetIdent } .
NestedModule
= "MODULE" GetIdent [ Priority ] ";" { Import } [ Export ]
DeclSeq [ "BEGIN" [ StatSeq ] ] "END" GetIdent .
Priority
= "[" integer "]" .
Export
= "EXPORT" [ "QUALIFIED" ] GetIdent { "," GetIdent } ";" .
Import
= "FROM" GetIdent "IMPORT" ImpList ";"
| "IMPORT" ImpList ";" .
ImpList
= GetIdent { "," GetIdent } .
TypeBlock
= "TYPE" { TypeItem ";" | ClassItem ";" } .
TypeItem
= GetIdent ( "=" Type | ) .
Type
= TypeIdent
| [ IntegerTypeSubrange ] "[" Expr ".." Expr "]" [ "OF" Type ]
| "(" EnumList ")" (* enumeration *)
| "ARRAY" [ "[" Bound { "," Bound } "]" ] "OF" Type
| "RECORD" FieldListSequence "END"
| "SET" "OF" Type
| "POINTER" "TO" Type
| "PROCEDURE" [ "(" [ ProcTypeParam { "," ProcTypeParam } ] ")" ] .
ProcTypeParam
= [ "VAR" ] Type .
Bound
= integer | GetIdent | subrange | enum .
FieldListSequence
= { FieldList } .
FieldList
= [ IdentList ":" Type ] | "CASE" Ident [ ":" Type ] "OF"
VariantList "END" | ";" .
VariantList
= [ "|" ] Variant { "|" Variant } [ "ELSE" FieldListSequence ] .
Variant
= VariantLabels ":" FieldListSequence .
ClassItem
= "CLASS" ( "IMPLEMENTATION" ClassImplRest | ClassRest ) .
ClassRest
= GetIdent [ Parents ] ";" { ClassField ";" }
{ MethodHeading ";" ( "FORWARD" ";"
| "BEGIN" [ StatSeq ] "END" GetIdent ";"
| ) } [ "BEGIN" [ StatSeq ] ] "END" GetIdent .
Parents
= "(" GetIdent [ "CLAUSE" GetIdent ] { "," GetIdent } ")" .
ClassField
= GetIdent ( "=" GetIdent
| { "," GetIdent } ":" Type ) .
MethodHeading
= [ "VIRTUAL" ] ProcHeading .
ClassImplRest
= GetIdent ";" { MethodImpl ";" } [ "BEGIN" [ StatSeq ] ]
"END" GetIdent .
ConstBlock
= "CONST" { ConstDecl ";" } .
ConstDecl
= GetIdent ( "=" Expr | "::=" Expr ) .
VarBlock
= "VAR" { VarDecl ";" | "[" Expr ":" Expr "]" : ";" } .
VarDecl
= VarIdents ":" Type .
VarIdents
= GetIdent [ "[" Bound ":" Bound "]" ] { "," GetIdent
[ "[" Bound ":" Bound "]" ] } . (* incl. mapped-array nil slots *)
ParIdents
= GetIdent { "," GetIdent } .
ProcHeading
= "PROCEDURE" GetIdent [ FormalParams ] [ ":" Type ]
[ "IN" GetIdent ] .
FormalParams
= "(" [ ParIdents ":" Type { ";" ParIdents ":" Type } ] ")" .
ProcDecl
= "INLINE" ProcHeading ";"
| ProcHeading ";"
( "FORWARD"
| Block )
| "PROCEDURE" GetIdent [ FormalParams ] ";" "IN" GetIdent .
Block
= DeclSeq [ "BEGIN" [ StatSeq ] ] "END" GetIdent .
StatSeq
= Statement { ";" [ Statement ] } .
Statement
= DesignStat
| "IF" Expr "THEN" [ StatSeq ]
{ "ELSIF" Expr "THEN" [ StatSeq ] }
[ "ELSE" [ StatSeq ] ] "END"
| "WHILE" Expr "DO" [ StatSeq ] "END"
| "REPEAT" [ StatSeq ] "UNTIL" Expr
| "LOOP" [ StatSeq ] "END"
| "FOR" GetIdent ":=" Expr "TO" Expr [ "BY" Expr ]
"DO" [ StatSeq ] "END"
| "CASE" Expr "OF" [ "|" ] CaseAlt { "|" CaseAlt }
[ "ELSE" [ StatSeq ] ] "END"
| "WITH" Designator [ "," Designator ] "DO" [ StatSeq ] "END"
| "RETURN" [ Expr ]
| "GOTO" GetIdent
| "EXIT" .
DesignStat
= Designator
( ":=" Expr
| "(" [ ActualParams ] ")"
| ) .
CaseAlt
= CaseLabel { "," CaseLabel } ":" [ StatSeq ] .
CaseLabel
= Expr [ ".." Expr ] .
ActualParams
= Expr { "," Expr } .
Expr
= SimExpr [ Rel SimExpr ] .
Rel
= "=" | "#" | "<>" | "<" | "<=" | ">" | ">=" | "IN" | "IS" .
SimExpr
= [ "+" | "-" ] Term { ( "+" | "-" | "OR" ) [ Term ] } .
Term
= Fact { ( "*" | "/" | "DIV" | "MOD" | "AND" | "&" | "<<" | ">>" )
Fact } .
Fact
= integer | real | string
| "{" [ SetItems ] "}"
| "[" Expr ":" Expr [ TypeIdent2 ] "]" MapTail (* mapped array *)
| Design2
| "(" Expr ")"
| "NOT" Fact | "~" Fact .
MapTail
= { "." GetIdent | "^" | "[" Expr "]" | "(" [ ActualParams ] ")" } .
Design2
= Designator { "." GetIdent | "^" | "[" ExprList "]" |
"(" [ ActualParams ] ")" } .
Designator
= TypeIdent | GetIdent .
TypeIdent2
= GetIdent { "." GetIdent } .
SetItems
= SetItem { "," SetItem } .
SetItem
= Expr [ ".." Expr ] .
GetIdent
= ident .
Semantic markers: constructs the backend cannot lower yet parse fully and end
with SemError(230) (not supported yet), following the parse-now/
lower-later discipline of M2.atg. Semantic codes reused from the V1/V2/Test2
family: 200 duplicate, 201 undeclared, 202 module-name mismatch, 210 bad
assignment, 211 bad arithmetic, 212 boolean operand, 213 incompatible
comparison, 214 boolean-cond required, 220 FOR bounds, 221 not a type name,
222 set mismatch, 230 not supported yet, 231 opaque outside definition,
232 bad RETURN.