-
Notifications
You must be signed in to change notification settings - Fork 3
AST Specification
M2Sharp encodes valid Modula-2 input in memory as an abstract syntax tree (AST).
The AST used by M2Sharp uses three kinds of nodes.
- an
EMPTYsentinel node - non-terminal nodes
- terminal nodes
The sentinel node EMPTY is used to encode the absence of an optional sub-node in non-terminal nodes.
Non-terminal nodes are used to encode non-terminal symbols such as modules, imports, definitions, declarations, statements and expressions.
AST, DEFMOD, IMPLIST, IMPORT, UNQIMP, DEFLIST, CONSTDEF, TYPEDEF, PROCDEF, SUBR, ENUM, SET, ARRAY, RECORD, POINTER, PROCTYPE, EXTREC, VRNTREC, INDEXLIST, FIELDLISTSEQ, FIELDLIST, VFLISTSEQ, VFLIST, VARIANTLIST, VARIANT, CLABELLIST, CLABELS, FTYPELIST, OPENARRAY, CONSTP, VARP, FPARAMLIST, FPARAMS, IMPMOD, BLOCK, DECLLIST, TYPEDECL, VARDECL, PROC, MODDECL, VSREC, VSFIELD, EXPORT, QUALEXP, STMTSEQ, ASSIGN, PCALL, RETURN, WITH, IF, SWITCH, LOOP, WHILE, REPEAT, FORTO, EXIT, ARGS, ELSIFSEQ, ELSIF, CASELIST, CASE, FIELD, INDEX, DESIG, DEREF, NEG, NOT, EQ, NEQ, LT, LTEQ, GT, GTEQ, IN, PLUS, MINUS, OR, ASTERISK, SOLIDUS, DIV, MOD, AND, FCALL, SETVAL.
Terminal nodes are used to encode terminal symbols such as filenames, options, identifiers, integer literals, real number literals, character code and quoted literals.
IDENT, QUALIDENT, IDENTLIST, INTVAL, REALVAL, CHRVAL, QUOTEDVAL, FILENAME, OPTIONS.
Any AST node may be represented in a serialised format of the form
( nodetype subnode-0 subnode-1 subnode-2 ... subnode-N )
where the actual number of sub-nodes is dependent on the node type.
This form of tree representation is called an S-expression.
The structure of the AST used by M2Sharp is described below in S-expression format.
The EMPTY node encodes the absence of an optional sub-node.
emptyNode :=
'(' EMPTY ')'
;
The AST node encodes the root of the syntax tree.
astRecord :=
'(' AST filename options compilationUnit ')'
;
filename := filenameNode ; /* terminal node */
options := optionsNode ; /* terminal node */
compilationUnit :=
defModuleNode | impModuleNode
;
The DEFMOD node encodes a definition module.
defModuleNode :=
'(' DEFMOD moduleIdent importList definitionList ')'
;
moduleIdent := identNode ; /* terminal node */
importList :=
importListNode | emptyNode
;
definitionList :=
definitionListNode | emptyNode
;
The IMPLIST node encodes the entirety of import directives in a module.
importListNode :=
'(' IMPLIST import+ ')'
;
import :=
qImportNode | unqImportNode
;
The IMPORT node encodes a qualified import directive.
qImportNode :=
'(' IMPORT identList ')'
;
identList := identListNode ; /* terminal node */
The UNQIMP node encodes an unqualified import directive.
unqImportNode :=
'(' UNQIMP moduleIdent identList ')'
;
The DEFLIST node encodes one or more definitions.
definitionListNode :=
'(' DEFLIST definition+ ')'
;
definition :=
constDefNode | typeDefNode | varDeclNode | ProcDefNode
;
The CONSTDEF node encodes a constant definition.
constDefNode :=
'(' CONSTDEF identNode exprNode ')'
;
The TYPEDEF node encodes a type definition.
typeDefNode :=
'(' TYPEDEF identNode ( typeNode | emptyNode ) ')'
;
typeNode :=
identNode | qualidentNode |
subrTypeNode | enumTypeNode | setTypeNode | arrayTypeNode | recTypeNode |
extRecTypeNode | vrntRecTypeNode | pointerTypeNode | procTypeNode
;
The PROCDEF node encodes a procedure definition.
procDefNode :=
'(' PROCDEF identNode formalParamList returnType ')'
;
formalParamList :=
formalParamListNode | emptyNode
;
The SUBR node encodes a subrange type definition.
subrTypeNode :=
'(' SUBR lowerBound upperBound subrBaseType ')'
;
lowerBound := exprNode ;
upperBound := exprNode ;
subrBaseType :=
identNode | qualidentNode | emptyNode
;
The ENUM node encodes an enumeration type definition.
enumTypeNode :=
'(' ENUM identListNode ')'
;
The SET node encodes a set type definition.
setTypeNode :=
'(' SET countableType ')'
;
countableType :=
identNode | qualidentNode | subrTypeNode | enumTypeNode
;
The ARRAY node encodes an array type definition.
arrayTypeNode :=
'(' ARRAY indexTypeListNode arrayBaseType ')'
;
arrayBaseType := fieldType ;
The RECORD node encodes a non-variant non-extensible record type definition.
recTypeNode :=
'(' RECORD fieldListSeqNode ')'
;
The POINTER node encodes a pointer type definition.
pointerTypeNode :=
'(' POINTER typeNode ')'
;
The PROCTYPE node encodes a procedure type definition.
procTypeNode :=
'(' PROCTYPE formalTypeList returnedType ')'
;
formalTypeList :=
formalTypeListNode | emptyNode
;
returnedType :=
identNode | qualidentNode | emptyNode
;
The EXTREC node encodes an extensible record type definition.
extRecTypeNode :=
'(' EXTREC recBaseType fieldListSeqNode ')'
;
recBaseType :=
identNode | qualidentNode
;
The VRNTREC node encodes a variant record type definition.
variantRecTypeNode :=
'(' VRNTREC variantFieldListSeqNode ')'
;
The INDEXLIST node encodes one or more index types within an array type definition.
indexTypeListNode :=
'(' INDEXLIST indexType+ ')'
;
indexType := countableType ;
The FIELDLISTSEQ node encodes a non-variant field list sequence within a record type definition.
fieldListSeqNode :=
'(' FIELDLISTSEQ fieldListNode+ ')'
;
The FIELDLIST node encodes a non-variant field list within a field list sequence
fieldListNode :=
'(' FIELDLIST identListNode fieldType ')'
;
fieldType :=
identNode | qualidentNode | subrTypeNode | enumTypeNode | setTypeNode |
arrayTypeNode | recTypeNode | pointerTypeNode | procTypeNode
;
The VFLISTSEQ node encodes a variant field list sequence within a variant record type definition.
variantFieldListSeqNode :=
'(' VFLISTSEQ ( fieldListNode | variantFieldListNode )+ ')'
;
The VFLIST node encodes a variant field list within a variant field list sequence.
variantFieldListNode :=
'(' VFLIST caseIdent caseType variantList defaultFieldListSeq ')'
;
caseIdent :=
identNode | emptyNode
;
caseType :=
identNode | qualidentNode
;
defaultFieldListSeq :=
fieldListSeqNode | emptyNode
;
The VARIANTLIST node encodes a variant list within a variant field list.
variantList :=
'(' VARIANTLIST variantNode+ ')'
;
The VARIANT node encodes a variant within a variant list.
variantNode :=
'(' VARIANT caseLabelListNode fieldListSeqNode ')'
;
The CLABELLIST node encodes a case label list within a variant record definition or case statement.
caseLabelListNode :=
'(' CLABELLIST caseLabelsNode+ ')
;
The CLABELS node encodes start and end labels within a case label list.
caseLabelsNode :=
'(' CLABELS startLabel endLabel ')'
;
startLabel := exprNode ;
endLabel := exprNode | emptyNode ;
The FTYPELIST node encodes a formal type list within a procedure type definition.
formalTypeListNode :
'(' FTYPELIST formalType+ ')'
;
formalType :=
simpleFormalType | attrFormalType
;
simpleFormalType :=
typeIdent | openArrayTypeNode
;
attrFormalType :=
constAttrFormalTypeNode | varAttrFormalTypeNode
;
The OPENARRAY node encodes an open array parameter within a formal type list.
openArrayTypeNode :=
'(' OPENARRAY typeIdent ')'
;
typeIdent :=
identNode | qualidentNode
;
The CONSTP node encodes a CONST parameter within a formal type list.
constAttrFormalTypeNode :=
'(' CONSTP simpleFormalType ')'
;
The VARP node encodes a VAR parameter within a formal type list.
varAttrFormalTypeNode :=
'(' VARP simpleFormalType ')'
;
The FPARAMLIST node encodes a formal parameter list within a procedure type definition or procedure signature.
formalParamListNode :=
'(' FPARAMLIST formalParamsNode+ ')'
;
The PARAMS node encodes formal parameters within a formal parameter list.
formalParamsNode :=
'(' FPARAMS identListNode formalTypeNode ')'
;
(34) IMPMOD -- Program Or Implementation Module Node
impModuleNode := '(' IMPMOD moduleIdent priority importListNode blockNode ')' ;
priority := exprNode | emptyNode ;
(35) BLOCK -- Block Node
blockNode := '(' BLOCK declarationList body ')' ;
declarationList := declarationListNode | emptyNode ;
body := statementSeqNode | emptyNode ;
(36) DECLLIST -- Declaration List Node
declarationListNode := '(' DECLLIST declarationNode+ ')' ;
declarationNode := constDefNode | typeDeclNode | varDeclNode | procDeclNode | modDeclNode ;
(37) TYPEDECL -- Type Declaration Node
typeDeclNode := '(' TYPEDECL identNode ( typeNode | vsrTypeNode ) ')' ;
(38) VARDECL -- Variable Declaration Node
varDeclNode := '(' VARDECL identListNode fieldType ')' ;
(39) PROC -- Procedure Declaration Node
procDeclNode := '(' PROC procDefNode blockNode ')' ;
(40) MODDECL -- Module Declaration Node
modDeclNode := '(' MODDECL moduleIdent priority importListNode exportList blockNode ')' ;
exportList := unqualExportNode | qualExportNode | emptyNode ;
(41) VSREC -- Variable Size Record Type Declaration Node
vsrTypeNode := '(' VSREC fieldListSeqNode varSizeFieldNode ')' ;
(42) VSFIELD -- Variable Size Field Node
varSizeFieldNode := '(' VSFIELD varSizeField determinantField varSizeFieldType ')' ;
varSizeField := IdentNode ;
determinantField := IdentNode ;
varSizeFieldType := qualidentNode ;
(43) EXPORT -- Unqualified Export Node
unqualExportNode := '(' EXPORT identListNode ')' ;
(44) QUALEXP -- Qualified Export Node
qualExportNode := '(' QUALEXP identListNode ')' ;
(45) STMTSEQ -- Statement Sequence Node
statementSeqNode := '(' STMTSEQ statementNode+ ')' ;
statementNode := assignmentNode | procCallNode | returnStmtNode | withStmtNode | ifStmtNode | caseStmtNode | loopStmtNode | whileStmtNode | repeatStmtNode | forStmtNode | exitStmtNode ;
(46) ASSIGN -- Assignment Node
assignmentNode := '(' ASSIGN designator exprNode ')' ;
designator := identNode | qualidentNode | derefNode | designatorNode ;
(47) PCALL -- Procedure Call Node
procCallNode := '( PCALL designator actualParams ')' ;
actualParams := actualParamsNode | emptyNode ;
(48) RETURN -- RETURN Statement Node
returnStmtNode := '(' RETURN returnValue ')' ;
returnValue := exprNode | emptyNode ;
(49) WITH -- WITH Statement Node
withStmtNode := '(' WITH designator statementSeqNode ')' ;
(50) IF -- IF Statement Node
ifStmtNode := '(' IF exprNode ifBranch elsifSeq elseBranch ')' ;
ifBranch := statementSeqNode ;
elsifSeq := elsifSeqNode | emptyNode ;
elseBranch := statementSeqNode | emptyNode ;
(51) SWITCH -- CASE Statement Node
caseStmtNode := '(' SWITCH exprNode caseListNode elseBranch ')' ;
(52) LOOP -- LOOP Statement Node
loopStmtNode := '(' LOOP statementSeqNode ')' ;
(53) WHILE -- WHILE Statement Node
whileStmtNode := '(' WHILE exprNode statementSeqNode ')' ;
(54) REPEAT -- REPEAT Statement Node
repeatStmtNode := '(' REPEAT statementSeqNode exprNode ')' ;
(55) FORTO -- FOR Statement Node
forStmtNode := '(' FORTO identNode startValue endValue stepValue statementSeqNode ')' ;
startValue : exprNode ;
endValue := expNode ;
stepValue := exprNode | emptyNode ;
(56) EXIT -- EXIT Statement Node
exitStmtNode := '(' EXIT ')' ;
(57) ARGS -- Actual Parameters Node
actualParamsNode := '(' ARGS exprNode+ ')' ;
(58) ELSIFSEQ -- ELSIFSEQ Node
elsifSeqNode := '(' ELSIFSEQ elsifNode+ ')' ;
(59) ELSIF -- ELSIF Node
elsifNode := '(' ELSIF exprNode statementSeqNode ')' ;
(60) CASELIST -- CASE List Node
caseListNode := '(' CASELIST caseBranchNode+ ')' ;
(61) CASE -- CASE Branch Node
caseBranchNode := '(' CASE caseLabelListNode statementSeqNode ')' ;
(62) ELEMLIST -- Set Element List Node
elementListNode := '(' ELEMLIST element+ ')' ;
element := expr | range ;
(63) RANGE -- Expression Range Node
range := '(' RANGE lowerValue upperValue ')' ;
lowerValue := expr ;
upperValue := expr ;
(64) FIELD -- Record Field Selector Node
fieldSelectorNode := '(' FIELD selector ')' ;
selector := identNode | qualidentNode | designatorNode ;
(65) INDEX -- Array Index Node
arrayIndexNode := '(' INDEX subscript+ ')' ;
subscript := exprNode ;
exprNode := negNode | notNode | eqNode | neqNode | ltNode | ltEqNode | gtNode | gtEqNode | inNode | plusNode | minusNode | orNode | asteriskNode | solidusNode | divNode | modulusNode | andNode | designator | intValNode | realValNode | chrValNode | quotedValNode | funcCallNode | setValNode ;
(66) DESIG -- Designator Node
designatorNode := '(' DESIG head tail ')' ;
head := identNode | qualidentNode | derefNode ;
tail := fieldSelectorNode | arrayIndexNode ;
(67) DEREF -- Pointer Dereference Node
derefNode := '(' DEREF designator ')' ;
(68) NEG -- Arithmetic Negation Sub-Expression Node
negNode := '(' NEG right ')' ;
right : exprNode ;
(69) NOT -- Logical Negation Sub-Expression Node
notNode := '(' NOT right ')' ;
(70) EQ -- Equality Sub-Expression Node
eqNode := '(' EQ left right ')' ;
left : exprNode ;
(71) NEQ -- Inequality Sub-Expression Node
neqNode := '(' NEQ left right ')' ;
(72) LT -- Less-Than Sub-Expression Node
ltNode := '(' '<' left right ')' ;
(73) LTEQ -- Less-Than-Or-Equal Sub-Expression Node
ltEqNode := '(' '<=' left right ')' ;
(74) GT -- Greater-Than Sub-Expression Node
gtNode := '(' '>' left right ')' ;
(75) GTEQ -- Greater-Than-Or-Equal Sub-Expression Node
gtEqNode := '(' '>=' left right ')' ;
(76) IN -- Set Membership Sub-Expression Node
inNode := '(' IN left right ')' ;
(77) PLUS -- Plus Sub-Expression Node
plusNode := '(' '+' left right ')' ;
(78) MINUS -- Minus Sub-Expression Node
minusNode := '(' '-' left right ')' ;
(79) OR -- Logical Disjunction Sub-Expression Node
orNode := '(' OR left right ')' ;
(80) ASTERISK -- Asterisk Sub-Expression Node
asteriskNode := '(' '*' left right ')' ;
(81) SOLIDUS -- Solidus Sub-Expression Node
solidusNode := '(' '/' left right ')' ;
(82) DIV -- Euclidean Division Sub-Expression Node
divNode := '(' DIV left right ')' ;
(83) MOD -- Remainder of Euclidean Division Sub-Expression Node
modulusNode := '(' MOD left right ')' ;
(84) AND -- Logical Conjunction Sub-Expression Node
andNode := '(' AND left right ')' ;
(85) FCALL -- Function Call Sub-Expression Node
funcCallNode := '( FCALL designator actualParams ')' ;
(86) SETVAL -- Set Value Sub-Expression Node
setValNode := '( SETVAL setTypeIdent elementList ')' ;
setTypeIdent := ident | qualident | emptyNode ;
elementList := actualParams | emptyNode ;
(87) FILENAME -- File Node
Signature: (FILENAME "filename")
filenameNode := '(' FILENAME '"' filename '"' ')' ;
(88) OPTIONS -- Compiler Options Node
Signature: (OPTIONS "foo" "bar" "baz" ...)
optionsNode := '(' OPTIONS ( '"' option-name '"' )+ ')' ;
(89) IDENT -- Identifier Node
Signature: (IDENT "identifier")
identNode := '(' IDENT '"' Ident '"' ')' ;
(90) IDENTLIST -- Identifier List Node
Signature: (IDENTLIST "foo" "bar" "baz" ...)
identListNode := '(' IDENTLIST ( '"' Ident '"' )+ ')' ;
(91) QUALIDENT -- Qualified Identifier Node
Signature: (QUALIDENT "foo" "bar" ...)
qualidentNode := '(' QUALIDENT ( '"' Ident '"' ) ( '"' Ident '"' )+ ')' ;
(92) INTVAL -- Whole Number Value Node
Signature: (INTVAL 12345) | (INTVAL #0x7FFF)
intValNode := '(' INTVAL ( lexeme | '#' lexeme ) ')' ;
(93) REALVAL -- Real Number Value Node
Signature: (REALVAL 1.23e45)
realValNode := '(' REALVAL lexeme ')' ;
(94) CHRVAL -- Character Code Value Node
Signature: (CHRVAL #0u7F)
chrValNode := '(' CHRVAL '#' lexeme ')' ;
(95) QUOTEDVAL -- Quoted Character or String Value Node
Signature: (QUOTEDVAL "quoted character or string")
quotedValNode := '(' QUOTEDVAL '"' lexeme '"' ')' ;
+++
Copyright (C) 2017 Modula-2 Software Foundation