blob: 0033d33e446a5623f7fd5b50917869a6b0545e1c [file] [log] [blame]
--
-- 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