2 -- mc-
5.bnf grammar and associated actions for mcp
5.
4 -- Copyright
(C
) 2016-
2024 Free Software Foundation, Inc
.
5 -- Contributed by Gaius Mulley <gaius
.mulley@southwales
.ac
.uk>
.
7 -- This file is part of GNU Modula-
2.
9 -- GNU Modula-
2 is free software; you can redistribute it and/or modify
10 -- it under the terms of the GNU General Public License as published by
11 -- the Free Software Foundation; either version
3, or
(at your option
)
14 -- GNU Modula-
2 is distributed in the hope that it will be useful, but
15 -- WITHOUT ANY WARRANTY; without even the implied warranty of
16 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
. See the GNU
17 -- General Public License for more details
.
19 -- You should have received a copy of the GNU General Public License
20 -- along with GNU Modula-
2; see the file COPYING
3. If not see
21 -- <http
://www.gnu.org/licenses/>.
24 (* output from mc-
5.bnf, automatically generated do not edit
.
26 Copyright
(C
) 2016-
2024 Free Software Foundation, Inc
.
27 Contributed by Gaius Mulley <gaius
.mulley@southwales
.ac
.uk>
.
29 This file is part of GNU Modula-
2.
31 GNU Modula-
2 is free software; you can redistribute it and/or modify
32 it under the terms of the GNU General Public License as published by
33 the Free Software Foundation; either version
3, or
(at your option
)
36 GNU Modula-
2 is distributed in the hope that it will be useful, but
37 WITHOUT ANY WARRANTY; without even the implied warranty of
38 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
. See the GNU
39 General Public License for more details
.
41 You should have received a copy of the GNU General Public License
42 along with GNU Modula-
2; see the file COPYING
. If not,
43 see <https
://www.gnu.org/licenses/>. *)
45 IMPLEMENTATION MODULE mcp
5 ;
47 FROM DynamicStrings IMPORT String, InitString, KillString, Mark,
50 FROM mcError IMPORT errorStringAt, flushErrors ;
51 FROM nameKey IMPORT NulName, Name, makekey ;
52 FROM mcPrintf IMPORT printf
0, printf
1 ;
53 FROM mcDebug IMPORT assert ;
54 FROM mcReserved IMPORT toktype ;
55 FROM mcComment IMPORT setProcedureComment ;
56 FROM mcMetaError IMPORT metaError
1, metaError
2 ;
57 FROM mcStack IMPORT stack ;
61 FROM mcLexBuf IMPORT currentstring, currenttoken, getToken, insertToken,
62 insertTokenAndRewind, getTokenNo, lastcomment,
63 getBodyComment, getAfterComment ;
65 FROM decl IMPORT node, lookupDef, lookupImp, lookupModule, getSymName,
66 enterScope, leaveScope,
67 makeEnum, makeEnumField, putType, lookupSym, isDef, makeSubrange,
70 makeVarargs, makeVarParameter, makeNonVarParameter,
71 putSubrangeType, putConst, getType, skipType,
72 makeArray, putUnbounded, getCardinal, makeBinaryTok, makeUnaryTok,
73 makeRecord, isRecord, isRecordField, isVarientField, makeVarient,
74 addFieldsToRecord, isVarient, buildVarientSelector,
75 buildVarientFieldRecord, paramEnter, paramLeave,
76 makeIdentList, putIdent, addVarParameters, addNonVarParameters,
77 lookupInScope, import, lookupExported, isImp, isModule, isConst,
78 makeLiteralInt, makeLiteralReal, makeString, getBuiltinConst,
79 getNextEnum, makeComponentRef, makeArrayRef, makeDeRef,
81 makeExpList, putExpList, isExpList, isArray, isPointer, isVar,
83 makeStatementSequence, addStatement, putBegin, putFinally,
84 makeReturn, putReturn, makeExit, makeComment,
85 isStatementSequence, isWhile, makeWhile, putWhile,
86 makeAssignment, makeFuncCall, isReturn,
87 makeIf, makeElsif, putElse, isIf,
88 makeFor, putFor, isFor,
89 makeRepeat, putRepeat,
90 resetConstExpPos, getNextConstExp,
91 makeSetValue, putSetValue, includeSetValue,
92 makeCase, putCaseExpression, putCaseElse,
93 putCaseStatement, makeCaseList, putCaseRange,
94 dupExpr, makeLoop, putLoop, isLoop,
95 addCommentBody, addCommentAfter, addIfComments,
96 addElseComments, addIfEndComments,
97 addWhileDoComment, addWhileEndComment,
98 addRepeatComment, addUntilComment,
107 WasNoError : BOOLEAN ;
127 PROCEDURE followNode
(n
: node
) ;
131 printf
0 ("variable: ")
132 ELSIF isParameter
(n
)
134 printf
0 ("parameter: ")
136 n := skipType
(getType
(n
)) ;
142 printf
0 ("pointer\n")
156 PROCEDURE push
(n
: node
) : node ;
158 RETURN mcStack
.push
(stk, n
)
166 PROCEDURE pop
() : node ;
168 RETURN mcStack
.pop
(stk
)
176 PROCEDURE replace
(n
: node
) : node ;
178 RETURN mcStack
.replace
(stk, n
)
183 peep - returns the top node on the stack without removing it
.
186 PROCEDURE peep
() : node ;
193 depth - returns the depth of the stack
.
196 PROCEDURE depth
() : CARDINAL ;
198 RETURN mcStack
.depth
(stk
)
206 PROCEDURE checkDuplicate
(b
: BOOLEAN
) ;
213 isQualident - returns TRUE if, n, is a qualident
.
216 PROCEDURE isQualident
(n
: node
) : BOOLEAN ;
224 type := skipType
(getType
(n
)) ;
225 RETURN
(type # NIL
) AND isRecord
(type
)
236 PROCEDURE startWith
(n
: node
) ;
238 n := mcStack
.push
(withStk, n
)
250 n := mcStack
.pop
(withStk
)
258 PROCEDURE lookupWithSym
(i
: Name
) : node ;
263 d := mcStack
.depth
(withStk
) ;
265 n := mcStack
.access
(withStk, d
) ;
266 t := skipType
(getType
(n
)) ;
267 m := lookupInScope
(t, i
) ;
271 RETURN makeComponentRef
(n, m
)
280 pushStmt - push a node, n, to the statement stack and return node, n
.
283 PROCEDURE pushStmt
(n
: node
) : node ;
285 RETURN mcStack
.push
(stmtStk, n
)
290 popStmt - pop the top node from the statement stack
.
293 PROCEDURE popStmt
() : node ;
295 RETURN mcStack
.pop
(stmtStk
)
300 peepStmt - return the top node from the statement stack,
301 but leave the stack unchanged
.
304 PROCEDURE peepStmt
() : node ;
306 RETURN pushStmt
(popStmt
())
311 pushLoop - push a node, n, to the loop stack and return node, n
.
314 PROCEDURE pushLoop
(n
: node
) : node ;
316 RETURN mcStack
.push
(loopStk, n
)
321 popLoop - pop the top node from the loop stack
.
324 PROCEDURE popLoop
() : node ;
326 RETURN mcStack
.pop
(loopStk
)
331 peepLoop - return the top node from the loop stack,
332 but leave the stack unchanged
.
335 PROCEDURE peepLoop
() : node ;
337 RETURN pushLoop
(popLoop
())
341 PROCEDURE ErrorString
(s
: String
) ;
343 errorStringAt
(s, getTokenNo
()) ;
348 PROCEDURE ErrorArray
(a
: ARRAY OF CHAR
) ;
350 ErrorString
(InitString
(a
))
358 PROCEDURE pushNunbounded
(c
: CARDINAL
) ;
366 subrange := makeSubrange
(NIL, NIL
) ;
367 putSubrangeType
(subrange, getCardinal
()) ;
369 array := makeArray
(subrange, type
) ;
370 putUnbounded
(array
) ;
371 type := push
(array
) ;
378 makeIndexedArray - builds and returns an array of type, t, with, c, indices
.
381 PROCEDURE makeIndexedArray
(c
: CARDINAL; t
: node
) : node ;
386 t := makeArray
(pop
(), t
) ;
390 END makeIndexedArray ;
394 importInto - from, m, import, name, into module, current
.
395 It checks to see if curident is an enumeration type
396 and if so automatically includes all enumeration fields
400 PROCEDURE importInto
(m
: node; name
: Name; current
: node
) ;
405 assert
(isDef
(current
) OR isModule
(current
) OR isImp
(current
)) ;
406 s := lookupExported
(m, name
) ;
409 metaError
2 ('
{%
1k
} was not exported from definition module
{%
2a
}', name, m
)
411 o := import
(current, s
) ;
414 metaError
2 ('
{%
1ad
} cannot be imported into the current module as it causes a name clash with
{%
2ad
}',
422 checkEndName - if module does not have, name, then issue an error containing, desc
.
425 PROCEDURE checkEndName
(module
: node; name
: Name; desc
: ARRAY OF CHAR
) ;
429 IF getSymName
(module
)#name
431 s := InitString
('inconsistent module name found with this '
) ;
432 s := ConCat
(s, Mark
(InitString
(desc
))) ;
437 % declaration mcp
5 begin
441 SyntaxError - after a syntax error we skip all tokens up until we reach
445 PROCEDURE SyntaxError
(stopset
0: SetOfStop
0; stopset
1: SetOfStop
1; stopset
2: SetOfStop
2) ;
450 printf
0('
\nskipping token *** '
)
453 yes the ORD
(currenttoken
) looks ugly, but it is *much* safer than
454 using currenttoken<sometok as a change to the ordering of the
455 token declarations below would cause this to break
. Using ORD
() we are
456 immune from such changes
458 WHILE NOT
(((ORD
(currenttoken
)<
32) AND
(currenttoken IN stopset
0)) OR
459 ((ORD
(currenttoken
)>
=32) AND
(ORD
(currenttoken
)<
64) AND
(currenttoken IN stopset
1)) OR
460 ((ORD
(currenttoken
)>
=64) AND
(currenttoken IN stopset
2)))
475 PROCEDURE SyntaxCheck
(stopset
0: SetOfStop
0; stopset
1: SetOfStop
1; stopset
2: SetOfStop
2) ;
477 (* and again
(see above re
: ORD
)
479 IF NOT
(((ORD
(currenttoken
)<
32) AND
(currenttoken IN stopset
0)) OR
480 ((ORD
(currenttoken
)>
=32) AND
(ORD
(currenttoken
)<
64) AND
(currenttoken IN stopset
1)) OR
481 ((ORD
(currenttoken
)>
=64) AND
(currenttoken IN stopset
2)))
483 SyntaxError
(stopset
0, stopset
1, stopset
2)
489 WarnMissingToken - generates a warning message about a missing token, t
.
492 PROCEDURE WarnMissingToken
(t
: toktype
) ;
511 str := DescribeStop
(s
0, s
1, s
2) ;
513 str := ConCat
(InitString
('syntax error,'
), Mark
(str
)) ;
514 errorStringAt
(str, getTokenNo
())
515 END WarnMissingToken ;
519 MissingToken - generates a warning message about a missing token, t
.
522 PROCEDURE MissingToken
(t
: toktype
) ;
524 WarnMissingToken
(t
) ;
525 IF
(t#identtok
) AND
(t#integertok
) AND
(t#realtok
) AND
(t#stringtok
)
529 printf
0 ('inserting token
\n'
)
540 PROCEDURE CheckAndInsert
(t
: toktype; stopset
0: SetOfStop
0; stopset
1: SetOfStop
1; stopset
2: SetOfStop
2) : BOOLEAN ;
542 IF
((ORD
(t
)<
32) AND
(t IN stopset
0)) OR
543 ((ORD
(t
)>
=32) AND
(ORD
(t
)<
64) AND
(t IN stopset
1)) OR
544 ((ORD
(t
)>
=64) AND
(t IN stopset
2))
546 WarnMissingToken
(t
) ;
547 insertTokenAndRewind
(t
) ;
559 PROCEDURE InStopSet
(t
: toktype; stopset
0: SetOfStop
0; stopset
1: SetOfStop
1; stopset
2: SetOfStop
2) : BOOLEAN ;
561 IF
((ORD
(t
)<
32) AND
(t IN stopset
0)) OR
562 ((ORD
(t
)>
=32) AND
(ORD
(t
)<
64) AND
(t IN stopset
1)) OR
563 ((ORD
(t
)>
=64) AND
(t IN stopset
2))
573 PeepToken - peep token checks to see whether the stopset is satisfied by currenttoken
574 If it is not then it will insert a token providing the token
575 is one of ;
] ) } . OF END ,
577 if the stopset contains <identtok> then we do not insert a token
580 PROCEDURE PeepToken
(stopset
0: SetOfStop
0; stopset
1: SetOfStop
1; stopset
2: SetOfStop
2) ;
582 (* and again
(see above re
: ORD
)
584 IF
(NOT
(((ORD
(currenttoken
)<
32) AND
(currenttoken IN stopset
0)) OR
585 ((ORD
(currenttoken
)>
=32) AND
(ORD
(currenttoken
)<
64) AND
(currenttoken IN stopset
1)) OR
586 ((ORD
(currenttoken
)>
=64) AND
(currenttoken IN stopset
2)))) AND
587 (NOT InStopSet
(identtok, stopset
0, stopset
1, stopset
2))
589 (* SyntaxCheck would fail since currentoken is not part of the stopset
590 we check to see whether any of currenttoken might be a commonly omitted token *
)
591 IF CheckAndInsert
(semicolontok, stopset
0, stopset
1, stopset
2) OR
592 CheckAndInsert
(rsbratok, stopset
0, stopset
1, stopset
2) OR
593 CheckAndInsert
(rparatok, stopset
0, stopset
1, stopset
2) OR
594 CheckAndInsert
(rcbratok, stopset
0, stopset
1, stopset
2) OR
595 CheckAndInsert
(periodtok, stopset
0, stopset
1, stopset
2) OR
596 CheckAndInsert
(oftok, stopset
0, stopset
1, stopset
2) OR
597 CheckAndInsert
(endtok, stopset
0, stopset
1, stopset
2) OR
598 CheckAndInsert
(commatok, stopset
0, stopset
1, stopset
2)
609 PROCEDURE Expect
(t
: toktype; stopset
0: SetOfStop
0; stopset
1: SetOfStop
1; stopset
2: SetOfStop
2) ;
616 PeepToken
(stopset
0, stopset
1, stopset
2)
621 SyntaxCheck
(stopset
0, stopset
1, stopset
2)
626 CompilationUnit - returns TRUE if the input was correct enough to parse
630 PROCEDURE CompilationUnit
() : BOOLEAN ;
632 stk := mcStack
.init
() ;
633 withStk := mcStack
.init
() ;
634 stmtStk := mcStack
.init
() ;
635 loopStk := mcStack
.init
() ;
638 FileUnit
(SetOfStop
0{eoftok
}, SetOfStop
1{}, SetOfStop
2{}) ;
640 mcStack
.kill
(withStk
) ;
641 mcStack
.kill
(stmtStk
) ;
642 mcStack
.kill
(loopStk
) ;
644 END CompilationUnit ;
648 Ident - error checking varient of Ident
651 PROCEDURE Ident
(stopset
0: SetOfStop
0; stopset
1: SetOfStop
1; stopset
2: SetOfStop
2) ;
653 curident := makekey
(currentstring
) ;
654 Expect
(identtok, stopset
0, stopset
1, stopset
2)
662 PROCEDURE string
(stopset
0: SetOfStop
0; stopset
1: SetOfStop
1; stopset
2: SetOfStop
2) ;
664 curstring := makekey
(currentstring
) ;
665 Expect
(stringtok, stopset
0, stopset
1, stopset
2)
673 PROCEDURE Integer
(stopset
0: SetOfStop
0; stopset
1: SetOfStop
1; stopset
2: SetOfStop
2) ;
677 n := push
(makeLiteralInt
(makekey
(currentstring
))) ;
678 Expect
(integertok, stopset
0, stopset
1, stopset
2)
686 PROCEDURE Real
(stopset
0: SetOfStop
0; stopset
1: SetOfStop
1; stopset
2: SetOfStop
2) ;
690 n := push
(makeLiteralReal
(makekey
(currentstring
))) ;
691 Expect
(realtok, stopset
0, stopset
1, stopset
2)
697 error 'ErrorArray' 'ErrorString'
698 tokenfunc 'currenttoken'
700 token '' eoftok -- internal token
705 token '
:=' becomestok
706 token '&' ambersandtok
709 token
";" semicolontok
712 token '
[' lsbratok -- left square brackets
713 token '
]' rsbratok -- right square brackets
714 token '
{' lcbratok -- left curly brackets
715 token '
}' rcbratok -- right curly brackets
717 token
"'" singlequotetok
722 token '<>' lessgreatertok
723 token '<
=' lessequaltok
724 token '>
=' greaterequaltok
725 token '<*' ldirectivetok
726 token '*>' rdirectivetok
727 token '
..' periodperiodtok
729 token '
"' doublequotestok
732 token 'ARRAY' arraytok
733 token 'BEGIN' begintok
736 token 'CONST' consttok
737 token 'DEFINITION' definitiontok
741 token 'ELSIF' elsiftok
743 token 'EXCEPT' excepttok
745 token 'EXPORT' exporttok
746 token 'FINALLY' finallytok
750 token 'IMPLEMENTATION' implementationtok
751 token 'IMPORT' importtok
755 token 'MODULE' moduletok
759 token 'PACKEDSET' packedsettok
760 token 'POINTER' pointertok
761 token 'PROCEDURE' proceduretok
762 token 'QUALIFIED' qualifiedtok
763 token 'UNQUALIFIED' unqualifiedtok
764 token 'RECORD' recordtok
766 token 'REPEAT' repeattok
767 token 'RETRY' retrytok
768 token 'RETURN' returntok
773 token 'UNTIL' untiltok
775 token 'WHILE' whiletok
778 token 'VOLATILE' volatiletok
779 token '...' periodperiodperiodtok
780 token '__DATE__' datetok
781 token '__LINE__' linetok
782 token '__FILE__' filetok
783 token '__ATTRIBUTE__' attributetok
784 token '__BUILTIN__' builtintok
785 token '__INLINE__' inlinetok
786 token 'integer number' integertok
787 token 'identifier' identtok
788 token 'real number' realtok
789 token 'string' stringtok
791 special Ident first { < identtok > } follow { }
792 special Integer first { < integertok > } follow { }
793 special Real first { < realtok > } follow { }
794 special string first { < stringtok > } follow { }
798 -- the following are provided by the module m2flex and also handbuild procedures below
799 -- Ident := Letter { ( Letter | Digit ) } =:
800 -- Integer := Digit { Digit } | OctalDigit { OctalDigit } ( " B
" | " C
" ) |
801 -- Digit { HexDigit } " H
" =:
802 -- Real := Digit { Digit } " . " { Digit } [ ScaleFactor ] =:
803 -- ScaleFactor := " E
" [ ( " +
" | " -
" ) ] Digit { Digit } =:
804 -- HexDigit := Digit | " A
" | " B
" | " C
" | " D
" | " E
" | " F
" =:
805 -- Digit := OctalDigit | " 8 " | " 9 " =:
806 -- OctalDigit := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" =:
809 FileUnit := DefinitionModule | ImplementationOrProgramModule
812 ProgramModule := "MODULE
"
813 Ident % curmodule := lookupModule (curident) %
814 % addCommentBody (curmodule) %
815 % enterScope (curmodule) %
816 % resetConstExpPos (curmodule) %
820 Ident % checkEndName (curmodule, curident, 'program module') %
826 ImplementationModule := "IMPLEMENTATION
" "MODULE
"
827 Ident % curmodule := lookupImp (curident) %
828 % addCommentBody (curmodule) %
829 % enterScope (lookupDef (curident)) %
830 % enterScope (curmodule) %
831 % resetConstExpPos (curmodule) %
835 Ident % checkEndName (curmodule, curident, 'implementation module') %
836 % leaveScope ; leaveScope %
840 ImplementationOrProgramModule := ImplementationModule | ProgramModule =:
842 ConstInteger := Integer % VAR i: node ; %
846 ConstReal := Real % VAR r: node ; %
850 ConstNumber := ConstInteger | ConstReal =:
852 Number := Integer | Real =:
854 Qualident := Ident { "." Ident } =:
856 ConstantDeclaration := Ident "=" ConstExpressionNop =:
858 ConstExpressionNop := % VAR c: node ; %
859 % c := getNextConstExp () %
860 SimpleConstExpr [ Relation SimpleConstExpr ] =:
862 ConstExpression := % VAR c: node ; %
863 % c := push (getNextConstExp ()) %
864 SimpleConstExpr [ Relation SimpleConstExpr ] =:
876 SimpleConstExpr := UnaryOrConstTerm { AddOperator ConstTerm } =:
893 ConstTerm := ConstFactor { MulOperator ConstFactor } =:
904 NotConstFactor := "NOT
" ConstFactor % VAR n: node ; %
905 % n := push (makeUnaryTok (nottok, pop ())) %
908 ConstFactor := ConstNumber | ConstString | ConstSetOrQualidentOrFunction |
909 "(" ConstExpressionNop ")" | NotConstFactor
912 -- to help satisfy LL1
914 ConstString := string =:
916 ConstComponentElement := ConstExpressionNop [ ".." ConstExpressionNop ]
919 ConstComponentValue := ConstComponentElement [ 'BY' ConstExpressionNop ]
922 ConstArraySetRecordValue := ConstComponentValue { ',' ConstComponentValue }
925 ConstConstructor := '{'
926 [ ConstArraySetRecordValue ]
929 ConstSetOrQualidentOrFunction := Qualident
930 [ ConstConstructor | ConstActualParameters ]
934 ConstActualParameters := "(" [ ConstExpList ] ")" =:
936 ConstExpList := ConstExpressionNop { ",
" ConstExpressionNop }
939 ConstAttribute := "__ATTRIBUTE__
" "__BUILTIN__
" "(" "("
940 ConstAttributeExpression
943 ConstAttributeExpression := Ident | "<
" Qualident ',' Ident ">
" =:
945 ByteAlignment := '<*' AttributeExpression '*>'
948 OptAlignmentExpression := [ AlignmentExpression ] =:
950 AlignmentExpression := "(" ConstExpressionNop ")" =:
952 Alignment := [ ByteAlignment ] =:
954 IdentList := Ident { ",
" Ident }
957 SubrangeType := "[" ConstExpressionNop ".." ConstExpressionNop "]" =:
959 ArrayType := "ARRAY
" SimpleType { ",
" SimpleType } "OF
" Type =:
961 RecordType := "RECORD
" [ DefaultRecordAttributes ]
965 DefaultRecordAttributes := '<*' AttributeExpression '*>' =:
967 RecordFieldPragma := [ '<*' FieldPragmaExpression
968 { ',' FieldPragmaExpression } '*>' ] =:
970 FieldPragmaExpression := Ident PragmaConstExpression =:
972 PragmaConstExpression := [ '(' ConstExpressionNop ')' ] =:
974 AttributeExpression := Ident '(' ConstExpressionNop ')' =:
976 FieldListSequence := FieldListStatement { ";
" FieldListStatement } =:
978 FieldListStatement := [ FieldList ] =:
980 FieldList := IdentList ":" Type RecordFieldPragma
981 | "CASE
" CaseTag "OF
" Varient { "|
" Varient }
987 TagIdent := Ident | % curident := NulName %
990 CaseTag := TagIdent [ ":" Qualident ]
993 Varient := [ VarientCaseLabelList ":" FieldListSequence ] =:
995 VarientCaseLabelList := VarientCaseLabels { ",
" VarientCaseLabels } =:
997 VarientCaseLabels := ConstExpressionNop [ ".." ConstExpressionNop ]
1000 SetType := ( "SET
" | "PACKEDSET
" ) "OF
" SimpleType =:
1002 PointerType := "POINTER
" "TO
" Type =:
1004 ProcedureType := "PROCEDURE
" [ FormalTypeList ] =:
1006 FormalTypeList := "(" ( ")" FormalReturn |
1007 ProcedureParameters ")" FormalReturn ) =:
1009 FormalReturn := [ ":" OptReturnType ] =:
1011 OptReturnType := "[" Qualident "]" | Qualident
1014 ProcedureParameters := ProcedureParameter
1015 { ",
" ProcedureParameter } =:
1017 ProcedureParameter := "..." | "VAR
" FormalType | FormalType =:
1020 VarIdent := Ident [ "[" ConstExpressionNop "]" ]
1023 VarIdentList := VarIdent { ",
" VarIdent } =:
1025 VariableDeclaration := VarIdentList ":" Type Alignment
1028 Designator := PushQualident { SubDesignator } =:
1030 SubDesignator := % VAR n, field, type: node ; %
1034 ErrorArray ('no expression found') ;
1038 % type := skipType (getType (n)) %
1040 Ident % IF isRecord (type)
1042 field := lookupInScope (type, curident) ;
1045 metaError2 ('field {%1k} cannot be found in record {%2ad}', curident, type)
1047 n := replace (makeComponentRef (n, field))
1050 metaError2 ('attempting to access a field {%1k} from {%2ad} which does not have a record type', curident, type)
1053 | "[" ArrayExpList % IF isArray (type)
1055 n := replace (makeArrayRef (n, pop ()))
1057 metaError1 ('attempting to access an array but the expression is not an array but a {%1d}', type)
1064 SubPointer := % VAR n, field, type: node ; %
1066 % type := skipType (getType (n)) %
1067 "^
" ( "." Ident % IF isPointer (type)
1069 type := skipType (getType (type)) ;
1072 field := lookupInScope (type, curident) ;
1075 metaError2 ('field {%1k} cannot be found in record {%2ad}', curident, type)
1077 n := replace (makePointerRef (n, field))
1080 metaError2 ('attempting to access a field {%1k} from {%2ad} which does not have a record type', curident, type)
1083 metaError2 ('trying to dereference {%1k} which was not declared as a pointer but a {%2tad}', n, n)
1086 | % IF isPointer (type)
1088 n := replace (makeDeRef (n))
1090 metaError1 ('attempting to dereference a pointer but the expression is not a pointer but a {%1d}', type)
1097 ArrayExpList := % VAR l: node ; %
1098 % l := push (makeExpList ()) %
1099 Expression % putExpList (l, pop ()) %
1100 % assert (isExpList (peep ())) %
1102 Expression % putExpList (l, pop ()) %
1103 % assert (isExpList (peep ())) %
1107 ExpList := % VAR p, n: node ; %
1109 % assert (isExpList (p)) %
1110 Expression % putExpList (p, pop ()) %
1111 % assert (isExpList (peep ())) %
1112 { ",
" Expression % putExpList (p, pop ()) %
1113 % assert (isExpList (peep ())) %
1118 Expression := % VAR c, l, r: node ; op: toktype ; %
1119 SimpleExpression % op := currenttoken %
1120 [ Relation % l := pop () %
1121 SimpleExpression % r := pop () %
1122 % r := push (makeBinaryTok (op, l, r)) %
1126 SimpleExpression := % VAR op: toktype ; n: node ; %
1127 UnaryOrTerm { % op := currenttoken %
1129 AddOperator Term % n := push (makeBinaryTok (op, n, pop ())) %
1133 UnaryOrTerm := % VAR n: node ; %
1134 "+
" Term % n := push (makeUnaryTok (plustok, pop ())) %
1135 | "-
" Term % n := push (makeUnaryTok (minustok, pop ())) %
1139 Term := % VAR op: toktype ; n: node ; %
1140 Factor { % op := currenttoken %
1141 MulOperator % n := pop () %
1142 Factor % n := push (makeBinaryTok (op, n, pop ())) %
1145 PushString := string % VAR n: node ; %
1146 % n := push (makeString (curstring)) %
1149 Factor := Number | PushString | SetOrDesignatorOrFunction |
1150 "(" Expression ")" | "NOT
" ( Factor % VAR n: node ; %
1151 % n := push (makeUnaryTok (nottok, pop ())) %
1153 % n := push (makeUnaryTok (nottok, pop ())) %
1156 ComponentElement := Expression % VAR l, h, n: node ; %
1159 [ ".." Expression % h := pop () %
1160 % ErrorArray ('implementation restriction range is not allowed') %
1161 ] % n := push (includeSetValue (pop (), l, h)) %
1164 ComponentValue := ComponentElement [ 'BY' % ErrorArray ('implementation restriction BY not allowed') %
1168 ArraySetRecordValue := ComponentValue { ',' ComponentValue }
1171 Constructor := '{' % VAR n: node ; %
1172 % n := push (makeSetValue ()) %
1173 [ ArraySetRecordValue ]
1176 SetOrDesignatorOrFunction := PushQualident % VAR q, p, n: node ; %
1177 [ Constructor % p := pop () %
1179 % n := push (putSetValue (p, q)) %
1183 ActualParameters % p := pop () %
1184 % p := push (makeFuncCall (q, p)) %
1189 -- SimpleDes := { "." Ident | "[" ExpList "]" | "^
" } =:
1190 SimpleDes := { SubDesignator } =:
1192 ActualParameters := "(" % VAR n: node ; %
1193 % n := push (makeExpList ()) %
1194 [ ExpList ] ")" % assert (isExpList (peep ())) %
1198 ExitStatement := % VAR n: node ; %
1202 ErrorArray ('EXIT can only be used inside a LOOP statement')
1204 n := pushStmt (makeExit (peepLoop (), loopNo))
1208 ReturnStatement := % VAR n: node ; %
1209 % n := pushStmt (makeReturn ()) %
1210 "RETURN
" [ Expression % putReturn (n, pop ()) %
1211 ] % addCommentBody (peepStmt ()) %
1212 % addCommentAfter (peepStmt ()) %
1213 % assert (isReturn (peepStmt ())) %
1216 Statement := ( AssignmentOrProcedureCall | IfStatement | CaseStatement |
1217 WhileStatement | RepeatStatement | LoopStatement |
1218 ForStatement | WithStatement | AsmStatement |
1219 ExitStatement | ReturnStatement | RetryStatement | % VAR s: node ; %
1220 % s := pushStmt (NIL) %
1224 RetryStatement := % VAR s: node ; %
1225 % s := pushStmt (makeComment ("retry
")) %
1229 AssignmentOrProcedureCall := % VAR d, a, p: node ; %
1230 Designator % d := pop () %
1231 ( ":=" Expression % a := pushStmt (makeAssignment (d, pop ())) %
1233 ActualParameters % a := pushStmt (makeFuncCall (d, pop ())) %
1234 | % a := pushStmt (makeFuncCall (d, NIL)) %
1236 % addCommentBody (peepStmt ()) %
1237 % addCommentAfter (peepStmt ()) %
1240 -- these two break LL1 as both start with a Designator
1241 -- ProcedureCall := Designator [ ActualParameters ] =:
1242 -- Assignment := Designator ":=" Expression =:
1244 StatementSequence := % VAR s, t: node ; %
1245 % s := pushStmt (makeStatementSequence ()) %
1246 % assert (isStatementSequence (peepStmt ())) %
1247 Statement % addStatement (s, popStmt ()) %
1248 % assert (isStatementSequence (peepStmt ())) %
1249 { ";
" Statement % addStatement (s, popStmt ()) %
1250 % assert (isStatementSequence (peepStmt ())) %
1254 IfStatement := % VAR i, a, b: node ; %
1255 "IF
" % b := makeCommentS (getBodyComment ()) %
1256 Expression % a := makeCommentS (getAfterComment ()) %
1257 "THEN
" StatementSequence % i := pushStmt (makeIf (pop (), popStmt ())) %
1258 % addIfComments (i, b, a) %
1259 { "ELSIF
" % b := makeCommentS (getBodyComment ()) %
1260 Expression % a := makeCommentS (getAfterComment ()) %
1261 "THEN
" % addElseComments (peepStmt (), b, a) %
1262 StatementSequence % i := makeElsif (i, pop (), popStmt ()) %
1265 StatementSequence % putElse (i, popStmt ()) %
1266 ] "END
" % b := makeCommentS (getBodyComment ()) %
1267 % a := makeCommentS (getAfterComment ()) %
1268 % assert (isIf (peepStmt ())) %
1269 % addIfEndComments (peepStmt (), b, a) %
1272 CaseStatement := % VAR s, e: node ; %
1273 % s := pushStmt (makeCase ()) %
1275 Expression % s := putCaseExpression (s, pop ()) %
1276 "OF
" Case { "|
" Case }
1280 CaseEndStatement := % VAR c: node ; %
1283 % c := peepStmt () %
1284 StatementSequence % c := putCaseElse (c, popStmt ()) %
1288 Case := [ CaseLabelList ":" % VAR l, c: node ; %
1290 % c := peepStmt () %
1291 StatementSequence % c := putCaseStatement (c, l, popStmt ()) %
1295 CaseLabelList := % VAR l: node ; %
1296 % l := push (makeCaseList ()) %
1297 CaseLabels { ",
" CaseLabels } =:
1299 CaseLabels := % VAR lo, hi, l: node ; %
1300 % lo := NIL ; hi := NIL %
1302 ConstExpression % lo := pop () %
1303 [ ".." ConstExpression % hi := pop () %
1304 ] % l := putCaseRange (l, lo, hi) %
1307 WhileStatement := % VAR s, w, e, a, b: node ; %
1308 % w := pushStmt (makeWhile ()) %
1309 "WHILE
" Expression "DO
" % b := makeCommentS (getBodyComment ()) %
1310 % a := makeCommentS (getAfterComment ()) %
1311 % addWhileDoComment (w, b, a) %
1313 StatementSequence % s := popStmt () %
1314 "END
" % (* assert (isStatementSequence (peepStmt ())) *) %
1315 % putWhile (w, e, s) %
1316 % b := makeCommentS (getBodyComment ()) %
1317 % a := makeCommentS (getAfterComment ()) %
1318 % addWhileEndComment (w, b, a) %
1321 RepeatStatement := % VAR r, s, a, b: node ; %
1322 % r := pushStmt (makeRepeat ()) %
1324 % b := makeCommentS (getBodyComment ()) %
1325 % a := makeCommentS (getAfterComment ()) %
1326 % addRepeatComment (r, b, a) %
1327 StatementSequence % s := popStmt () %
1328 "UNTIL
" Expression % putRepeat (r, s, pop ()) %
1329 % b := makeCommentS (getBodyComment ()) %
1330 % a := makeCommentS (getAfterComment ()) %
1331 % addUntilComment (r, b, a) %
1334 ForStatement := % VAR f, i, s, e, b: node ; %
1336 % f := pushStmt (makeFor ()) %
1337 "FOR
" Ident % i := lookupWithSym (curident) %
1338 ":=" Expression % s := pop () %
1339 "TO
" Expression % e := pop () %
1340 [ "BY
" ConstExpression % b := pop () %
1342 StatementSequence % putFor (f, i, s, e, b, popStmt ()) %
1346 LoopStatement := % VAR l, s: node ; %
1347 "LOOP
" % l := pushStmt (pushLoop (makeLoop ())) %
1349 StatementSequence % s := popStmt () %
1352 "END
" % l := popLoop () %
1353 % assert (isLoop (peepStmt ())) %
1356 WithStatement := "WITH
" Designator "DO
" % startWith (pop ()) %
1361 ProcedureDeclaration := ProcedureHeading ";
" ProcedureBlock
1362 Ident % leaveScope %
1365 ProcedureIdent := Ident % curproc := lookupSym (curident) %
1366 % enterScope (curproc) %
1367 % setProcedureComment (lastcomment, curident) %
1371 DefProcedureIdent := Ident % curproc := lookupSym (curident) %
1374 DefineBuiltinProcedure := [ "__ATTRIBUTE__
" "__BUILTIN__
" "(" "(" Ident ")" ")" | "__INLINE__
" ]
1377 ProcedureHeading := "PROCEDURE
" DefineBuiltinProcedure ( ProcedureIdent
1378 [ FormalParameters ]
1382 Builtin := [ "__BUILTIN__
" | "__INLINE__
" ] =:
1384 DefProcedureHeading := "PROCEDURE
" Builtin ( DefProcedureIdent
1385 [ DefFormalParameters ]
1389 -- introduced procedure block so we can produce more informative
1392 ProcedureBlock := { Declaration } [ "BEGIN
" ProcedureBlockBody ] "END
"
1395 Block := { Declaration } InitialBlock FinalBlock "END
"
1398 InitialBlock := [ "BEGIN
" InitialBlockBody ] =:
1400 FinalBlock := [ "FINALLY
" FinalBlockBody ] =:
1402 InitialBlockBody := NormalPart % putBegin (curmodule, popStmt ()) %
1403 [ "EXCEPT
" ExceptionalPart ] =:
1405 FinalBlockBody := NormalPart % putFinally (curmodule, popStmt ()) %
1406 [ "EXCEPT
" ExceptionalPart ] =:
1408 ProcedureBlockBody := ProcedureNormalPart
1409 [ "EXCEPT
" ExceptionalPart ] =:
1411 ProcedureNormalPart := StatementSequence % putBegin (curproc, popStmt ()) %
1414 NormalPart := StatementSequence
1417 ExceptionalPart := StatementSequence
1420 Declaration := "CONST
" { ConstantDeclaration ";
" } |
1421 "TYPE
" { TypeDeclaration } |
1422 "VAR
" { VariableDeclaration ";
" } |
1423 ProcedureDeclaration ";
" |
1424 ModuleDeclaration ";
" =:
1426 DefFormalParameters := "(" % paramEnter (curproc) %
1427 [ DefMultiFPSection ] ")" % paramLeave (curproc) %
1430 AttributeNoReturn := [ "<*
" Ident "*>
" ] =:
1432 AttributeUnused := [ "<*
" Ident "*>
" ] =:
1434 DefMultiFPSection := DefExtendedFP | FPSection [ ";
" DefMultiFPSection ] =:
1436 FormalParameters := "(" % paramEnter (curproc) %
1437 [ MultiFPSection ] ")" % paramLeave (curproc) %
1440 MultiFPSection := ExtendedFP | FPSection [ ";
" MultiFPSection ] =:
1442 FPSection := NonVarFPSection | VarFPSection =:
1444 DefExtendedFP := DefOptArg | "..." =:
1446 ExtendedFP := OptArg | "..." =:
1448 VarFPSection := "VAR
" IdentList ":" FormalType [ AttributeUnused ]
1451 NonVarFPSection := IdentList ":" FormalType [ AttributeUnused ]
1454 OptArg := "[" Ident ":" FormalType [ "=" ConstExpressionNop ] "]" =:
1456 DefOptArg := "[" Ident ":" FormalType "=" ConstExpressionNop "]" =:
1458 FormalType := { "ARRAY
" "OF
" } Qualident =:
1460 ModuleDeclaration := "MODULE
" Ident [ Priority ] ";
"
1461 { Import } [ Export ]
1465 Priority := "[" ConstExpressionNop "]" =:
1467 Export := "EXPORT
" ( "QUALIFIED
"
1473 FromIdentList := Ident { ",
" Ident } =:
1475 FromImport := "FROM
" Ident "IMPORT
" FromIdentList ";
"
1478 ImportModuleList := Ident { ",
" Ident } =:
1480 WithoutFromImport := "IMPORT
" ImportModuleList ";
"
1483 Import := FromImport | WithoutFromImport =:
1485 DefinitionModule := "DEFINITION
" "MODULE
" [ "FOR
" string ] Ident ";
" % curmodule := lookupDef (curident) %
1486 % enterScope (curmodule) %
1487 { Import } [ Export ]
1489 "END
" Ident "." % checkEndName (curmodule, curident, 'definition module') %
1493 PushQualident := % VAR type, field: node ; %
1494 Ident % qualid := push (lookupWithSym (curident)) %
1497 metaError1 ('the symbol {%1k} is not visible in this scope (or any other nested scope)', curident)
1500 % IF NOT isQualident (qualid)
1502 ErrorArray ('the first component of this qualident must be a definition module or a parameter/variable/constant which has record type')
1504 Ident % IF isDef (qualid)
1506 qualid := replace (lookupInScope (qualid, curident))
1508 type := skipType (getType (qualid)) ;
1509 field := lookupInScope (type, curident) ;
1512 metaError2 ('field {%1k} cannot be found in {%2ad}', curident, qualid)
1514 qualid := replace (makeComponentRef (qualid, field))
1519 metaError1 ('qualified component of the identifier {%1k} cannot be found', curident)
1524 OptSubrange := [ SubrangeType ] =:
1526 TypeEquiv := Qualident OptSubrange =:
1528 EnumIdentList := Ident { ",
" Ident } =:
1530 Enumeration := "(" EnumIdentList ")" =:
1532 SimpleType := TypeEquiv | Enumeration | SubrangeType =:
1534 Type := SimpleType | ArrayType | RecordType | SetType |
1535 PointerType | ProcedureType
1538 TypeDeclaration := { Ident ( ";
" | "=" Type Alignment ";
" ) }
1541 Definition := "CONST
" { ConstantDeclaration ";
" } |
1542 "TYPE
" { TypeDeclaration } |
1543 "VAR
" { VariableDeclaration ";
" } |
1544 DefProcedureHeading ";
" =:
1546 AsmStatement := % VAR s: node ; %
1547 % s := pushStmt (makeComment ("asm
")) %
1548 'ASM' [ 'VOLATILE' ] '(' AsmOperands ')' =:
1550 AsmOperands := string [ AsmOperandSpec ]
1553 AsmOperandSpec := [ ':' AsmList [ ':' AsmList [ ':' TrashList ] ] ]
1556 AsmList := [ AsmElement ] { ',' AsmElement } =:
1558 NamedOperand := '[' Ident ']' =:
1560 AsmOperandName := [ NamedOperand ]
1563 AsmElement := AsmOperandName string '(' Expression ')'
1566 TrashList := [ string ] { ',' string } =: