2 -- m2-3.bnf grammar and associated actions for pass 3.
4 -- Copyright (C) 2001-2021 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 COPYING3. If not see
21 -- <http://www.gnu.org/licenses/>.
22 % module P3Build begin
23 (* output from m2-3.bnf, automatically generated do not edit if these
24 are the top two lines in the file.
26 Copyright (C) 2001-2021 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 P3Build ;
47 FROM M2LexBuf IMPORT currentstring, currenttoken, GetToken, InsertToken,
48 InsertTokenAndRewind, GetTokenNo, PrintTokenNo, MakeVirtualTok,
51 FROM M2Error IMPORT ErrorStringAt, WriteFormat1, WriteFormat2 ;
52 FROM NameKey IMPORT NulName, Name, makekey ;
53 FROM DynamicStrings IMPORT String, InitString, KillString, Mark, ConCat, ConCatChar ;
54 FROM M2Printf IMPORT printf0, printf1 ;
55 FROM M2Debug IMPORT Assert ;
56 FROM P2SymBuild IMPORT BuildString, BuildNumber ;
57 FROM M2MetaError IMPORT MetaErrorT0 ;
59 FROM M2Reserved IMPORT tokToTok, toktype,
60 NulTok, ImportTok, ExportTok, QualifiedTok, UnQualifiedTok,
61 EqualTok, HashTok, LessGreaterTok, LessTok, LessEqualTok,
62 GreaterTok, GreaterEqualTok, InTok, PlusTok, MinusTok,
63 OrTok, TimesTok, DivTok, DivideTok, ModTok, RemTok,
64 AndTok, AmbersandTok, PeriodPeriodTok, ByTok ;
66 FROM M2Quads IMPORT PushT, PopT, PushTF, PopTF, PopNothing, Annotate,
67 PushTtok, PushTFtok, PopTtok, PopTFtok, OperandTok,
69 StartBuildDefFile, StartBuildModFile,
83 BuildFunctionCall, BuildConstFunctionCall,
84 BuildBinaryOp, BuildUnaryOp, BuildRelOp, BuildNot,
85 BuildEmptySet, BuildInclRange, BuildInclBit,
86 BuildSetStart, BuildSetEnd,
87 PushLineNo, BuildSizeCheckStart,
88 BuildBuiltinConst, BuildBuiltinTypeInfo,
89 BuildAssignment, BuildAlignment,
90 BuildRepeat, BuildUntil,
91 BuildWhile, BuildDoWhile, BuildEndWhile,
92 BuildLoop, BuildExit, BuildEndLoop,
93 BuildThenIf, BuildElse, BuildEndIf,
94 BuildForToByDo, BuildPseudoBy, BuildEndFor,
95 BuildElsif1, BuildElsif2,
96 BuildProcedureCall, BuildReturn, BuildNulExpression,
98 StartBuildWith, EndBuildWith,
105 BuildCaseStartStatementSequence,
106 BuildCaseEndStatementSequence,
108 BuildCaseRange, BuildCaseEquality,
109 BuildConstructorStart,
111 SilentBuildConstructorStart,
112 NextConstructorField, BuildTypeForConstructor,
114 BeginVarient, EndVarient, ElseVarient,
115 BeginVarientList, EndVarientList,
118 BuildDesignatorRecord,
119 BuildDesignatorArray,
120 BuildDesignatorPointer,
121 BuildBooleanVariable,
126 AddVarientRange, AddVarientEquality,
127 BeginVarient, EndVarient, BeginVarientList, EndVarientList,
128 PushInConstExpression, PopInConstExpression, IsInConstExpression,
129 BuildDefaultFieldAlignment, BuildPragmaField,
130 IsAutoPushOn, PushAutoOff, PushAutoOn, PopAuto ;
132 FROM P3SymBuild IMPORT P3StartBuildProgModule,
133 P3EndBuildProgModule,
135 P3StartBuildDefModule,
138 P3StartBuildImpModule,
141 StartBuildInnerModule,
144 CheckImportListOuterModule,
147 BuildProcedureHeading,
153 BuildOptArgInitializer ;
155 FROM SymbolTable IMPORT MakeGnuAsm, PutGnuAsmVolatile, PutGnuAsm, PutGnuAsmInput,
156 PutGnuAsmOutput, PutGnuAsmTrash,
157 PutGnuAsmVolatile, PutGnuAsmSimple,
160 IsRegInterface, IsGnuAsmVolatile, IsGnuAsm,
161 GetSymName, GetType, SkipType,
163 StartScope, EndScope,
165 IsVarParam, IsProcedure, IsDefImp, IsModule, IsProcType,
167 RequestSym, IsExported,
168 GetSym, GetLocalSym ;
170 FROM M2Batch IMPORT IsModuleKnown ;
172 FROM M2CaseList IMPORT BeginCaseList, EndCaseList ;
178 Pass1 = FALSE ; (* permanently disabled for the time being *)
180 Pass3 = TRUE ; (* permanently disabled for the time being *)
184 WasNoError: BOOLEAN ;
187 PROCEDURE ErrorString (s: String) ;
189 ErrorStringAt(s, GetTokenNo ()) ;
194 PROCEDURE ErrorArray (a: ARRAY OF CHAR) ;
196 ErrorString(InitString(a))
200 % declaration P3Build begin
204 SyntaxError - after a syntax error we skip all tokens up until we reach
208 PROCEDURE SyntaxError (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ;
213 printf0('\nskipping token *** ')
215 (* --fixme-- this assumes a 32 bit word size. *)
216 WHILE NOT (((ORD(currenttoken)<32) AND (currenttoken IN stopset0)) OR
217 ((ORD(currenttoken)>=32) AND (ORD(currenttoken)<64) AND (currenttoken IN stopset1)) OR
218 ((ORD(currenttoken)>=64) AND (currenttoken IN stopset2)))
233 PROCEDURE SyntaxCheck (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ;
235 (* --fixme-- this assumes a 32 bit word size. *)
236 IF NOT (((ORD(currenttoken)<32) AND (currenttoken IN stopset0)) OR
237 ((ORD(currenttoken)>=32) AND (ORD(currenttoken)<64) AND (currenttoken IN stopset1)) OR
238 ((ORD(currenttoken)>=64) AND (currenttoken IN stopset2)))
240 SyntaxError(stopset0, stopset1, stopset2)
246 WarnMissingToken - generates a warning message about a missing token, t.
249 PROCEDURE WarnMissingToken (t: toktype) ;
268 str := DescribeStop(s0, s1, s2) ;
270 str := ConCat(InitString('syntax error,'), Mark(str)) ;
271 ErrorStringAt (str, GetTokenNo ())
272 END WarnMissingToken ;
276 MissingToken - generates a warning message about a missing token, t.
279 PROCEDURE MissingToken (t: toktype) ;
281 WarnMissingToken(t) ;
282 IF (t#identtok) AND (t#integertok) AND (t#realtok) AND (t#stringtok)
286 printf0('inserting token\n')
297 PROCEDURE CheckAndInsert (t: toktype; stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) : BOOLEAN ;
299 IF ((ORD(t)<32) AND (t IN stopset0)) OR
300 ((ORD(t)>=32) AND (ORD(t)<64) AND (t IN stopset1)) OR
301 ((ORD(t)>=64) AND (t IN stopset2))
303 WarnMissingToken(t) ;
304 InsertTokenAndRewind(t) ;
316 PROCEDURE InStopSet (t: toktype; stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) : BOOLEAN ;
318 IF ((ORD(t)<32) AND (t IN stopset0)) OR
319 ((ORD(t)>=32) AND (ORD(t)<64) AND (t IN stopset1)) OR
320 ((ORD(t)>=64) AND (t IN stopset2))
330 PeepToken - peep token checks to see whether the stopset is satisfied by currenttoken
331 If it is not then it will insert a token providing the token
332 is one of ; ] ) } . OF END ,
334 if the stopset contains <identtok> then we do not insert a token
337 PROCEDURE PeepToken (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ;
339 (* and again (see above re: ORD)
341 IF (NOT (((ORD(currenttoken)<32) AND (currenttoken IN stopset0)) OR
342 ((ORD(currenttoken)>=32) AND (ORD(currenttoken)<64) AND (currenttoken IN stopset1)) OR
343 ((ORD(currenttoken)>=64) AND (currenttoken IN stopset2)))) AND
344 (NOT InStopSet(identtok, stopset0, stopset1, stopset2))
346 (* SyntaxCheck would fail since currentoken is not part of the stopset
347 we check to see whether any of currenttoken might be a commonly omitted token *)
348 IF CheckAndInsert(semicolontok, stopset0, stopset1, stopset2) OR
349 CheckAndInsert(rsbratok, stopset0, stopset1, stopset2) OR
350 CheckAndInsert(rparatok, stopset0, stopset1, stopset2) OR
351 CheckAndInsert(rcbratok, stopset0, stopset1, stopset2) OR
352 CheckAndInsert(periodtok, stopset0, stopset1, stopset2) OR
353 CheckAndInsert(oftok, stopset0, stopset1, stopset2) OR
354 CheckAndInsert(endtok, stopset0, stopset1, stopset2) OR
355 CheckAndInsert(commatok, stopset0, stopset1, stopset2)
366 PROCEDURE Expect (t: toktype; stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ;
373 PeepToken(stopset0, stopset1, stopset2)
378 SyntaxCheck(stopset0, stopset1, stopset2)
383 CompilationUnit - returns TRUE if the input was correct enough to parse
387 PROCEDURE CompilationUnit () : BOOLEAN ;
390 FileUnit(SetOfStop0{eoftok}, SetOfStop1{}, SetOfStop2{}) ;
392 END CompilationUnit ;
396 Ident - error checking varient of Ident
399 PROCEDURE Ident (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ;
403 PushTFtok (makekey (currentstring), identtok, GetTokenNo ())
404 (* ; MetaErrorT0 (GetTokenNo(), "{%W}an ident") *)
406 Expect(identtok, stopset0, stopset1, stopset2)
414 PROCEDURE string (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ;
418 PushTFtok(makekey(currentstring), stringtok, GetTokenNo ()) ;
421 Expect(stringtok, stopset0, stopset1, stopset2)
429 PROCEDURE Integer (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ;
433 PushTFtok (makekey(currentstring), integertok, GetTokenNo ()) ;
436 Expect(integertok, stopset0, stopset1, stopset2)
444 PROCEDURE Real (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ;
448 PushTFtok (makekey(currentstring), realtok, GetTokenNo ()) ;
451 Expect(realtok, stopset0, stopset1, stopset2)
457 error 'ErrorArray' 'ErrorString'
458 tokenfunc 'currenttoken'
460 token '' eoftok -- internal token
465 token ':=' becomestok
466 token '&' ambersandtok
469 token ";" semicolontok
472 token '[' lsbratok -- left square brackets
473 token ']' rsbratok -- right square brackets
474 token '{' lcbratok -- left curly brackets
475 token '}' rcbratok -- right curly brackets
477 token "'" singlequotetok
482 token '<>' lessgreatertok
483 token '<=' lessequaltok
484 token '>=' greaterequaltok
485 token '<*' ldirectivetok
486 token '*>' rdirectivetok
487 token '..' periodperiodtok
489 token '"' doublequotestok
492 token 'ARRAY' arraytok
493 token 'BEGIN' begintok
496 token 'CONST' consttok
497 token 'DEFINITION' definitiontok
501 token 'ELSIF' elsiftok
503 token 'EXCEPT' excepttok
505 token 'EXPORT' exporttok
506 token 'FINALLY' finallytok
510 token 'IMPLEMENTATION' implementationtok
511 token 'IMPORT' importtok
515 token 'MODULE' moduletok
519 token 'PACKEDSET' packedsettok
520 token 'POINTER' pointertok
521 token 'PROCEDURE' proceduretok
522 token 'QUALIFIED' qualifiedtok
523 token 'UNQUALIFIED' unqualifiedtok
524 token 'RECORD' recordtok
526 token 'REPEAT' repeattok
527 token 'RETRY' retrytok
528 token 'RETURN' returntok
533 token 'UNTIL' untiltok
535 token 'WHILE' whiletok
538 token 'VOLATILE' volatiletok
539 token '...' periodperiodperiodtok
540 token '__DATE__' datetok
541 token '__LINE__' linetok
542 token '__FILE__' filetok
543 token '__ATTRIBUTE__' attributetok
544 token '__BUILTIN__' builtintok
545 token '__INLINE__' inlinetok
546 token 'integer number' integertok
547 token 'identifier' identtok
548 token 'real number' realtok
549 token 'string' stringtok
551 special Ident first { < identtok > } follow { }
552 special Integer first { < integertok > } follow { }
553 special Real first { < realtok > } follow { }
554 special string first { < stringtok > } follow { }
558 -- the following are provided by the module m2flex and also handbuild procedures below
559 -- Ident := Letter { ( Letter | Digit ) } =:
560 -- Integer := Digit { Digit } | OctalDigit { OctalDigit } ( " B " | " C " ) |
561 -- Digit { HexDigit } " H " =:
562 -- Real := Digit { Digit } " . " { Digit } [ ScaleFactor ] =:
563 -- ScaleFactor := " E " [ ( " + " | " - " ) ] Digit { Digit } =:
564 -- HexDigit := Digit | " A " | " B " | " C " | " D " | " E " | " F " =:
565 -- Digit := OctalDigit | " 8 " | " 9 " =:
566 -- OctalDigit := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" =:
569 FileUnit := % PushAutoOff %
571 ImplementationOrProgramModule ) % PopAuto %
574 ProgramModule := "MODULE" % M2Error.DefaultProgramModule %
576 Ident % P3StartBuildProgModule %
577 % StartBuildModFile %
585 Ident % EndBuildFile %
586 % P3EndBuildProgModule %
587 "." % PopAuto ; PopAuto %
590 ImplementationModule := "IMPLEMENTATION" % M2Error.DefaultImplementationModule %
591 "MODULE" % PushAutoOn %
592 Ident % StartBuildModFile %
593 % P3StartBuildImpModule %
601 Ident % EndBuildFile %
602 % P3EndBuildImpModule %
603 "." % PopAuto ; PopAuto ; PopAuto %
606 ImplementationOrProgramModule := % PushAutoOff %
607 ( ImplementationModule | ProgramModule ) % PopAuto %
610 Number := Integer | Real =:
613 -- In pass 3 Qualident needs some care as we must only parse module.module.ident
614 -- and not ident.recordfield. We leave the ident.recordfield to be parsed by
615 -- SubDesignator. Note that Qualident is called by SubDesignator so if
616 -- IsAutoPushOff then we just consume tokens.
619 Qualident := % VAR name : Name ;
621 tokstart, tok : CARDINAL ; %
625 PopTtok(name, tokstart) ;
627 init := RequestSym (tok, name) ;
628 WHILE IsDefImp (init) OR IsModule (init) DO
629 Expect (periodtok, stopset0, stopset1, stopset2 + SetOfStop2{identtok}) ;
631 Ident (stopset0, stopset1, stopset2) ;
632 PopTtok (name, tok) ;
633 ip1 := RequestSym (tok, name) ;
636 CheckCanBeImported(init, ip1) ;
641 tok := MakeVirtualTok (tokstart, tokstart, tok)
643 IF IsProcedure(init) OR IsProcType(init)
647 PushTFtok(init, GetType(init), tok) ;
650 { "." Ident } % END %
653 ConstantDeclaration := % VAR tokno: CARDINAL ; %
655 ( Ident "=" % tokno := GetTokenNo () -1 %
657 ConstExpression ) % BuildAssignment (tokno) %
661 ConstExpression := % VAR tokpos: CARDINAL ; %
663 SimpleConstExpr [ Relation % tokpos := GetTokenNo ()-1 %
664 SimpleConstExpr % BuildRelOp (tokpos) %
668 Relation := "=" % PushTtok(EqualTok, GetTokenNo() -1) %
669 | "#" % PushTtok(HashTok, GetTokenNo() -1) %
670 | "<>" % PushTtok(LessGreaterTok, GetTokenNo() -1) %
671 | "<" % PushTtok(LessTok, GetTokenNo() -1) %
672 | "<=" % PushTtok(LessEqualTok, GetTokenNo() -1) %
673 | ">" % PushTtok(GreaterTok, GetTokenNo() -1) %
674 | ">=" % PushTtok(GreaterEqualTok, GetTokenNo() -1) %
675 | "IN" % PushTtok(InTok, GetTokenNo() -1) %
678 SimpleConstExpr := UnaryOrConstTerm { AddOperator ConstTerm % BuildBinaryOp %
681 UnaryOrConstTerm := "+" % PushTtok(PlusTok, GetTokenNo() -1) %
682 ConstTerm % BuildUnaryOp %
684 "-" % PushTtok(MinusTok, GetTokenNo() -1) %
685 ConstTerm % BuildUnaryOp %
689 AddOperator := "+" % PushTtok(PlusTok, GetTokenNo() -1) ;
691 | "-" % PushTtok(MinusTok, GetTokenNo() -1) ;
693 | "OR" % PushTtok(OrTok, GetTokenNo() -1) ;
697 ConstTerm := ConstFactor { MulOperator ConstFactor % BuildBinaryOp %
700 MulOperator := "*" % PushTtok(TimesTok, GetTokenNo() -1) ;
702 | "/" % PushTtok(DivideTok, GetTokenNo() -1) ;
704 | "DIV" % PushTtok(DivTok, GetTokenNo() -1) ;
706 | "MOD" % PushTtok(ModTok, GetTokenNo() -1) ;
708 | "REM" % PushTtok(RemTok, GetTokenNo() -1) ;
710 | "AND" % PushTtok(AndTok, GetTokenNo() -1) ;
712 | "&" % PushTtok(AmbersandTok, GetTokenNo() -1) ;
716 ConstFactor := Number | ConstString | ConstSetOrQualidentOrFunction |
717 "(" ConstExpression ")" | "NOT" ConstFactor % BuildNot %
720 -- to help satisfy LL1
722 ConstString := string =:
724 ComponentElement := ConstExpression ( ".." ConstExpression % PushT(PeriodPeriodTok) %
729 ComponentValue := ComponentElement ( 'BY' ConstExpression % PushT(ByTok) %
735 ArraySetRecordValue := ComponentValue % BuildComponentValue %
736 { ',' % NextConstructorField %
737 ComponentValue % BuildComponentValue %
741 Constructor := '{' % BuildConstructorStart %
742 [ ArraySetRecordValue ] % BuildConstructorEnd %
745 ConstSetOrQualidentOrFunction := Qualident
746 [ Constructor | ConstActualParameters % BuildConstFunctionCall %
748 | % BuildTypeForConstructor %
751 ConstActualParameters := % PushInConstExpression %
752 ActualParameters % PopInConstExpression %
755 ConstAttribute := "__ATTRIBUTE__" "__BUILTIN__" "(" "(" % PushAutoOn %
756 ConstAttributeExpression % PopAuto %
759 ConstAttributeExpression :=
760 Ident % BuildBuiltinConst %
761 | "<" Qualident ',' Ident % BuildBuiltinTypeInfo %
765 ByteAlignment := '<*' % PushAutoOn %
766 AttributeExpression % BuildAlignment %
770 Alignment := [ ByteAlignment ] =:
772 TypeDeclaration := Ident "=" Type Alignment
777 ( SimpleType | ArrayType
781 | ProcedureType ) % PopAuto %
784 SimpleType := Qualident [ SubrangeType ] | Enumeration | SubrangeType =:
792 IdentList := Ident % VAR
795 % on := IsAutoPushOn() ;
810 SubrangeType := "[" ConstExpression ".." ConstExpression "]" % BuildSubrange ; %
822 RecordType := "RECORD" [ DefaultRecordAttributes ] FieldListSequence "END" =:
824 DefaultRecordAttributes := '<*' % PushAutoOn %
825 AttributeExpression % BuildDefaultFieldAlignment %
829 RecordFieldPragma := [ '<*' FieldPragmaExpression
830 { ',' FieldPragmaExpression } '*>' ] =:
832 FieldPragmaExpression := % PushAutoOn %
833 Ident PragmaConstExpression % BuildPragmaField %
837 PragmaConstExpression := ( '(' ConstExpression ')' | % PushT(NulSym) %
838 % Annotate('NulSym||no pragma const') %
841 AttributeExpression := Ident '(' ConstExpression ')' =:
843 FieldListSequence := FieldListStatement { ";" FieldListStatement } =:
845 -- at present FieldListStatement is as follows:
846 FieldListStatement := [ FieldList ] =:
847 -- later replace it with FieldList to comply with PIM2
849 -- sadly the PIM rules are not LL1 as Ident and Qualident have the same first
850 -- symbols. We rewrite FieldList to inline qualident
852 -- FieldList := IdentList ":" % BuildNulName %
854 -- "CASE" [ Ident ":" ] Qualident "OF" Varient { "|" Varient }
855 -- [ "ELSE" FieldListSequence ] "END" =:
857 FieldList := IdentList ":"
858 Type RecordFieldPragma
860 "CASE" % BeginVarient %
862 Varient { "|" Varient }
863 [ "ELSE" % ElseVarient %
865 ] "END" % EndVarient %
868 TagIdent := [ Ident ] =:
870 CaseTag := TagIdent [":" Qualident ] =:
872 Varient := [ % BeginVarientList %
873 VarientCaseLabelList ":" FieldListSequence % EndVarientList %
876 VarientCaseLabelList := VarientCaseLabels { "," VarientCaseLabels } =:
878 VarientCaseLabels := ConstExpression ( ".." ConstExpression % AddVarientRange %
879 | % AddVarientEquality ; (* epsilon *) %
884 -- the following rules are a copy of the ConstExpression ebnf rules but without
885 -- any actions all prefixed with Silent.
886 -- At present they are only used by CaseLabels, if this continues to be true we
887 -- might consider restricting the SilentConstExpression. Eg it makes no sence to allow
888 -- String in these circumstances!
891 SilentConstExpression := % PushAutoOff %
892 SilentSimpleConstExpr
893 [ SilentRelation SilentSimpleConstExpr ] % PopAuto %
896 SilentRelation := "=" | "#" | "<>" | "<" | "<=" | ">" | ">=" | "IN" =:
898 SilentSimpleConstExpr := SilentUnaryOrConstTerm { SilentAddOperator SilentConstTerm } =:
900 SilentUnaryOrConstTerm := "+" SilentConstTerm | "-" SilentConstTerm | SilentConstTerm =:
902 SilentAddOperator := "+" | "-" | "OR" =:
904 SilentConstTerm := SilentConstFactor { SilentMulOperator SilentConstFactor } =:
906 SilentMulOperator := "*" | "/" | "DIV" | "MOD" | "REM" | "AND" | "&" =:
908 SilentConstFactor := Number | SilentConstString | SilentConstSetOrQualidentOrFunction |
909 "(" SilentConstExpression ")" | "NOT" SilentConstFactor
910 | SilentConstAttribute =:
912 SilentConstString := string =:
914 SilentConstAttribute := "__ATTRIBUTE__" "__BUILTIN__" "(" "(" SilentConstAttributeExpression ")" ")" =:
916 SilentConstAttributeExpression := Ident | "<" Ident ',' SilentConstString ">" =:
918 SilentComponentElement := SilentConstExpression [ ".." SilentConstExpression ] =:
920 SilentComponentValue := SilentComponentElement [ 'BY' SilentConstExpression ] =:
922 SilentArraySetRecordValue := SilentComponentValue { ',' SilentComponentValue } =:
924 SilentConstructor := '{' % SilentBuildConstructorStart %
925 [ SilentArraySetRecordValue ] '}' =:
927 SilentConstSetOrQualidentOrFunction := SilentConstructor | Qualident
928 [ SilentConstructor | SilentActualParameters ] =:
930 SilentActualParameters := "(" [ SilentExpList ] ")" =:
932 SilentExpList := SilentConstExpression { "," SilentConstExpression } =:
934 -- end of the Silent constant rules
936 SetType := ( "SET" | "PACKEDSET" ) "OF" SimpleType =:
938 PointerType := "POINTER" "TO"
942 ProcedureType := "PROCEDURE"
943 [ FormalTypeList ] =:
945 FormalTypeList := "(" ( ")" FormalReturn |
946 ProcedureParameters ")" FormalReturn ) =:
948 FormalReturn := [ ":" OptReturnType ] =:
950 OptReturnType := "[" Qualident "]" | Qualident =:
952 ProcedureParameters := ProcedureParameter
953 { "," ProcedureParameter } =:
955 ProcedureParameter := "..." | "VAR" FormalType | FormalType =:
959 Sym, Type: CARDINAL ;
961 % on := IsAutoPushOn() %
972 [ "[" ConstExpression % BuildVarAtAddress %
978 VarIdentList := VarIdent % VAR
981 % on := IsAutoPushOn() ;
986 { "," VarIdent % IF on
996 VariableDeclaration := VarIdentList ":"
1000 Designator := Qualident % CheckWithReference %
1001 { SubDesignator } =:
1003 SubDesignator := "." % VAR Sym, Type, tok,
1004 dotpostok : CARDINAL ;
1006 % dotpostok := GetTokenNo () -1 ;
1007 PopTFtok (Sym, Type, tok) ;
1008 Type := SkipType(Type) ;
1009 PushTFtok(Sym, Type, tok) ;
1012 n1 := GetSymName(Sym) ;
1013 IF IsModuleKnown(GetSymName(Sym))
1015 WriteFormat2('%a looks like a module which has not been globally imported (eg. suggest that you IMPORT %a ;)',
1018 WriteFormat1('%a is not a record variable', n1)
1020 ELSIF NOT IsRecord(Type)
1022 n1 := GetSymName(Type) ;
1023 WriteFormat1('%a is not a record type', n1)
1027 % PopTtok (name, tok) ;
1028 Sym := GetLocalSym(Type, name) ;
1031 n1 := GetSymName(Type) ;
1032 WriteFormat2('field %a does not exist within record %a', name, n1)
1034 Type := GetType(Sym) ;
1035 PushTFtok (Sym, Type, tok) ;
1038 BuildDesignatorRecord (dotpostok) %
1041 | "^" % BuildDesignatorPointer (GetTokenNo () -1) %
1045 Expression % BuildBooleanVariable %
1046 % BuildDesignatorArray %
1048 Expression % BuildBooleanVariable %
1049 % BuildDesignatorArray %
1053 ExpList := % VAR n: CARDINAL ; %
1054 Expression % BuildBooleanVariable %
1057 Expression % BuildBooleanVariable %
1063 Expression := % VAR tokpos: CARDINAL ; %
1065 SimpleExpression [ Relation % tokpos := GetTokenNo ()-1 %
1066 SimpleExpression % BuildRelOp (tokpos) %
1070 SimpleExpression := UnaryOrTerm { AddOperator Term % BuildBinaryOp %
1073 UnaryOrTerm := "+" % PushTtok(PlusTok, GetTokenNo() -1) %
1074 Term % BuildUnaryOp %
1075 | "-" % PushTtok(MinusTok, GetTokenNo() -1) %
1076 Term % BuildUnaryOp %
1079 Term := Factor { MulOperator Factor % BuildBinaryOp %
1082 Factor := Number | string | SetOrDesignatorOrFunction |
1083 "(" Expression ")" | "NOT" ( Factor % BuildNot %
1087 SetOrDesignatorOrFunction := Qualident
1088 % Assert (OperandTok(1) # UnknownTokenNo) %
1089 % CheckWithReference %
1090 % Assert (OperandTok(1) # UnknownTokenNo) %
1092 SimpleDes % (* Assert (OperandTok(1) # UnknownTokenNo) *) %
1093 [ ActualParameters % IF IsInConstExpression()
1095 BuildConstFunctionCall
1101 % BuildTypeForConstructor %
1104 -- SimpleDes := { "." Ident | "[" ExpList "]" | "^" } =:
1105 SimpleDes := { SubDesignator } =:
1107 ActualParameters := "(" % BuildSizeCheckStart %
1108 ( ExpList | % BuildNulParam %
1111 ExitStatement := "EXIT" % BuildExit %
1114 ReturnStatement := "RETURN" % VAR tokno: CARDINAL ; %
1115 % tokno := GetTokenNo () -1 %
1116 ( Expression | % BuildNulExpression (* in epsilon *) %
1117 ) % BuildReturn (tokno) %
1120 Statement := % BuildStmtNote (0) %
1121 % PushAutoOn ; DisplayStack %
1122 [ AssignmentOrProcedureCall | IfStatement | CaseStatement |
1123 WhileStatement | RepeatStatement | LoopStatement |
1124 ForStatement | WithStatement | AsmStatement |
1125 ExitStatement | ReturnStatement | RetryStatement
1129 RetryStatement := "RETRY" % BuildRetry %
1132 AssignmentOrProcedureCall := % VAR isFunc: BOOLEAN ;
1133 tokno : CARDINAL ; %
1136 % tokno := GetTokenNo () %
1138 % (* PrintTokenNo (tokno) *) %
1139 Expression % BuildAssignment (tokno) %
1140 | % isFunc := CheckBuildFunction() %
1141 ( ActualParameters | % BuildNulParam (* in epsilon *) %
1145 BuildAssignment (tokno)
1147 BuildProcedureCall (tokno - 1)
1152 -- these two break LL1 as both start with a Designator
1153 -- ProcedureCall := Designator [ ActualParameters ] =:
1154 -- Assignment := Designator ":=" Expression =:
1156 StatementSequence :=
1164 "THEN" % BuildThenIf %
1165 % BuildStmtNote (-1) %
1169 % BuildStmtNote (-1) %
1171 "THEN" % BuildThenIf %
1172 % BuildStmtNote (-1) %
1173 StatementSequence % BuildElsif2 %
1176 "ELSE" % BuildElse %
1177 % BuildStmtNote (-1) %
1178 StatementSequence ] "END" % BuildEndIf %
1179 % BuildStmtNote (-1) %
1182 CaseStatement := "CASE"
1183 Expression % BuildCaseStart %
1184 "OF" Case { "|" Case }
1188 CaseEndStatement := "END" % BuildStmtNote (-1) %
1192 | "ELSE" % BuildStmtNote (-1) %
1194 StatementSequence % BuildStmtNote (0) %
1199 Case := [ % BuildStmtNote (-1) %
1200 CaseLabelList % BuildCaseStartStatementSequence %
1202 StatementSequence % BuildCaseEndStatementSequence %
1207 CaseLabelList := % BeginCaseList(NulSym) %
1208 CaseLabels { "," % BuildCaseOr %
1211 CaseLabels := ConstExpression ( ".." ConstExpression % BuildCaseRange ;
1213 | % BuildCaseEquality ; (* epsilon *)
1217 WhileStatement := "WHILE" % BuildWhile %
1218 % BuildStmtNote (0) %
1220 % BuildStmtNote (0) %
1221 "DO" % BuildDoWhile %
1222 StatementSequence % BuildStmtNote (0) %
1223 "END" % DisplayStack ; BuildEndWhile %
1226 RepeatStatement := "REPEAT"
1228 StatementSequence % BuildStmtNote (0) %
1230 Expression % BuildUntil %
1233 ForStatement := % VAR endpostok: CARDINAL ; %
1235 "FOR" Ident ":=" Expression "TO" Expression
1236 ( "BY" ConstExpression | % BuildPseudoBy (* epsilon *) %
1238 % BuildStmtNote (0) %
1239 "DO" % BuildForToByDo %
1240 StatementSequence % BuildStmtNote (0) %
1241 % endpostok := GetTokenNo () %
1242 "END" % BuildEndFor (endpostok) %
1245 LoopStatement := "LOOP"
1247 StatementSequence % BuildStmtNote (0) %
1248 "END" % BuildEndLoop %
1251 WithStatement := "WITH"
1252 Designator % StartBuildWith %
1255 % BuildStmtNote (0) %
1256 "END" % EndBuildWith %
1259 ProcedureDeclaration := ProcedureHeading ";" ProcedureBlock % BuildProcedureEnd ;
1262 Ident % EndBuildProcedure ;
1266 DefineBuiltinProcedure := [ "__ATTRIBUTE__" "__BUILTIN__"
1267 "(" "(" % PushAutoOff %
1269 ")" ")" | "__INLINE__" ]
1272 ProcedureHeading := "PROCEDURE" % M2Error.DefaultProcedure %
1274 DefineBuiltinProcedure
1276 % StartBuildProcedure ;
1278 [ FormalParameters ] AttributeNoReturn
1279 % BuildProcedureHeading ;
1284 Builtin := [ "__BUILTIN__" | "__INLINE__" ] =:
1286 DefProcedureHeading := "PROCEDURE" % M2Error.DefaultProcedure %
1290 % StartBuildProcedure ;
1292 [ DefFormalParameters ] AttributeNoReturn
1293 % BuildProcedureHeading ;
1296 % M2Error.LeaveErrorScope %
1299 AttributeNoReturn := [ "<*" Ident "*>" ] =:
1301 -- introduced procedure block so we can produce more informative
1304 ProcedureBlock := % BuildProcedureStart %
1305 { Declaration } % BuildProcedureBegin %
1306 [ "BEGIN" % BuildStmtNote (-1) %
1307 ProcedureBlockBody ] % BuildStmtNote (0) %
1311 Block := { Declaration } % StartBuildInit %
1312 InitialBlock % EndBuildInit ;
1314 FinalBlock % EndBuildFinally %
1318 InitialBlock := [ "BEGIN" % BuildStmtNote (-1) %
1319 InitialBlockBody ] =:
1321 FinalBlock := [ "FINALLY" % BuildStmtNote (-1) %
1324 InitialBlockBody := NormalPart [
1325 "EXCEPT" % BuildStmtNote (-1) %
1326 % BuildExceptInitial %
1327 ExceptionalPart ] =:
1329 FinalBlockBody := NormalPart [
1330 "EXCEPT" % BuildStmtNote (-1) %
1331 % BuildExceptFinally %
1332 ExceptionalPart ] =:
1334 ProcedureBlockBody := NormalPart [
1335 "EXCEPT" % BuildStmtNote (-1) %
1336 % BuildExceptProcedure %
1337 ExceptionalPart ] =:
1339 NormalPart := StatementSequence =:
1341 ExceptionalPart := StatementSequence % BuildReThrow (GetTokenNo()) %
1344 Declaration := "CONST" { ConstantDeclaration ";" } |
1345 "TYPE" { TypeDeclaration ";" } |
1346 "VAR" { VariableDeclaration ";" } |
1347 ProcedureDeclaration ";" |
1348 ModuleDeclaration ";" =:
1350 DefFormalParameters := "(" [ DefMultiFPSection ] ")" FormalReturn =:
1352 DefMultiFPSection := DefExtendedFP |
1353 FPSection [ ";" DefMultiFPSection ] =:
1355 FormalParameters := "(" [ MultiFPSection ] ")" FormalReturn =:
1357 MultiFPSection := ExtendedFP |
1358 FPSection [ ";" MultiFPSection ] =:
1360 FPSection := NonVarFPSection | VarFPSection =:
1362 DefExtendedFP := DefOptArg | "..." =:
1364 ExtendedFP := OptArg | "..." =:
1366 VarFPSection := "VAR" IdentList ":" FormalType =:
1368 NonVarFPSection := IdentList ":" FormalType =:
1370 OptArg := "[" Ident ":" FormalType [ "=" ConstExpression % BuildOptArgInitializer %
1373 DefOptArg := "[" Ident ":" FormalType "=" ConstExpression % BuildOptArgInitializer %
1376 FormalType := { "ARRAY" "OF" } Qualident =:
1378 ModuleDeclaration := "MODULE" % M2Error.DefaultInnerModule %
1380 Ident % StartBuildInnerModule %
1381 % BuildModuleStart ;
1384 { Import } [ Export ]
1385 Block % PushAutoOn %
1386 Ident % EndBuildInnerModule %
1387 % PopAuto ; PopAuto ; PopAuto %
1390 Priority := "[" % PushAutoOn %
1391 ConstExpression % BuildModulePriority ;
1395 Export := "EXPORT" ( "QUALIFIED"
1401 FromImport := % PushAutoOn %
1402 "FROM" Ident "IMPORT" IdentList ";" % CheckImportListOuterModule %
1406 WithoutFromImport := % PushAutoOff %
1407 "IMPORT" IdentList ";"
1411 Import := FromImport | WithoutFromImport =:
1413 DefinitionModule := "DEFINITION" % M2Error.DefaultDefinitionModule %
1414 "MODULE" % PushAutoOn %
1416 Ident % StartBuildDefFile ;
1417 P3StartBuildDefModule ;
1423 "END" % PushAutoOn %
1424 Ident % EndBuildFile ;
1425 P3EndBuildDefModule %
1426 "." % PopAuto ; PopAuto ; PopAuto %
1429 Definition := "CONST" { ConstantDeclaration ";" } |
1432 | "=" Type Alignment ";" )
1435 "VAR" { VariableDeclaration ";" } |
1436 DefProcedureHeading ";" =:
1438 AsmStatement := % VAR CurrentAsm: CARDINAL ; %
1442 PushT(0) ; (* operand count *)
1446 [ 'VOLATILE' % IF Pass3
1449 PutGnuAsmVolatile(CurrentAsm) ;
1453 ] '(' AsmOperands % IF Pass3
1455 PopNothing ; (* throw away interface sym *)
1457 PopNothing ; (* throw away count *)
1463 AsmOperands := % VAR CurrentAsm, count: CARDINAL ;
1470 Assert(IsGnuAsm(CurrentAsm) OR IsGnuAsmVolatile(CurrentAsm)) ;
1474 printf1('1: count of asm operands: %d\n', count)
1477 (* adds the name/instruction for this asm *)
1478 PutGnuAsm(CurrentAsm, str) ;
1480 PushT(NulSym) (* the InterfaceSym *)
1483 ( AsmOperandSpec | % (* epsilon *)
1486 PutGnuAsmSimple(CurrentAsm)
1492 AsmOperandSpec := % VAR CurrentAsm, outputs, inputs, trash, count: CARDINAL ;
1494 [ ':' AsmList % IF Pass3
1498 Assert(IsGnuAsm(CurrentAsm) OR IsGnuAsmVolatile(CurrentAsm)) ;
1502 printf1('2: output count of asm operands: %d\n', count)
1504 PutGnuAsmOutput(CurrentAsm, outputs) ;
1505 PushT(0) ; (* reset count *)
1507 PushT(NulSym) (* the InterfaceSym *)
1510 [ ':' AsmList % IF Pass3
1514 Assert(IsGnuAsm(CurrentAsm) OR IsGnuAsmVolatile(CurrentAsm)) ;
1518 printf1('3: input count of asm operands: %d\n', count)
1520 PutGnuAsmInput(CurrentAsm, inputs) ;
1521 PushT(0) ; (* reset count *)
1523 PushT(NulSym) (* the InterfaceSym *)
1526 [ ':' TrashList % IF Pass3
1530 Assert(IsGnuAsm(CurrentAsm) OR IsGnuAsmVolatile(CurrentAsm)) ;
1534 printf1('4: trash count of asm operands: %d\n', count)
1536 PutGnuAsmTrash(CurrentAsm, trash) ;
1537 PushT(0) ; (* reset count *)
1539 PushT(NulSym) (* the InterfaceSym *)
1545 AsmList := % VAR count, CurrentAsm, CurrentInterface: CARDINAL ; %
1548 PopT(CurrentInterface) ;
1551 Assert(IsGnuAsm(CurrentAsm) OR IsGnuAsmVolatile(CurrentAsm)) ;
1554 PushT(CurrentInterface) ;
1557 printf1('8: AsmList has a count of asm operands: %d\n', count)
1561 [ AsmElement ] { ',' AsmElement } =:
1563 NamedOperand := '[' Ident ']' =:
1565 AsmOperandName := ( NamedOperand
1566 | % IF IsAutoPushOn()
1568 PushTF(NulName, identtok)
1574 AsmElement := % VAR n, str, expr,
1576 CurrentAsm, name: CARDINAL ; %
1579 string '(' Expression % IF Pass3
1584 PopT(CurrentInterface) ;
1586 Assert(IsGnuAsm(CurrentAsm) OR IsGnuAsmVolatile(CurrentAsm)) ;
1589 IF CurrentInterface=NulSym
1591 CurrentInterface := MakeRegInterface()
1595 printf1('5: count of asm operands: %d\n', n)
1597 PutRegInterface(CurrentInterface, n, name, str, expr) ;
1600 PushT(CurrentInterface)
1606 TrashList := % VAR CurrentInterface,
1608 n, str : CARDINAL ; %
1612 PopT(CurrentInterface) ;
1616 Assert(IsGnuAsm(CurrentAsm) OR IsGnuAsmVolatile(CurrentAsm)) ;
1619 printf1('6: count of asm trash operands: %d\n', n)
1621 IF CurrentInterface=NulSym
1623 CurrentInterface := MakeRegInterface()
1625 PutRegInterface(CurrentInterface, n, NulName, str, NulSym) ;
1628 PushT(CurrentInterface)
1631 ] { ',' string % IF Pass3
1634 PopT(CurrentInterface) ;
1638 Assert(IsGnuAsm(CurrentAsm) OR IsGnuAsmVolatile(CurrentAsm)) ;
1641 printf1('7: count of asm trash operands: %d\n', n)
1643 IF CurrentInterface=NulSym
1645 CurrentInterface := MakeRegInterface()
1647 PutRegInterface(CurrentInterface, n, NulName, str, NulSym) ;
1650 PushT(CurrentInterface)