| -- |
| -- m2-2.bnf grammar and associated actions for pass 2. |
| -- |
| -- Copyright (C) 2001-2025 Free Software Foundation, Inc. |
| -- Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>. |
| -- |
| -- This file is part of GNU Modula-2. |
| -- |
| -- GNU Modula-2 is free software; you can redistribute it and/or modify |
| -- it under the terms of the GNU General Public License as published by |
| -- the Free Software Foundation; either version 3, or (at your option) |
| -- any later version. |
| -- |
| -- GNU Modula-2 is distributed in the hope that it will be useful, but |
| -- WITHOUT ANY WARRANTY; without even the implied warranty of |
| -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| -- General Public License for more details. |
| -- |
| -- You should have received a copy of the GNU General Public License |
| -- along with GNU Modula-2; see the file COPYING3. If not see |
| -- <http://www.gnu.org/licenses/>. |
| % module P2Build begin |
| (* output from m2-2.bnf, automatically generated do not edit if these |
| are the top two lines in the file. |
| |
| Copyright (C) 2001-2025 Free Software Foundation, Inc. |
| Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>. |
| |
| This file is part of GNU Modula-2. |
| |
| GNU Modula-2 is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GNU Modula-2 is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Modula-2; see the file COPYING. If not, |
| see <https://www.gnu.org/licenses/>. *) |
| |
| |
| IMPLEMENTATION MODULE P2Build ; |
| |
| FROM M2LexBuf IMPORT currentstring, currenttoken, GetToken, InsertToken, |
| InsertTokenAndRewind, GetTokenNo, MakeVirtual2Tok, |
| MakeVirtualTok ; |
| |
| FROM M2MetaError IMPORT MetaErrorStringT0, MetaErrorT1 ; |
| FROM NameKey IMPORT NulName, Name, makekey, MakeKey ; |
| FROM M2Reserved IMPORT tokToTok, toktype, NulTok, ImportTok, ExportTok, QualifiedTok, UnQualifiedTok ; |
| FROM DynamicStrings IMPORT String, InitString, KillString, Mark, ConCat, ConCatChar ; |
| FROM M2Printf IMPORT printf0 ; |
| FROM M2Debug IMPORT Assert ; |
| |
| FROM M2Quads IMPORT PushT, PopT, PushTF, PopTF, PopNothing, OperandT, PushTFA, Top, Annotate, |
| OperandTok, |
| PushTFtok, PopTFtok, PushTFAtok, PopTtok, PushTtok, |
| StartBuildInit, |
| EndBuildInit, |
| BuildProcedureStart, |
| BuildProcedureEnd, |
| BuildAssignment, |
| AddRecordToList, AddVarientToList, |
| IsAutoPushOn, PushAutoOff, PushAutoOn, PopAuto, DisplayStack ; |
| |
| FROM P2SymBuild IMPORT P2StartBuildProgramModule, |
| P2EndBuildProgramModule, |
| P2StartBuildDefModule, |
| P2EndBuildDefModule, |
| P2StartBuildImplementationModule, |
| P2EndBuildImplementationModule, |
| StartBuildInnerModule, |
| EndBuildInnerModule, |
| |
| BuildImportOuterModule, |
| BuildImportInnerModule, |
| BuildExportOuterModule, |
| BuildExportInnerModule, |
| |
| BlockStart, BlockEnd, BlockBegin, BlockFinally, |
| BuildString, BuildNumber, |
| BuildConst, |
| BuildVariable, |
| BuildTypeEnd, |
| BuildNulName, |
| BuildType, |
| StartBuildEnumeration, |
| |
| StartBuildFormalParameters, |
| EndBuildFormalParameters, |
| BuildFPSection, |
| BuildVarArgs, |
| BuildOptArg, |
| BuildFormalVarArgs, |
| BuildProcedureHeading, |
| StartBuildProcedure, |
| EndBuildProcedure, |
| BuildFunction, BuildOptFunction, |
| BuildNoReturnAttribute, |
| EndBuildForward, |
| |
| BuildPointerType, |
| BuildRecord, BuildFieldRecord, |
| StartBuildVarient, EndBuildVarient, |
| BuildVarientSelector, |
| StartBuildVarientFieldRecord, |
| EndBuildVarientFieldRecord, |
| StartBuildArray, |
| EndBuildArray, |
| BuildFieldArray, BuildArrayComma, |
| BuildSubrange, BuildAligned, |
| BuildTypeAlignment, BuildVarAlignment, |
| P2BuildDefaultFieldAlignment, BuildPragmaConst, |
| BuildSetType, |
| BuildFormalType, BuildFunction, BuildProcedureType, |
| DetermineType, PushType, PopType, |
| SeenUnknown, SeenSet, SeenString, SeenArray, SeenConstructor, |
| SeenCast, |
| PushRememberConstant, PopRememberConstant, |
| CheckProcedure ; |
| |
| FROM M2Reserved IMPORT ArrayTok, VarTok ; |
| |
| FROM SymbolTable IMPORT MakeGnuAsm, PutGnuAsmVolatile, PutGnuAsm, PutGnuAsmInput, |
| PutGnuAsmOutput, PutGnuAsmTrash, PutGnuAsmVolatile, |
| MakeRegInterface, |
| PutRegInterface, GetRegInterface, |
| GetSymName, GetType, MakeConstLit, IsProcType, |
| NulSym, |
| StartScope, EndScope, GetCurrentModule, |
| PutIncluded, |
| PutExceptionFinally, PutExceptionBlock, GetCurrentScope, |
| IsVarParam, IsProcedure, IsDefImp, IsModule, |
| IsRecord, IsAModula2Type, IsImported, |
| RequestSym ; |
| |
| IMPORT M2Error ; |
| |
| |
| CONST |
| Debugging = FALSE ; |
| Pass1 = FALSE ; (* permanently disabled for the time being *) |
| Pass2 = TRUE ; |
| Pass3 = FALSE ; (* permanently disabled for the time being *) |
| |
| VAR |
| WasNoError: BOOLEAN ; |
| |
| |
| PROCEDURE ErrorString (s: String) ; |
| BEGIN |
| MetaErrorStringT0 (GetTokenNo (), s) ; |
| WasNoError := FALSE |
| END ErrorString ; |
| |
| |
| PROCEDURE ErrorArray (a: ARRAY OF CHAR) ; |
| BEGIN |
| ErrorString (InitString (a)) |
| END ErrorArray ; |
| |
| |
| % declaration P2Build begin |
| |
| (* |
| checkReturnAttribute - |
| *) |
| |
| PROCEDURE checkReturnAttribute ; |
| VAR |
| ident: Name ; |
| tok : CARDINAL ; |
| BEGIN |
| PopTtok (ident, tok) ; |
| IF ident # MakeKey ('noreturn') |
| THEN |
| MetaErrorT1 (tok, 'attribute {%1k} is not allowed in the procedure return type, only noreturn is allowed', ident) |
| END |
| END checkReturnAttribute ; |
| |
| |
| (* |
| checkParameterAttribute - |
| *) |
| |
| PROCEDURE checkParameterAttribute ; |
| VAR |
| ident: Name ; |
| tok : CARDINAL ; |
| BEGIN |
| PopTtok (ident, tok) ; |
| IF ident # MakeKey ('unused') |
| THEN |
| MetaErrorT1 (tok, 'attribute {%1k} is not allowed in the parameter formal type section, only unused is allowed', ident) |
| END |
| END checkParameterAttribute ; |
| |
| |
| (* |
| SyntaxError - after a syntax error we skip all tokens up until we reach |
| a stop symbol. |
| *) |
| |
| PROCEDURE SyntaxError (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ; |
| BEGIN |
| DescribeError ; |
| IF Debugging |
| THEN |
| printf0('\nskipping token *** ') |
| END ; |
| (* --fixme-- this assumes a 32 bit word size. *) |
| WHILE NOT (((ORD(currenttoken)<32) AND (currenttoken IN stopset0)) OR |
| ((ORD(currenttoken)>=32) AND (ORD(currenttoken)<64) AND (currenttoken IN stopset1)) OR |
| ((ORD(currenttoken)>=64) AND (currenttoken IN stopset2))) |
| DO |
| GetToken |
| END ; |
| IF Debugging |
| THEN |
| printf0(' ***\n') |
| END |
| END SyntaxError ; |
| |
| |
| (* |
| SyntaxCheck - |
| *) |
| |
| PROCEDURE SyntaxCheck (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ; |
| BEGIN |
| (* --fixme-- this assumes a 32 bit word size. *) |
| IF NOT (((ORD(currenttoken)<32) AND (currenttoken IN stopset0)) OR |
| ((ORD(currenttoken)>=32) AND (ORD(currenttoken)<64) AND (currenttoken IN stopset1)) OR |
| ((ORD(currenttoken)>=64) AND (currenttoken IN stopset2))) |
| THEN |
| SyntaxError(stopset0, stopset1, stopset2) |
| END |
| END SyntaxCheck ; |
| |
| |
| (* |
| WarnMissingToken - generates a warning message about a missing token, t. |
| *) |
| |
| PROCEDURE WarnMissingToken (t: toktype) ; |
| VAR |
| s0 : SetOfStop0 ; |
| s1 : SetOfStop1 ; |
| s2 : SetOfStop2 ; |
| str: String ; |
| BEGIN |
| s0 := SetOfStop0{} ; |
| s1 := SetOfStop1{} ; |
| s2 := SetOfStop2{} ; |
| IF ORD (t) <32 |
| THEN |
| INCL (s0, t) |
| ELSIF ORD (t) <64 |
| THEN |
| INCL (s1, t) |
| ELSE |
| INCL (s2, t) |
| END ; |
| str := DescribeStop (s0, s1, s2) ; |
| |
| str := ConCat (InitString ('syntax error,'), Mark (str)) ; |
| MetaErrorStringT0 (GetTokenNo (), str) |
| END WarnMissingToken ; |
| |
| |
| (* |
| MissingToken - generates a warning message about a missing token, t. |
| *) |
| |
| PROCEDURE MissingToken (t: toktype) ; |
| BEGIN |
| WarnMissingToken(t) ; |
| IF (t#identtok) AND (t#integertok) AND (t#realtok) AND (t#stringtok) |
| THEN |
| IF Debugging |
| THEN |
| printf0('inserting token\n') |
| END ; |
| InsertToken(t) |
| END |
| END MissingToken ; |
| |
| |
| (* |
| CheckAndInsert - |
| *) |
| |
| PROCEDURE CheckAndInsert (t: toktype; stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) : BOOLEAN ; |
| BEGIN |
| IF ((ORD(t)<32) AND (t IN stopset0)) OR |
| ((ORD(t)>=32) AND (ORD(t)<64) AND (t IN stopset1)) OR |
| ((ORD(t)>=64) AND (t IN stopset2)) |
| THEN |
| WarnMissingToken(t) ; |
| InsertTokenAndRewind(t) ; |
| RETURN( TRUE ) |
| ELSE |
| RETURN( FALSE ) |
| END |
| END CheckAndInsert ; |
| |
| |
| (* |
| InStopSet |
| *) |
| |
| PROCEDURE InStopSet (t: toktype; stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) : BOOLEAN ; |
| BEGIN |
| IF ((ORD(t)<32) AND (t IN stopset0)) OR |
| ((ORD(t)>=32) AND (ORD(t)<64) AND (t IN stopset1)) OR |
| ((ORD(t)>=64) AND (t IN stopset2)) |
| THEN |
| RETURN( TRUE ) |
| ELSE |
| RETURN( FALSE ) |
| END |
| END InStopSet ; |
| |
| |
| (* |
| PeepToken - peep token checks to see whether the stopset is satisfied by currenttoken |
| If it is not then it will insert a token providing the token |
| is one of ; ] ) } . OF END , |
| |
| if the stopset contains <identtok> then we do not insert a token |
| *) |
| |
| PROCEDURE PeepToken (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ; |
| BEGIN |
| (* and again (see above re: ORD) |
| *) |
| IF (NOT (((ORD(currenttoken)<32) AND (currenttoken IN stopset0)) OR |
| ((ORD(currenttoken)>=32) AND (ORD(currenttoken)<64) AND (currenttoken IN stopset1)) OR |
| ((ORD(currenttoken)>=64) AND (currenttoken IN stopset2)))) AND |
| (NOT InStopSet(identtok, stopset0, stopset1, stopset2)) |
| THEN |
| (* SyntaxCheck would fail since currentoken is not part of the stopset |
| we check to see whether any of currenttoken might be a commonly omitted token *) |
| IF CheckAndInsert(semicolontok, stopset0, stopset1, stopset2) OR |
| CheckAndInsert(rsbratok, stopset0, stopset1, stopset2) OR |
| CheckAndInsert(rparatok, stopset0, stopset1, stopset2) OR |
| CheckAndInsert(rcbratok, stopset0, stopset1, stopset2) OR |
| CheckAndInsert(periodtok, stopset0, stopset1, stopset2) OR |
| CheckAndInsert(oftok, stopset0, stopset1, stopset2) OR |
| CheckAndInsert(endtok, stopset0, stopset1, stopset2) OR |
| CheckAndInsert(commatok, stopset0, stopset1, stopset2) |
| THEN |
| END |
| END |
| END PeepToken ; |
| |
| |
| (* |
| Expect - |
| *) |
| |
| PROCEDURE Expect (t: toktype; stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ; |
| BEGIN |
| IF currenttoken=t |
| THEN |
| GetToken ; |
| IF Pass1 |
| THEN |
| PeepToken(stopset0, stopset1, stopset2) |
| END |
| ELSE |
| MissingToken(t) |
| END ; |
| SyntaxCheck(stopset0, stopset1, stopset2) |
| END Expect ; |
| |
| |
| (* |
| CompilationUnit - returns TRUE if the input was correct enough to parse |
| in future passes. |
| *) |
| |
| PROCEDURE CompilationUnit () : BOOLEAN ; |
| BEGIN |
| WasNoError := TRUE ; |
| FileUnit(SetOfStop0{eoftok}, SetOfStop1{}, SetOfStop2{}) ; |
| RETURN( WasNoError ) |
| END CompilationUnit ; |
| |
| |
| (* |
| Ident - error checking varient of Ident |
| *) |
| |
| PROCEDURE Ident (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ; |
| BEGIN |
| IF IsAutoPushOn() |
| THEN |
| PushTFtok(makekey(currentstring), identtok, GetTokenNo()) ; |
| Annotate("%1n|identtok||Ident rule") |
| END ; |
| Expect(identtok, stopset0, stopset1, stopset2) |
| END Ident ; |
| |
| |
| (* |
| string - |
| *) |
| |
| PROCEDURE string (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ; |
| BEGIN |
| IF IsAutoPushOn() |
| THEN |
| PushTF(makekey(currentstring), stringtok) ; |
| BuildString |
| END ; |
| Expect(stringtok, stopset0, stopset1, stopset2) |
| END string ; |
| |
| |
| (* |
| Integer - |
| *) |
| |
| PROCEDURE Integer (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ; |
| BEGIN |
| IF IsAutoPushOn() |
| THEN |
| PushTFtok (makekey(currentstring), integertok, GetTokenNo ()) ; |
| BuildNumber |
| END ; |
| Expect(integertok, stopset0, stopset1, stopset2) |
| END Integer ; |
| |
| |
| (* |
| Real - |
| *) |
| |
| PROCEDURE Real (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ; |
| BEGIN |
| IF IsAutoPushOn() |
| THEN |
| PushTFtok (makekey(currentstring), realtok, GetTokenNo ()) ; |
| BuildNumber |
| END ; |
| Expect(realtok, stopset0, stopset1, stopset2) |
| END Real ; |
| |
| |
| (* |
| CheckModuleQualident - check to see if the beginning ident of the qualident is an |
| imported module. |
| *) |
| |
| PROCEDURE CheckModuleQualident (stopset0: SetOfStop0; |
| stopset1: SetOfStop1; |
| stopset2: SetOfStop2) ; |
| VAR |
| name : Name ; |
| init, |
| nextLevel, |
| tok, tokstart: CARDINAL ; |
| BEGIN |
| PopTtok (name, tokstart) ; |
| tok := tokstart ; |
| init := RequestSym (tok, name) ; |
| IF IsImported (GetCurrentModule (), init) AND (IsDefImp (init) OR IsModule (init)) |
| THEN |
| WHILE IsDefImp (init) OR IsModule (init) DO |
| Expect (periodtok, stopset0, stopset1, stopset2 + SetOfStop2{identtok}) ; |
| StartScope (init) ; |
| Ident (stopset0, stopset1, stopset2) ; |
| PopTtok (name, tok) ; |
| nextLevel := RequestSym (tok, name) ; |
| EndScope ; |
| init := nextLevel |
| END ; |
| IF tok#tokstart |
| THEN |
| tok := MakeVirtualTok (tokstart, tokstart, tok) |
| END ; |
| IF IsProcedure (init) OR IsProcType (init) |
| THEN |
| PushTtok (init, tok) |
| ELSE |
| Annotate ("%1s(%1d)|%1s(%1d)||qualident|type") ; |
| PushTFtok (init, GetType (init), tok) ; |
| END ; |
| PutIncluded (init) |
| ELSE |
| PushTFtok (init, GetType (init), tok) ; |
| Annotate ("%1s(%1d)|%1s(%1d)||qualident|type") |
| END |
| END CheckModuleQualident ; |
| |
| |
| % module P2Build end |
| END P2Build. |
| % rules |
| error 'ErrorArray' 'ErrorString' |
| tokenfunc 'currenttoken' |
| |
| token '' eoftok -- internal token |
| token '+' plustok |
| token '-' minustok |
| token '*' timestok |
| token '/' dividetok |
| token ':=' becomestok |
| token '&' ambersandtok |
| token "." periodtok |
| token "," commatok |
| token ";" semicolontok |
| token '(' lparatok |
| token ')' rparatok |
| token '[' lsbratok -- left square brackets |
| token ']' rsbratok -- right square brackets |
| token '{' lcbratok -- left curly brackets |
| token '}' rcbratok -- right curly brackets |
| token '^' uparrowtok |
| token "'" singlequotetok |
| token '=' equaltok |
| token '#' hashtok |
| token '<' lesstok |
| token '>' greatertok |
| token '<>' lessgreatertok |
| token '<=' lessequaltok |
| token '>=' greaterequaltok |
| token '<*' ldirectivetok |
| token '*>' rdirectivetok |
| token '..' periodperiodtok |
| token ':' colontok |
| token '"' doublequotestok |
| token '|' bartok |
| token 'AND' andtok |
| token 'ARRAY' arraytok |
| token 'BEGIN' begintok |
| token 'BY' bytok |
| token 'CASE' casetok |
| token 'CONST' consttok |
| token 'DEFINITION' definitiontok |
| token 'DIV' divtok |
| token 'DO' dotok |
| token 'ELSE' elsetok |
| token 'ELSIF' elsiftok |
| token 'END' endtok |
| token 'EXCEPT' excepttok |
| token 'EXIT' exittok |
| token 'EXPORT' exporttok |
| token 'FINALLY' finallytok |
| token 'FOR' fortok |
| token 'FORWARD' forwardtok |
| token 'FROM' fromtok |
| token 'IF' iftok |
| token 'IMPLEMENTATION' implementationtok |
| token 'IMPORT' importtok |
| token 'IN' intok |
| token 'LOOP' looptok |
| token 'MOD' modtok |
| token 'MODULE' moduletok |
| token 'NOT' nottok |
| token 'OF' oftok |
| token 'OR' ortok |
| token 'PACKEDSET' packedsettok |
| token 'POINTER' pointertok |
| token 'PROCEDURE' proceduretok |
| token 'QUALIFIED' qualifiedtok |
| token 'UNQUALIFIED' unqualifiedtok |
| token 'RECORD' recordtok |
| token 'REM' remtok |
| token 'REPEAT' repeattok |
| token 'RETRY' retrytok |
| token 'RETURN' returntok |
| token 'SET' settok |
| token 'THEN' thentok |
| token 'TO' totok |
| token 'TYPE' typetok |
| token 'UNTIL' untiltok |
| token 'VAR' vartok |
| token 'WHILE' whiletok |
| token 'WITH' withtok |
| token 'ASM' asmtok |
| token 'VOLATILE' volatiletok |
| token '...' periodperiodperiodtok |
| token '__DATE__' datetok |
| token '__LINE__' linetok |
| token '__FILE__' filetok |
| token '__ATTRIBUTE__' attributetok |
| token '__BUILTIN__' builtintok |
| token '__INLINE__' inlinetok |
| token 'integer number' integertok |
| token 'identifier' identtok |
| token 'real number' realtok |
| token 'string' stringtok |
| |
| special Ident first { < identtok > } follow { } |
| special Integer first { < integertok > } follow { } |
| special Real first { < realtok > } follow { } |
| special string first { < stringtok > } follow { } |
| |
| BNF |
| |
| -- the following are provided by the module m2flex and also handbuilt procedures below |
| -- Ident := Letter { ( Letter | Digit ) } =: |
| -- Integer := Digit { Digit } | OctalDigit { OctalDigit } ( " B " | " C " ) | |
| -- Digit { HexDigit } " H " =: |
| -- Real := Digit { Digit } " . " { Digit } [ ScaleFactor ] =: |
| -- ScaleFactor := " E " [ ( " + " | " - " ) ] Digit { Digit } =: |
| -- HexDigit := Digit | " A " | " B " | " C " | " D " | " E " | " F " =: |
| -- Digit := OctalDigit | " 8 " | " 9 " =: |
| -- OctalDigit := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" =: |
| -- String |
| |
| FileUnit := % PushAutoOn % |
| ( DefinitionModule | |
| ImplementationOrProgramModule ) % PopAuto % |
| =: |
| |
| ProgramModule := "MODULE" % M2Error.DefaultProgramModule % |
| % BlockStart (GetTokenNo () -1) % |
| Ident % P2StartBuildProgramModule ; % |
| |
| |
| |
| |
| [ Priority |
| ] |
| ";" |
| |
| { Import % BuildImportOuterModule ; % |
| } |
| |
| Block |
| % BlockEnd (GetTokenNo () -1) % |
| Ident % P2EndBuildProgramModule ; % |
| "." |
| =: |
| |
| ImplementationModule := "IMPLEMENTATION" % M2Error.DefaultImplementationModule % |
| % BlockStart (GetTokenNo () -1) % |
| "MODULE" |
| Ident % P2StartBuildImplementationModule ; % |
| |
| [ Priority |
| ] ";" |
| { Import % BuildImportOuterModule % |
| } |
| Block |
| % BlockEnd (GetTokenNo () -1) % |
| Ident % P2EndBuildImplementationModule ; % |
| "." =: |
| |
| ImplementationOrProgramModule := ImplementationModule | ProgramModule =: |
| |
| Number := Integer | Real =: |
| |
| Qualident := Ident |
| % IF IsAutoPushOn() |
| THEN |
| CheckModuleQualident (stopset0, stopset1, stopset2) |
| ELSE (* just parse qualident *) % |
| { "." Ident } % END % |
| =: |
| |
| ConstantDeclaration := Ident "=" % SeenUnknown ; |
| BuildConst % |
| ConstExpressionInitial % DetermineType ; |
| PopNothing % |
| =: |
| |
| ConstExpressionInitial := % PushAutoOff % |
| SimpleConstExpr [ Relation SimpleConstExpr ] % PopAuto % |
| =: |
| |
| ConstExpression := % PushType ; SeenUnknown ; PushAutoOff % |
| SimpleConstExpr [ Relation SimpleConstExpr ] % PopAuto ; PopType % |
| =: |
| |
| Relation := % SeenUnknown (* actually it will be a BOOLEAN, but this is not a constructor and not a string *) % |
| "=" | "#" | "<>" | "<" | "<=" | ">" | ">=" | "IN" =: |
| |
| SimpleConstExpr := UnaryOrConstTerm { AddOperator ConstTerm } =: |
| |
| UnaryOrConstTerm := "+" ConstTerm | "-" ConstTerm | ConstTerm =: |
| |
| AddOperator := "+" | "-" | |
| "OR" % SeenUnknown (* actually it will be a BOOLEAN, but this is not a constructor and not a string *) % |
| =: |
| |
| ConstTerm := ConstFactor { MulOperator ConstFactor } =: |
| |
| MulOperator := "*" | "/" |
| | "DIV" % SeenUnknown % |
| | "MOD" % SeenUnknown % |
| | "REM" % SeenUnknown % |
| | "AND" % SeenUnknown % |
| | "&" % SeenUnknown % |
| =: |
| |
| ConstFactor := Number | ConstString | ConstSetOrQualidentOrFunction | |
| "(" ConstExpression ")" | "NOT" ConstFactor | |
| ConstAttribute =: |
| |
| -- to help satisfy LL1 |
| |
| ConstString := string % SeenString % |
| =: |
| |
| ComponentElement := ConstExpression [ ".." % PopType ; SeenSet ; PushType ; SeenUnknown % |
| ConstExpression ] =: |
| |
| ComponentValue := % PushType ; SeenUnknown ; PushRememberConstant % |
| ComponentElement [ 'BY' % PopType ; SeenArray ; PushType ; SeenUnknown % |
| ConstExpression ] |
| % PopType (* double check position, it must balance PushType *) % |
| % PopRememberConstant % |
| =: |
| |
| ArraySetRecordValue := ComponentValue { ',' ComponentValue } =: |
| |
| Constructor := '{' % SeenConstructor % |
| [ ArraySetRecordValue ] '}' =: |
| |
| ConstSetOrQualidentOrFunction := Constructor | Qualident |
| [ Constructor | ConstActualParameters ] =: |
| |
| |
| ConstActualParameters := % PushType ; SeenUnknown % |
| "(" [ ExpList ] ")" % PopType % |
| =: |
| |
| -- to help satisfy LL1 |
| |
| ConstAttribute := "__ATTRIBUTE__" "__BUILTIN__" "(" "(" ConstAttributeExpression ")" ")" =: |
| |
| ConstAttributeExpression := Ident | "<" Qualident ',' Ident ">" =: |
| |
| ByteAlignment := '<*' % PushAutoOn % |
| AttributeExpression % BuildAligned % |
| % PopAuto % |
| '*>' =: |
| |
| -- OptAlignmentExpression := [ AlignmentExpression ] =: |
| |
| -- AlignmentExpression := "(" ConstExpression ")" =: |
| |
| Alignment := ByteAlignment | % PushT(NulSym) % |
| =: |
| |
| TypeDeclaration := % VAR top: CARDINAL ; % |
| % top := Top() % |
| Ident "=" Type Alignment % BuildTypeAlignment % |
| % Assert(top=Top()) % |
| =: |
| |
| Type := |
| % PushAutoOn ; % |
| ( SimpleType | ArrayType % BuildType ; % |
| | RecordType % BuildType ; % |
| | SetType % BuildType ; % |
| | PointerType % BuildType ; % |
| | ProcedureType % BuildType ; % |
| ) % PopAuto ; % |
| =: |
| |
| SimpleType := |
| ( Qualident [ PrefixedSubrangeType ] % BuildType ; % |
| | Enumeration % BuildType ; % |
| | SubrangeType % BuildType ; % |
| ) |
| =: |
| |
| Enumeration := "(" |
| ( IdentList |
| ) |
| ")" % StartBuildEnumeration ; % |
| =: |
| |
| IdentList := Ident % VAR |
| on: BOOLEAN ; |
| n : CARDINAL ; % |
| % on := IsAutoPushOn() ; |
| IF on |
| THEN |
| n := 1 |
| END % |
| { "," Ident % IF on |
| THEN |
| INC(n) |
| END % |
| } % IF on |
| THEN |
| PushT(n) |
| END % |
| =: |
| |
| SubrangeType := % VAR start, combined: CARDINAL ; % |
| % start := GetTokenNo () % |
| "[" ConstExpression ".." ConstExpression "]" % combined := MakeVirtual2Tok (start, GetTokenNo ()-1) % |
| % BuildSubrange (combined, NulSym) % |
| =: |
| |
| PrefixedSubrangeType := % VAR qual, start, combined: CARDINAL ; % |
| % PopTtok (qual, start) % |
| "[" ConstExpression ".." ConstExpression "]" |
| % combined := MakeVirtual2Tok (start, GetTokenNo ()-1) % |
| % BuildSubrange (combined, qual) % |
| =: |
| |
| ArrayType := "ARRAY" % VAR arrayType, tok: CARDINAL ; % |
| % StartBuildArray ; |
| PopTtok(arrayType, tok) ; |
| PushTtok(arrayType, tok) ; |
| BuildNulName ; % |
| SimpleType % BuildFieldArray ; % |
| { "," % BuildArrayComma ; |
| BuildNulName ; % |
| SimpleType % BuildFieldArray ; % |
| } "OF" % BuildNulName ; % |
| Type % EndBuildArray ; |
| tok := OperandTok (1) ; |
| PopNothing ; |
| PushTtok (arrayType, tok) % |
| =: |
| |
| RecordType := "RECORD" % BuildRecord % |
| [ DefaultRecordAttributes ] |
| FieldListSequence "END" =: |
| |
| DefaultRecordAttributes := '<*' % PushAutoOn % |
| AttributeExpression % P2BuildDefaultFieldAlignment % |
| % PopAuto % |
| '*>' =: |
| |
| RecordFieldPragma := ( '<*' FieldPragmaExpression % VAR n: CARDINAL ; % |
| % n := 1 % |
| % PushT(n) % |
| % Annotate('(%1d)||pragma count') % |
| { ',' % PopT(n) % |
| FieldPragmaExpression % INC(n) % |
| % PushT(n) % |
| % Annotate('(%1d)||pragma count') % |
| } '*>' | % n := 0 % |
| % PushT(n) % |
| % Annotate('(%1d)||pragma count') % |
| ) =: |
| |
| FieldPragmaExpression := % PushAutoOn % |
| Ident PragmaConstExpression |
| % PopAuto % |
| =: |
| |
| PragmaConstExpression := ( % PushAutoOff % |
| '(' ConstExpression % BuildPragmaConst % |
| ')' % PopAuto % |
| | % PushT(NulSym) % |
| % Annotate('NulSym||no pragma const') % |
| ) =: |
| |
| AttributeExpression := Ident '(' ConstExpression ')' =: |
| |
| FieldListSequence := FieldListStatement { ";" FieldListStatement } =: |
| |
| FieldListStatement := [ FieldList ] =: |
| |
| -- sadly the PIM rules are not LL1 as Ident and Qualident have the same first |
| -- symbols. We rewrite FieldList to inline qualident |
| |
| FieldList := IdentList ":" % BuildNulName % |
| Type RecordFieldPragma % BuildFieldRecord % |
| | |
| "CASE" % AddRecordToList % |
| % StartBuildVarient % |
| % AddVarientToList % |
| CaseTag "OF" |
| Varient { "|" Varient } |
| [ "ELSE" % StartBuildVarientFieldRecord % |
| FieldListSequence % EndBuildVarientFieldRecord % |
| ] "END" % EndBuildVarient % |
| =: |
| |
| TagIdent := Ident | % BuildNulName % |
| =: |
| |
| CaseTag := TagIdent ( ":" Qualident | % PushT(NulSym) % |
| ) % BuildVarientSelector % |
| =: |
| |
| Varient := [ % StartBuildVarientFieldRecord % |
| VarientCaseLabelList ":" FieldListSequence % EndBuildVarientFieldRecord % |
| ] |
| =: |
| |
| VarientCaseLabelList := VarientCaseLabels { "," VarientCaseLabels } =: |
| |
| VarientCaseLabels := ConstExpression [ ".." ConstExpression ] =: |
| |
| CaseLabelList := CaseLabels { "," CaseLabels } =: |
| |
| CaseLabels := ConstExpression [ ".." ConstExpression ] =: |
| |
| SetType := % VAR ispacked: BOOLEAN ; |
| setpos : CARDINAL ; % |
| % setpos := GetTokenNo () % |
| % ispacked := FALSE % |
| ( "SET" % ispacked := FALSE % |
| | "PACKEDSET" % ispacked := TRUE % |
| ) "OF" % BuildNulName % |
| SimpleType % BuildSetType (setpos, ispacked) % |
| =: |
| |
| |
| PointerType := % VAR pointerpos: CARDINAL ; % |
| % pointerpos := GetTokenNo () % |
| "POINTER" "TO" % BuildNulName % |
| Type % BuildPointerType (pointerpos) % |
| =: |
| |
| ProcedureType := "PROCEDURE" % BuildProcedureType ; % |
| [ FormalTypeList ] =: |
| |
| FormalTypeList := "(" ( ")" FormalReturn | |
| ProcedureParameters |
| ")" FormalReturn ) =: |
| |
| FormalReturn := ( ":" OptReturnType | % CheckProcedure % |
| ) |
| =: |
| |
| OptReturnType := "[" Qualident % BuildOptFunction % |
| "]" | Qualident % BuildFunction % |
| =: |
| |
| ProcedureParameters := ProcedureParameter |
| { "," ProcedureParameter } =: |
| |
| ProcedureParameter := "..." % BuildFormalVarArgs % |
| | "VAR" % PushT(VarTok) ; % |
| FormalType % BuildFormalType ; % |
| | % PushT(NulTok) ; % |
| FormalType % BuildFormalType ; % |
| =: |
| |
| VarIdent := Ident % VAR |
| on : BOOLEAN ; |
| Sym, Type, tok: CARDINAL ; % |
| [ "[" % on := IsAutoPushOn() ; |
| IF on |
| THEN |
| PopTFtok(Sym, Type, tok) ; |
| PushTFAtok(Sym, Type, Sym, tok) |
| END % |
| ConstExpression "]" ] |
| =: |
| |
| VarIdentList := VarIdent % VAR |
| on: BOOLEAN ; |
| n : CARDINAL ; % |
| % on := IsAutoPushOn() ; |
| IF on |
| THEN |
| n := 1 |
| END % |
| { "," VarIdent % IF on |
| THEN |
| INC(n) |
| END % |
| } % IF on |
| THEN |
| PushT(n) |
| END % |
| =: |
| |
| VariableDeclaration := VarIdentList ":" % BuildNulName % |
| % DisplayStack % |
| Type % DisplayStack % |
| Alignment % DisplayStack % |
| % BuildVarAlignment % |
| % DisplayStack % |
| % BuildVariable % |
| =: |
| |
| Designator := Qualident { SubDesignator } =: |
| |
| SubDesignator := "." Ident | "[" ExpList "]" | "^" =: |
| |
| ExpList := Expression { "," Expression } =: |
| |
| Expression := % PushType ; SeenUnknown ; PushAutoOff % |
| SimpleExpression [ Relation SimpleExpression ] % PopAuto ; PopType % |
| =: |
| |
| SimpleExpression := UnaryOrTerm { AddOperator Term } =: |
| |
| UnaryOrTerm := "+" Term | "-" Term | Term =: |
| |
| Term := Factor { MulOperator Factor } =: |
| |
| Factor := Number | string | SetOrDesignatorOrFunction | |
| "(" Expression ")" | "NOT" Factor | ConstAttribute =: |
| |
| SetOrDesignatorOrFunction := ( Qualident [ Constructor | |
| SimpleDes [ ActualParameters ] |
| ] | Constructor |
| ) |
| =: |
| |
| SimpleDes := { "." Ident | "[" ExpList "]" | "^" } =: |
| |
| ActualParameters := "(" [ ExpList ] ")" =: |
| |
| Statement := % PushAutoOff ; % |
| [ AssignmentOrProcedureCall | IfStatement | CaseStatement | |
| WhileStatement | RepeatStatement | LoopStatement | |
| ForStatement | WithStatement | AsmStatement | |
| "EXIT" | "RETURN" [ Expression ] | RetryStatement ] % PopAuto ; % |
| =: |
| |
| RetryStatement := "RETRY" =: |
| |
| AssignmentOrProcedureCall := Designator ( ":=" Expression | |
| ActualParameters | % (* epsilon *) % |
| ) =: |
| |
| -- these two break LL1 as both start with a Designator |
| -- ProcedureCall := Designator [ ActualParameters ] =: |
| -- Assignment := Designator ":=" Expression =: |
| |
| StatementSequence := Statement { ";" Statement } =: |
| |
| IfStatement := "IF" Expression "THEN" StatementSequence |
| { "ELSIF" Expression "THEN" StatementSequence } |
| [ "ELSE" StatementSequence ] "END" =: |
| |
| CaseStatement := "CASE" Expression "OF" Case { "|" Case } |
| [ "ELSE" StatementSequence ] "END" =: |
| |
| Case := [ CaseLabelList ":" StatementSequence ] =: |
| |
| WhileStatement := "WHILE" Expression "DO" StatementSequence "END" =: |
| |
| RepeatStatement := "REPEAT" StatementSequence "UNTIL" Expression =: |
| |
| ForStatement := "FOR" Ident ":=" Expression "TO" Expression |
| [ "BY" ConstExpression ] "DO" |
| StatementSequence "END" =: |
| |
| LoopStatement := "LOOP" StatementSequence "END" =: |
| |
| WithStatement := "WITH" Designator "DO" StatementSequence "END" =: |
| |
| ProcedureDeclaration := % VAR top: CARDINAL ; % |
| % top := Top () % |
| ProcedureHeading % Assert(IsProcedure(OperandT(1))) % |
| ";" PostProcedureHeading % Assert (top = Top ()) % |
| =: |
| |
| PostProcedureHeading := ProperProcedure | ForwardDeclaration =: |
| |
| ForwardDeclaration := "FORWARD" % Assert (IsProcedure (OperandT (1))) % |
| % EndBuildForward % |
| =: |
| |
| ProperProcedure := ProcedureBlock % Assert(IsProcedure(OperandT(1))) % |
| Ident % EndBuildProcedure % |
| =: |
| |
| DefineBuiltinProcedure := [ "__ATTRIBUTE__" "__BUILTIN__" |
| "(" "(" % PushAutoOff % |
| Ident % PopAuto % |
| ")" ")" | "__INLINE__" ] |
| =: |
| |
| ProcedureHeading := "PROCEDURE" % M2Error.DefaultProcedure % |
| DefineBuiltinProcedure |
| ( Ident |
| % StartBuildProcedure % |
| % Assert(IsProcedure(OperandT(1))) % |
| % StartBuildFormalParameters % |
| % Assert(IsProcedure(OperandT(2))) % |
| [ FormalParameters |
| % Assert(IsProcedure(OperandT(2))) % |
| ] % EndBuildFormalParameters % |
| AttributeNoReturn |
| % BuildProcedureHeading % |
| ) |
| =: |
| |
| Builtin := [ "__BUILTIN__" | "__INLINE__" ] =: |
| |
| DefProcedureHeading := "PROCEDURE" % M2Error.DefaultProcedure % |
| Builtin |
| ( Ident |
| % StartBuildProcedure % |
| % Assert(IsProcedure(OperandT(1))) % |
| % DisplayStack % |
| % StartBuildFormalParameters % |
| % DisplayStack % |
| [ DefFormalParameters % DisplayStack % |
| ] % DisplayStack % |
| % EndBuildFormalParameters % |
| AttributeNoReturn |
| % BuildProcedureHeading % |
| ) % M2Error.LeaveErrorScope % |
| =: |
| |
| AttributeNoReturn := [ "<*" % PushAutoOn % |
| Ident % PopAuto % |
| % checkReturnAttribute % |
| % Assert(IsProcedure(OperandT(1))) % |
| % BuildNoReturnAttribute % |
| "*>" ] =: |
| |
| AttributeUnused := [ "<*" % PushAutoOn % |
| Ident % PopAuto % |
| % checkParameterAttribute % |
| "*>" ] =: |
| |
| -- introduced procedure block so we can produce more informative |
| -- error messages |
| |
| ProcedureBlock := % Assert(IsProcedure(OperandT(1))) % |
| { % Assert(IsProcedure(OperandT(1))) % |
| Declaration % Assert(IsProcedure(OperandT(1))) % |
| } [ "BEGIN" ProcedureBlockBody ] "END" % Assert(IsProcedure(OperandT(1))) % |
| =: |
| |
| Block := { Declaration } InitialBlock FinalBlock "END" =: |
| |
| InitialBlock := [ "BEGIN" % BlockBegin (GetTokenNo () -1) % |
| InitialBlockBody ] =: |
| |
| FinalBlock := [ "FINALLY" % BlockFinally (GetTokenNo () -1) % |
| FinalBlockBody ] =: |
| |
| InitialBlockBody := NormalPart [ "EXCEPT" % PutExceptionBlock(GetCurrentScope()) % |
| ExceptionalPart ] =: |
| |
| FinalBlockBody := NormalPart [ "EXCEPT" % PutExceptionFinally(GetCurrentScope()) % |
| ExceptionalPart ] =: |
| |
| ProcedureBlockBody := NormalPart [ "EXCEPT" % PutExceptionBlock(GetCurrentScope()) % |
| ExceptionalPart ] =: |
| |
| NormalPart := StatementSequence =: |
| |
| ExceptionalPart := StatementSequence =: |
| |
| Declaration := "CONST" { ConstantDeclaration ";" } | |
| "TYPE" { TypeDeclaration ";" } | |
| "VAR" { VariableDeclaration ";" } | |
| ProcedureDeclaration ";" | |
| ModuleDeclaration ";" =: |
| |
| DefFormalParameters := "(" |
| [ DefMultiFPSection ] % VAR n: CARDINAL; % |
| % PopT(n) ; (* remove param count *) % |
| ")" |
| FormalReturn % PushT(n) ; (* restore param count *) |
| Annotate ("%1d||running total of no. of parameters") % |
| =: |
| |
| DefMultiFPSection := DefExtendedFP | |
| FPSection [ ";" DefMultiFPSection ] =: |
| |
| FormalParameters := "(" |
| [ MultiFPSection ] % VAR n: CARDINAL; % |
| % PopT(n) ; (* remove param count *) % |
| ")" |
| FormalReturn % PushT(n) ; (* restore param count *) ; |
| Annotate ("%1d||running total of no. of parameters") % |
| =: |
| |
| MultiFPSection := ExtendedFP | |
| FPSection [ ";" MultiFPSection ] =: |
| |
| FPSection := NonVarFPSection | VarFPSection |
| =: |
| |
| DefExtendedFP := DefOptArg | "..." % BuildVarArgs % |
| =: |
| |
| ExtendedFP := OptArg | "..." % BuildVarArgs % |
| =: |
| |
| OptArg := "[" % VAR n: CARDINAL ; % |
| % PopT(n) % |
| % PushT(NulTok) % |
| Ident % PushT(1) % |
| ":" FormalType % PushT(n) % |
| % Annotate ("%1d||running total of no. of parameters") % |
| % BuildFPSection % |
| % BuildOptArg % |
| [ "=" ConstExpression ] |
| "]" =: |
| |
| DefOptArg := "[" % VAR n: CARDINAL ; % |
| % PopT(n) % |
| % PushT(NulTok) % |
| Ident % PushT(1) % |
| ":" FormalType % PushT(n) % |
| % Annotate ("%1d||running total of no. of parameters") % |
| % BuildFPSection % |
| % BuildOptArg % |
| "=" ConstExpression |
| "]" =: |
| |
| VarFPSection := "VAR" % VAR n: CARDINAL ; % |
| % PopT(n) ; % |
| % PushT(VarTok) ; % |
| IdentList ":" FormalType % PushT(n) % |
| % Annotate ("%1d||running total of no. of parameters") % |
| [ AttributeUnused ] |
| % BuildFPSection % |
| =: |
| |
| NonVarFPSection := % VAR n: CARDINAL ; % |
| % PopT(n) % |
| % PushT(NulTok) % |
| IdentList ":" FormalType % PushT(n) % |
| % Annotate ("%1d||running total of no. of parameters") % |
| [ AttributeUnused ] |
| % BuildFPSection % |
| =: |
| |
| FormalType := "ARRAY" "OF" % VAR n, tok: CARDINAL ; % |
| % PushTF(ArrayTok, 1) % |
| { "ARRAY" "OF" % PopTF(ArrayTok, n) % |
| % INC(n) % |
| % PushTF(ArrayTok, n) % |
| } Qualident |
| | % VAR Sym, Type: CARDINAL ; % |
| Qualident |
| % PopTFtok (Sym, Type, tok) ; |
| PushT(NulTok) ; |
| PushTFtok (Sym, Type, tok) % |
| =: |
| |
| ModuleDeclaration := "MODULE" % M2Error.DefaultInnerModule % |
| % BlockStart (GetTokenNo () -1) % |
| Ident % StartBuildInnerModule % |
| [ Priority |
| ] ";" |
| { Import % BuildImportInnerModule % |
| } [ Export % BuildExportInnerModule % |
| ] |
| Block |
| % BlockEnd (GetTokenNo () -1) % |
| Ident % EndBuildInnerModule % |
| =: |
| |
| Priority := "[" ConstExpression "]" =: |
| |
| Export := "EXPORT" ( "QUALIFIED" % PushT(QualifiedTok) % |
| IdentList | |
| "UNQUALIFIED" % PushT(UnQualifiedTok) % |
| IdentList | % PushT(ExportTok) % |
| IdentList ) ";" =: |
| |
| Import := "FROM" Ident "IMPORT" IdentList ";" | |
| "IMPORT" % PushT(ImportTok) |
| (* determines whether Ident or Module *) % |
| IdentList ";" =: |
| |
| DefinitionModule := "DEFINITION" % M2Error.DefaultDefinitionModule % |
| "MODULE" |
| [ "FOR" string ] |
| Ident % P2StartBuildDefModule % |
| ";" |
| { Import % BuildImportOuterModule % |
| } [ Export % BuildExportOuterModule % |
| ] |
| { Definition } |
| "END" Ident % P2EndBuildDefModule % |
| "." |
| =: |
| |
| Definition := "CONST" { ConstantDeclaration ";" } | |
| "TYPE" |
| { Ident ( ";" |
| | "=" Type Alignment % BuildVarAlignment % |
| ";" ) % BuildTypeEnd % |
| } |
| | |
| "VAR" { VariableDeclaration ";" } | |
| DefProcedureHeading ";" =: |
| |
| AsmStatement := 'ASM' [ 'VOLATILE' ] '(' AsmOperands ')' =: |
| |
| NamedOperand := '[' Ident ']' =: |
| |
| AsmOperandName := [ NamedOperand ] =: |
| |
| AsmOperands := ConstExpression [ ':' AsmList [ ':' AsmList [ ':' TrashList ] ] ] |
| =: |
| |
| AsmList := [ AsmElement ] { ',' AsmElement } =: |
| |
| AsmElement := AsmOperandName ConstExpression '(' Expression ')' |
| =: |
| |
| TrashList := [ ConstExpression ] { ',' ConstExpression } =: |
| |
| FNB |