| -- |
| -- m2-3.bnf grammar and associated actions for pass 3. |
| -- |
| -- 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 P3Build begin |
| (* output from m2-3.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 P3Build ; |
| |
| FROM M2LexBuf IMPORT currentstring, currenttoken, GetToken, InsertToken, |
| InsertTokenAndRewind, GetTokenNo, PrintTokenNo, MakeVirtualTok, |
| UnknownTokenNo ; |
| |
| FROM M2Error IMPORT ErrorStringAt, WriteFormat1, WriteFormat2 ; |
| FROM NameKey IMPORT NulName, Name, makekey ; |
| FROM DynamicStrings IMPORT String, InitString, KillString, Mark, ConCat, ConCatChar ; |
| FROM M2Printf IMPORT printf0, printf1 ; |
| FROM M2Debug IMPORT Assert ; |
| FROM P2SymBuild IMPORT BuildString, BuildNumber ; |
| FROM M2MetaError IMPORT MetaErrorT0, MetaErrorT2 ; |
| FROM M2CaseList IMPORT ElseCase ; |
| |
| FROM M2Reserved IMPORT tokToTok, toktype, |
| NulTok, ImportTok, ExportTok, QualifiedTok, UnQualifiedTok, |
| EqualTok, HashTok, LessGreaterTok, LessTok, LessEqualTok, |
| GreaterTok, GreaterEqualTok, InTok, PlusTok, MinusTok, |
| OrTok, TimesTok, DivTok, DivideTok, ModTok, RemTok, |
| AndTok, AmbersandTok, PeriodPeriodTok, ByTok ; |
| |
| FROM M2Quads IMPORT PushT, PopT, PushTF, PopTF, PopNothing, Annotate, |
| PushTtok, PushTFtok, PopTtok, PopTFtok, OperandTok, |
| DupFrame, Top, |
| BuildModuleStart, |
| StartBuildDefFile, StartBuildModFile, |
| EndBuildFile, |
| StartBuildInit, |
| EndBuildInit, |
| StartBuildFinally, |
| EndBuildFinally, |
| BuildExceptInitial, |
| BuildExceptFinally, |
| BuildExceptProcedure, |
| BuildReThrow, |
| BuildProcedureStart, |
| BuildProcedureBegin, |
| BuildProcedureEnd, |
| BuildScaffold, |
| BuildStmtNote, |
| BuildFunctionCall, BuildConstFunctionCall, |
| BuildBinaryOp, BuildUnaryOp, BuildRelOp, BuildNot, |
| BuildEmptySet, BuildInclRange, BuildInclBit, |
| BuildSetStart, BuildSetEnd, |
| PushLineNo, BuildSizeCheckStart, |
| BuildBuiltinConst, BuildBuiltinTypeInfo, |
| BuildAssignment, BuildAssignConstant, |
| BuildAlignment, |
| BuildRepeat, BuildUntil, |
| BuildWhile, BuildDoWhile, BuildEndWhile, |
| BuildLoop, BuildExit, BuildEndLoop, |
| BuildThenIf, BuildElse, BuildEndIf, |
| BuildForToByDo, BuildPseudoBy, BuildEndFor, |
| BuildElsif1, BuildElsif2, |
| BuildProcedureCall, BuildReturn, BuildNulExpression, |
| CheckBuildFunction, |
| StartBuildWith, EndBuildWith, |
| BuildAsm, |
| BuildCaseStart, |
| BuildCaseOr, |
| BuildCaseElse, |
| BuildCaseEnd, |
| BuildCaseCheck, |
| BuildCaseStartStatementSequence, |
| BuildCaseEndStatementSequence, |
| BuildCaseList, |
| BuildCaseRange, BuildCaseEquality, |
| BuildConstructorStart, |
| BuildConstructorEnd, |
| SilentBuildConstructorStart, |
| NextConstructorField, BuildTypeForConstructor, |
| BuildComponentValue, |
| BeginVarient, EndVarient, ElseVarient, |
| BeginVarientList, EndVarientList, |
| RecordOp, |
| BuildNulParam, |
| BuildDesignatorRecord, |
| BuildDesignatorArray, |
| BuildDesignatorPointer, |
| BuildBooleanVariable, |
| CheckWithReference, |
| BuildModulePriority, |
| BuildRetry, |
| DisplayStack, |
| AddVarientRange, AddVarientEquality, |
| BuildAsmElement, BuildAsmTrash, |
| BeginVarient, EndVarient, BeginVarientList, EndVarientList, |
| PushInConstExpression, PopInConstExpression, |
| PushInConstParameters, PopInConstParameters, IsInConstParameters, |
| BuildDefaultFieldAlignment, BuildPragmaField, |
| OperandT, OperandTok, |
| IsAutoPushOn, PushAutoOff, PushAutoOn, PopAuto ; |
| |
| FROM P3SymBuild IMPORT P3StartBuildProgModule, |
| P3EndBuildProgModule, |
| |
| P3StartBuildDefModule, |
| P3EndBuildDefModule, |
| |
| P3StartBuildImpModule, |
| P3EndBuildImpModule, |
| |
| StartBuildInnerModule, |
| EndBuildInnerModule, |
| |
| CheckImportListOuterModule, |
| CheckCanBeImported, |
| StartBuildProcedure, |
| BuildProcedureHeading, |
| EndBuildProcedure, |
| EndBuildForward, |
| BuildVarAtAddress, |
| BuildConst, |
| BuildSubrange, |
| BuildNulName, |
| BuildOptArgInitializer ; |
| |
| FROM SymbolTable IMPORT MakeGnuAsm, PutGnuAsmVolatile, PutGnuAsm, PutGnuAsmInput, |
| PutGnuAsmOutput, PutGnuAsmTrash, |
| PutGnuAsmVolatile, PutGnuAsmSimple, |
| MakeRegInterface, |
| PutRegInterface, |
| IsRegInterface, IsGnuAsmVolatile, IsGnuAsm, |
| GetCurrentModule, IsInnerModule, |
| GetSymName, GetType, SkipType, |
| NulSym, |
| StartScope, EndScope, |
| PutIncluded, |
| IsVarParam, IsProcedure, IsDefImp, IsModule, IsProcType, |
| IsRecord, |
| RequestSym, IsExported, IsImported, |
| GetSym, GetLocalSym ; |
| |
| FROM M2Batch IMPORT IsModuleKnown ; |
| |
| FROM M2CaseList IMPORT BeginCaseList, EndCaseList ; |
| |
| FROM M2StateCheck IMPORT StateCheck, |
| InitState, PushState, PopState, |
| InclConst, ExclConst, |
| InclType, ExclType, |
| InclVar, ExclVar, |
| InclConstructor, ExclConstructor, |
| InclConstFunc, CheckQualident ; |
| |
| IMPORT M2Error ; |
| |
| CONST |
| Debugging = FALSE ; |
| DebugAsm = FALSE ; |
| |
| VAR |
| seenError : BOOLEAN ; |
| BlockState: StateCheck ; |
| |
| |
| PROCEDURE ErrorString (s: String) ; |
| BEGIN |
| ErrorStringAt (s, GetTokenNo ()) ; |
| seenError := TRUE |
| END ErrorString ; |
| |
| |
| PROCEDURE ErrorArray (a: ARRAY OF CHAR) ; |
| BEGIN |
| ErrorString (InitString (a)) |
| END ErrorArray ; |
| |
| |
| % declaration P3Build begin |
| |
| |
| (* |
| 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 |
| s0 := SetOfStop0{t} |
| ELSIF ORD(t)<64 |
| THEN |
| s1 := SetOfStop1{t} |
| ELSE |
| s2 := SetOfStop2{t} |
| END ; |
| str := DescribeStop(s0, s1, s2) ; |
| |
| str := ConCat(InitString('syntax error,'), Mark(str)) ; |
| ErrorStringAt (str, GetTokenNo ()) |
| 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) ; |
| CONST |
| Pass1 = FALSE ; |
| 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 |
| seenError := FALSE ; |
| FileUnit(SetOfStop0{eoftok}, SetOfStop1{}, SetOfStop2{}) ; |
| RETURN NOT seenError |
| 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 ()) |
| (* ; MetaErrorT0 (GetTokenNo(), "{%W}an ident") *) |
| END ; |
| Expect(identtok, stopset0, stopset1, stopset2) |
| END Ident ; |
| |
| |
| (* |
| string - |
| *) |
| |
| PROCEDURE string (stopset0: SetOfStop0; stopset1: SetOfStop1; stopset2: SetOfStop2) ; |
| BEGIN |
| IF IsAutoPushOn() |
| THEN |
| PushTFtok(makekey(currentstring), stringtok, GetTokenNo ()) ; |
| 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 ; |
| |
| |
| (* |
| PushTFQualident - push the result of the Qualident |
| to the stack. It checks to see if init |
| is a procedure or proc type and if so |
| it does not push the return type. |
| *) |
| |
| PROCEDURE PushTFQualident (tok, tokstart: CARDINAL; |
| init: CARDINAL) ; |
| BEGIN |
| IF tok#tokstart |
| THEN |
| tok := MakeVirtualTok (tokstart, tokstart, tok) |
| END ; |
| IF IsProcedure (init) OR IsProcType (init) OR IsModule (init) OR IsDefImp (init) |
| THEN |
| PushTtok (init, tok) ; |
| Annotate ("%1s(%1d)||qualident procedure/proctype") ; |
| ELSE |
| Annotate ("%1s(%1d)|%1s(%1d)||qualident|type") ; |
| PushTFtok (init, GetType (init), tok) ; |
| END |
| END PushTFQualident ; |
| |
| |
| (* |
| 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 ; |
| CheckCanBeImported (init, nextLevel) ; |
| init := nextLevel |
| END ; |
| PushTFQualident (tok, tokstart, init) ; |
| PutIncluded (init) |
| ELSE |
| PushTFQualident (tok, tokstart, init) |
| END |
| END CheckModuleQualident ; |
| |
| % module P3Build end |
| BEGIN |
| BlockState := InitState () |
| END P3Build. |
| % 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 handbuild 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 := % PushAutoOff % |
| ( DefinitionModule | |
| ImplementationOrProgramModule ) % PopAuto % |
| =: |
| |
| ProgramModule := % VAR modulet, endt: CARDINAL ; % |
| % modulet := GetTokenNo () % |
| "MODULE" % M2Error.DefaultProgramModule % |
| % PushAutoOn % |
| Ident % P3StartBuildProgModule % |
| % StartBuildModFile (modulet) % |
| % BuildModuleStart (modulet) % |
| % PushAutoOff % |
| [ Priority |
| ] |
| ";" % BuildScaffold (modulet, |
| GetCurrentModule ()) % |
| { Import } |
| Block % PushAutoOn % |
| % endt := GetTokenNo () -1 % |
| Ident % EndBuildFile (endt) % |
| % P3EndBuildProgModule % |
| "." % PopAuto ; PopAuto % |
| =: |
| |
| ImplementationModule := % VAR modulet, endt: CARDINAL ; % |
| % modulet := GetTokenNo () % |
| "IMPLEMENTATION" % M2Error.DefaultImplementationModule % |
| "MODULE" % PushAutoOn % |
| Ident % StartBuildModFile (modulet) % |
| % P3StartBuildImpModule % |
| % BuildModuleStart (modulet) % |
| % PushAutoOff % |
| [ Priority |
| ] ";" % BuildScaffold (modulet, |
| GetCurrentModule ()) % |
| { Import } |
| Block % PushAutoOn % |
| % endt := GetTokenNo () -1 % |
| Ident % EndBuildFile (endt) % |
| % P3EndBuildImpModule % |
| "." % PopAuto ; PopAuto ; PopAuto % |
| =: |
| |
| ImplementationOrProgramModule := % PushAutoOff % |
| ( ImplementationModule | ProgramModule ) % PopAuto % |
| =: |
| |
| Number := Integer | Real =: |
| |
| -- |
| -- In pass 3 Qualident needs some care as we must only parse module.module.ident |
| -- and not ident.recordfield. We leave the ident.recordfield to be parsed by |
| -- SubDesignator. Note that Qualident is called by SubDesignator so if |
| -- IsAutoPushOff then we just consume tokens. |
| -- |
| |
| Qualident := Ident |
| % IF IsAutoPushOn() |
| THEN |
| CheckModuleQualident (stopset0, stopset1, stopset2) |
| ELSE (* just parse qualident *) % |
| { "." Ident } % END % |
| =: |
| |
| |
| QualidentCheck := % PushAutoOn % |
| Qualident |
| % PopAuto % |
| % CheckQualident (OperandTok (1), BlockState, OperandT (1)) % |
| % IF NOT IsAutoPushOn () |
| THEN |
| PopNothing |
| END % |
| =: |
| |
| ConstantDeclaration := % VAR tokno: CARDINAL ; % |
| % InclConst (BlockState) % |
| % PushAutoOn % |
| ( Ident "=" % tokno := GetTokenNo () -1 % |
| % BuildConst % |
| ConstExpression ) % BuildAssignConstant (tokno) % |
| % PopAuto % |
| % ExclConst (BlockState) % |
| =: |
| |
| ConstExpression := % VAR tokpos: CARDINAL ; % |
| % PushInConstExpression % |
| % PushAutoOn % |
| SimpleConstExpr [ Relation % tokpos := GetTokenNo ()-1 % |
| SimpleConstExpr % BuildRelOp (tokpos) % |
| ] % PopAuto % |
| % PopInConstExpression % |
| =: |
| |
| Relation := "=" % PushTtok(EqualTok, GetTokenNo() -1) ; |
| RecordOp % |
| | "#" % PushTtok(HashTok, GetTokenNo() -1) ; |
| RecordOp % |
| | "<>" % PushTtok(LessGreaterTok, GetTokenNo() -1) ; |
| RecordOp % |
| | "<" % PushTtok(LessTok, GetTokenNo() -1) % |
| | "<=" % PushTtok(LessEqualTok, GetTokenNo() -1) % |
| | ">" % PushTtok(GreaterTok, GetTokenNo() -1) % |
| | ">=" % PushTtok(GreaterEqualTok, GetTokenNo() -1) % |
| | "IN" % PushTtok(InTok, GetTokenNo() -1) % |
| =: |
| |
| SimpleConstExpr := UnaryOrConstTerm { AddOperator ConstTerm % BuildBinaryOp % |
| } =: |
| |
| UnaryOrConstTerm := "+" % PushTtok(PlusTok, GetTokenNo() -1) % |
| ConstTerm % BuildUnaryOp % |
| | |
| "-" % PushTtok(MinusTok, GetTokenNo() -1) % |
| ConstTerm % BuildUnaryOp % |
| | |
| ConstTerm =: |
| |
| AddOperator := "+" % PushTtok(PlusTok, GetTokenNo() -1) ; |
| RecordOp % |
| | "-" % PushTtok(MinusTok, GetTokenNo() -1) ; |
| RecordOp % |
| | "OR" % PushTtok(OrTok, GetTokenNo() -1) ; |
| RecordOp % |
| =: |
| |
| ConstTerm := ConstFactor { MulOperator ConstFactor % BuildBinaryOp % |
| } =: |
| |
| MulOperator := "*" % PushTtok(TimesTok, GetTokenNo() -1) ; |
| RecordOp % |
| | "/" % PushTtok(DivideTok, GetTokenNo() -1) ; |
| RecordOp % |
| | "DIV" % PushTtok(DivTok, GetTokenNo() -1) ; |
| RecordOp % |
| | "MOD" % PushTtok(ModTok, GetTokenNo() -1) ; |
| RecordOp % |
| | "REM" % PushTtok(RemTok, GetTokenNo() -1) ; |
| RecordOp % |
| | "AND" % PushTtok(AndTok, GetTokenNo() -1) ; |
| RecordOp % |
| | "&" % PushTtok(AmbersandTok, GetTokenNo() -1) ; |
| RecordOp % |
| =: |
| |
| ConstFactor := % VAR tokpos: CARDINAL ; % |
| Number | ConstString | ConstSetOrQualidentOrFunction | |
| "(" ConstExpression ")" | "NOT" % tokpos := GetTokenNo() -1 % |
| ConstFactor % BuildNot (tokpos) % |
| | ConstAttribute =: |
| |
| -- to help satisfy LL1 |
| |
| ConstString := string =: |
| |
| ComponentElement := ConstExpression ( ".." ConstExpression % PushTtok(PeriodPeriodTok, GetTokenNo() -1) % |
| | % PushT(NulTok) % |
| ) |
| =: |
| |
| ComponentValue := % VAR tokpos: CARDINAL ; % |
| ( |
| % tokpos := GetTokenNo () % |
| ComponentElement ( % tokpos := GetTokenNo () % |
| 'BY' ConstExpression % PushTtok (ByTok, tokpos) % |
| |
| | % PushTtok (NulTok, tokpos) % |
| ) |
| ) |
| =: |
| |
| ArraySetRecordValue := ComponentValue % BuildComponentValue % |
| { ',' % NextConstructorField % |
| ComponentValue % BuildComponentValue % |
| } |
| =: |
| |
| Constructor := % VAR tokpos: CARDINAL ; % |
| % DisplayStack % |
| % InclConstructor (BlockState) % |
| % CheckQualident (OperandTok (1), BlockState, OperandT (1)) % |
| '{' % tokpos := GetTokenNo () -1 % |
| % BuildConstructorStart (tokpos) % |
| [ ArraySetRecordValue ] % BuildConstructorEnd (tokpos, GetTokenNo()) % |
| '}' |
| % ExclConstructor (BlockState) % |
| =: |
| |
| ConstSetOrQualidentOrFunction := % VAR tokpos: CARDINAL ; % |
| % tokpos := GetTokenNo () % |
| ( |
| Qualident |
| [ Constructor | ConstActualParameters % BuildConstFunctionCall % |
| ] |
| | % BuildTypeForConstructor (tokpos) % |
| Constructor |
| ) =: |
| |
| ConstActualParameters := % PushState (BlockState) % |
| % InclConstFunc (BlockState) % |
| % CheckQualident (OperandTok (1), BlockState, OperandT (1)) % |
| % PushInConstParameters % |
| ActualParameters % PopInConstParameters % |
| % PopState (BlockState) % |
| =: |
| |
| ConstAttribute := "__ATTRIBUTE__" "__BUILTIN__" "(" "(" % PushAutoOn % |
| ConstAttributeExpression % PopAuto % |
| ")" ")" =: |
| |
| ConstAttributeExpression := |
| Ident % BuildBuiltinConst % |
| | "<" Qualident ',' Ident % BuildBuiltinTypeInfo % |
| ">" |
| =: |
| |
| ByteAlignment := % VAR tokpos: CARDINAL ; % |
| '<*' % PushAutoOn % |
| % tokpos := GetTokenNo () % |
| AttributeExpression % BuildAlignment (tokpos) % |
| '*>' % PopAuto % |
| =: |
| |
| Alignment := [ ByteAlignment ] =: |
| |
| TypeDeclaration := % InclType (BlockState) % |
| Ident "=" Type Alignment |
| % ExclType (BlockState) % |
| =: |
| |
| Type := |
| % PushAutoOff % |
| ( SimpleType | ArrayType |
| | RecordType |
| | SetType |
| | PointerType |
| | ProcedureType ) % PopAuto % |
| =: |
| |
| SimpleType := QualidentCheck [ SubrangeType ] | Enumeration | SubrangeType =: |
| |
| Enumeration := "(" |
| ( IdentList |
| ) |
| ")" |
| =: |
| |
| 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 := "[" ConstExpression ".." ConstExpression "]" % BuildSubrange ; % |
| =: |
| |
| ArrayType := "ARRAY" |
| |
| SimpleType |
| { "," |
| SimpleType |
| } "OF" |
| Type |
| =: |
| |
| RecordType := "RECORD" [ DefaultRecordAttributes ] FieldListSequence "END" =: |
| |
| DefaultRecordAttributes := '<*' % PushAutoOn % |
| AttributeExpression % BuildDefaultFieldAlignment % |
| % PopAuto % |
| '*>' =: |
| |
| RecordFieldPragma := [ '<*' FieldPragmaExpression |
| { ',' FieldPragmaExpression } '*>' ] =: |
| |
| FieldPragmaExpression := % PushAutoOn % |
| Ident PragmaConstExpression % BuildPragmaField % |
| % PopAuto % |
| =: |
| |
| PragmaConstExpression := ( '(' ConstExpression ')' | % PushT(NulSym) % |
| % Annotate('NulSym||no pragma const') % |
| ) =: |
| |
| AttributeExpression := Ident '(' ConstExpression ')' =: |
| |
| FieldListSequence := FieldListStatement { ";" FieldListStatement } =: |
| |
| -- at present FieldListStatement is as follows: |
| FieldListStatement := [ FieldList ] =: |
| -- later replace it with FieldList to comply with PIM2 |
| |
| -- sadly the PIM rules are not LL1 as Ident and Qualident have the same first |
| -- symbols. We rewrite FieldList to inline qualident |
| -- was |
| -- FieldList := IdentList ":" % BuildNulName % |
| -- Type | |
| -- "CASE" [ Ident ":" ] Qualident "OF" Varient { "|" Varient } |
| -- [ "ELSE" FieldListSequence ] "END" =: |
| |
| FieldList := IdentList ":" |
| Type RecordFieldPragma |
| | |
| "CASE" % BeginVarient % |
| CaseTag "OF" |
| Varient { "|" Varient } |
| [ "ELSE" % ElseVarient % |
| FieldListSequence |
| ] "END" % EndVarient % |
| =: |
| |
| TagIdent := [ Ident ] =: |
| |
| CaseTag := TagIdent [":" QualidentCheck ] =: |
| |
| Varient := [ % BeginVarientList % |
| VarientCaseLabelList ":" FieldListSequence % EndVarientList % |
| ] =: |
| |
| VarientCaseLabelList := VarientCaseLabels { "," VarientCaseLabels } =: |
| |
| VarientCaseLabels := ConstExpression ( ".." ConstExpression % AddVarientRange % |
| | % AddVarientEquality ; (* epsilon *) % |
| ) |
| =: |
| |
| -- |
| -- the following rules are a copy of the ConstExpression ebnf rules but without |
| -- any actions all prefixed with Silent. |
| -- At present they are only used by CaseLabels, if this continues to be true we |
| -- might consider restricting the SilentConstExpression. Eg it makes no sence to allow |
| -- String in these circumstances! |
| -- |
| |
| SilentConstExpression := % PushAutoOff % |
| SilentSimpleConstExpr |
| [ SilentRelation SilentSimpleConstExpr ] % PopAuto % |
| =: |
| |
| SilentRelation := "=" | "#" | "<>" | "<" | "<=" | ">" | ">=" | "IN" =: |
| |
| SilentSimpleConstExpr := SilentUnaryOrConstTerm { SilentAddOperator SilentConstTerm } =: |
| |
| SilentUnaryOrConstTerm := "+" SilentConstTerm | "-" SilentConstTerm | SilentConstTerm =: |
| |
| SilentAddOperator := "+" | "-" | "OR" =: |
| |
| SilentConstTerm := SilentConstFactor { SilentMulOperator SilentConstFactor } =: |
| |
| SilentMulOperator := "*" | "/" | "DIV" | "MOD" | "REM" | "AND" | "&" =: |
| |
| SilentConstFactor := Number | SilentConstString | SilentConstSetOrQualidentOrFunction | |
| "(" SilentConstExpression ")" | "NOT" SilentConstFactor |
| | SilentConstAttribute =: |
| |
| SilentConstString := string =: |
| |
| SilentConstAttribute := "__ATTRIBUTE__" "__BUILTIN__" "(" "(" SilentConstAttributeExpression ")" ")" =: |
| |
| SilentConstAttributeExpression := Ident | "<" Ident ',' SilentConstString ">" =: |
| |
| SilentComponentElement := SilentConstExpression [ ".." SilentConstExpression ] =: |
| |
| SilentComponentValue := SilentComponentElement [ 'BY' SilentConstExpression ] =: |
| |
| SilentArraySetRecordValue := SilentComponentValue { ',' SilentComponentValue } =: |
| |
| SilentConstructor := '{' % SilentBuildConstructorStart % |
| [ SilentArraySetRecordValue ] '}' =: |
| |
| SilentConstSetOrQualidentOrFunction := SilentConstructor | Qualident |
| [ SilentConstructor | SilentActualParameters ] =: |
| |
| SilentActualParameters := "(" [ SilentExpList ] ")" =: |
| |
| SilentExpList := SilentConstExpression { "," SilentConstExpression } =: |
| |
| -- end of the Silent constant rules |
| |
| SetType := ( "SET" | "PACKEDSET" ) "OF" SimpleType =: |
| |
| PointerType := "POINTER" "TO" |
| Type |
| =: |
| |
| ProcedureType := "PROCEDURE" |
| [ FormalTypeList ] =: |
| |
| FormalTypeList := "(" ( ")" FormalReturn | |
| ProcedureParameters ")" FormalReturn ) =: |
| |
| FormalReturn := [ ":" OptReturnType ] =: |
| |
| OptReturnType := "[" QualidentCheck "]" | QualidentCheck =: |
| |
| ProcedureParameters := ProcedureParameter |
| { "," ProcedureParameter } =: |
| |
| ProcedureParameter := "..." | "VAR" FormalType | FormalType =: |
| |
| |
| VarIdent := % VAR |
| Sym, Type: CARDINAL ; |
| on: BOOLEAN ; % |
| % on := IsAutoPushOn() % |
| % IF NOT on |
| THEN |
| PushAutoOn |
| END % |
| Ident % IF on |
| THEN |
| PopTF(Sym, Type) ; |
| PushTF(Sym, Type) ; |
| PushTF(Sym, Type) |
| END % |
| [ "[" ConstExpression % BuildVarAtAddress % |
| "]" ] |
| % PopNothing ; |
| PopAuto % |
| =: |
| |
| 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 ":" |
| % InclVar (BlockState) % |
| Type Alignment |
| % ExclVar (BlockState) % |
| =: |
| |
| Designator := QualidentCheck % CheckWithReference % |
| { SubDesignator } =: |
| |
| SubDesignator := "." % VAR Sym, Type, tok, |
| dotpostok : CARDINAL ; |
| name, n1 : Name ; % |
| % dotpostok := GetTokenNo () -1 ; |
| PopTFtok (Sym, Type, tok) ; |
| Type := SkipType(Type) ; |
| PushTFtok(Sym, Type, tok) ; |
| IF Type=NulSym |
| THEN |
| n1 := GetSymName(Sym) ; |
| IF IsModuleKnown(GetSymName(Sym)) |
| THEN |
| WriteFormat2('%a looks like a module which has not been globally imported (eg. suggest that you IMPORT %a)', |
| n1, n1) |
| ELSE |
| WriteFormat1('%a is not a record variable', n1) |
| END |
| ELSIF NOT IsRecord(Type) |
| THEN |
| MetaErrorT2 (tok, "the type of {%1ad} is not a record (but {%2ad}) and therefore it has no field", Sym, Type) ; |
| END ; |
| StartScope(Type) % |
| Ident |
| % PopTtok (name, tok) ; |
| Sym := GetLocalSym(Type, name) ; |
| IF Sym=NulSym |
| THEN |
| n1 := GetSymName(Type) ; |
| WriteFormat2('field %a does not exist within record %a', name, n1) |
| END ; |
| Type := GetType(Sym) ; |
| PushTFtok (Sym, Type, tok) ; |
| EndScope ; |
| PushT(1) ; |
| BuildDesignatorRecord (dotpostok) % |
| | "[" ArrayExpList |
| "]" |
| | "^" % BuildDesignatorPointer (GetTokenNo () -1) % |
| =: |
| |
| ArrayExpList := |
| Expression % BuildBooleanVariable % |
| % BuildDesignatorArray % |
| { "," |
| Expression % BuildBooleanVariable % |
| % BuildDesignatorArray % |
| } |
| =: |
| |
| ExpList := % VAR n: CARDINAL ; % |
| Expression % BuildBooleanVariable % |
| % n := 1 % |
| { "," |
| Expression % BuildBooleanVariable % |
| % INC(n) % |
| } |
| % PushT(n) % |
| =: |
| |
| Expression := % VAR tokpos: CARDINAL ; % |
| % PushAutoOn % |
| SimpleExpression [ Relation % tokpos := GetTokenNo ()-1 % |
| SimpleExpression % BuildRelOp (tokpos) % |
| ] % PopAuto % |
| =: |
| |
| SimpleExpression := UnaryOrTerm { AddOperator Term % BuildBinaryOp % |
| } =: |
| |
| UnaryOrTerm := "+" % PushTtok(PlusTok, GetTokenNo() -1) % |
| Term % BuildUnaryOp % |
| | "-" % PushTtok(MinusTok, GetTokenNo() -1) % |
| Term % BuildUnaryOp % |
| | Term =: |
| |
| Term := Factor |
| { MulOperator Factor % BuildBinaryOp % |
| } =: |
| |
| Factor := % VAR tokpos: CARDINAL ; % |
| Number | string | SetOrDesignatorOrFunction | |
| "(" Expression ")" | "NOT" % tokpos := GetTokenNo ()-1 % |
| ( Factor % BuildNot (tokpos) % |
| | ConstAttribute |
| ) =: |
| |
| SetOrDesignatorOrFunction := % VAR tokpos: CARDINAL ; % |
| % tokpos := GetTokenNo () % |
| ( |
| Qualident |
| % Assert (OperandTok (1) # UnknownTokenNo) % |
| % CheckWithReference % |
| % Assert (OperandTok (1) # UnknownTokenNo) % |
| [ Constructor | |
| SimpleDes % (* Assert (OperandTok(1) # UnknownTokenNo) *) % |
| [ ActualParameters % IF IsInConstParameters () |
| THEN |
| BuildConstFunctionCall |
| ELSE |
| BuildFunctionCall (FALSE) |
| END % |
| ] |
| ] | |
| % BuildTypeForConstructor (tokpos) % |
| Constructor ) =: |
| |
| -- SimpleDes := { "." Ident | "[" ExpList "]" | "^" } =: |
| SimpleDes := { SubDesignator } =: |
| |
| ActualParameters := "(" % BuildSizeCheckStart % |
| ( ExpList | % BuildNulParam % |
| ) ")" =: |
| |
| ExitStatement := "EXIT" % BuildExit % |
| =: |
| |
| ReturnStatement := "RETURN" % VAR tokno: CARDINAL ; % |
| % tokno := GetTokenNo () -1 % |
| ( Expression | % BuildNulExpression (tokno) % |
| ) % BuildReturn (tokno) % |
| =: |
| |
| Statement := % BuildStmtNote (0) % |
| % PushAutoOn ; DisplayStack % |
| [ AssignmentOrProcedureCall | IfStatement | CaseStatement | |
| WhileStatement | RepeatStatement | LoopStatement | |
| ForStatement | WithStatement | AsmStatement | |
| ExitStatement | ReturnStatement | RetryStatement |
| ] % PopAuto ; % |
| =: |
| |
| RetryStatement := "RETRY" % BuildRetry (GetTokenNo () -1) % |
| =: |
| |
| AssignmentOrProcedureCall := % VAR isFunc: BOOLEAN ; |
| tokno : CARDINAL ; % |
| % DisplayStack % |
| Designator |
| % tokno := GetTokenNo () % |
| ( ":=" |
| % (* PrintTokenNo (tokno) *) % |
| Expression % BuildAssignment (tokno) % |
| | % isFunc := CheckBuildFunction() % |
| ( ActualParameters | % BuildNulParam (* in epsilon *) % |
| ) % IF isFunc |
| THEN |
| BuildFunctionCall (FALSE) ; |
| BuildAssignment (tokno) |
| ELSE |
| BuildProcedureCall (tokno - 1) |
| END % |
| ) % DisplayStack % |
| =: |
| |
| -- these two break LL1 as both start with a Designator |
| -- ProcedureCall := Designator [ ActualParameters ] =: |
| -- Assignment := Designator ":=" Expression =: |
| |
| StatementSequence := |
| Statement |
| { ";" |
| Statement } |
| =: |
| |
| IfStatement := "IF" |
| Expression |
| "THEN" % BuildThenIf % |
| % BuildStmtNote (-1) % |
| StatementSequence |
| { "ELSIF" |
| % BuildElsif1 % |
| % BuildStmtNote (-1) % |
| Expression |
| "THEN" % BuildThenIf % |
| % BuildStmtNote (-1) % |
| StatementSequence % BuildElsif2 % |
| } |
| [ |
| "ELSE" % BuildElse % |
| % BuildStmtNote (-1) % |
| StatementSequence ] "END" % BuildEndIf % |
| % BuildStmtNote (-1) % |
| =: |
| |
| CaseStatement := "CASE" |
| Expression % BuildCaseStart % |
| "OF" Case { "|" Case } |
| CaseEndStatement |
| =: |
| |
| CaseEndStatement := "END" % BuildStmtNote (-1) % |
| % BuildCaseElse % |
| % BuildCaseCheck % |
| % BuildCaseEnd % |
| | "ELSE" % BuildStmtNote (-1) % |
| % BuildCaseElse % |
| % ElseCase (NulSym) % |
| StatementSequence % BuildStmtNote (0) % |
| "END" |
| % BuildCaseEnd % |
| =: |
| |
| Case := [ % BuildStmtNote (-1) % |
| CaseLabelList % BuildCaseStartStatementSequence % |
| ":" |
| StatementSequence % BuildCaseEndStatementSequence % |
| % EndCaseList % |
| ] |
| =: |
| |
| CaseLabelList := % BeginCaseList(NulSym) % |
| CaseLabels { "," % BuildCaseOr % |
| CaseLabels } =: |
| |
| CaseLabels := ConstExpression ( ".." ConstExpression % BuildCaseRange ; |
| BuildCaseList % |
| | % BuildCaseEquality ; (* epsilon *) |
| BuildCaseList % |
| ) =: |
| |
| WhileStatement := "WHILE" % BuildWhile % |
| % BuildStmtNote (0) % |
| Expression |
| % BuildStmtNote (0) % |
| "DO" % BuildDoWhile % |
| StatementSequence % BuildStmtNote (0) % |
| "END" % DisplayStack ; BuildEndWhile (-1) % |
| =: |
| |
| RepeatStatement := "REPEAT" |
| % BuildRepeat % |
| StatementSequence % BuildStmtNote (0) % |
| "UNTIL" |
| Expression % BuildUntil % |
| =: |
| |
| ForStatement := % VAR endpostok: CARDINAL ; % |
| % PushLineNo % |
| "FOR" Ident ":=" Expression "TO" Expression |
| ( "BY" ConstExpression | % BuildPseudoBy (* epsilon *) % |
| ) % PushLineNo % |
| % BuildStmtNote (0) % |
| "DO" % BuildForToByDo % |
| StatementSequence % BuildStmtNote (0) % |
| % endpostok := GetTokenNo () % |
| "END" % BuildEndFor (endpostok) % |
| =: |
| |
| LoopStatement := "LOOP" |
| % BuildLoop % |
| StatementSequence % BuildStmtNote (0) % |
| "END" % BuildEndLoop % |
| =: |
| |
| WithStatement := % VAR |
| tok: CARDINAL ; % |
| "WITH" % tok := GetTokenNo () -1 % |
| Designator % StartBuildWith (tok) % |
| % BuildStmtNote (0) % |
| "DO" |
| StatementSequence |
| % BuildStmtNote (0) % |
| "END" % EndBuildWith % |
| =: |
| |
| ProcedureDeclaration := % VAR top: CARDINAL ; % |
| % top := Top () % |
| ProcedureHeading ";" PostProcedureHeading % Assert (top = Top ()) % |
| =: |
| |
| PostProcedureHeading := ProperProcedure | ForwardDeclaration =: |
| |
| ForwardDeclaration := "FORWARD" % EndBuildForward % |
| =: |
| |
| ProperProcedure := ProcedureBlock % BuildProcedureEnd ; |
| PushAutoOn % |
| Ident % EndBuildProcedure ; |
| PopAuto % |
| =: |
| |
| DefineBuiltinProcedure := [ "__ATTRIBUTE__" "__BUILTIN__" |
| "(" "(" % PushAutoOff % |
| Ident % PopAuto % |
| ")" ")" | "__INLINE__" ] |
| =: |
| |
| ProcedureHeading := "PROCEDURE" % M2Error.DefaultProcedure % |
| % PushAutoOn % |
| DefineBuiltinProcedure |
| ( Ident |
| % StartBuildProcedure ; |
| PushAutoOff % |
| [ FormalParameters ] AttributeNoReturn |
| % BuildProcedureHeading ; |
| PopAuto % |
| ) % PopAuto % |
| =: |
| |
| Builtin := [ "__BUILTIN__" | "__INLINE__" ] =: |
| |
| DefProcedureHeading := "PROCEDURE" % M2Error.DefaultProcedure % |
| % PushAutoOn % |
| Builtin |
| ( Ident |
| % StartBuildProcedure ; |
| PushAutoOff % |
| [ DefFormalParameters ] AttributeNoReturn |
| % BuildProcedureHeading ; |
| PopAuto % |
| ) % PopAuto % |
| % M2Error.LeaveErrorScope % |
| =: |
| |
| AttributeNoReturn := [ "<*" Ident "*>" ] =: |
| |
| AttributeUnused := [ "<*" Ident "*>" ] =: |
| |
| -- introduced procedure block so we can produce more informative |
| -- error messages |
| |
| ProcedureBlock := % BuildProcedureStart % |
| { Declaration } % BuildProcedureBegin % |
| [ "BEGIN" % BuildStmtNote (-1) % |
| ProcedureBlockBody ] % BuildStmtNote (0) % |
| "END" |
| =: |
| |
| Block := { Declaration } |
| % StartBuildInit (GetTokenNo ()) % |
| InitialBlock % EndBuildInit (GetTokenNo ()) ; |
| StartBuildFinally (GetTokenNo ()) % |
| FinalBlock % EndBuildFinally (GetTokenNo ()) % |
| "END" |
| =: |
| |
| InitialBlock := [ "BEGIN" % BuildStmtNote (-1) % |
| InitialBlockBody ] =: |
| |
| FinalBlock := [ "FINALLY" % BuildStmtNote (-1) % |
| FinalBlockBody ] =: |
| |
| InitialBlockBody := NormalPart [ |
| "EXCEPT" % BuildStmtNote (-1) % |
| % BuildExceptInitial (GetTokenNo() -1) % |
| ExceptionalPart ] =: |
| |
| FinalBlockBody := NormalPart [ |
| "EXCEPT" % BuildStmtNote (-1) % |
| % BuildExceptFinally (GetTokenNo() -1) % |
| ExceptionalPart ] =: |
| |
| ProcedureBlockBody := NormalPart [ |
| "EXCEPT" % BuildStmtNote (-1) % |
| % BuildExceptProcedure (GetTokenNo() -1) % |
| ExceptionalPart ] =: |
| |
| NormalPart := StatementSequence =: |
| |
| ExceptionalPart := StatementSequence % BuildReThrow (GetTokenNo()) % |
| =: |
| |
| Declaration := "CONST" { ConstantDeclaration ";" } | |
| "TYPE" { TypeDeclaration ";" } | |
| "VAR" { VariableDeclaration ";" } | |
| ProcedureDeclaration ";" | |
| ModuleDeclaration ";" =: |
| |
| DefFormalParameters := "(" [ DefMultiFPSection ] ")" FormalReturn =: |
| |
| DefMultiFPSection := DefExtendedFP | |
| FPSection [ ";" DefMultiFPSection ] =: |
| |
| FormalParameters := "(" [ MultiFPSection ] ")" FormalReturn =: |
| |
| MultiFPSection := ExtendedFP | |
| FPSection [ ";" MultiFPSection ] =: |
| |
| FPSection := NonVarFPSection | VarFPSection =: |
| |
| DefExtendedFP := DefOptArg | "..." =: |
| |
| ExtendedFP := OptArg | "..." =: |
| |
| VarFPSection := "VAR" IdentList ":" FormalType [ AttributeUnused ] =: |
| |
| NonVarFPSection := IdentList ":" FormalType [ AttributeUnused ] =: |
| |
| OptArg := "[" Ident ":" FormalType [ "=" ConstExpression % BuildOptArgInitializer % |
| ] "]" =: |
| |
| DefOptArg := "[" Ident ":" FormalType "=" ConstExpression % BuildOptArgInitializer % |
| "]" =: |
| |
| FormalType := { "ARRAY" "OF" } QualidentCheck =: |
| |
| ModuleDeclaration := % VAR modulet: CARDINAL ; % |
| % modulet := GetTokenNo () % |
| "MODULE" % M2Error.DefaultInnerModule % |
| % PushAutoOn % |
| Ident % StartBuildInnerModule % |
| % BuildModuleStart (modulet) ; |
| PushAutoOff % |
| [ Priority ] ";" |
| { Import } [ Export ] |
| Block % PushAutoOn % |
| Ident % EndBuildInnerModule % |
| % PopAuto ; PopAuto ; PopAuto % |
| =: |
| |
| Priority := "[" % PushAutoOn % |
| ConstExpression % BuildModulePriority ; |
| PopAuto % |
| "]" =: |
| |
| Export := "EXPORT" ( "QUALIFIED" |
| IdentList | |
| "UNQUALIFIED" |
| IdentList | |
| IdentList ) ";" =: |
| |
| FromImport := % PushAutoOn % |
| "FROM" Ident "IMPORT" IdentList ";" % CheckImportListOuterModule % |
| % PopAuto % |
| =: |
| |
| WithoutFromImport := % PushAutoOff % |
| "IMPORT" IdentList ";" |
| % PopAuto % |
| =: |
| |
| Import := FromImport | WithoutFromImport =: |
| |
| DefinitionModule := % VAR deft, endt: CARDINAL ; % |
| % deft := GetTokenNo () % |
| "DEFINITION" % M2Error.DefaultDefinitionModule % |
| "MODULE" % PushAutoOn % |
| [ "FOR" string ] |
| Ident % StartBuildDefFile (deft) ; |
| P3StartBuildDefModule ; |
| PushAutoOff % |
| ";" |
| { Import } [ Export |
| ] |
| { Definition } % endt := GetTokenNo () % |
| "END" % PushAutoOn % |
| Ident % EndBuildFile (endt) ; |
| P3EndBuildDefModule % |
| "." % PopAuto ; PopAuto ; PopAuto % |
| =: |
| |
| Definition := "CONST" { ConstantDeclaration ";" } | |
| "TYPE" |
| { Ident ( ";" |
| | "=" Type Alignment ";" ) |
| } |
| | |
| "VAR" { VariableDeclaration ";" } | |
| DefProcedureHeading ";" =: |
| |
| AsmStatement := % VAR CurrentAsm: CARDINAL ; |
| tok: CARDINAL ; % |
| % tok := GetTokenNo () % |
| 'ASM' % PushAutoOn ; |
| PushT (0) ; (* operand count *) |
| PushT (MakeGnuAsm ()) |
| % |
| [ 'VOLATILE' % PopT (CurrentAsm) ; |
| PutGnuAsmVolatile (CurrentAsm) ; |
| PushT (CurrentAsm) |
| % |
| ] '(' AsmOperands % PopNothing ; (* throw away interface sym *) |
| BuildAsm (tok) ; |
| PopNothing ; (* throw away count *) |
| PopAuto |
| % |
| ')' =: |
| |
| AsmOperands := % VAR CurrentAsm, count: CARDINAL ; |
| str: CARDINAL ; |
| % |
| ConstExpression % PopT (str) ; |
| PopT (CurrentAsm) ; |
| Assert (IsGnuAsm (CurrentAsm) OR IsGnuAsmVolatile (CurrentAsm)) ; |
| PopT (count) ; |
| IF DebugAsm |
| THEN |
| printf1 ('1: count of asm operands: %d\n', count) |
| END ; |
| PushT (count) ; |
| (* adds the name/instruction for this asm *) |
| PutGnuAsm (CurrentAsm, str) ; |
| PushT (CurrentAsm) ; |
| PushT (NulSym) (* the InterfaceSym *) |
| % |
| ( AsmOperandSpec | % (* epsilon *) |
| PutGnuAsmSimple (CurrentAsm) |
| % |
| ) |
| =: |
| |
| AsmOperandSpec := % VAR CurrentAsm, outputs, inputs, trash, count: CARDINAL ; |
| % |
| ':' AsmOutputList % PopT(outputs) ; |
| PopT(CurrentAsm) ; |
| Assert(IsGnuAsm(CurrentAsm) OR IsGnuAsmVolatile(CurrentAsm)) ; |
| PopT(count) ; |
| IF DebugAsm |
| THEN |
| printf1('2: output count of asm operands: %d\n', count) |
| END ; |
| PutGnuAsmOutput(CurrentAsm, outputs) ; |
| PushT(0) ; (* reset count *) |
| PushT(CurrentAsm) ; |
| PushT(NulSym) (* the InterfaceSym *) |
| % |
| [ ':' AsmInputList % PopT(inputs) ; |
| PopT(CurrentAsm) ; |
| Assert(IsGnuAsm(CurrentAsm) OR IsGnuAsmVolatile(CurrentAsm)) ; |
| PopT(count) ; |
| IF DebugAsm |
| THEN |
| printf1('3: input count of asm operands: %d\n', count) |
| END ; |
| PutGnuAsmInput(CurrentAsm, inputs) ; |
| PushT(0) ; (* reset count *) |
| PushT(CurrentAsm) ; |
| PushT(NulSym) (* the InterfaceSym *) |
| % |
| [ ':' AsmTrashList % PopT(trash) ; |
| PopT(CurrentAsm) ; |
| Assert(IsGnuAsm(CurrentAsm) OR IsGnuAsmVolatile(CurrentAsm)) ; |
| PopT(count) ; |
| IF DebugAsm |
| THEN |
| printf1('4: trash count of asm operands: %d\n', count) |
| END ; |
| PutGnuAsmTrash(CurrentAsm, trash) ; |
| PushT(0) ; (* reset count *) |
| PushT(CurrentAsm) ; |
| PushT(NulSym) (* the InterfaceSym *) |
| % |
| ] ] |
| =: |
| |
| AsmOutputList := [ AsmOutputElement ] { ',' AsmOutputElement } =: |
| |
| AsmInputList := [ AsmInputElement ] { ',' AsmInputElement } =: |
| |
| NamedOperand := '[' Ident ']' =: |
| |
| AsmOperandName := ( NamedOperand |
| | % IF IsAutoPushOn() |
| THEN |
| PushTF (NulName, identtok) |
| END |
| % |
| ) |
| =: |
| |
| AsmInputElement := AsmOperandName |
| ConstExpression '(' Expression % BuildAsmElement (TRUE, FALSE) |
| % |
| ')' |
| =: |
| |
| AsmOutputElement := AsmOperandName |
| ConstExpression '(' Expression % BuildAsmElement (FALSE, TRUE) |
| % |
| ')' |
| =: |
| |
| AsmTrashList := [ ConstExpression % BuildAsmTrash |
| % |
| ] { ',' ConstExpression % BuildAsmTrash |
| % |
| } =: |
| |
| FNB |