1 (* M2Quads.mod generates quadruples.
3 Copyright (C) 2001-2024 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
6 This file is part of GNU Modula-2.
8 GNU Modula-2 is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GNU Modula-2 is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Modula-2; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. *)
22 IMPLEMENTATION MODULE M2Quads ;
25 FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
26 FROM M2Debug IMPORT Assert, WriteDebug ;
27 FROM NameKey IMPORT Name, NulName, MakeKey, GetKey, makekey, KeyToCharStar, WriteKey ;
28 FROM FormatStrings IMPORT Sprintf0, Sprintf1, Sprintf2, Sprintf3 ;
29 FROM M2DebugStack IMPORT DebugStack ;
30 FROM M2Scaffold IMPORT DeclareScaffold, mainFunction, initFunction,
31 finiFunction, linkFunction, PopulateCtorArray,
32 ForeachModuleCallInit, ForeachModuleCallFinish ;
34 FROM M2MetaError IMPORT MetaError0, MetaError1, MetaError2, MetaError3,
35 MetaErrors1, MetaErrors2, MetaErrors3,
36 MetaErrorT0, MetaErrorT1, MetaErrorT2,
37 MetaErrorsT1, MetaErrorsT2, MetaErrorT3,
38 MetaErrorStringT0, MetaErrorStringT1,
39 MetaErrorString1, MetaErrorString2,
40 MetaErrorN1, MetaErrorN2,
41 MetaErrorNT0, MetaErrorNT1, MetaErrorNT2 ;
43 FROM DynamicStrings IMPORT String, string, InitString, KillString,
44 ConCat, InitStringCharStar, Dup, Mark,
45 PushAllocation, PopAllocationExemption,
46 InitStringDB, InitStringCharStarDB,
47 InitStringCharDB, MultDB, DupDB, SliceDB ;
49 FROM SymbolTable IMPORT ModeOfAddr, GetMode, PutMode, GetSymName, IsUnknown,
51 MakeTemporaryFromExpression,
52 MakeTemporaryFromExpressions,
53 MakeConstLit, MakeConstLitString,
54 MakeConstString, MakeConstant,
56 RequestSym, MakePointer, PutPointer,
58 GetDType, GetSType, GetLType,
59 GetScope, GetCurrentScope,
60 GetSubrange, SkipTypeAndSubrange,
61 GetModule, GetMainModule,
62 GetCurrentModule, GetFileModule, GetLocalSym,
63 GetStringLength, GetString,
64 GetArraySubscript, GetDimension,
67 GetFirstUsed, GetDeclaredMod,
68 GetQuads, GetReadQuads, GetWriteQuads,
69 GetWriteLimitQuads, GetReadLimitQuads,
71 GetModuleQuads, GetProcedureQuads,
74 MakeConstStringCnul, MakeConstStringM2nul,
76 PutModuleStartQuad, PutModuleEndQuad,
77 PutModuleFinallyStartQuad, PutModuleFinallyEndQuad,
78 PutProcedureStartQuad, PutProcedureEndQuad,
79 PutProcedureScopeQuad,
81 GetVarPointerCheck, PutVarPointerCheck,
83 PutReadQuad, RemoveReadQuad,
84 PutWriteQuad, RemoveWriteQuad,
85 PutPriority, GetPriority,
86 PutProcedureBegin, PutProcedureEnd,
87 PutVarConst, IsVarConst,
89 IsVarParam, IsProcedure, IsPointer, IsParameter,
90 IsUnboundedParam, IsEnumeration, IsDefinitionForC,
91 IsVarAParam, IsVarient, IsLegal,
92 UsesVarArgs, UsesOptArg,
98 IsGnuAsm, IsGnuAsmVolatile,
99 MakeRegInterface, PutRegInterface,
100 HasExceptionBlock, PutExceptionBlock,
101 HasExceptionFinally, PutExceptionFinally,
102 GetParent, GetRecord, IsRecordField, IsFieldVarient, IsRecord,
104 IsVar, IsProcType, IsType, IsSubrange, IsExported,
105 IsConst, IsConstString, IsModule, IsDefImp,
106 IsArray, IsUnbounded, IsProcedureNested,
107 IsParameterUnbounded,
108 IsPartialUnbounded, IsProcedureBuiltin,
109 IsSet, IsConstSet, IsConstructor, PutConst,
110 PutConstructor, PutConstructorFrom,
112 MakeComponentRecord, MakeComponentRef,
113 IsSubscript, IsComponent,
116 PutLeftValueFrontBackType,
117 PushSize, PushValue, PopValue,
118 GetVariableAtAddress, IsVariableAtAddress,
119 MakeError, UnknownReported,
120 IsProcedureBuiltinAvailable,
123 IsImportStatement, IsImport, GetImportModule, GetImportDeclared,
124 GetImportStatementList,
125 GetModuleDefImportStatementList, GetModuleModImportStatementList,
126 IsCtor, IsPublic, IsExtern, IsMonoName,
128 GetUnboundedRecordType,
129 GetUnboundedAddressOffset,
130 GetUnboundedHighOffset,
133 ForeachFieldEnumerationDo, ForeachLocalSymDo,
134 GetExported, PutImported, GetSym, GetLibName,
138 FROM M2Batch IMPORT MakeDefinitionSource ;
139 FROM M2GCCDeclare IMPORT PutToBeSolvedByQuads ;
141 FROM FifoQueue IMPORT GetConstFromFifoQueue,
142 PutConstructorIntoFifoQueue, GetConstructorFromFifoQueue ;
144 FROM M2Comp IMPORT CompilingImplementationModule,
145 CompilingProgramModule ;
147 FROM M2LexBuf IMPORT currenttoken, UnknownTokenNo, BuiltinTokenNo,
148 GetToken, MakeVirtualTok,
149 GetFileName, TokenToLineNo, GetTokenName,
150 GetTokenNo, GetLineNo, GetPreviousTokenLineNo, PrintTokenNo ;
152 FROM M2Error IMPORT Error,
154 WriteFormat0, WriteFormat1, WriteFormat2, WriteFormat3,
155 NewError, NewWarning, ErrorFormat0, ErrorFormat1,
156 ErrorFormat2, ErrorFormat3, FlushErrors, ChainError,
158 ErrorStringAt, ErrorStringAt2, ErrorStringsAt2,
159 WarnStringAt, WarnStringAt2, WarnStringsAt2 ;
161 FROM M2Printf IMPORT printf0, printf1, printf2, printf3, printf4 ;
163 FROM M2Reserved IMPORT PlusTok, MinusTok, TimesTok, DivTok, ModTok,
165 OrTok, AndTok, AmbersandTok,
166 EqualTok, LessEqualTok, GreaterEqualTok,
167 LessTok, GreaterTok, HashTok, LessGreaterTok,
169 UpArrowTok, RParaTok, LParaTok, CommaTok,
171 SemiColonTok, toktype ;
173 FROM M2Base IMPORT True, False, Boolean, Cardinal, Integer, Char,
174 Real, LongReal, ShortReal, Nil,
177 NegateType, ComplexToScalar, GetCmplxReturnType,
178 IsAssignmentCompatible, IsExpressionCompatible,
179 AssignmentRequiresWarning,
180 CannotCheckTypeInPass3, ScalarToComplex, MixTypes,
181 CheckAssignmentCompatible, CheckExpressionCompatible,
182 High, LengthS, New, Dispose, Inc, Dec, Incl, Excl,
184 IsOrd, Chr, Convert, Val, IsFloat, IsTrunc,
186 IsPseudoBaseProcedure, IsPseudoBaseFunction,
187 IsMathType, IsOrdinalType, IsRealType,
188 IsBaseType, GetBaseTypeMinMax, ActivationPointer ;
190 FROM M2System IMPORT IsPseudoSystemFunction, IsPseudoSystemProcedure,
191 IsSystemType, GetSystemTypeMinMax,
192 IsPseudoSystemFunctionConstExpression,
194 Adr, TSize, TBitSize, AddAdr, SubAdr, DifAdr, Cast,
195 Shift, Rotate, MakeAdr, Address, Byte, Word, Loc, Throw ;
197 FROM M2Size IMPORT Size ;
198 FROM M2Bitset IMPORT Bitset ;
200 FROM M2ALU IMPORT PushInt, Gre, Less, PushNulSet, AddBitRange, AddBit,
201 IsGenericNulSet, IsValueAndTreeKnown, AddField,
202 AddElements, ChangeToConstructor ;
204 FROM Lists IMPORT List, InitList, GetItemFromList, NoOfItemsInList, PutItemIntoList,
205 IsItemInList, KillList, IncludeItemIntoList ;
207 FROM M2Options IMPORT NilChecking,
208 WholeDivChecking, WholeValueChecking,
209 IndexChecking, RangeChecking,
210 CaseElseChecking, ReturnChecking,
211 UnusedVariableChecking, UnusedParameterChecking,
212 Iso, Pim, Pim2, Pim3, Pim4, PositiveModFloorDiv,
213 Pedantic, CompilerDebugging, GenerateDebugging,
214 GenerateLineDebug, Exceptions,
215 Profiling, Coding, Optimizing,
216 UninitVariableChecking,
217 ScaffoldDynamic, ScaffoldStatic, cflag,
218 ScaffoldMain, SharedFlag, WholeProgram,
219 GetRuntimeModuleOverride ;
221 FROM M2Pass IMPORT IsPassCodeGeneration, IsNoPass ;
223 FROM M2StackAddress IMPORT StackOfAddress, InitStackAddress, KillStackAddress,
224 PushAddress, PopAddress, PeepAddress,
225 IsEmptyAddress, NoOfItemsInStackAddress ;
227 FROM M2StackWord IMPORT StackOfWord, InitStackWord, KillStackWord,
228 PushWord, PopWord, PeepWord, RemoveTop,
229 IsEmptyWord, NoOfItemsInStackWord ;
231 FROM Indexing IMPORT Index, InitIndex, GetIndice, PutIndice, InBounds, HighIndice, IncludeIndiceIntoIndex ;
233 FROM M2Range IMPORT InitAssignmentRangeCheck,
234 InitReturnRangeCheck,
235 InitSubrangeRangeCheck,
236 InitStaticArraySubscriptRangeCheck,
237 InitDynamicArraySubscriptRangeCheck,
244 InitTypesAssignmentCheck,
245 InitTypesExpressionCheck,
246 InitTypesParameterCheck,
247 InitForLoopBeginRangeCheck,
248 InitForLoopToRangeCheck,
249 InitForLoopEndRangeCheck,
250 InitPointerRangeCheck,
251 InitNoReturnRangeCheck,
252 InitNoElseRangeCheck,
254 InitWholeZeroDivisionCheck,
255 InitWholeZeroRemainderCheck,
256 InitParameterRangeCheck,
259 FROM M2CaseList IMPORT PushCase, PopCase, AddRange, BeginCaseList, EndCaseList, ElseCase ;
260 FROM PCSymBuild IMPORT SkipConst ;
261 FROM m2builtins IMPORT GetBuiltinTypeInfoType ;
267 DebugStackOn = TRUE ;
268 DebugVarients = FALSE ;
270 DebugTokPos = FALSE ;
273 ConstructorFrame = POINTER TO RECORD
278 BoolFrame = POINTER TO RECORD
279 TrueExit : CARDINAL ;
280 FalseExit : CARDINAL ;
281 Unbounded : CARDINAL ;
282 BooleanOp : BOOLEAN ;
283 Dimension : CARDINAL ;
284 ReadWrite : CARDINAL ;
290 QuadFrame = POINTER TO RECORD
291 Operator : QuadOperator ;
292 Operand1 : CARDINAL ;
293 Operand2 : CARDINAL ;
294 Operand3 : CARDINAL ;
296 Next : CARDINAL ; (* Next quadruple. *)
297 LineNo : CARDINAL ; (* Line No of source text. *)
298 TokenNo : CARDINAL ; (* Token No of source text. *)
299 NoOfTimesReferenced: CARDINAL ; (* No of times quad is referenced. *)
300 CheckOverflow : BOOLEAN ; (* should backend check overflow *)
303 op3pos : CARDINAL ; (* Token position of operands. *)
306 WithFrame = POINTER TO RECORD
307 RecordSym : CARDINAL ;
308 RecordType : CARDINAL ;
309 RecordRef : CARDINAL ;
310 rw : CARDINAL ; (* The record variable. *)
311 RecordTokPos: CARDINAL ; (* Token of the record. *)
314 ForLoopInfo = POINTER TO RECORD
316 StartOfForLoop, (* We keep a list of all for *)
317 EndOfForLoop, (* loops so we can check index. *)
319 IndexTok : CARDINAL ; (* Used to ensure iterators are not *)
323 LineNote = POINTER TO RECORD
332 WithStack : StackOfAddress ;
342 ReturnStack : StackOfWord ; (* Return quadruple of the procedure. *)
343 PriorityStack : StackOfWord ; (* Temporary variable holding old *)
345 SuppressWith : BOOLEAN ;
347 NextQuad : CARDINAL ; (* Next quadruple number to be created. *)
348 FreeList : CARDINAL ; (* FreeList of quadruples. *)
349 CurrentProc : CARDINAL ; (* Current procedure being compiled, used *)
350 (* to determine which procedure a RETURN. *)
351 (* ReturnValueOp must have as its 3rd op. *)
352 InitQuad : CARDINAL ; (* Initial Quad BackPatch that starts the *)
353 (* suit of Modules. *)
354 LastQuadNo : CARDINAL ; (* Last Quadruple accessed by GetQuad. *)
355 ArithPlusTok, (* Internal + token for arithmetic only. *)
356 LogicalOrTok, (* Internal _LOR token. *)
357 LogicalAndTok, (* Internal _LAND token. *)
358 LogicalXorTok, (* Internal _LXOR token. *)
359 LogicalDifferenceTok : Name ; (* Internal _LDIFF token. *)
361 IsAutoOn, (* Should parser automatically push *)
363 MustNotCheckBounds : BOOLEAN ;
364 ForInfo : Index ; (* Start and end of all FOR loops. *)
365 GrowInitialization : CARDINAL ; (* Upper limit of where the initialized *)
369 QuadrupleGeneration : BOOLEAN ; (* Should we be generating quadruples? *)
370 FreeLineList : LineNote ; (* Free list of line notes. *)
371 VarientFields : List ; (* The list of all varient fields created. *)
372 VarientFieldNo : CARDINAL ; (* Used to retrieve the VarientFields *)
374 NoOfQuads : CARDINAL ; (* Number of used quadruples. *)
375 Head : CARDINAL ; (* Head of the list of quadruples. *)
379 Rules for file and initialization quadruples:
381 StartModFileOp - indicates that this file (module) has produced the
383 StartDefFileOp - indicates that this definition module has produced
385 EndFileOp - indicates that a module has finished
386 InitStartOp - the start of the initialization code of a module
387 InitEndOp - the end of the above
388 FinallyStartOp - the start of the finalization code of a module
389 FinallyEndOp - the end of the above
394 #define InitString(X) InitStringDB(X, __FILE__, __LINE__)
395 #define InitStringCharStar(X) InitStringCharStarDB(X, __FILE__, __LINE__)
396 #define InitStringChar(X) InitStringCharDB(X, __FILE__, __LINE__)
397 #define Mult(X,Y) MultDB(X, Y, __FILE__, __LINE__)
398 #define Dup(X) DupDB(X, __FILE__, __LINE__)
399 #define Slice(X,Y,Z) SliceDB(X, Y, Z, __FILE__, __LINE__)
408 PROCEDURE doDSdbEnter ;
419 PROCEDURE doDSdbExit (s: String) ;
421 s := PopAllocationExemption(TRUE, s)
429 PROCEDURE DSdbEnter ;
444 #define DBsbEnter doDBsbEnter
445 #define DBsbExit doDBsbExit
450 SetOptionProfiling - builds a profile quadruple if the profiling
451 option was given to the compiler.
454 PROCEDURE SetOptionProfiling (b: BOOLEAN) ;
466 END SetOptionProfiling ;
470 SetOptionCoding - builds a code quadruple if the profiling
471 option was given to the compiler.
474 PROCEDURE SetOptionCoding (b: BOOLEAN) ;
486 END SetOptionCoding ;
490 SetOptionOptimizing - builds a quadruple to say that the optimization option
491 has been found in a comment.
494 PROCEDURE SetOptionOptimizing (b: BOOLEAN) ;
502 END SetOptionOptimizing ;
506 GetQF - returns the QuadFrame associated with, q.
509 PROCEDURE GetQF (q: CARDINAL) : QuadFrame ;
511 RETURN QuadFrame (GetIndice (QuadArray, q))
516 Opposite - returns the opposite comparison operator.
519 PROCEDURE Opposite (Operator: QuadOperator) : QuadOperator ;
525 IfNotEquOp : Op := IfEquOp |
526 IfEquOp : Op := IfNotEquOp |
527 IfLessEquOp: Op := IfGreOp |
528 IfGreOp : Op := IfLessEquOp |
529 IfGreEquOp : Op := IfLessOp |
530 IfLessOp : Op := IfGreEquOp |
531 IfInOp : Op := IfNotInOp |
532 IfNotInOp : Op := IfInOp
535 InternalError ('unexpected operator')
542 IsReferenced - returns true if QuadNo is referenced by another quadruple.
545 PROCEDURE IsReferenced (QuadNo: CARDINAL) : BOOLEAN ;
551 RETURN( (Operator=ProcedureScopeOp) OR (Operator=NewLocalVarOp) OR
552 (NoOfTimesReferenced>0) )
558 IsBackReference - returns TRUE if quadruple, q, is referenced from a quad further on.
561 PROCEDURE IsBackReference (q: CARDINAL) : BOOLEAN ;
565 op1, op2, op3: CARDINAL ;
569 GetQuad (i, op, op1, op2, op3) ;
580 StartModFileOp: RETURN( FALSE ) | (* run into end of procedure or module *)
599 InternalError ('fix this for the sake of efficiency..')
600 END IsBackReference ;
604 IsUnConditional - returns true if QuadNo is an unconditional jump.
607 PROCEDURE IsUnConditional (QuadNo: CARDINAL) : BOOLEAN ;
619 GotoOp : RETURN( TRUE )
625 END IsUnConditional ;
629 IsConditional - returns true if QuadNo is a conditional jump.
632 PROCEDURE IsConditional (QuadNo: CARDINAL) : BOOLEAN ;
647 IfGreEquOp : RETURN( TRUE )
657 IsBackReferenceConditional - returns TRUE if quadruple, q, is referenced from
658 a conditional quad further on.
661 PROCEDURE IsBackReferenceConditional (q: CARDINAL) : BOOLEAN ;
665 op1, op2, op3: CARDINAL ;
669 GetQuad (i, op, op1, op2, op3) ;
680 StartModFileOp: RETURN( FALSE ) | (* run into end of procedure or module *)
692 IfNotInOp : IF (op3=q) AND IsConditional(q)
702 InternalError ('fix this for the sake of efficiency..')
703 END IsBackReferenceConditional ;
707 IsQuadA - returns true if QuadNo is a op.
710 PROCEDURE IsQuadA (QuadNo: CARDINAL; op: QuadOperator) : BOOLEAN ;
716 RETURN( Operator=op )
722 IsGoto - returns true if QuadNo is a goto operation.
725 PROCEDURE IsGoto (QuadNo: CARDINAL) : BOOLEAN ;
727 RETURN( IsQuadA (QuadNo, GotoOp) )
732 IsCall - returns true if QuadNo is a call operation.
735 PROCEDURE IsCall (QuadNo: CARDINAL) : BOOLEAN ;
737 RETURN( IsQuadA(QuadNo, CallOp) )
742 IsReturn - returns true if QuadNo is a return operation.
745 PROCEDURE IsReturn (QuadNo: CARDINAL) : BOOLEAN ;
747 RETURN( IsQuadA(QuadNo, ReturnOp) )
752 IsNewLocalVar - returns true if QuadNo is a NewLocalVar operation.
755 PROCEDURE IsNewLocalVar (QuadNo: CARDINAL) : BOOLEAN ;
757 RETURN( IsQuadA(QuadNo, NewLocalVarOp) )
762 IsKillLocalVar - returns true if QuadNo is a KillLocalVar operation.
765 PROCEDURE IsKillLocalVar (QuadNo: CARDINAL) : BOOLEAN ;
767 RETURN( IsQuadA(QuadNo, KillLocalVarOp) )
772 IsProcedureScope - returns true if QuadNo is a ProcedureScope operation.
775 PROCEDURE IsProcedureScope (QuadNo: CARDINAL) : BOOLEAN ;
777 RETURN( IsQuadA(QuadNo, ProcedureScopeOp) )
778 END IsProcedureScope ;
782 IsCatchBegin - returns true if QuadNo is a catch begin quad.
785 PROCEDURE IsCatchBegin (QuadNo: CARDINAL) : BOOLEAN ;
787 RETURN( IsQuadA(QuadNo, CatchBeginOp) )
792 IsCatchEnd - returns true if QuadNo is a catch end quad.
795 PROCEDURE IsCatchEnd (QuadNo: CARDINAL) : BOOLEAN ;
797 RETURN( IsQuadA(QuadNo, CatchEndOp) )
802 IsInitStart - returns true if QuadNo is a init start quad.
805 PROCEDURE IsInitStart (QuadNo: CARDINAL) : BOOLEAN ;
807 RETURN( IsQuadA(QuadNo, InitStartOp) )
812 IsInitEnd - returns true if QuadNo is a init end quad.
815 PROCEDURE IsInitEnd (QuadNo: CARDINAL) : BOOLEAN ;
817 RETURN( IsQuadA(QuadNo, InitEndOp) )
822 IsFinallyStart - returns true if QuadNo is a finally start quad.
825 PROCEDURE IsFinallyStart (QuadNo: CARDINAL) : BOOLEAN ;
827 RETURN( IsQuadA(QuadNo, FinallyStartOp) )
832 IsFinallyEnd - returns true if QuadNo is a finally end quad.
835 PROCEDURE IsFinallyEnd (QuadNo: CARDINAL) : BOOLEAN ;
837 RETURN( IsQuadA(QuadNo, FinallyEndOp) )
842 IsInitialisingConst - returns TRUE if the quadruple is setting
843 a const (op1) with a value.
846 PROCEDURE IsInitialisingConst (QuadNo: CARDINAL) : BOOLEAN ;
849 op1, op2, op3: CARDINAL ;
851 GetQuad (QuadNo, op, op1, op2, op3) ;
887 RestoreExceptionOp: RETURN( IsConst(op1) )
892 END IsInitialisingConst ;
896 IsOptimizeOn - returns true if the Optimize flag was true at QuadNo.
899 PROCEDURE IsOptimizeOn (QuadNo: CARDINAL) : BOOLEAN ;
908 WHILE (q#0) AND (q#QuadNo) DO
911 IF Operator=OptimizeOnOp
914 ELSIF Operator=OptimizeOffOp
927 IsProfileOn - returns true if the Profile flag was true at QuadNo.
930 PROCEDURE IsProfileOn (QuadNo: CARDINAL) : BOOLEAN ;
939 WHILE (q#0) AND (q#QuadNo) DO
942 IF Operator=ProfileOnOp
945 ELSIF Operator=ProfileOffOp
958 IsCodeOn - returns true if the Code flag was true at QuadNo.
961 PROCEDURE IsCodeOn (QuadNo: CARDINAL) : BOOLEAN ;
970 WHILE (q#0) AND (q#QuadNo) DO
976 ELSIF Operator=CodeOffOp
989 IsDefOrModFile - returns TRUE if QuadNo is a start of Module or Def file
993 PROCEDURE IsDefOrModFile (QuadNo: CARDINAL) : BOOLEAN ;
999 RETURN( (Operator=StartDefFileOp) OR (Operator=StartModFileOp) )
1001 END IsDefOrModFile ;
1005 IsPseudoQuad - returns true if QuadNo is a compiler directive.
1006 ie code, profile and optimize.
1010 PROCEDURE IsPseudoQuad (QuadNo: CARDINAL) : BOOLEAN ;
1014 f := GetQF(QuadNo) ;
1016 RETURN( (Operator=CodeOnOp) OR (Operator=CodeOffOp) OR
1017 (Operator=ProfileOnOp) OR (Operator=ProfileOffOp) OR
1018 (Operator=OptimizeOnOp) OR (Operator=OptimizeOffOp) OR
1019 (Operator=EndFileOp) OR
1020 (Operator=StartDefFileOp) OR (Operator=StartModFileOp)
1027 GetLastFileQuad - returns the Quadruple number of the last StartDefFile or
1028 StartModFile quadruple.
1031 PROCEDURE GetLastFileQuad (QuadNo: CARDINAL) : CARDINAL ;
1035 FileQuad: CARDINAL ;
1042 IF (Operator=StartModFileOp) OR (Operator=StartDefFileOp)
1049 UNTIL (i=QuadNo) OR (i=0) ;
1051 Assert(FileQuad#0) ;
1053 END GetLastFileQuad ;
1057 GetLastQuadNo - returns the last quadruple number referenced
1061 PROCEDURE GetLastQuadNo () : CARDINAL ;
1063 RETURN( LastQuadNo )
1068 QuadToLineNo - Converts a QuadNo into the approprate line number of the
1069 source file, the line number is returned.
1071 This may be used to yield an idea where abouts in the
1072 source file the code generetion is
1076 PROCEDURE QuadToLineNo (QuadNo: CARDINAL) : CARDINAL ;
1080 IF ((LastQuadNo=0) AND (NOT IsNoPass()) AND (NOT IsPassCodeGeneration())) OR
1081 (NOT InBounds(QuadArray, QuadNo))
1085 f := GetQF(QuadNo) ;
1092 QuadToTokenNo - Converts a QuadNo into the approprate token number of the
1093 source file, the line number is returned.
1095 This may be used to yield an idea where abouts in the
1096 source file the code generetion is
1100 PROCEDURE QuadToTokenNo (QuadNo: CARDINAL) : CARDINAL ;
1104 IF ((LastQuadNo=0) AND (NOT IsNoPass()) AND (NOT IsPassCodeGeneration())) OR
1105 (NOT InBounds(QuadArray, QuadNo))
1109 f := GetQF(QuadNo) ;
1110 RETURN( f^.TokenNo )
1116 GetQuad - returns the Quadruple QuadNo.
1119 PROCEDURE GetQuad (QuadNo: CARDINAL;
1120 VAR Op: QuadOperator;
1121 VAR Oper1, Oper2, Oper3: CARDINAL) ;
1125 f := GetQF(QuadNo) ;
1126 LastQuadNo := QuadNo ;
1137 GetQuadtok - returns the Quadruple QuadNo.
1140 PROCEDURE GetQuadtok (QuadNo: CARDINAL;
1141 VAR Op: QuadOperator;
1142 VAR Oper1, Oper2, Oper3: CARDINAL;
1143 VAR Op1Pos, Op2Pos, Op3Pos: CARDINAL) ;
1147 f := GetQF (QuadNo) ;
1148 LastQuadNo := QuadNo ;
1162 GetQuadOtok - returns the Quadruple QuadNo.
1165 PROCEDURE GetQuadOtok (QuadNo: CARDINAL;
1167 VAR Op: QuadOperator;
1168 VAR Oper1, Oper2, Oper3: CARDINAL;
1169 VAR overflowChecking: BOOLEAN ;
1170 VAR Op1Pos, Op2Pos, Op3Pos: CARDINAL) ;
1174 f := GetQF (QuadNo) ;
1175 LastQuadNo := QuadNo ;
1185 overflowChecking := CheckOverflow
1191 PutQuadOtok - alters a quadruple QuadNo with Op, Oper1, Oper2, Oper3, and
1192 sets a boolean to determinine whether overflow should be checked.
1195 PROCEDURE PutQuadOtok (QuadNo: CARDINAL;
1198 Oper1, Oper2, Oper3: CARDINAL;
1199 overflowChecking: BOOLEAN ;
1200 Op1Pos, Op2Pos, Op3Pos: CARDINAL) ;
1204 IF QuadNo = BreakAtQuad
1208 IF QuadrupleGeneration
1210 EraseQuad (QuadNo) ;
1211 AddQuadInformation (QuadNo, Op, Oper1, Oper2, Oper3) ;
1212 f := GetQF (QuadNo) ;
1218 CheckOverflow := overflowChecking ;
1229 AddQuadInformation - adds variable analysis and jump analysis to the new quadruple.
1232 PROCEDURE AddQuadInformation (QuadNo: CARDINAL;
1234 Oper1, Oper2, Oper3: CARDINAL) ;
1245 IfGreEquOp : ManipulateReference(QuadNo, Oper3) ;
1246 CheckAddVariableRead(Oper1, FALSE, QuadNo) ;
1247 CheckAddVariableRead(Oper2, FALSE, QuadNo) |
1251 GotoOp : ManipulateReference(QuadNo, Oper3) |
1253 (* variable references *)
1256 ExclOp : CheckConst(Oper1) ;
1257 CheckAddVariableRead(Oper3, FALSE, QuadNo) ;
1258 CheckAddVariableWrite(Oper1, TRUE, QuadNo) |
1264 SizeOp : CheckConst(Oper1) ;
1265 CheckAddVariableWrite(Oper1, FALSE, QuadNo) ;
1266 CheckAddVariableRead(Oper3, FALSE, QuadNo) |
1267 AddrOp : CheckConst(Oper1) ;
1268 CheckAddVariableWrite(Oper1, FALSE, QuadNo) ;
1269 (* CheckAddVariableReadLeftValue(Oper3, QuadNo) *)
1270 (* the next line is a kludge and assumes we _will_
1271 write to the variable as we have taken its address *)
1272 CheckRemoveVariableWrite(Oper1, TRUE, QuadNo) |
1273 ReturnValueOp : CheckAddVariableRead(Oper1, FALSE, QuadNo) |
1277 CallOp : CheckAddVariableRead(Oper3, TRUE, QuadNo) |
1279 ParamOp : CheckAddVariableRead(Oper2, FALSE, QuadNo) ;
1280 CheckAddVariableRead(Oper3, FALSE, QuadNo) ;
1281 IF (Oper1>0) AND (Oper1<=NoOfParam(Oper2)) AND
1282 IsVarParam(Oper2, Oper1)
1284 (* _may_ also write to a var parameter, although we dont know *)
1285 CheckAddVariableWrite(Oper3, TRUE, QuadNo)
1307 DivTruncOp : CheckConst(Oper1) ;
1308 CheckAddVariableWrite(Oper1, FALSE, QuadNo) ;
1309 CheckAddVariableRead(Oper2, FALSE, QuadNo) ;
1310 CheckAddVariableRead(Oper3, FALSE, QuadNo) |
1312 XIndrOp : CheckConst(Oper1) ;
1313 CheckAddVariableWrite(Oper1, TRUE, QuadNo) ;
1314 CheckAddVariableRead(Oper3, FALSE, QuadNo) |
1316 IndrXOp : CheckConst(Oper1) ;
1317 CheckAddVariableWrite(Oper1, FALSE, QuadNo) ;
1318 CheckAddVariableRead(Oper3, TRUE, QuadNo) |
1320 (* RangeCheckOp : CheckRangeAddVariableRead(Oper3, QuadNo) | *)
1321 SaveExceptionOp : CheckConst(Oper1) ;
1322 CheckAddVariableWrite(Oper1, FALSE, QuadNo) |
1323 RestoreExceptionOp: CheckAddVariableRead(Oper1, FALSE, QuadNo)
1327 END AddQuadInformation ;
1330 PROCEDURE stop ; BEGIN END stop ;
1334 PutQuadO - alters a quadruple QuadNo with Op, Oper1, Oper2, Oper3, and
1335 sets a boolean to determinine whether overflow should be checked.
1338 PROCEDURE PutQuadO (QuadNo: CARDINAL;
1340 Oper1, Oper2, Oper3: CARDINAL;
1341 overflow: BOOLEAN) ;
1345 IF QuadNo = BreakAtQuad
1349 IF QuadrupleGeneration
1351 EraseQuad (QuadNo) ;
1352 AddQuadInformation (QuadNo, Op, Oper1, Oper2, Oper3) ;
1353 f := GetQF (QuadNo) ;
1359 CheckOverflow := overflow
1366 PutQuad - overwrites a quadruple QuadNo with Op, Oper1, Oper2, Oper3
1369 PROCEDURE PutQuad (QuadNo: CARDINAL;
1371 Oper1, Oper2, Oper3: CARDINAL) ;
1373 PutQuadO (QuadNo, Op, Oper1, Oper2, Oper3, TRUE)
1381 PROCEDURE UndoReadWriteInfo (QuadNo: CARDINAL;
1383 Oper1, Oper2, Oper3: CARDINAL) ;
1387 (* jumps, calls and branches *)
1395 IfGreEquOp : RemoveReference(QuadNo) ;
1396 CheckRemoveVariableRead(Oper1, FALSE, QuadNo) ;
1397 CheckRemoveVariableRead(Oper2, FALSE, QuadNo) |
1401 GotoOp : RemoveReference(QuadNo) |
1403 (* variable references *)
1406 ExclOp : CheckRemoveVariableRead(Oper1, FALSE, QuadNo) ;
1407 CheckRemoveVariableWrite(Oper1, TRUE, QuadNo) |
1414 SizeOp : CheckRemoveVariableWrite(Oper1, FALSE, QuadNo) ;
1415 CheckRemoveVariableRead(Oper3, FALSE, QuadNo) |
1416 AddrOp : CheckRemoveVariableWrite(Oper1, FALSE, QuadNo) ;
1417 (* CheckRemoveVariableReadLeftValue(Oper3, QuadNo) ; *)
1418 (* the next line is a kludge and assumes we _will_
1419 write to the variable as we have taken its address *)
1420 CheckRemoveVariableWrite(Oper1, TRUE, QuadNo) |
1421 ReturnValueOp : CheckRemoveVariableRead(Oper1, FALSE, QuadNo) |
1426 ParamOp : CheckRemoveVariableRead(Oper2, FALSE, QuadNo) ;
1427 CheckRemoveVariableRead(Oper3, FALSE, QuadNo) ;
1428 IF (Oper1>0) AND (Oper1<=NoOfParam(Oper2)) AND
1429 IsVarParam(Oper2, Oper1)
1431 (* _may_ also write to a var parameter, although we dont know *)
1432 CheckRemoveVariableWrite(Oper3, TRUE, QuadNo)
1454 DivTruncOp : CheckRemoveVariableWrite(Oper1, FALSE, QuadNo) ;
1455 CheckRemoveVariableRead(Oper2, FALSE, QuadNo) ;
1456 CheckRemoveVariableRead(Oper3, FALSE, QuadNo) |
1458 XIndrOp : CheckRemoveVariableWrite(Oper1, TRUE, QuadNo) ;
1459 CheckRemoveVariableRead(Oper3, FALSE, QuadNo) |
1461 IndrXOp : CheckRemoveVariableWrite(Oper1, FALSE, QuadNo) ;
1462 CheckRemoveVariableRead(Oper3, TRUE, QuadNo) |
1464 (* RangeCheckOp : CheckRangeRemoveVariableRead(Oper3, QuadNo) | *)
1465 SaveExceptionOp : CheckRemoveVariableWrite(Oper1, FALSE, QuadNo) |
1466 RestoreExceptionOp: CheckRemoveVariableRead(Oper1, FALSE, QuadNo)
1470 END UndoReadWriteInfo ;
1474 EraseQuad - erases a quadruple QuadNo, the quadruple is still in the list
1478 PROCEDURE EraseQuad (QuadNo: CARDINAL) ;
1482 f := GetQF(QuadNo) ;
1484 UndoReadWriteInfo(QuadNo, Operator, Operand1, Operand2, Operand3) ;
1485 Operator := DummyOp ; (* finally blank it out *)
1490 op1pos := UnknownTokenNo ;
1491 op2pos := UnknownTokenNo ;
1492 op3pos := UnknownTokenNo
1498 CheckAddVariableReadLeftValue -
1502 PROCEDURE CheckAddVariableReadLeftValue (sym: CARDINAL; q: CARDINAL) ;
1506 PutReadQuad(sym, LeftValue, q)
1508 END CheckAddVariableReadLeftValue ;
1513 CheckRemoveVariableReadLeftValue -
1517 PROCEDURE CheckRemoveVariableReadLeftValue (sym: CARDINAL; q: CARDINAL) ;
1521 RemoveReadQuad(sym, LeftValue, q)
1523 END CheckRemoveVariableReadLeftValue ;
1528 CheckAddVariableRead - checks to see whether symbol, Sym, is a variable or
1529 a parameter and if so it then adds this quadruple
1530 to the variable list.
1533 PROCEDURE CheckAddVariableRead (Sym: CARDINAL; canDereference: BOOLEAN; Quad: CARDINAL) ;
1537 PutReadQuad(Sym, GetMode(Sym), Quad) ;
1538 IF (GetMode(Sym)=LeftValue) AND canDereference
1540 PutReadQuad(Sym, RightValue, Quad)
1543 END CheckAddVariableRead ;
1547 CheckRemoveVariableRead - checks to see whether, Sym, is a variable or
1548 a parameter and if so then it removes the
1549 quadruple from the variable list.
1552 PROCEDURE CheckRemoveVariableRead (Sym: CARDINAL; canDereference: BOOLEAN; Quad: CARDINAL) ;
1556 RemoveReadQuad(Sym, GetMode(Sym), Quad) ;
1557 IF (GetMode(Sym)=LeftValue) AND canDereference
1559 RemoveReadQuad(Sym, RightValue, Quad)
1562 END CheckRemoveVariableRead ;
1566 CheckAddVariableWrite - checks to see whether symbol, Sym, is a variable and
1567 if so it then adds this quadruple to the variable list.
1570 PROCEDURE CheckAddVariableWrite (Sym: CARDINAL; canDereference: BOOLEAN; Quad: CARDINAL) ;
1574 IF (GetMode(Sym)=LeftValue) AND canDereference
1576 PutReadQuad(Sym, LeftValue, Quad) ;
1577 PutWriteQuad(Sym, RightValue, Quad)
1579 PutWriteQuad(Sym, GetMode(Sym), Quad)
1582 END CheckAddVariableWrite ;
1586 CheckRemoveVariableWrite - checks to see whether, Sym, is a variable and
1587 if so then it removes the quadruple from the
1591 PROCEDURE CheckRemoveVariableWrite (Sym: CARDINAL; canDereference: BOOLEAN; Quad: CARDINAL) ;
1595 IF (GetMode(Sym)=LeftValue) AND canDereference
1597 RemoveReadQuad(Sym, LeftValue, Quad) ;
1598 RemoveWriteQuad(Sym, RightValue, Quad)
1600 RemoveWriteQuad(Sym, GetMode(Sym), Quad)
1603 END CheckRemoveVariableWrite ;
1610 PROCEDURE CheckConst (sym: CARDINAL) ;
1614 PutToBeSolvedByQuads(sym)
1620 GetFirstQuad - returns the first quadruple.
1623 PROCEDURE GetFirstQuad () : CARDINAL ;
1630 GetNextQuad - returns the Quadruple number following QuadNo.
1633 PROCEDURE GetNextQuad (QuadNo: CARDINAL) : CARDINAL ;
1637 f := GetQF(QuadNo) ;
1643 SubQuad - subtracts a quadruple QuadNo from a list Head.
1646 PROCEDURE SubQuad (QuadNo: CARDINAL) ;
1651 f := GetQF(QuadNo) ;
1653 AlterReference(Head, QuadNo, f^.Next) ;
1654 UndoReadWriteInfo(QuadNo, Operator, Operand1, Operand2, Operand3)
1662 WHILE g^.Next#QuadNo DO
1668 f^.Operator := DummyOp ;
1674 GetRealQuad - returns the Quadruple number of the real quadruple
1675 at QuadNo or beyond.
1678 PROCEDURE GetRealQuad (QuadNo: CARDINAL) : CARDINAL ;
1683 IF InBounds(QuadArray, QuadNo)
1685 f := GetQF(QuadNo) ;
1687 IF (NOT IsPseudoQuad(QuadNo)) AND
1688 (Operator#DummyOp) AND (Operator#LineNumberOp) AND (Operator#StatementNoteOp)
1703 AlterReference - alters all references from OldQuad, to NewQuad in a
1704 quadruple list Head.
1707 PROCEDURE AlterReference (Head, OldQuad, NewQuad: CARDINAL) ;
1712 f := GetQF(OldQuad) ;
1713 WHILE (f^.NoOfTimesReferenced>0) AND (Head#0) DO
1728 GotoOp : IF Operand3=OldQuad
1730 ManipulateReference(Head, NewQuad)
1739 END AlterReference ;
1743 GrowQuads - grows the list of quadruples to the quadruple, to.
1746 PROCEDURE GrowQuads (to: CARDINAL) ;
1751 IF (to#0) AND (to>GrowInitialization)
1753 i := GrowInitialization+1 ;
1755 IF InBounds(QuadArray, i)
1757 Assert(GetIndice(QuadArray, i)#NIL)
1762 InternalError ('out of memory error when trying to allocate a quadruple')
1764 PutIndice(QuadArray, i, f) ;
1765 f^.NoOfTimesReferenced := 0
1769 GrowInitialization := to
1775 ManipulateReference - manipulates the quadruple, q, so that it now points to quad, to.
1778 PROCEDURE ManipulateReference (q: CARDINAL; to: CARDINAL) ;
1782 Assert((GrowInitialization>=q) OR (to=0)) ;
1784 RemoveReference(q) ;
1790 INC(f^.NoOfTimesReferenced)
1792 END ManipulateReference ;
1796 RemoveReference - remove the reference by quadruple, q, to wherever
1800 PROCEDURE RemoveReference (q: CARDINAL) ;
1805 IF (f^.Operand3#0) AND (f^.Operand3<NextQuad)
1807 g := GetQF(f^.Operand3) ;
1808 Assert(g^.NoOfTimesReferenced#0) ;
1809 DEC(g^.NoOfTimesReferenced)
1811 END RemoveReference ;
1815 CountQuads - returns the number of quadruples.
1818 PROCEDURE CountQuads () : CARDINAL ;
1825 NewQuad - sets QuadNo to a new quadruple.
1828 PROCEDURE NewQuad (VAR QuadNo: CARDINAL) ;
1832 QuadNo := FreeList ;
1833 IF InBounds (QuadArray, QuadNo) AND (GetIndice (QuadArray, QuadNo) # NIL)
1835 f := GetIndice (QuadArray, QuadNo)
1840 InternalError ('out of memory error trying to allocate a quadruple')
1843 PutIndice (QuadArray, QuadNo, f) ;
1844 f^.NoOfTimesReferenced := 0
1848 Operator := DummyOp ;
1853 IF GrowInitialization < FreeList
1855 GrowInitialization := FreeList
1861 CheckVariableAt - checks to see whether, sym, was declared at a particular address.
1864 PROCEDURE CheckVariableAt (sym: CARDINAL) ;
1866 IF IsVar (sym) AND IsVariableAtAddress (sym)
1868 IF GetMode (sym) = LeftValue
1870 GenQuad (InitAddressOp, sym, NulSym, GetVariableAtAddress (sym))
1872 InternalError ('expecting lvalue for this variable which is declared at an explicit address')
1875 END CheckVariableAt ;
1879 CheckVariablesAt - checks to see whether we need to initialize any pointers
1880 which point to variable declared at addresses.
1883 PROCEDURE CheckVariablesAt (scope: CARDINAL) ;
1885 ForeachLocalSymDo (scope, CheckVariableAt)
1886 END CheckVariablesAt ;
1890 GetTurnInterrupts - returns the TurnInterrupts procedure function.
1893 PROCEDURE GetTurnInterrupts (tok: CARDINAL) : CARDINAL ;
1897 RETURN GetQualidentImport (tok,
1898 MakeKey ('TurnInterrupts'), MakeKey ('COROUTINES'))
1900 RETURN GetQualidentImport (tok,
1901 MakeKey ('TurnInterrupts'), MakeKey ('SYSTEM'))
1903 END GetTurnInterrupts ;
1907 GetProtection - returns the PROTECTION data type.
1910 PROCEDURE GetProtection (tok: CARDINAL) : CARDINAL ;
1914 RETURN GetQualidentImport (tok,
1915 MakeKey ('PROTECTION'), MakeKey ('COROUTINES'))
1917 RETURN GetQualidentImport (tok,
1918 MakeKey ('PROTECTION'), MakeKey ('SYSTEM'))
1924 CheckNeedPriorityBegin - checks to see whether we need to save the old
1925 module priority and change to another module
1927 The current module initialization or procedure
1928 being built is defined by, scope. The module whose
1929 priority will be used is defined by, module.
1932 PROCEDURE CheckNeedPriorityBegin (tok: CARDINAL; scope, module: CARDINAL) ;
1934 ProcSym, old: CARDINAL ;
1936 IF GetPriority (module) # NulSym
1938 (* module has been given a priority *)
1939 ProcSym := GetTurnInterrupts (tok) ;
1942 old := MakeTemporary (tok, RightValue) ;
1943 PutVar (old, GetProtection (tok)) ;
1945 GenQuadO (tok, SavePriorityOp, old, scope, ProcSym, FALSE) ;
1946 PushWord (PriorityStack, old)
1949 END CheckNeedPriorityBegin ;
1953 CheckNeedPriorityEnd - checks to see whether we need to restore the old
1955 The current module initialization or procedure
1956 being built is defined by, scope.
1959 PROCEDURE CheckNeedPriorityEnd (tok: CARDINAL;
1960 scope, module: CARDINAL) ;
1962 ProcSym, old: CARDINAL ;
1964 IF GetPriority (module) # NulSym
1966 (* module has been given a priority *)
1967 ProcSym := GetTurnInterrupts (tok) ;
1970 old := PopWord (PriorityStack) ;
1971 GenQuad (RestorePriorityOp, old, scope, ProcSym)
1974 END CheckNeedPriorityEnd ;
1978 StartBuildDefFile - generates a StartFileDefOp quadruple indicating the file
1979 that has produced the subsequent quadruples.
1980 The code generator uses the StartDefFileOp quadruples
1981 to relate any error to the appropriate file.
1989 +------------+ +------------+
1990 | ModuleName | | ModuleName |
1991 |------------| |------------|
1996 q StartDefFileOp _ _ ModuleSym
1999 PROCEDURE StartBuildDefFile (tok: CARDINAL) ;
2004 PushT (ModuleName) ;
2005 GenQuadO (tok, StartDefFileOp, tok, NulSym, GetModule (ModuleName), FALSE)
2006 END StartBuildDefFile ;
2010 StartBuildModFile - generates a StartModFileOp quadruple indicating the file
2011 that has produced the subsequent quadruples.
2012 The code generator uses the StartModFileOp quadruples
2013 to relate any error to the appropriate file.
2021 +------------+ +------------+
2022 | ModuleName | | ModuleName |
2023 |------------| |------------|
2028 q StartModFileOp lineno filename ModuleSym
2031 PROCEDURE StartBuildModFile (tok: CARDINAL) ;
2033 GenQuadO (tok, StartModFileOp, tok,
2034 WORD (makekey (string (GetFileName ()))),
2035 GetFileModule (), FALSE)
2036 END StartBuildModFile ;
2040 EndBuildFile - generates an EndFileOp quadruple indicating the file
2041 that has produced the previous quadruples has ended.
2048 +------------+ +------------+
2049 | ModuleName | | ModuleName |
2050 |------------| |------------|
2055 q EndFileOp _ _ ModuleSym
2058 PROCEDURE EndBuildFile (tok: CARDINAL) ;
2062 ModuleName := OperandT (1) ;
2063 GenQuadO (tok, EndFileOp, NulSym, NulSym, GetModule (ModuleName), FALSE)
2068 StartBuildInit - Sets the start of initialization code of the
2069 current module to the next quadruple.
2072 PROCEDURE StartBuildInit (tok: CARDINAL) ;
2075 ModuleSym: CARDINAL ;
2078 ModuleSym := GetCurrentModule() ;
2079 Assert(IsModule(ModuleSym) OR IsDefImp(ModuleSym)) ;
2080 Assert(GetSymName(ModuleSym)=name) ;
2081 PutModuleStartQuad(ModuleSym, NextQuad) ;
2082 GenQuad(InitStartOp, tok, GetFileModule(), ModuleSym) ;
2083 PushWord(ReturnStack, 0) ;
2085 CheckVariablesAt(ModuleSym) ;
2086 CheckNeedPriorityBegin(tok, ModuleSym, ModuleSym) ;
2087 PushWord(TryStack, NextQuad) ;
2088 PushWord(CatchStack, 0) ;
2089 IF HasExceptionBlock(ModuleSym)
2091 GenQuad(TryOp, NulSym, NulSym, 0)
2093 END StartBuildInit ;
2097 EndBuildInit - Sets the end initialization code of a module.
2100 PROCEDURE EndBuildInit (tok: CARDINAL) ;
2102 IF HasExceptionBlock(GetCurrentModule())
2104 BuildRTExceptLeave (tok, TRUE) ;
2105 GenQuadO (tok, CatchEndOp, NulSym, NulSym, NulSym, FALSE)
2107 BackPatch (PopWord (ReturnStack), NextQuad) ;
2108 CheckNeedPriorityEnd (tok, GetCurrentModule(), GetCurrentModule()) ;
2109 PutModuleEndQuad (GetCurrentModule(), NextQuad) ;
2110 CheckVariablesInBlock (GetCurrentModule()) ;
2111 GenQuadO (tok, InitEndOp, tok, GetFileModule(), GetCurrentModule(), FALSE)
2116 StartBuildFinally - Sets the start of finalization code of the
2117 current module to the next quadruple.
2120 PROCEDURE StartBuildFinally (tok: CARDINAL) ;
2123 ModuleSym: CARDINAL ;
2126 ModuleSym := GetCurrentModule() ;
2127 Assert(IsModule(ModuleSym) OR IsDefImp(ModuleSym)) ;
2128 Assert(GetSymName(ModuleSym)=name) ;
2129 PutModuleFinallyStartQuad(ModuleSym, NextQuad) ;
2130 GenQuadO (tok, FinallyStartOp, tok, GetFileModule(), ModuleSym, FALSE) ;
2131 PushWord (ReturnStack, 0) ;
2133 (* CheckVariablesAt(ModuleSym) ; *)
2134 CheckNeedPriorityBegin (tok, ModuleSym, ModuleSym) ;
2135 PushWord (TryStack, NextQuad) ;
2136 PushWord (CatchStack, 0) ;
2137 IF HasExceptionFinally (ModuleSym)
2139 GenQuadO (tok, TryOp, NulSym, NulSym, 0, FALSE)
2141 END StartBuildFinally ;
2145 EndBuildFinally - Sets the end finalization code of a module.
2148 PROCEDURE EndBuildFinally (tok: CARDINAL) ;
2150 IF HasExceptionFinally(GetCurrentModule())
2152 BuildRTExceptLeave (tok, TRUE) ;
2153 GenQuadO (tok, CatchEndOp, NulSym, NulSym, NulSym, FALSE)
2155 BackPatch (PopWord (ReturnStack), NextQuad) ;
2156 CheckNeedPriorityEnd (tok, GetCurrentModule (), GetCurrentModule ()) ;
2157 PutModuleFinallyEndQuad(GetCurrentModule (), NextQuad) ;
2158 CheckVariablesInBlock (GetCurrentModule ()) ;
2159 GenQuadO (tok, FinallyEndOp, tok, GetFileModule (),
2160 GetCurrentModule(), FALSE)
2161 END EndBuildFinally ;
2165 BuildRTExceptEnter - informs RTExceptions that we are about to enter the except state.
2168 PROCEDURE BuildRTExceptEnter (tok: CARDINAL) ;
2175 (* now inform the Modula-2 runtime we are in the exception state *)
2176 ProcSym := GetQualidentImport (tok,
2177 MakeKey('SetExceptionState'), MakeKey('RTExceptions')) ;
2181 '{%W}no procedure SetExceptionState found in RTExceptions which is needed to implement exception handling')
2183 old := MakeTemporary (tok, RightValue) ;
2184 PutVar (old, Boolean) ;
2185 GenQuadO (tok, SaveExceptionOp, old, NulSym, ProcSym, FALSE) ;
2186 PushWord (ExceptStack, old)
2190 '{%E}cannot use {%kEXCEPT} blocks with the -fno-exceptions flag')
2192 END BuildRTExceptEnter ;
2196 BuildRTExceptLeave - informs RTExceptions that we are about to leave the except state.
2197 If, destroy, is TRUE then pop the ExceptStack.
2200 PROCEDURE BuildRTExceptLeave (tok: CARDINAL; destroy: BOOLEAN) ;
2207 (* now inform the Modula-2 runtime we are in the exception state *)
2208 ProcSym := GetQualidentImport (tok,
2209 MakeKey('SetExceptionState'), MakeKey('RTExceptions')) ;
2214 old := PopWord (ExceptStack)
2216 old := PeepWord (ExceptStack, 1)
2218 GenQuadO (tok, RestoreExceptionOp, old, NulSym, ProcSym, FALSE)
2221 (* no need for an error message here as it will be generated in the Enter procedure above *)
2223 END BuildRTExceptLeave ;
2227 BuildExceptInitial - adds an CatchBeginOp, CatchEndOp quadruple
2228 in the current block.
2231 PROCEDURE BuildExceptInitial (tok: CARDINAL) ;
2233 previous: CARDINAL ;
2235 (* we have finished the 'try' block, so now goto the return
2236 section which will tidy up (any) priorities before returning.
2238 GenQuadO (tok, GotoOp, NulSym, NulSym, PopWord(ReturnStack), FALSE) ;
2239 PushWord (ReturnStack, NextQuad-1) ;
2241 this is the 'catch' block.
2243 BackPatch (PeepWord (TryStack, 1), NextQuad) ;
2244 GenQuadO (tok, CatchBeginOp, NulSym, NulSym, NulSym, FALSE) ;
2245 previous := PopWord (CatchStack) ;
2249 '{%E}only allowed one EXCEPT statement in a procedure or module')
2251 PushWord (CatchStack, NextQuad-1) ;
2252 BuildRTExceptEnter (tok)
2253 END BuildExceptInitial ;
2257 BuildExceptFinally - adds an ExceptOp quadruple in a modules
2261 PROCEDURE BuildExceptFinally (tok: CARDINAL) ;
2263 BuildExceptInitial (tok)
2264 END BuildExceptFinally ;
2268 BuildExceptProcedure - adds an ExceptOp quadruple in a procedure
2272 PROCEDURE BuildExceptProcedure (tok: CARDINAL) ;
2274 BuildExceptInitial (tok)
2275 END BuildExceptProcedure ;
2279 BuildRetry - adds an RetryOp quadruple.
2282 PROCEDURE BuildRetry (tok: CARDINAL);
2284 IF PeepWord (CatchStack, 1) = 0
2287 '{%E}the {%kRETRY} statement must occur after an {%kEXCEPT} statement in the same module or procedure block')
2289 BuildRTExceptLeave (tok, FALSE) ;
2290 GenQuadO (tok, RetryOp, NulSym, NulSym, PeepWord (TryStack, 1), FALSE)
2296 SafeRequestSym - only used during scaffold to get argc, argv, envp.
2297 It attempts to get symbol name from the current scope(s) and if
2298 it fails then it falls back onto default constants.
2301 PROCEDURE SafeRequestSym (tok: CARDINAL; name: Name) : CARDINAL ;
2305 sym := GetSym (name) ;
2308 IF name = MakeKey ('argc')
2310 RETURN MakeConstLit (tok, MakeKey ('0'), ZType)
2311 ELSIF (name = MakeKey ('argv')) OR (name = MakeKey ('envp'))
2315 InternalError ('not expecting this parameter name') ;
2320 END SafeRequestSym ;
2324 callRequestDependant - create a call:
2325 RequestDependant (GetSymName (modulesym), GetLibName (modulesym),
2326 GetSymName (depModuleSym), GetLibName (depModuleSym));
2329 PROCEDURE callRequestDependant (tokno: CARDINAL;
2330 moduleSym, depModuleSym: CARDINAL;
2331 requestDep: CARDINAL) ;
2333 Assert (requestDep # NulSym) ;
2334 PushTtok (requestDep, tokno) ;
2335 PushTF (Adr, Address) ;
2336 PushTtok (MakeConstLitString (tokno, GetSymName (moduleSym)), tokno) ;
2340 PushTF (Adr, Address) ;
2341 PushTtok (MakeConstLitString (tokno, GetLibName (moduleSym)), tokno) ;
2345 IF depModuleSym = NulSym
2347 PushTF (Nil, Address) ;
2348 PushTF (Nil, Address)
2350 PushTF (Adr, Address) ;
2351 PushTtok (MakeConstLitString (tokno, GetSymName (depModuleSym)), tokno) ;
2355 PushTF (Adr, Address) ;
2356 PushTtok (MakeConstLitString (tokno, GetLibName (depModuleSym)), tokno) ;
2362 BuildProcedureCall (tokno)
2363 END callRequestDependant ;
2367 ForeachImportInDepDo -
2370 PROCEDURE ForeachImportInDepDo (importStatements: List; moduleSym, requestDep: CARDINAL) ;
2378 IF importStatements # NIL
2381 n := NoOfItemsInList (importStatements) ;
2383 stmt := GetItemFromList (importStatements, i) ;
2384 Assert (IsImportStatement (stmt)) ;
2385 l := GetImportStatementList (stmt) ;
2387 m := NoOfItemsInList (l) ;
2389 imported := GetItemFromList (l, j) ;
2390 Assert (IsImport (imported)) ;
2391 callRequestDependant (GetImportDeclared (imported),
2392 moduleSym, GetImportModule (imported),
2399 END ForeachImportInDepDo ;
2403 ForeachImportedModuleDo -
2406 PROCEDURE ForeachImportedModuleDo (moduleSym, requestDep: CARDINAL) ;
2408 importStatements: List ;
2410 importStatements := GetModuleModImportStatementList (moduleSym) ;
2411 ForeachImportInDepDo (importStatements, moduleSym, requestDep) ;
2412 importStatements := GetModuleDefImportStatementList (moduleSym) ;
2413 ForeachImportInDepDo (importStatements, moduleSym, requestDep)
2414 END ForeachImportedModuleDo ;
2418 BuildM2DepFunction - creates the dependency graph procedure using IR:
2422 M2RTS_RequestDependant (module_name, libname, "b", "b libname");
2423 M2RTS_RequestDependant (module_name, libname, NULL, NULL);
2427 PROCEDURE BuildM2DepFunction (tokno: CARDINAL; moduleSym: CARDINAL) ;
2430 ctor, init, fini, dep: CARDINAL ;
2434 (* Scaffold required and dynamic dependency graph should be produced. *)
2435 GetModuleCtors (moduleSym, ctor, init, fini, dep) ;
2437 BuildProcedureStart ;
2438 BuildProcedureBegin ;
2440 requestDep := GetQualidentImport (tokno,
2441 MakeKey ("RequestDependant"),
2442 MakeKey ("M2RTS")) ;
2443 IF requestDep # NulSym
2445 ForeachImportedModuleDo (moduleSym, requestDep) ;
2446 callRequestDependant (tokno, moduleSym, NulSym, requestDep)
2452 END BuildM2DepFunction ;
2456 BuildM2LinkFunction - creates the _M2_link procedure which will
2457 cause the linker to pull in all the module ctors.
2460 PROCEDURE BuildM2LinkFunction (tokno: CARDINAL) ;
2464 IF linkFunction # NulSym
2469 for each module in uselist do
2470 PROC foo_%d = _M2_module_ctor
2473 PushT (linkFunction) ;
2474 BuildProcedureStart ;
2475 BuildProcedureBegin ;
2476 StartScope (linkFunction) ;
2477 PopulateCtorArray (tokno) ;
2483 END BuildM2LinkFunction ;
2487 BuildTry - build the try statement for main.
2490 PROCEDURE BuildTry (tokno: CARDINAL) ;
2494 PushWord (TryStack, NextQuad) ;
2495 PushWord (CatchStack, 0) ;
2496 GenQuadO (tokno, TryOp, NulSym, NulSym, 0, FALSE)
2502 BuildExcept - build the except block for main.
2505 PROCEDURE BuildExcept (tokno: CARDINAL) ;
2507 catchProcedure: CARDINAL ;
2511 BuildExceptInitial (tokno) ;
2512 catchProcedure := GetQualidentImport (tokno,
2513 MakeKey ('DefaultErrorCatch'),
2514 MakeKey ('RTExceptions')) ;
2515 IF catchProcedure # NulSym
2517 PushTtok (catchProcedure, tokno) ;
2519 BuildProcedureCall (tokno)
2521 BuildRTExceptLeave (tokno, TRUE) ;
2522 GenQuadO (tokno, CatchEndOp, NulSym, NulSym, NulSym, FALSE)
2528 BuildM2MainFunction - creates the main function with appropriate calls to the scaffold.
2531 PROCEDURE BuildM2MainFunction (tokno: CARDINAL) ;
2533 IF (ScaffoldDynamic OR ScaffoldStatic) AND (NOT SharedFlag)
2535 (* Scaffold required and main should be produced. *)
2538 main (int argc, char *argv[], char *envp[])
2541 _M2_init (argc, argv, envp);
2542 _M2_fini (argc, argv, envp);
2546 RTExceptions_DefaultErrorCatch ();
2551 PushT (mainFunction) ;
2552 BuildProcedureStart ;
2553 BuildProcedureBegin ;
2554 StartScope (mainFunction) ;
2556 (* _M2_init (argc, argv, envp); *)
2557 PushTtok (initFunction, tokno) ;
2558 PushTtok (RequestSym (tokno, MakeKey ("argc")), tokno) ;
2559 PushTtok (RequestSym (tokno, MakeKey ("argv")), tokno) ;
2560 PushTtok (RequestSym (tokno, MakeKey ("envp")), tokno) ;
2562 BuildProcedureCall (tokno) ;
2564 (* _M2_fini (argc, argv, envp); *)
2565 PushTtok (finiFunction, tokno) ;
2566 PushTtok (RequestSym (tokno, MakeKey ("argc")), tokno) ;
2567 PushTtok (RequestSym (tokno, MakeKey ("argv")), tokno) ;
2568 PushTtok (RequestSym (tokno, MakeKey ("envp")), tokno) ;
2570 BuildProcedureCall (tokno) ;
2571 PushZero (tokno, Integer) ;
2572 BuildReturn (tokno) ;
2573 BuildExcept (tokno) ;
2574 PushZero (tokno, Integer) ;
2575 BuildReturn (tokno) ;
2580 END BuildM2MainFunction ;
2584 BuildStringAdrParam - push the address of a nul terminated string onto the quad stack.
2587 PROCEDURE BuildStringAdrParam (tok: CARDINAL; name: Name);
2589 str, m2strnul: CARDINAL ;
2591 PushTF (Adr, Address) ;
2592 str := MakeConstLitString (tok, name) ;
2593 m2strnul := MakeConstStringM2nul (tok, str) ;
2594 PushTtok (m2strnul, tok) ;
2597 END BuildStringAdrParam ;
2601 BuildM2InitFunction -
2604 PROCEDURE BuildM2InitFunction (tok: CARDINAL; moduleSym: CARDINAL) ;
2606 constructModules: CARDINAL ;
2608 IF ScaffoldDynamic OR ScaffoldStatic
2610 (* Scaffold required and main should be produced. *)
2612 _M2_init (int argc, char *argv[], char *envp[])
2614 M2RTS_ConstructModules (module_name, libname,
2615 overrideliborder, argc, argv, envp);
2617 PushT (initFunction) ;
2618 BuildProcedureStart ;
2619 BuildProcedureBegin ;
2620 StartScope (initFunction) ;
2623 IF linkFunction # NulSym
2626 PushTtok (linkFunction, tok) ;
2628 BuildProcedureCall (tok)
2631 (* Lookup ConstructModules and call it. *)
2632 constructModules := GetQualidentImport (tok,
2633 MakeKey ("ConstructModules"),
2634 MakeKey ("M2RTS")) ;
2635 IF constructModules # NulSym
2637 (* ConstructModules (module_name, argc, argv, envp); *)
2638 PushTtok (constructModules, tok) ;
2640 BuildStringAdrParam (tok, GetSymName (moduleSym)) ;
2641 BuildStringAdrParam (tok, GetLibName (moduleSym)) ;
2642 BuildStringAdrParam (tok, makekey (GetRuntimeModuleOverride ())) ;
2644 PushTtok (SafeRequestSym (tok, MakeKey ("argc")), tok) ;
2645 PushTtok (SafeRequestSym (tok, MakeKey ("argv")), tok) ;
2646 PushTtok (SafeRequestSym (tok, MakeKey ("envp")), tok) ;
2648 BuildProcedureCall (tok) ;
2650 ELSIF ScaffoldStatic
2652 ForeachModuleCallInit (tok,
2653 SafeRequestSym (tok, MakeKey ("argc")),
2654 SafeRequestSym (tok, MakeKey ("argv")),
2655 SafeRequestSym (tok, MakeKey ("envp")))
2661 END BuildM2InitFunction ;
2665 BuildM2FiniFunction -
2668 PROCEDURE BuildM2FiniFunction (tok: CARDINAL; moduleSym: CARDINAL) ;
2670 deconstructModules: CARDINAL ;
2672 IF ScaffoldDynamic OR ScaffoldStatic
2674 (* Scaffold required and main should be produced. *)
2675 PushT (finiFunction) ;
2676 BuildProcedureStart ;
2677 BuildProcedureBegin ;
2678 StartScope (finiFunction) ;
2682 _M2_finish (int argc, char *argv[], char *envp[])
2684 M2RTS_DeconstructModules (module_name, argc, argv, envp);
2686 deconstructModules := GetQualidentImport (tok,
2687 MakeKey ("DeconstructModules"),
2688 MakeKey ("M2RTS")) ;
2689 IF deconstructModules # NulSym
2691 (* DeconstructModules (module_name, argc, argv, envp); *)
2692 PushTtok (deconstructModules, tok) ;
2694 PushTF(Adr, Address) ;
2695 PushTtok (MakeConstLitString (tok, GetSymName (moduleSym)), tok) ;
2699 PushTF(Adr, Address) ;
2700 PushTtok (MakeConstLitString (tok, GetLibName (moduleSym)), tok) ;
2704 PushTtok (SafeRequestSym (tok, MakeKey ("argc")), tok) ;
2705 PushTtok (SafeRequestSym (tok, MakeKey ("argv")), tok) ;
2706 PushTtok (SafeRequestSym (tok, MakeKey ("envp")), tok) ;
2708 BuildProcedureCall (tok)
2710 ELSIF ScaffoldStatic
2712 ForeachModuleCallFinish (tok,
2713 SafeRequestSym (tok, MakeKey ("argc")),
2714 SafeRequestSym (tok, MakeKey ("argv")),
2715 SafeRequestSym (tok, MakeKey ("envp")))
2721 END BuildM2FiniFunction ;
2725 BuildM2CtorFunction - create a constructor function associated with moduleSym.
2730 M2RTS_RegisterModule (GetSymName (moduleSym), GetLibName (moduleSym),
2731 init, fini, dependencies);
2735 PROCEDURE BuildM2CtorFunction (tok: CARDINAL; moduleSym: CARDINAL) ;
2737 RegisterModule : CARDINAL ;
2738 ctor, init, fini, dep: CARDINAL ;
2742 GetModuleCtors (moduleSym, ctor, init, fini, dep) ;
2745 Assert (IsProcedure (ctor)) ;
2747 BuildProcedureStart ;
2748 BuildProcedureBegin ;
2750 RegisterModule := GetQualidentImport (tok,
2751 MakeKey ("RegisterModule"),
2752 MakeKey ("M2RTS")) ;
2753 IF RegisterModule # NulSym
2755 (* RegisterModule (module_name, init, fini, dependencies); *)
2756 PushTtok (RegisterModule, tok) ;
2758 PushTF (Adr, Address) ;
2759 PushTtok (MakeConstLitString (tok, GetSymName (moduleSym)), tok) ;
2763 PushTF (Adr, Address) ;
2764 PushTtok (MakeConstLitString (tok, GetLibName (moduleSym)), tok) ;
2768 PushTtok (init, tok) ;
2769 PushTtok (fini, tok) ;
2770 PushTtok (dep, tok) ;
2772 BuildProcedureCall (tok)
2779 END BuildM2CtorFunction ;
2783 BuildScaffold - generate the main, init, finish functions if
2784 no -c and this is the application module.
2787 PROCEDURE BuildScaffold (tok: CARDINAL; moduleSym: CARDINAL) ;
2789 IF GetMainModule () = moduleSym
2791 DeclareScaffold (tok) ;
2792 IF (ScaffoldMain OR (NOT cflag))
2794 (* There are module init/fini functions and
2795 application init/fini functions.
2796 Here we create the application pair. *)
2797 BuildM2LinkFunction (tok) ;
2798 BuildM2MainFunction (tok) ;
2799 BuildM2InitFunction (tok, moduleSym) ; (* Application init. *)
2800 BuildM2FiniFunction (tok, moduleSym) ; (* Application fini. *)
2802 BuildM2DepFunction (tok, moduleSym) ; (* Per module dependency. *)
2803 (* Each module needs a ctor to register the module
2804 init/finish/dep with M2RTS. *)
2805 BuildM2CtorFunction (tok, moduleSym)
2808 DeclareScaffold (tok) ;
2809 BuildM2DepFunction (tok, moduleSym) ; (* Per module dependency. *)
2810 (* Each module needs a ctor to register the module
2811 init/finish/dep with M2RTS. *)
2812 BuildM2CtorFunction (tok, moduleSym)
2818 BuildModuleStart - starts current module scope.
2821 PROCEDURE BuildModuleStart (tok: CARDINAL) ;
2825 WORD (makekey (string (GetFileName ()))), GetCurrentModule (), FALSE)
2826 END BuildModuleStart ;
2830 StartBuildInnerInit - Sets the start of initialization code of the
2831 inner module to the next quadruple.
2834 PROCEDURE StartBuildInnerInit (tok: CARDINAL) ;
2836 PutModuleStartQuad (GetCurrentModule(), NextQuad) ;
2837 GenQuadO (tok, InitStartOp, tok, NulSym, GetCurrentModule(), FALSE) ;
2838 PushWord (ReturnStack, 0) ;
2839 CheckNeedPriorityBegin (tok, GetCurrentModule(), GetCurrentModule()) ;
2840 PushWord (TryStack, NextQuad) ;
2841 PushWord (CatchStack, 0) ;
2842 IF HasExceptionFinally (GetCurrentModule())
2844 GenQuadO (tok, TryOp, NulSym, NulSym, 0, FALSE)
2846 END StartBuildInnerInit ;
2850 EndBuildInnerInit - Sets the end initialization code of a module.
2853 PROCEDURE EndBuildInnerInit (tok: CARDINAL) ;
2855 IF HasExceptionBlock (GetCurrentModule())
2857 BuildRTExceptLeave (tok, TRUE) ;
2858 GenQuadO (tok, CatchEndOp, NulSym, NulSym, NulSym, FALSE)
2860 PutModuleEndQuad (GetCurrentModule(), NextQuad) ;
2861 CheckVariablesInBlock (GetCurrentModule ()) ;
2862 BackPatch (PopWord (ReturnStack), NextQuad) ;
2863 CheckNeedPriorityEnd (tok, GetCurrentModule (), GetCurrentModule ()) ;
2864 GenQuadO (tok, InitEndOp, tok, NulSym, GetCurrentModule (), FALSE)
2865 END EndBuildInnerInit ;
2869 BuildModulePriority - assigns the current module with a priority
2870 from the top of stack.
2882 PROCEDURE BuildModulePriority ;
2884 Priority: CARDINAL ;
2887 PutPriority (GetCurrentModule (), Priority)
2888 END BuildModulePriority ;
2892 ForLoopAnalysis - checks all the FOR loops for index variable manipulation
2893 and dangerous usage outside the loop.
2896 PROCEDURE ForLoopAnalysis ;
2899 forDesc: ForLoopInfo ;
2903 n := HighIndice (ForInfo) ;
2906 forDesc := GetIndice (ForInfo, i) ;
2907 CheckForIndex (forDesc) ;
2911 END ForLoopAnalysis ;
2915 AddForInfo - adds the description of the FOR loop into the record list.
2916 This is used if -pedantic is turned on to check index variable
2920 PROCEDURE AddForInfo (Start, End, IncQuad: CARDINAL; Sym: CARDINAL; idtok: CARDINAL) ;
2922 forDesc: ForLoopInfo ;
2928 IncrementQuad := IncQuad ;
2929 StartOfForLoop := Start ;
2930 EndOfForLoop := End ;
2931 ForLoopIndex := Sym ;
2934 IncludeIndiceIntoIndex (ForInfo, forDesc)
2940 CheckForIndex - checks the quadruples: Start..End to see whether a
2941 for loop index is manipulated by the programmer.
2942 It generates a warning if this is the case.
2943 It also checks to see whether the IndexSym is read
2944 immediately outside the loop in which case a warning
2948 PROCEDURE CheckForIndex (forDesc: ForLoopInfo) ;
2951 WriteStart, WriteEnd: CARDINAL ;
2953 GetWriteLimitQuads (forDesc^.ForLoopIndex, RightValue, forDesc^.StartOfForLoop, forDesc^.EndOfForLoop, WriteStart, WriteEnd) ;
2954 IF (WriteStart < forDesc^.IncrementQuad) AND (WriteStart > forDesc^.StartOfForLoop)
2956 MetaErrorT1 (forDesc^.IndexTok,
2957 '{%kFOR} loop index variable {%1Wad} is being manipulated inside the loop',
2958 forDesc^.ForLoopIndex) ;
2959 MetaErrorT1 (QuadToTokenNo (WriteStart),
2960 '{%kFOR} loop index variable {%1Wad} is being manipulated, this is considered bad practice and may cause unknown program behaviour',
2961 forDesc^.ForLoopIndex)
2963 GetWriteLimitQuads (forDesc^.ForLoopIndex, RightValue, forDesc^.EndOfForLoop, 0, WriteStart, WriteEnd) ;
2964 GetReadLimitQuads (forDesc^.ForLoopIndex, RightValue, forDesc^.EndOfForLoop, 0, ReadStart, ReadEnd) ;
2965 IF (ReadStart#0) AND ((ReadStart < WriteStart) OR (WriteStart = 0))
2967 MetaErrorT1 (forDesc^.IndexTok,
2968 '{%kFOR} loop index variable {%1Wad} is being read outside the FOR loop (without being reset)',
2969 forDesc^.ForLoopIndex) ;
2970 MetaErrorT1 (QuadToTokenNo (ReadStart),
2971 '{%kFOR} loop index variable {%1Wad} is being read outside the FOR loop (without being reset), this is considered extremely bad practice and may cause unknown program behaviour',
2972 forDesc^.ForLoopIndex)
2978 GetCurrentFunctionName - returns the name for the current __FUNCTION__
2982 PROCEDURE GetCurrentFunctionName () : Name ;
2987 IF CurrentProc=NulSym
2989 s := InitStringCharStar(KeyToCharStar(GetSymName(GetCurrentModule()))) ;
2990 s := Sprintf1(Mark(InitString('module %s initialization')), s) ;
2991 n := makekey(string(s)) ;
2992 s := KillString(s) ;
2995 RETURN( GetSymName(CurrentProc) )
2997 END GetCurrentFunctionName ;
3002 BuildRange - generates a RangeCheckOp quad with, r, as its operand.
3005 PROCEDURE BuildRange (r: CARDINAL) ;
3007 GenQuad (RangeCheckOp, WORD (GetLineNo ()), NulSym, r)
3012 BuildError - generates a ErrorOp quad, indicating that if this
3013 quadruple is reachable, then a runtime error would
3017 PROCEDURE BuildError (r: CARDINAL) ;
3019 GenQuad (ErrorOp, WORD (GetLineNo ()), NulSym, r)
3024 CheckPointerThroughNil - builds a range quadruple, providing, sym, is
3025 a candidate for checking against NIL.
3026 This range quadruple is only expanded into
3027 code during the code generation phase
3028 thus allowing limited compile time checking.
3031 PROCEDURE CheckPointerThroughNil (tokpos: CARDINAL; sym: CARDINAL) ;
3033 IF IsVar (sym) AND GetVarPointerCheck (sym)
3035 (* PutVarPointerCheck(sym, FALSE) ; (* so we do not detect this again *) *)
3036 BuildRange (InitPointerRangeCheck (tokpos, sym, GetMode (sym) = LeftValue))
3038 END CheckPointerThroughNil ;
3042 CollectLow - returns the low of the subrange value.
3045 PROCEDURE CollectLow (sym: CARDINAL) : CARDINAL ;
3047 low, high: CARDINAL ;
3051 GetSubrange (sym, high, low) ;
3054 InternalError ('expecting Subrange symbol')
3060 CollectHigh - returns the high of the subrange value, sym.
3063 PROCEDURE CollectHigh (sym: CARDINAL) : CARDINAL ;
3065 low, high: CARDINAL ;
3069 GetSubrange (sym, high, low) ;
3072 InternalError ('expecting Subrange symbol')
3078 BackPatchSubrangesAndOptParam - runs through all the quadruples and finds SubrangeLow or SubrangeHigh
3079 quadruples and replaces it by an assignment to the Low or High component
3080 of the subrange type.
3083 SubrangeLow op1 op3 (* op3 is a subrange *)
3089 SubrangeHigh op1 op3 (* op3 is a subrange *)
3095 OptParam op1 op2 op3
3098 Param op1 op2 GetOptArgInit(op3)
3101 PROCEDURE BackPatchSubrangesAndOptParam ;
3106 q := GetFirstQuad () ;
3114 SubrangeLowOp : Operand3 := CollectLow (Operand3) ;
3115 Operator := BecomesOp |
3116 SubrangeHighOp: Operand3 := CollectHigh (Operand3) ;
3117 Operator := BecomesOp |
3118 OptParamOp : Operand3 := GetOptArgInit (Operand3) ;
3127 END BackPatchSubrangesAndOptParam ;
3131 CheckCompatibleWithBecomes - checks to see that symbol, sym, is
3132 compatible with the := operator.
3135 PROCEDURE CheckCompatibleWithBecomes (des, expr,
3136 destok, exprtok: CARDINAL) ;
3140 MetaErrorT1 (destok,
3141 'an assignment cannot assign a value to a type {%1a}', des)
3142 ELSIF IsProcedure (des)
3144 MetaErrorT1 (destok,
3145 'an assignment cannot assign a value to a procedure {%1a}', des)
3146 ELSIF IsFieldEnumeration (des)
3148 MetaErrorT1 (destok,
3149 'an assignment cannot assign a value to an enumeration field {%1a}', des)
3151 IF IsPseudoBaseProcedure (expr) OR IsPseudoBaseFunction (expr)
3153 MetaErrorT1 (exprtok,
3154 'an assignment cannot assign a {%1d} {%1a}', expr)
3156 END CheckCompatibleWithBecomes ;
3160 BuildAssignmentWithoutBounds - calls BuildAssignment but makes sure we do not
3164 PROCEDURE BuildAssignmentWithoutBounds (tok: CARDINAL; checkTypes, checkOverflow: BOOLEAN) ;
3168 old := MustNotCheckBounds ;
3169 MustNotCheckBounds := TRUE ;
3170 doBuildAssignment (tok, checkTypes, checkOverflow) ;
3171 MustNotCheckBounds := old
3172 END BuildAssignmentWithoutBounds ;
3176 MarkArrayWritten - marks, Array, as being written.
3179 PROCEDURE MarkArrayWritten (Array: CARDINAL) ;
3181 IF (Array#NulSym) AND IsVarAParam(Array)
3183 PutVarWritten (Array, TRUE)
3185 END MarkArrayWritten ;
3189 MarkAsReadWrite - marks the variable or parameter as being
3193 PROCEDURE MarkAsReadWrite (sym: CARDINAL) ;
3195 IF (sym#NulSym) AND IsVar(sym)
3197 PutReadQuad (sym, RightValue, NextQuad) ;
3198 PutWriteQuad (sym, RightValue, NextQuad)
3200 END MarkAsReadWrite ;
3204 MarkAsRead - marks the variable or parameter as being read.
3207 PROCEDURE MarkAsRead (sym: CARDINAL) ;
3209 IF (sym#NulSym) AND IsVar(sym)
3211 PutReadQuad (sym, RightValue, NextQuad)
3217 MarkAsWrite - marks the variable or parameter as being written.
3220 PROCEDURE MarkAsWrite (sym: CARDINAL) ;
3222 IF (sym # NulSym) AND IsVar (sym)
3224 PutWriteQuad (sym, RightValue, NextQuad)
3230 doVal - return an expression which is VAL(type, expr). If
3231 expr is a constant then return expr.
3234 PROCEDURE doVal (type, expr: CARDINAL) : CARDINAL ;
3236 IF (NOT IsConst (expr)) AND (SkipType (type) # GetDType (expr))
3238 PushTF (Convert, NulSym) ;
3239 PushT (SkipType(type)) ;
3241 PushT (2) ; (* Two parameters *)
3242 BuildConvertFunction ;
3253 PROCEDURE MoveWithMode (tokno: CARDINAL;
3254 Des, Exp, Array: CARDINAL;
3255 destok, exptok: CARDINAL;
3256 checkOverflow: BOOLEAN) ;
3260 IF IsConstString(Exp) AND IsConst(Des)
3262 GenQuadOtok (tokno, BecomesOp, Des, NulSym, Exp, TRUE,
3263 destok, UnknownTokenNo, exptok) ;
3264 PutConstString (tokno, Des, GetString (Exp))
3266 IF GetMode(Des)=RightValue
3268 IF GetMode(Exp)=LeftValue
3270 CheckPointerThroughNil (tokno, Exp) ; (* Des = *Exp *)
3271 doIndrX (tokno, Des, Exp)
3273 GenQuadOtok (tokno, BecomesOp, Des, NulSym, Exp, TRUE,
3274 destok, UnknownTokenNo, exptok)
3276 ELSIF GetMode(Des)=LeftValue
3278 MarkArrayWritten (Array) ;
3279 IF GetMode(Exp) = LeftValue
3281 t := MakeTemporary (tokno, RightValue) ;
3282 PutVar(t, GetSType(Exp)) ;
3283 CheckPointerThroughNil (tokno, Exp) ;
3284 doIndrX (tokno, t, Exp) ;
3285 CheckPointerThroughNil (tokno, Des) ; (* *Des = Exp *)
3286 GenQuadO (tokno, XIndrOp, Des, GetSType (Des), doVal (GetSType (Des), t),
3289 CheckPointerThroughNil (tokno, Des) ; (* *Des = Exp *)
3290 GenQuadO (tokno, XIndrOp, Des, GetSType (Des), doVal (GetSType (Des), Exp),
3294 GenQuadOtok (tokno, BecomesOp, Des, NulSym, Exp, TRUE,
3295 destok, UnknownTokenNo, exptok)
3302 BuildBuiltinConst - makes reference to a builtin constant within gm2.
3307 +------------+ +------------+
3309 |------------| |------------|
3313 q Sym BuiltinConstOp Ident
3316 PROCEDURE BuildBuiltinConst ;
3322 PopTtok (Id, idtok) ;
3323 Sym := MakeTemporary (idtok, ImmediateValue) ;
3324 PutVar (Sym, Integer) ;
3326 CASE GetBuiltinConstType(KeyToCharStar(Name(Id))) OF
3328 0: ErrorFormat1(NewError(GetTokenNo()),
3329 '%a unrecognised builtin constant', Id) |
3330 1: PutVar(Sym, Integer) |
3331 2: PutVar(Sym, Real)
3334 InternalError ('unrecognised value')
3337 GenQuadO (idtok, BuiltinConstOp, Sym, NulSym, Id, FALSE) ;
3338 PushTtok (Sym, idtok)
3339 END BuildBuiltinConst ;
3343 BuildBuiltinTypeInfo - make reference to a builtin typeinfo function
3351 |-------------| +------------+
3353 |-------------| |------------|
3357 q Sym BuiltinTypeInfoOp Type Ident
3360 PROCEDURE BuildBuiltinTypeInfo ;
3367 PopTtok (Ident, idtok) ;
3369 Sym := MakeTemporary (BuiltinTokenNo, ImmediateValue) ;
3370 CASE GetBuiltinTypeInfoType (KeyToCharStar (Name (Ident))) OF
3372 0: ErrorFormat1 (NewError(idtok),
3373 '%a unrecognised builtin constant', Ident) |
3374 1: PutVar (Sym, Boolean) |
3375 2: PutVar (Sym, ZType) |
3376 3: PutVar (Sym, RType)
3379 InternalError ('unrecognised value')
3381 GenQuadO (idtok, BuiltinTypeInfoOp, Sym, Type, Ident, FALSE) ;
3382 PushTtok (Sym, idtok)
3383 END BuildBuiltinTypeInfo ;
3387 CheckBecomesMeta - checks to make sure that we are not
3388 assigning a variable to a constant.
3389 Also check we are not assigning to an
3393 PROCEDURE CheckBecomesMeta (Des, Exp: CARDINAL; combinedtok, destok, exprtok: CARDINAL) ;
3395 IF IsConst (Des) AND IsVar (Exp)
3397 MetaErrorsT2 (combinedtok,
3398 'in assignment, cannot assign a variable {%2a} to a constant {%1a}',
3399 'designator {%1Da} is declared as a {%kCONST}', Des, Exp)
3401 IF (GetDType(Des) # NulSym) AND IsVar (Des) AND IsUnbounded (GetDType (Des))
3403 MetaErrorT1 (destok,
3404 'in assignment, cannot assign to an unbounded array {%1ad}', Des)
3406 IF (GetDType(Exp) # NulSym) AND IsVar (Exp) AND IsUnbounded (GetDType (Exp))
3408 MetaErrorT1 (exprtok,
3409 'in assignment, cannot assign from an unbounded array {%1ad}', Exp)
3411 END CheckBecomesMeta ;
3415 BuildAssignment - Builds an assignment from the values given on the
3416 quad stack. Either an assignment to an
3417 arithmetic expression or an assignment to a
3418 boolean expression. This procedure should not
3419 be called in CONST declarations.
3420 The Stack is expected to contain:
3433 |------------| +------------+
3435 |------------| |------------|
3440 q BecomesOp Designator _ Expression
3452 |------------| +------------+
3454 |------------| |------------|
3459 q BecomesOp Designator _ TRUE
3461 q+2 BecomesOp Designator _ FALSE
3465 PROCEDURE BuildAssignment (becomesTokNo: CARDINAL) ;
3467 des, exp : CARDINAL ;
3470 combinedtok: CARDINAL ;
3472 des := OperandT (2) ;
3475 destok := OperandTok (2) ;
3476 exptok := OperandTok (1) ;
3477 exp := OperandT (1) ;
3480 MetaErrorT1 (destok, 'destok {%1Ead}', des) ;
3481 MetaErrorT1 (exptok, 'exptok {%1Ead}', exp)
3483 combinedtok := MakeVirtualTok (becomesTokNo, destok, exptok) ;
3486 MetaErrorT1 (combinedtok, 'combined {%1Ead}', des)
3490 MetaErrorT1 (combinedtok,
3491 'cannot assign expression to a constant designator {%1Ead}', des)
3493 exp := OperandT (1) ;
3494 MetaErrorT2 (combinedtok,
3495 'cannot assign a constant designator {%1Ead} with an expression {%2Ead}',
3498 PopN (2) (* Remove both parameters. *)
3501 PopN (2) (* Remove both parameters. *)
3503 doBuildAssignment (becomesTokNo, TRUE, TRUE)
3505 END BuildAssignment ;
3509 BuildAssignConstant - used to create constant in the CONST declaration.
3510 The stack is expected to contain:
3522 |------------| +------------+
3524 |------------| |------------|
3529 q BecomesOp Designator _ Expression
3541 |------------| +------------+
3543 |------------| |------------|
3548 q BecomesOp Designator _ TRUE
3550 q+2 BecomesOp Designator _ FALSE
3553 PROCEDURE BuildAssignConstant (equalsTokNo: CARDINAL) ;
3555 doBuildAssignment (equalsTokNo, TRUE, TRUE)
3556 END BuildAssignConstant ;
3560 doBuildAssignment - subsiduary procedure of BuildAssignment.
3561 It builds the assignment and optionally
3562 checks the types are compatible.
3565 PROCEDURE doBuildAssignment (becomesTokNo: CARDINAL; checkTypes, checkOverflow: BOOLEAN) ;
3570 Des, Exp : CARDINAL ;
3572 destok, exptok: CARDINAL ;
3578 PopTtok (Des, destok) ;
3579 (* Conditional Boolean Assignment. *)
3580 BackPatch (t, NextQuad) ;
3581 IF GetMode (Des) = RightValue
3583 GenQuadO (becomesTokNo, BecomesOp, Des, NulSym, True, checkOverflow)
3585 CheckPointerThroughNil (destok, Des) ;
3586 GenQuadO (destok, XIndrOp, Des, Boolean, True, checkOverflow)
3588 GenQuadO (destok, GotoOp, NulSym, NulSym, NextQuad+2, checkOverflow) ;
3589 BackPatch (f, NextQuad) ;
3590 IF GetMode (Des) = RightValue
3592 GenQuadO (becomesTokNo, BecomesOp, Des, NulSym, False, checkOverflow)
3594 CheckPointerThroughNil (destok, Des) ;
3595 GenQuadO (destok, XIndrOp, Des, Boolean, False, checkOverflow)
3598 PopTrwtok (Exp, r, exptok) ;
3602 MetaError0 ('{%E}unknown expression found during assignment') ;
3605 Array := OperandA (1) ;
3606 PopTrwtok (Des, w, destok) ;
3608 CheckCompatibleWithBecomes (Des, Exp, destok, exptok) ;
3609 combinedtok := MakeVirtualTok (becomesTokNo, destok, exptok) ;
3612 MetaErrorT1 (becomesTokNo, 'becomestok {%1Oad}', Des) ;
3613 MetaErrorT1 (destok, 'destok {%1Oad}', Des) ;
3614 MetaErrorT1 (exptok, 'exptok {%1Oad}', Exp)
3616 combinedtok := MakeVirtualTok (becomesTokNo, destok, exptok) ;
3619 MetaErrorT1 (combinedtok, 'combined {%1Oad}', Des)
3621 IF (GetSType (Des) # NulSym) AND (NOT IsSet (GetDType (Des)))
3623 (* Tell code generator to test runtime values of assignment so ensure we
3624 catch overflow and underflow. *)
3625 BuildRange (InitAssignmentRangeCheck (combinedtok, Des, Exp))
3629 CheckBecomesMeta (Des, Exp, combinedtok, destok, exptok)
3631 (* Simple assignment. *)
3632 MoveWithMode (becomesTokNo, Des, Exp, Array, destok, exptok, checkOverflow) ;
3636 IF (CannotCheckTypeInPass3 (Des) OR CannotCheckTypeInPass3 (Exp))
3638 (* We must do this after the assignment to allow the Designator to be
3639 resolved (if it is a constant) before the type checking is done. *)
3640 (* Prompt post pass 3 to check the assignment once all types are resolved. *)
3641 BuildRange (InitTypesAssignmentCheck (combinedtok, Des, Exp))
3644 (* BuildRange (InitTypesAssignmentCheck (combinedtok, Des, Exp)) ; *)
3645 CheckAssignCompatible (Des, Exp, combinedtok, destok, exptok)
3649 END doBuildAssignment ;
3653 CheckAssignCompatible - checks to see that an assignment is compatible.
3654 It performs limited checking - thorough checking
3655 is done in pass 3. But we do what we can here
3656 given knowledge so far.
3659 PROCEDURE CheckAssignCompatible (Des, Exp: CARDINAL; combinedtok, destok, exprtok: CARDINAL) ;
3661 DesT, ExpT, DesL: CARDINAL ;
3663 DesT := GetSType(Des) ;
3664 ExpT := GetSType(Exp) ;
3665 DesL := GetLType(Des) ;
3666 IF IsProcedure(Exp) AND
3667 ((DesT#NulSym) AND (NOT IsProcType(DesT))) AND
3668 ((DesL#NulSym) AND (NOT IsProcType(DesL)))
3670 MetaErrorT1 (destok,
3671 'incorrectly assigning a procedure to a designator {%1Ead} (designator is not a procedure type, {%1ast})', Des)
3672 ELSIF IsProcedure (Exp) AND IsProcedureNested (Exp)
3674 MetaErrorT1 (exprtok,
3675 'cannot call nested procedure {%1Ead} indirectly as the outer scope will not be known', Exp)
3676 ELSIF IsConstString(Exp)
3678 ELSIF (DesT#NulSym) AND (IsUnbounded(DesT))
3680 ELSIF (ExpT#NulSym) AND (IsUnbounded(ExpT))
3682 ELSIF (DesL#NulSym) AND IsArray(DesL)
3684 ELSIF IsConstructor(Exp)
3688 (* ignore type checking *)
3689 ELSIF (DesT=NulSym) AND IsConst(Des) AND (IsConstructor(Des) OR IsConstSet(Des))
3692 ELSIF NOT IsAssignmentCompatible(DesT, ExpT)
3694 MetaErrorT1 (combinedtok,
3695 'constructor expression is not compatible during assignment to {%1Ead}', Des)
3697 ELSIF (DesT#NulSym) AND IsSet(DesT) AND IsConst(Exp)
3699 (* We ignore checking of these types in pass 3 - but we do check them thoroughly post pass 3 *)
3700 ELSIF IsConst(Exp) AND (ExpT#Address) AND (NOT IsConst(Des)) AND
3701 (DesL#NulSym) AND ((DesL=Cardinal) OR (NOT IsSubrange(DesL))) AND
3702 (NOT IsEnumeration(DesL))
3704 IF (IsBaseType(DesL) OR IsSystemType(DesL))
3706 CheckAssignmentCompatible (combinedtok, ExpT, DesT)
3708 MetaErrorT2 (combinedtok,
3709 'assignment of a constant {%1Ead} can only be made to a variable whose type is equivalent to a Modula-2 base type {%2tsa}', Exp, Des)
3712 IF (DesT#NulSym) AND IsProcType(DesT) AND IsProcedure(Exp)
3714 DesT := GetSType(DesT) ; (* we can at least check RETURN values of procedure variables *)
3715 (* remember that thorough assignment checking is done post pass 3 *)
3716 CheckAssignmentCompatible (combinedtok, ExpT, DesT)
3719 END CheckAssignCompatible ;
3723 CheckBooleanId - Checks to see if the top operand is a boolean.
3724 If the operand is not a boolean then it is tested
3725 with true and a boolean is generated.
3731 +------------+ +------------+
3733 |------------| |------------|
3741 PROCEDURE CheckBooleanId ;
3745 IF NOT IsBoolean (1)
3747 tok := OperandTok (1) ;
3748 IF IsVar (OperandT (1))
3750 IF GetSType (OperandT (1)) # Boolean
3752 MetaError1 ('{%1Ua:is not a boolean expression}' +
3753 '{!%1Ua:boolean expression expected}', OperandT (1))
3760 END CheckBooleanId ;
3764 BuildAlignment - builds an assignment to an alignment constant.
3766 The Stack is expected to contain:
3777 |---------------| empty
3780 PROCEDURE BuildAlignment (tokno: CARDINAL) ;
3788 IF name # MakeKey ('bytealignment')
3790 MetaError1 ('expecting bytealignment identifier, rather than {%1Ea}',
3791 MakeError (tokno, name))
3793 GetConstFromFifoQueue (align) ;
3796 BuildAssignConstant (tokno)
3797 END BuildAlignment ;
3801 BuildBitLength - builds an assignment to a bit length constant.
3803 The Stack is expected to contain:
3812 |------------| empty
3815 PROCEDURE BuildBitLength (tokno: CARDINAL) ;
3821 GetConstFromFifoQueue (length) ;
3824 BuildAssignConstant (tokno)
3825 END BuildBitLength ;
3829 BuildDefaultFieldAlignment - builds an assignment to an alignment constant.
3831 The Stack is expected to contain:
3840 |------------| empty
3843 PROCEDURE BuildDefaultFieldAlignment ;
3851 IF name # MakeKey ('bytealignment')
3853 MetaError0 ('{%E}only allowed to use the attribute {%kbytealignment} in the default record field alignment pragma')
3855 GetConstFromFifoQueue (align) ;
3858 BuildAssignConstant (GetTokenNo ())
3859 END BuildDefaultFieldAlignment ;
3863 BuildPragmaField - builds an assignment to an alignment constant.
3865 The Stack is expected to contain:
3874 |------------| empty
3877 PROCEDURE BuildPragmaField ;
3885 IF (name # MakeKey ('unused')) AND (name # MakeKey ('bytealignment'))
3887 MetaError0 ('only allowed to use the attribute {%Ekbytealignment} in the default record field alignment pragma')
3891 GetConstFromFifoQueue (const) ;
3894 BuildAssignConstant (GetTokenNo ())
3896 END BuildPragmaField ;
3900 BuildRepeat - Builds the repeat statement from the quad stack.
3901 The Stack is expected to contain:
3916 PROCEDURE BuildRepeat ;
3923 BuildUntil - Builds the until part of the repeat statement
3924 from the quad stack.
3925 The Stack is expected to contain:
3935 | RepeatQuad | Empty
3939 PROCEDURE BuildUntil ;
3947 BackPatch(f, Repeat) ; (* If False then keep on repeating *)
3948 BackPatch(t, NextQuad) ; (* If True then exit repeat *)
3953 BuildWhile - Builds the While part of the While statement
3954 from the quad stack.
3955 The Stack is expected to contain:
3967 PROCEDURE BuildWhile ;
3974 BuildDoWhile - Builds the Do part of the while statement
3975 from the quad stack.
3976 The Stack is expected to contain:
3983 +------------+ +------------+
3985 |------------| |------------|
3986 | WhileQuad | | WhileQuad |
3987 |------------| |------------|
3991 BackPatch t exit to the NextQuad
3994 PROCEDURE BuildDoWhile ;
4000 BackPatch(t, NextQuad) ;
4006 BuildEndWhile - Builds the end part of the while statement
4007 from the quad stack.
4008 The Stack is expected to contain:
4024 False exit is backpatched with q+1
4027 PROCEDURE BuildEndWhile ;
4035 GenQuad(GotoOp, NulSym, NulSym, While) ;
4036 BackPatch(f, NextQuad)
4041 BuildLoop - Builds the Loop part of the Loop statement
4042 from the quad stack.
4043 The Stack is expected to contain:
4050 Empty +------------+
4055 PROCEDURE BuildLoop ;
4058 PushExit(0) (* Seperate Exit Stack for loop end *)
4063 BuildExit - Builds the Exit part of the Loop statement.
4066 PROCEDURE BuildExit ;
4068 IF IsEmptyWord(ExitStack)
4070 MetaError0 ('{%EkEXIT} is only allowed in a {%kLOOP} statement')
4072 GenQuad(GotoOp, NulSym, NulSym, 0) ;
4073 PushExit(Merge(PopExit(), NextQuad-1))
4079 BuildEndLoop - Builds the End part of the Loop statement
4080 from the quad stack.
4081 The Stack is expected to contain:
4097 PROCEDURE BuildEndLoop ;
4102 GenQuad(GotoOp, NulSym, NulSym, Loop) ;
4103 BackPatch(PopExit(), NextQuad)
4108 BuildThenIf - Builds the Then part of the If statement
4109 from the quad stack.
4110 The Stack is expected to contain:
4117 +------------+ +------------+
4119 |------------| |------------|
4123 The true exit is BackPatched to point to
4127 PROCEDURE BuildThenIf ;
4133 BackPatch(t, NextQuad) ;
4139 BuildElse - Builds the Else part of the If statement
4140 from the quad stack.
4141 The Stack is expected to contain:
4148 +------------+ +------------+
4149 | t | f | | t+q | 0 |
4150 |------------| |------------|
4155 q+1 <- BackPatched from f
4158 PROCEDURE BuildElse ;
4162 GenQuad(GotoOp, NulSym, NulSym, 0) ;
4164 BackPatch(f, NextQuad) ;
4165 PushBool(Merge(t, NextQuad-1), 0) (* NextQuad-1 = Goto Quad *)
4170 BuildEndIf - Builds the End part of the If statement
4171 from the quad stack.
4172 The Stack is expected to contain:
4185 Both t and f are backpatched to point to the NextQuad
4188 PROCEDURE BuildEndIf ;
4193 BackPatch(t, NextQuad) ;
4194 BackPatch(f, NextQuad)
4199 BuildElsif1 - Builds the Elsif part of the If statement
4200 from the quad stack.
4201 The Stack is expected to contain:
4208 +------------+ +------------+
4209 | t | f | | t+q | 0 |
4210 |------------| |------------|
4215 q+1 <- BackPatched from f
4218 PROCEDURE BuildElsif1 ;
4222 GenQuad(GotoOp, NulSym, NulSym, 0) ;
4224 BackPatch(f, NextQuad) ;
4225 PushBool(Merge(t, NextQuad-1), 0) (* NextQuad-1 = Goto Quad *)
4230 BuildElsif2 - Builds the Elsif until part of the If statement
4231 from the quad stack.
4232 The Stack is expected to contain:
4241 |--------------| +---------------+
4242 | t2 | f2 | | t2 | f1+f2 |
4243 |--------------| |---------------|
4246 PROCEDURE BuildElsif2 ;
4254 PushBool(t2, Merge(f1, f2))
4259 PushOne - pushes the value one to the stack.
4260 The Stack is changed:
4272 PROCEDURE PushOne (tok: CARDINAL; type: CARDINAL; message: ARRAY OF CHAR) ;
4276 PushTF (MakeConstLit (tok, MakeKey('1'), NulSym), NulSym)
4277 ELSIF IsEnumeration (type)
4279 IF NoOfElements (type) = 0
4281 MetaErrorString1 (ConCat (InitString ('enumeration type only has one element {%1Dad} and therefore '),
4282 Mark (InitString (message))),
4284 PushZero (tok, type)
4286 PushTF (Convert, NulSym) ;
4288 PushT (MakeConstLit (tok, MakeKey ('1'), ZType)) ;
4289 PushT (2) ; (* Two parameters *)
4290 BuildConvertFunction
4293 PushTF (MakeConstLit (tok, MakeKey ('1'), type), type)
4299 PushZero - pushes the value zero to the stack.
4300 The Stack is changed:
4312 PROCEDURE PushZero (tok: CARDINAL; type: CARDINAL) ;
4316 PushTFtok (MakeConstLit (tok, MakeKey ('0'), NulSym), NulSym, tok)
4317 ELSIF IsEnumeration (type)
4319 PushTFtok (Convert, NulSym, tok) ;
4320 PushTtok (type, tok) ;
4321 PushTtok (MakeConstLit (tok, MakeKey ('0'), ZType), tok) ;
4322 PushT (2) ; (* Two parameters *)
4323 BuildConvertFunction
4325 PushTFtok (MakeConstLit (tok, MakeKey ('0'), type), type, tok)
4331 BuildPseudoBy - Builds the Non existant part of the By
4332 clause of the For statement
4333 from the quad stack.
4334 The Stack is expected to contain:
4342 Ptr -> | BySym | t |
4343 +------------+ |------------|
4345 |------------| |------------|
4348 PROCEDURE BuildPseudoBy ;
4350 e, t, dotok: CARDINAL ;
4352 PopTFtok (e, t, dotok) ; (* as there is no BY token this position is the DO at the end of the last expression. *)
4353 PushTFtok (e, t, dotok) ;
4358 PushOne (dotok, t, 'the implied FOR loop increment will cause an overflow {%1ad}')
4363 BuildForLoopToRangeCheck - builds the range check to ensure that the id
4364 does not exceed the limits of its type.
4367 PROCEDURE BuildForLoopToRangeCheck ;
4374 BuildRange (InitForLoopToRangeCheck (d, e)) ;
4377 END BuildForLoopToRangeCheck ;
4381 BuildForToByDo - Builds the For To By Do part of the For statement
4382 from the quad stack.
4383 The Stack is expected to contain:
4391 +----------------+ |----------------|
4392 | BySym | ByType | | ForQuad |
4393 |----------------| |----------------|
4394 | e2 | | LastValue |
4395 |----------------| |----------------|
4396 | e1 | | BySym | ByType |
4397 |----------------| |----------------|
4398 | Ident | | IdentSym |
4399 |----------------| |----------------|
4403 LASTVALUE := ((e2-e1) DIV BySym) * BySym + e1
4427 q BecomesOp IdentSym _ e1
4428 q+ LastValue := ((e1-e2) DIV by) * by + e1
4429 q+1 if >= by 0 q+..2
4435 q+..2 If >= e2 e1 q+..4
4439 The For Loop is regarded:
4441 For ident := e1 To e2 By by Do
4446 PROCEDURE BuildForToByDo ;
4469 PopTFtok (BySym, ByType, bytok) ;
4470 PopTtok (e2, e2tok) ;
4471 PopTtok (e1, e1tok) ;
4472 PopTtok (Id, idtok) ;
4473 IdSym := RequestSym (idtok, Id) ;
4474 IF NOT IsExpressionCompatible (GetSType (e1), GetSType (e2))
4476 MetaError2 ('incompatible types found in {%EkFOR} loop header, initial expression {%1tsad} and final expression {%2tsad}',
4478 CheckExpressionCompatible (idtok, GetSType (e1), GetSType (e2))
4480 IF NOT IsExpressionCompatible( GetSType (e1), ByType)
4482 MetaError2 ('incompatible types found in {%EkFOR} loop header, initial expression {%1tsad} and {%kBY} {%2tsad}',
4484 CheckExpressionCompatible (e1tok, GetSType (e1), ByType)
4485 ELSIF NOT IsExpressionCompatible (GetSType (e2), ByType)
4487 MetaError2 ('incompatible types found in {%EkFOR} loop header, final expression {%1tsad} and {%kBY} {%2tsad}',
4489 CheckExpressionCompatible (e1tok, GetSType (e2), ByType)
4491 BuildRange (InitForLoopBeginRangeCheck (IdSym, e1)) ;
4492 PushTtok (IdSym, idtok) ;
4493 PushTtok (e1, e1tok) ;
4494 BuildAssignmentWithoutBounds (idtok, TRUE, TRUE) ;
4497 FinalValue := MakeTemporary (e2tok,
4498 AreConstant (IsConst (e1) AND IsConst (e2) AND
4500 PutVar (FinalValue, GetSType (IdSym)) ;
4501 etype := MixTypes (GetSType (e1), GetSType (e2), e2tok) ;
4502 e1 := doConvert (etype, e1) ;
4503 e2 := doConvert (etype, e2) ;
4505 PushTF (FinalValue, GetSType(FinalValue)) ;
4506 PushTFtok (e2, GetSType(e2), e2tok) ; (* FinalValue := ((e1-e2) DIV By) * By + e1 *)
4508 PushTFtok (e1, GetSType(e1), e1tok) ;
4509 doBuildBinaryOp (TRUE, FALSE) ;
4511 PushTFtok (BySym, ByType, bytok) ;
4512 doBuildBinaryOp (FALSE, FALSE) ;
4514 PushTFtok (BySym, ByType, bytok) ;
4515 doBuildBinaryOp (FALSE, FALSE) ;
4516 PushT (ArithPlusTok) ;
4517 PushTFtok (e1, GetSType (e1), e1tok) ;
4518 doBuildBinaryOp (FALSE, FALSE) ;
4519 BuildForLoopToRangeCheck ;
4520 BuildAssignmentWithoutBounds (e1tok, FALSE, FALSE) ;
4522 (* q+1 if >= by 0 q+..2 *)
4523 (* q+2 GotoOp q+3 *)
4524 PushTFtok (BySym, ByType, bytok) ; (* BuildRelOp 1st parameter *)
4525 PushT (GreaterEqualTok) ; (* 2nd parameter *)
4527 PushZero (bytok, ByType) ;
4529 BuildRelOp (e2tok) ; (* choose final expression position. *)
4531 BackPatch(f, NextQuad) ;
4532 (* q+3 If >= e1 e2 q+5 *)
4533 (* q+4 GotoOp Exit *)
4534 PushTFtok (e1, GetSType (e1), e1tok) ; (* BuildRelOp 1st parameter *)
4535 PushT (GreaterEqualTok) ; (* 2nd parameter *)
4536 PushTFtok (e2, GetSType (e2), e2tok) ; (* 3rd parameter *)
4537 BuildRelOp (e2tok) ; (* choose final expression position. *)
4538 PopBool (t1, exit1) ;
4539 BackPatch (t1, NextQuad) ;
4540 PushFor (Merge (PopFor(), exit1)) ; (* merge exit1 *)
4542 GenQuad (GotoOp, NulSym, NulSym, 0) ;
4543 ForLoop := NextQuad-1 ;
4547 BackPatch (t, NextQuad) ;
4548 PushTFtok (e2, GetSType(e2), e2tok) ; (* BuildRelOp 1st parameter *)
4549 PushT (GreaterEqualTok) ; (* 2nd parameter *)
4550 PushTFtok (e1, GetSType(e1), e1tok) ; (* 3rd parameter *)
4551 BuildRelOp (e2tok) ;
4552 PopBool (t1, exit1) ;
4553 BackPatch (t1, NextQuad) ;
4554 PushFor (Merge (PopFor (), exit1)) ; (* merge exit1 *)
4556 BackPatch(ForLoop, NextQuad) ; (* fixes the start of the for loop *)
4557 ForLoop := NextQuad ;
4559 (* and set up the stack *)
4561 PushTFtok (IdSym, GetSym (IdSym), idtok) ;
4562 PushTFtok (BySym, ByType, bytok) ;
4563 PushTFtok (FinalValue, GetSType (FinalValue), e2tok) ;
4565 END BuildForToByDo ;
4569 BuildEndFor - Builds the End part of the For statement
4570 from the quad stack.
4571 The Stack is expected to contain:
4589 PROCEDURE BuildEndFor (endpostok: CARDINAL) ;
4604 PopTFtok (BySym, ByType, bytok) ;
4605 PopTtok (IdSym, idtok) ;
4607 (* IF IdSym=LastSym THEN exit END *)
4608 PushTF(IdSym, GetSType (IdSym)) ;
4610 PushTF (LastSym, GetSType (LastSym)) ;
4611 BuildRelOp (endpostok) ;
4614 BackPatch (t, NextQuad) ;
4615 GenQuad (GotoOp, NulSym, NulSym, 0) ;
4616 PushFor (Merge (PopFor (), NextQuad-1)) ;
4617 BackPatch (f, NextQuad) ;
4618 IF GetMode (IdSym) = LeftValue
4620 (* index variable is a LeftValue, therefore we must dereference it *)
4621 tsym := MakeTemporary (idtok, RightValue) ;
4622 PutVar (tsym, GetSType (IdSym)) ;
4623 CheckPointerThroughNil (idtok, IdSym) ;
4624 doIndrX (endpostok, tsym, IdSym) ;
4625 BuildRange (InitForLoopEndRangeCheck (tsym, BySym)) ; (* --fixme-- pass endpostok. *)
4626 IncQuad := NextQuad ;
4627 (* we have explicitly checked using the above and also
4628 this addition can legitimately overflow if a cardinal type
4629 is counting down. The above test will generate a more
4630 precise error message, so we suppress overflow detection
4632 GenQuadO (bytok, AddOp, tsym, tsym, BySym, FALSE) ;
4633 CheckPointerThroughNil (idtok, IdSym) ;
4634 GenQuadO (idtok, XIndrOp, IdSym, GetSType (IdSym), tsym, FALSE)
4636 BuildRange (InitForLoopEndRangeCheck (IdSym, BySym)) ;
4637 IncQuad := NextQuad ;
4638 (* we have explicitly checked using the above and also
4639 this addition can legitimately overflow if a cardinal type
4640 is counting down. The above test will generate a more
4641 precise error message, so we suppress overflow detection
4643 GenQuadO (idtok, AddOp, IdSym, IdSym, BySym, FALSE)
4645 GenQuadO (endpostok, GotoOp, NulSym, NulSym, ForQuad, FALSE) ;
4646 BackPatch (PopFor (), NextQuad) ;
4647 AddForInfo (ForQuad, NextQuad-1, IncQuad, IdSym, idtok)
4652 BuildCaseStart - starts the case statement.
4653 It initializes a backpatch list on the compile
4654 time stack, the list is used to contain all
4655 case break points. The list is later backpatched
4656 and contains all positions of the case statement
4657 which jump to the end of the case statement.
4658 The stack also contains room for a boolean
4659 expression, this is needed to allow , operator
4660 in the CaseField alternatives.
4662 The Stack is expected to contain:
4673 +-------------+ |------------|
4674 | Expr | | | Expr | |
4675 |-------------| |------------|
4678 PROCEDURE BuildCaseStart ;
4680 BuildRange (InitCaseBounds (PushCase (NulSym, NulSym, OperandT (1)))) ;
4681 PushBool (0, 0) ; (* BackPatch list initialized *)
4682 PushBool (0, 0) (* Room for a boolean expression *)
4683 END BuildCaseStart ;
4687 BuildCaseStartStatementSequence - starts the statement sequence
4688 inside a case clause.
4689 BackPatches the true exit to the
4696 +-----------+ +------------+
4698 |-----------| |------------|
4701 PROCEDURE BuildCaseStartStatementSequence ;
4706 BackPatch (t, NextQuad) ;
4708 END BuildCaseStartStatementSequence ;
4712 BuildCaseEndStatementSequence - ends the statement sequence
4713 inside a case clause.
4714 BackPatches the false exit f1 to the
4716 Asserts that t1 and f2 is 0
4728 +-----------+ +------------+
4729 | t1 | f1 | | 0 | 0 |
4730 |-----------| |------------|
4731 | t2 | f2 | | t2+q | 0 |
4732 |-----------| |------------|
4735 PROCEDURE BuildCaseEndStatementSequence ;
4740 GenQuad (GotoOp, NulSym, NulSym, 0) ;
4742 PopBool (t2, f2) ; (* t2 contains the break list for the case *)
4743 BackPatch (f1, NextQuad) ; (* f1 no longer needed *)
4746 PushBool (Merge (t2, NextQuad-1), 0) ; (* NextQuad-1 = Goto Quad *)
4747 PushBool (0, 0) (* Room for boolean expression *)
4748 END BuildCaseEndStatementSequence ;
4752 BuildCaseRange - builds the range testing quaruples for
4755 IF (e1>=ce1) AND (e1<=ce2)
4767 |-----------| +-----------+
4769 |-----------| |-----------|
4770 | t1 | f1 | | t1 | f1 |
4771 |-----------| |-----------|
4772 | t2 | f2 | | t2 | f2 |
4773 |-----------| |-----------|
4775 |-----------| |-----------|
4778 PROCEDURE BuildCaseRange ;
4789 PopTtok (ce2, ce2tok) ;
4790 PopTtok (ce1, ce1tok) ;
4791 combinedtok := MakeVirtualTok (ce2tok, ce2tok, ce1tok) ;
4792 AddRange (ce1, ce2, combinedtok) ;
4795 PopTtok (e1, e1tok) ;
4796 PushTtok (e1, e1tok) ; (* leave e1 on bottom of stack when exit procedure *)
4798 PushBool (t1, f1) ; (* also leave t1 and f1 on the bottom of the stack *)
4799 PushTtok (e1, e1tok) ;
4800 PushT (GreaterEqualTok) ;
4801 PushTtok (ce1, ce1tok) ;
4802 BuildRelOp (combinedtok) ;
4805 PushTtok (e1, e1tok) ;
4806 PushT (LessEqualTok) ;
4807 PushTtok (ce2, ce2tok) ;
4808 BuildRelOp (combinedtok) ;
4810 END BuildCaseRange ;
4814 BuildCaseEquality - builds the range testing quadruples for
4827 +-----------+ +-----------+
4829 |-----------| |-----------|
4830 | t1 | f1 | | t1 | f1 |
4831 |-----------| |-----------|
4832 | t2 | f2 | | t2 | f2 |
4833 |-----------| |-----------|
4835 |-----------| |-----------|
4838 PROCEDURE BuildCaseEquality ;
4846 PopTtok (ce1, ce1tok) ;
4847 AddRange (ce1, NulSym, ce1tok) ;
4850 PopTtok (e1, e1tok) ;
4851 PushTtok (e1, e1tok) ; (* leave e1 on bottom of stack when exit procedure *)
4852 PushBool (t2, f2) ; (* also leave t2 and f2 on the bottom of the stack *)
4854 PushTtok (e1, e1tok) ;
4856 PushTtok (ce1, ce1tok) ;
4858 END BuildCaseEquality ;
4862 BuildCaseList - merges two case tests into one
4871 |-----------| +-------------+
4872 | t1 | f1 | | t1+t2| f1+f2|
4873 |-----------| |-------------|
4876 PROCEDURE BuildCaseList ;
4883 PushBool (Merge (t1, t2), Merge (f1, f2))
4888 BuildCaseOr - builds the , in the case clause.
4895 +-----------+ +------------+
4897 |-----------| |------------|
4900 PROCEDURE BuildCaseOr ;
4905 BackPatch (f, NextQuad) ;
4911 BuildCaseElse - builds the else of case clause.
4918 +-----------+ +------------+
4920 |-----------| |------------|
4923 PROCEDURE BuildCaseElse ;
4928 BackPatch (f, NextQuad) ;
4934 BuildCaseEnd - builds the end of case clause.
4950 PROCEDURE BuildCaseEnd ;
4956 BackPatch (f, NextQuad) ;
4957 BackPatch (t, NextQuad) ;
4959 BackPatch (f, NextQuad) ;
4960 BackPatch (t, NextQuad) ;
4967 BuildCaseCheck - builds the case checking code to ensure that
4968 the program does not need an else clause at runtime.
4969 The stack is unaltered.
4972 PROCEDURE BuildCaseCheck ;
4974 BuildError (InitNoElseRangeCheck ())
4975 END BuildCaseCheck ;
4979 BuildNulParam - Builds a nul parameter on the stack.
4985 Empty +------------+
4990 PROCEDURE BuildNulParam ;
4997 BuildSizeCheckStart - switches off all quadruple generation if the function SIZE or HIGH
4998 is being "called". This should be done as SIZE only requires the
4999 actual type of the expression, not its value. Consider the problem of
5000 SIZE(UninitializedPointer^) which is quite legal and it must
5002 ISO Modula-2 also allows HIGH(a[0]) for a two dimensional array
5003 and there is no need to compute a[0], we just need to follow the
5004 type and count dimensions. However if SIZE(a) or HIGH(a) occurs
5005 and, a, is an unbounded array then we turn on quadruple generation.
5007 The Stack is expected to contain:
5014 +----------------------+ +----------------------+
5015 | ProcSym | Type | tok | | ProcSym | Type | tok |
5016 |----------------------| |----------------------|
5019 PROCEDURE BuildSizeCheckStart ;
5021 ProcSym, Type, tok: CARDINAL ;
5023 PopTFtok (ProcSym, Type, tok) ;
5024 IF (ProcSym=Size) OR (ProcSym=TSize) OR (ProcSym=TBitSize)
5026 QuadrupleGeneration := FALSE ;
5027 BuildingSize := TRUE
5030 QuadrupleGeneration := FALSE ;
5031 BuildingHigh := TRUE
5033 PushTFtok (ProcSym, Type, tok)
5034 END BuildSizeCheckStart ;
5038 BuildSizeCheckEnd - checks to see whether the function "called" was in fact SIZE.
5039 If so then we restore quadruple generation.
5042 PROCEDURE BuildSizeCheckEnd (ProcSym: CARDINAL) ;
5044 IF (ProcSym=Size) OR (ProcSym=TSize) OR (ProcSym=TBitSize)
5046 QuadrupleGeneration := TRUE ;
5047 BuildingSize := FALSE
5050 QuadrupleGeneration := TRUE ;
5051 BuildingHigh := FALSE
5053 END BuildSizeCheckEnd ;
5057 BuildProcedureCall - builds a procedure call.
5058 Although this procedure does not directly
5059 destroy the procedure parameters, it calls
5060 routine which will manipulate the stack and
5061 so the entry and exit states of the stack are shown.
5082 | ProcSym | Type | Empty
5086 PROCEDURE BuildProcedureCall (tokno: CARDINAL) ;
5089 ProcSym : CARDINAL ;
5092 ProcSym := OperandT (NoOfParam+1) ;
5093 PushT (NoOfParam) ; (* Compile time stack restored to entry state *)
5094 IF IsPseudoBaseProcedure (ProcSym) OR IsPseudoSystemProcedure (ProcSym)
5097 ManipulatePseudoCallParameters ;
5099 BuildPseudoProcedureCall (tokno) ;
5101 ELSIF IsUnknown (ProcSym)
5103 MetaError1 ('{%1Ua} is not recognised as a procedure, check declaration or import', ProcSym) ;
5104 PopN (NoOfParam + 2)
5107 BuildRealProcedureCall (tokno) ;
5110 END BuildProcedureCall ;
5114 BuildRealProcedureCall - builds a real procedure call.
5134 | ProcSym | Type | Empty
5138 PROCEDURE BuildRealProcedureCall (tokno: CARDINAL) ;
5140 NoOfParam: CARDINAL ;
5141 ProcSym : CARDINAL ;
5145 ProcSym := OperandT (NoOfParam+2) ;
5146 ProcSym := SkipConst (ProcSym) ;
5147 (* tokno := OperandTtok (NoOfParam+2) ; *) (* --checkme-- *)
5150 (* Procedure Variable ? *)
5151 ProcSym := SkipType (OperandF (NoOfParam+2))
5153 IF IsDefImp (GetScope (ProcSym)) AND IsDefinitionForC (GetScope (ProcSym))
5155 BuildRealFuncProcCall (tokno, FALSE, TRUE, FALSE)
5157 BuildRealFuncProcCall (tokno, FALSE, FALSE, FALSE)
5159 END BuildRealProcedureCall ;
5163 BuildRealFuncProcCall - builds a real procedure or function call.
5183 | ProcSym | Type | Empty
5187 PROCEDURE BuildRealFuncProcCall (tokno: CARDINAL; IsFunc, IsForC, ConstExpr: BOOLEAN) ;
5192 ParamConstant : BOOLEAN ;
5200 Param1, (* Used to remember first param for allocate/deallocate. *)
5206 ParamType := NulSym ;
5207 CheckProcedureParameters (IsForC) ;
5208 PopT (NoOfParameters) ;
5209 PushT (NoOfParameters) ; (* Restore stack to original state. *)
5210 ProcSym := OperandT (NoOfParameters+2) ;
5211 proctok := tokno ; (* OperandTtok (NoOfParameters+2) ; *)
5212 IF proctok = UnknownTokenNo
5214 proctok := GetTokenNo ()
5216 paramtok := proctok ;
5217 ProcSym := SkipConst (ProcSym) ;
5218 ForcedFunc := FALSE ;
5219 AllocateProc := FALSE ;
5220 DeallocateProc := FALSE ;
5223 (* Procedure Variable ? *)
5224 Proc := SkipType (OperandF (NoOfParameters+2)) ;
5225 ParamConstant := FALSE
5228 ParamConstant := TRUE ;
5229 AllocateProc := GetSymName (Proc) = MakeKey('ALLOCATE') ;
5230 DeallocateProc := GetSymName (Proc) = MakeKey('DEALLOCATE')
5234 IF GetSType (Proc) = NulSym
5236 MetaErrors1 ('procedure {%1a} cannot be used as a function',
5237 'procedure {%1Da} does not have a return type',
5241 (* is being called as a procedure *)
5242 IF GetSType (Proc) # NulSym
5244 (* however it was declared as a procedure function *)
5245 IF NOT IsReturnOptional (Proc)
5247 MetaErrors1 ('function {%1a} is being called but its return value is ignored',
5248 'function {%1Da} return a type {%1ta:of {%1ta}}',
5255 IF AllocateProc OR DeallocateProc
5257 Param1 := OperandT (NoOfParameters+1) (* Remember this before manipulating. *)
5259 ManipulateParameters (IsForC) ;
5260 CheckParameterOrdinals ;
5261 PopT(NoOfParameters) ;
5264 GenQuad (ParamOp, 0, Proc, ProcSym) (* Space for return value *)
5266 IF (NoOfParameters+1=NoOfParam(Proc)) AND UsesOptArg(Proc)
5268 GenQuad (OptParamOp, NoOfParam(Proc), Proc, Proc)
5270 i := NoOfParameters ;
5271 pi := 1 ; (* stack index referencing stacked parameter, i *)
5273 paramtok := OperandTtok (pi) ;
5274 IF (AllocateProc OR DeallocateProc) AND (i = 1) AND (Param1 # NulSym)
5276 ParamType := GetItemPointedTo (Param1) ;
5277 IF ParamType = NulSym
5279 GenQuadO (paramtok, ParamOp, i, Proc, OperandT (pi), TRUE)
5283 trash := MakeTemporary (paramtok, RightValue) ;
5284 PutVar (trash, ParamType) ;
5285 PutVarHeap (trash, TRUE)
5287 Assert (DeallocateProc) ;
5290 GenQuadOTrash (paramtok, ParamOp, i, Proc, OperandT (pi), TRUE, trash)
5293 GenQuadO (paramtok, ParamOp, i, Proc, OperandT (pi), TRUE)
5295 IF NOT IsConst (OperandT (pi))
5297 ParamConstant := FALSE
5302 GenQuadO (proctok, CallOp, NulSym, NulSym, ProcSym, TRUE) ;
5303 PopN (NoOfParameters+1) ; (* Destroy arguments and procedure call *)
5306 (* ReturnVar has the type of the procedure. *)
5307 resulttok := MakeVirtualTok (proctok, proctok, paramtok) ;
5308 IF ConstExpr AND (NOT IsProcedureBuiltinAvailable (Proc))
5310 MetaError1('{%1d} {%1ad} cannot be used in a constant expression', Proc) ;
5311 ParamConstant := FALSE
5313 ReturnVar := MakeTemporary (resulttok, AreConstant (ParamConstant AND ConstExpr)) ;
5314 PutVar (ReturnVar, GetSType (Proc)) ;
5315 GenQuadO (resulttok, FunctValueOp, ReturnVar, NulSym, Proc, TRUE) ;
5318 PushTFtok (ReturnVar, GetSType (Proc), resulttok)
5321 END BuildRealFuncProcCall ;
5325 CheckProcedureParameters - Checks the parameters which are being passed to
5334 +----------------+ +----------------+
5335 | NoOfParam | | NoOfParam |
5336 |----------------| |----------------|
5337 | Param 1 | | Param 1 |
5338 |----------------| |----------------|
5339 | Param 2 | | Param 2 |
5340 |----------------| |----------------|
5344 |----------------| |----------------|
5345 | Param # | | Param # |
5346 |----------------| |----------------|
5347 | ProcSym | Type | | ProcSym | Type |
5348 |----------------| |----------------|
5352 PROCEDURE CheckProcedureParameters (IsForC: BOOLEAN) ;
5355 paramtok : CARDINAL ;
5368 PushT(ParamTotal) ; (* Restore stack to origional state *)
5369 ProcSym := OperandT(ParamTotal+1+1) ;
5370 proctok := OperandTtok(ParamTotal+1+1) ;
5371 IF IsVar(ProcSym) AND IsProcType(GetDType(ProcSym))
5373 (* Procedure Variable ? *)
5374 Proc := SkipType(OperandF(ParamTotal+1+1))
5376 Proc := SkipConst(ProcSym)
5378 IF NOT (IsProcedure(Proc) OR IsProcType(Proc))
5382 MetaError1('{%1Ua} is not recognised as a procedure, check declaration or import', Proc)
5384 MetaErrors1('{%1a} is not recognised as a procedure, check declaration or import',
5385 '{%1Ua} is not recognised as a procedure, check declaration or import',
5389 IF CompilerDebugging
5391 n1 := GetSymName(Proc) ;
5392 printf1(' %a ( ', n1)
5396 s := InitString ('procedure') ;
5397 WarnStringAt (s, proctok)
5401 pi := ParamTotal+1 ; (* stack index referencing stacked parameter, i *)
5402 WHILE i<=ParamTotal DO
5403 IF i<=NoOfParam(Proc)
5405 FormalI := GetParam(Proc, i) ;
5406 IF CompilerDebugging
5408 n1 := GetSymName(FormalI) ;
5409 n2 := GetSymName(GetSType(FormalI)) ;
5410 printf2('%a: %a', n1, n2)
5412 Actual := OperandT(pi) ;
5413 Dim := OperandD(pi) ;
5414 paramtok := OperandTtok(pi) ;
5417 s := InitString ('actual') ;
5418 WarnStringAt (s, paramtok)
5421 BuildRange (InitTypesParameterCheck (paramtok, Proc, i, FormalI, Actual)) ;
5424 IF IsVarParam(Proc, i)
5426 FailParameter (paramtok,
5427 'trying to pass a constant to a VAR parameter',
5428 Actual, FormalI, Proc, i)
5429 ELSIF IsConstString (Actual)
5431 IF (GetStringLength (Actual) = 0) (* if = 0 then it maybe unknown at this time *)
5433 (* dont check this yet *)
5434 ELSIF IsArray(GetDType(FormalI)) AND (GetSType(GetDType(FormalI))=Char)
5436 (* allow string literals to be passed to ARRAY [0..n] OF CHAR *)
5437 ELSIF (GetStringLength(Actual) = 1) (* if = 1 then it maybe treated as a char *)
5439 CheckParameter (paramtok, Actual, Dim, FormalI, Proc, i, NIL)
5440 ELSIF NOT IsUnboundedParam(Proc, i)
5442 IF IsForC AND (GetSType(FormalI)=Address)
5444 FailParameter (paramtok,
5445 'a string constant can either be passed to an ADDRESS parameter or an ARRAY OF CHAR',
5446 Actual, FormalI, Proc, i)
5448 FailParameter (paramtok,
5449 'cannot pass a string constant to a non unbounded array parameter',
5450 Actual, FormalI, Proc, i)
5455 CheckParameter (paramtok, Actual, Dim, FormalI, Proc, i, NIL)
5458 IF IsForC AND UsesVarArgs(Proc)
5460 (* these are varargs, therefore we don't check them *)
5463 MetaErrorT2 (proctok, 'too many parameters, {%2n} passed to {%1a} ', Proc, i)
5468 IF CompilerDebugging
5478 END CheckProcedureParameters ;
5482 CheckProcTypeAndProcedure - checks the ProcType with the call.
5485 PROCEDURE CheckProcTypeAndProcedure (tokno: CARDINAL; ProcType: CARDINAL; call: CARDINAL) ;
5488 i, n, t : CARDINAL ;
5489 CheckedProcedure: CARDINAL ;
5492 n := NoOfParam(ProcType) ;
5493 IF IsVar(call) OR IsTemporary(call) OR IsParameter(call)
5495 CheckedProcedure := GetDType(call)
5497 CheckedProcedure := call
5499 IF n#NoOfParam(CheckedProcedure)
5501 e := NewError(GetDeclaredMod(ProcType)) ;
5502 n1 := GetSymName(call) ;
5503 n2 := GetSymName(ProcType) ;
5504 ErrorFormat2(e, 'procedure (%a) is a parameter being passed as variable (%a) but they are declared with different number of parameters',
5506 e := ChainError(GetDeclaredMod(call), e) ;
5507 t := NoOfParam(CheckedProcedure) ;
5510 ErrorFormat3(e, 'procedure (%a) is being called incorrectly with (%d) parameter, declared with (%d)',
5513 ErrorFormat3(e, 'procedure (%a) is being called incorrectly with (%d) parameters, declared with (%d)',
5519 IF IsVarParam (ProcType, i) # IsVarParam (CheckedProcedure, i)
5521 MetaError3 ('parameter {%3n} in {%1dD} causes a mismatch it was declared as a {%2d}', ProcType, GetNth (ProcType, i), i) ;
5522 MetaError3 ('parameter {%3n} in {%1dD} causes a mismatch it was declared as a {%2d}', call, GetNth (call, i), i)
5524 BuildRange (InitTypesParameterCheck (tokno, CheckedProcedure, i,
5525 GetParam (CheckedProcedure, i),
5526 GetParam (ProcType, i))) ;
5527 (* CheckParameter(tokpos, GetParam(CheckedProcedure, i), 0, GetParam(ProcType, i), call, i, TypeList) ; *)
5531 END CheckProcTypeAndProcedure ;
5535 IsReallyPointer - returns TRUE is sym is a pointer, address or a type declared
5536 as a pointer or address.
5539 PROCEDURE IsReallyPointer (Sym: CARDINAL) : BOOLEAN ;
5543 Sym := GetSType(Sym)
5545 Sym := SkipType(Sym) ;
5546 RETURN( IsPointer(Sym) OR (Sym=Address) )
5547 END IsReallyPointer ;
5551 LegalUnboundedParam - returns TRUE if the parameter, Actual, can legitimately be
5552 passed to ProcSym, i, the, Formal, parameter.
5555 PROCEDURE LegalUnboundedParam (tokpos: CARDINAL; ProcSym, i, ActualType, Actual, Dimension, Formal: CARDINAL) : BOOLEAN ;
5557 FormalType: CARDINAL ;
5560 ActualType := SkipType(ActualType) ;
5561 FormalType := GetDType(Formal) ;
5562 FormalType := GetSType(FormalType) ; (* type of the unbounded ARRAY *)
5563 IF IsArray(ActualType)
5565 m := GetDimension(Formal) ;
5567 WHILE IsArray(ActualType) DO
5569 ActualType := GetDType(ActualType) ;
5570 IF (m=n) AND (ActualType=FormalType)
5577 (* now we fall though and test ActualType against FormalType *)
5579 IF IsGenericSystemType(FormalType)
5583 FailParameter(tokpos,
5584 'attempting to pass an array with the incorrect number dimenisons to an unbounded formal parameter of different dimensions',
5585 Actual, Formal, ProcSym, i) ;
5589 ELSIF IsUnbounded(ActualType)
5591 IF (Dimension=0) AND (GetDimension(Formal)=GetDimension(Actual))
5593 (* now we fall though and test ActualType against FormalType *)
5594 ActualType := GetSType(ActualType)
5596 IF IsGenericSystemType(FormalType)
5600 IF GetDimension(Actual)-Dimension = GetDimension(Formal)
5602 ActualType := GetSType(ActualType)
5604 FailParameter(tokpos,
5605 'attempting to pass an unbounded array with the incorrect number dimenisons to an unbounded formal parameter of different dimensions',
5606 Actual, Formal, ProcSym, i) ;
5612 IF IsGenericSystemType (FormalType) OR
5613 IsGenericSystemType (ActualType) OR
5614 IsAssignmentCompatible (FormalType, ActualType)
5616 (* we think it is legal, but we ask post pass 3 to check as
5617 not all types are known at this point *)
5620 FailParameter(tokpos,
5621 'identifier with an incompatible type is being passed to this procedure',
5622 Actual, Formal, ProcSym, i) ;
5625 END LegalUnboundedParam ;
5629 CheckParameter - checks that types ActualType and FormalType are compatible for parameter
5630 passing. ProcSym is the procedure and i is the parameter number.
5632 We obey the following rules:
5634 (1) we allow WORD, BYTE, LOC to be compitable with any like sized
5636 (2) we allow ADDRESS to be compatible with any pointer type.
5637 (3) we relax INTEGER and CARDINAL checking for Temporary variables.
5639 Note that type sizes are checked during the code generation pass.
5642 PROCEDURE CheckParameter (tokpos: CARDINAL;
5643 Actual, Dimension, Formal, ProcSym: CARDINAL;
5644 i: CARDINAL; TypeList: List) ;
5647 ActualType, FormalType: CARDINAL ;
5649 FormalType := GetDType(Formal) ;
5650 IF IsConstString(Actual) AND (GetStringLength(Actual) = 1) (* if = 1 then it maybe treated as a char *)
5653 ELSIF Actual=Boolean
5655 ActualType := Actual
5657 ActualType := GetDType(Actual)
5666 IF IsItemInList(TypeList, ActualType)
5668 (* no need to check *)
5671 IncludeItemIntoList(TypeList, ActualType) ;
5672 IF IsProcType(FormalType)
5674 IF (NOT IsProcedure(Actual)) AND ((ActualType=NulSym) OR (NOT IsProcType(SkipType(ActualType))))
5676 FailParameter(tokpos,
5677 'expecting a procedure or procedure variable as a parameter',
5678 Actual, Formal, ProcSym, i) ;
5681 IF IsProcedure(Actual) AND IsProcedureNested(Actual)
5683 MetaError2 ('cannot pass a nested procedure {%1Ea} seen in the {%2N} parameter as the outer scope will be unknown at runtime', Actual, i)
5685 (* we can check the return type of both proc types *)
5686 IF (ActualType#NulSym) AND IsProcType(ActualType)
5688 IF ((GetSType(ActualType)#NulSym) AND (GetSType(FormalType)=NulSym))
5690 FailParameter(tokpos,
5691 'the item being passed is a function whereas the formal procedure parameter is a procedure',
5692 Actual, Formal, ProcSym, i) ;
5694 ELSIF ((GetSType(ActualType)=NulSym) AND (GetSType(FormalType)#NulSym))
5696 FailParameter(tokpos,
5697 'the item being passed is a procedure whereas the formal procedure parameter is a function',
5698 Actual, Formal, ProcSym, i) ;
5700 ELSIF AssignmentRequiresWarning(GetSType(ActualType), GetSType(FormalType))
5702 WarnParameter(tokpos,
5703 'the return result of the procedure variable parameter may not be compatible on other targets with the return result of the item being passed',
5704 Actual, Formal, ProcSym, i) ;
5706 ELSIF IsGenericSystemType (GetSType(FormalType)) OR
5707 IsGenericSystemType (GetSType(ActualType)) OR
5708 IsAssignmentCompatible(GetSType(ActualType), GetSType(FormalType))
5712 FailParameter(tokpos,
5713 'the return result of the procedure variable parameter is not compatible with the return result of the item being passed',
5714 Actual, Formal, ProcSym, i) ;
5718 (* now to check each parameter of the proc type *)
5719 CheckProcTypeAndProcedure (tokpos, FormalType, Actual)
5720 ELSIF (ActualType#FormalType) AND (ActualType#NulSym)
5722 IF IsUnknown(FormalType)
5724 FailParameter(tokpos,
5725 'procedure parameter type is undeclared',
5726 Actual, Formal, ProcSym, i) ;
5729 IF IsUnbounded(ActualType) AND (NOT IsUnboundedParam(ProcSym, i))
5731 FailParameter(tokpos,
5732 'attempting to pass an unbounded array to a NON unbounded parameter',
5733 Actual, Formal, ProcSym, i) ;
5735 ELSIF IsUnboundedParam(ProcSym, i)
5737 IF NOT LegalUnboundedParam(tokpos, ProcSym, i, ActualType, Actual, Dimension, Formal)
5741 ELSIF ActualType#FormalType
5743 IF AssignmentRequiresWarning(FormalType, ActualType)
5745 WarnParameter (tokpos,
5746 'identifier being passed to this procedure may contain a possibly incompatible type when compiling for a different target',
5747 Actual, Formal, ProcSym, i)
5748 ELSIF IsGenericSystemType (FormalType) OR
5749 IsGenericSystemType (ActualType) OR
5750 IsAssignmentCompatible (ActualType, FormalType)
5752 (* so far we know it is legal, but not all types have been resolved
5753 and so this is checked later on in another pass. *)
5755 FailParameter (tokpos,
5756 'identifier with an incompatible type is being passed to this procedure',
5757 Actual, Formal, ProcSym, i)
5765 END CheckParameter ;
5769 DescribeType - returns a String describing a symbol, Sym, name and its type.
5772 PROCEDURE DescribeType (Sym: CARDINAL) : String ;
5781 IF IsConstString(Sym)
5783 IF (GetStringLength(Sym) = 1) (* if = 1 then it maybe treated as a char *)
5785 s := InitString('(constant string) or {%kCHAR}')
5787 s := InitString('(constant string)')
5791 s := InitString('(constant)')
5792 ELSIF IsUnknown(Sym)
5794 s := InitString('(unknown)')
5796 Type := GetSType(Sym) ;
5799 s := InitString('(unknown)')
5800 ELSIF IsUnbounded(Type)
5802 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(GetSType(Type))))) ;
5803 s := Sprintf1(Mark(InitString('{%%kARRAY} {%%kOF} %s')), s1)
5806 s := InitString('{%kARRAY} [') ;
5807 Subscript := GetArraySubscript(Type) ;
5810 Assert(IsSubscript(Subscript)) ;
5811 Subrange := GetSType(Subscript) ;
5812 IF NOT IsSubrange(Subrange)
5814 MetaError3 ('error in definition of array {%1Ead} in the {%2N} subscript which has no subrange, instead type given is {%3a}',
5815 Sym, Subscript, Subrange)
5817 Assert(IsSubrange(Subrange)) ;
5818 GetSubrange(Subrange, High, Low) ;
5819 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Low)))) ;
5820 s2 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(High)))) ;
5821 s := ConCat(s, Mark(Sprintf2(Mark(InitString('%s..%s')),
5824 s1 := Mark(DescribeType(Type)) ;
5825 s := ConCat(ConCat(s, Mark(InitString('] OF '))), s1)
5829 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Type)))) ;
5830 s := Sprintf1(Mark(InitString('%s (currently unknown, check declaration or import)')),
5833 s := InitStringCharStar(KeyToCharStar(GetSymName(Type)))
5842 FailParameter - generates an error message indicating that a parameter
5843 declaration has failed.
5847 CurrentState - string describing the current failing state.
5848 Given - the token that the source code provided.
5849 Expecting - token or identifier that was expected.
5850 ParameterNo - parameter number that has failed.
5851 ProcedureSym - procedure symbol where parameter has failed.
5853 If any parameter is Nul then it is ignored.
5856 PROCEDURE FailParameter (tokpos : CARDINAL;
5857 CurrentState : ARRAY OF CHAR;
5859 Expecting : CARDINAL;
5860 ProcedureSym : CARDINAL;
5861 ParameterNo : CARDINAL) ;
5864 ExpectType: CARDINAL ;
5865 s, s1, s2 : String ;
5867 MetaError2 ('parameter mismatch between the {%2N} parameter of procedure {%1Ead}',
5868 ProcedureSym, ParameterNo) ;
5869 s := InitString ('{%kPROCEDURE} {%1Eau} (') ;
5870 IF NoOfParam(ProcedureSym)>=ParameterNo
5874 s := ConCat(s, Mark(InitString('.., ')))
5876 IF IsVarParam(ProcedureSym, ParameterNo)
5878 s := ConCat(s, Mark(InitString('{%kVAR} ')))
5881 First := GetDeclaredMod(GetNthParam(ProcedureSym, ParameterNo)) ;
5882 ExpectType := GetSType(Expecting) ;
5883 IF IsUnboundedParam(ProcedureSym, ParameterNo)
5885 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Expecting)))) ;
5886 s2 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(GetSType(ExpectType))))) ;
5887 s := ConCat(s, Mark(Sprintf2(Mark(InitString('%s: {%%kARRAY} {%%kOF} %s')),
5890 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Expecting)))) ;
5891 s2 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(ExpectType)))) ;
5892 s := ConCat(s, Mark(Sprintf2(Mark(InitString('%s: %s')), s1, s2)))
5894 IF ParameterNo<NoOfParam(ProcedureSym)
5896 s := ConCat(s, Mark(InitString('; ... ')))
5899 First := GetDeclaredMod(ProcedureSym) ;
5900 IF NoOfParam(ProcedureSym)>0
5902 s := ConCat(s, Mark(InitString('..')))
5905 s := ConCat (s, Mark (InitString ('){%1Tau:% : {%1Tau}} ;'))) ;
5906 MetaErrorStringT1 (First, Dup (s), ProcedureSym) ;
5907 MetaErrorStringT1 (tokpos, s, ProcedureSym) ;
5908 MetaError1 ('item being passed is {%1EDda} {%1Dad} of type {%1Dtsd}', Given)
5913 WarnParameter - generates a warning message indicating that a parameter
5914 use might cause problems on another target.
5918 CurrentState - string describing the current failing state.
5919 Given - the token that the source code provided.
5920 Expecting - token or identifier that was expected.
5921 ParameterNo - parameter number that has failed.
5922 ProcedureSym - procedure symbol where parameter has failed.
5924 If any parameter is Nul then it is ignored.
5927 PROCEDURE WarnParameter (tokpos : CARDINAL;
5928 CurrentState : ARRAY OF CHAR;
5930 Expecting : CARDINAL;
5931 ProcedureSym : CARDINAL;
5932 ParameterNo : CARDINAL) ;
5936 ReturnType: CARDINAL ;
5937 s, s1, s2 : String ;
5939 s := InitString('{%W}') ;
5940 IF CompilingImplementationModule()
5942 s := ConCat(s, Sprintf0(Mark(InitString('warning issued while compiling the implementation module\n'))))
5943 ELSIF CompilingProgramModule()
5945 s := ConCat(s, Sprintf0(Mark(InitString('warning issued while compiling the program module\n'))))
5947 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(ProcedureSym)))) ;
5948 s := ConCat(s, Mark(Sprintf2(Mark(InitString('problem in parameter %d, PROCEDURE %s (')),
5951 IF NoOfParam(ProcedureSym)>=ParameterNo
5955 s := ConCat(s, Mark(InitString('.., ')))
5957 IF IsVarParam(ProcedureSym, ParameterNo)
5959 s := ConCat(s, Mark(InitString('{%kVAR} ')))
5962 First := GetDeclaredMod(GetNthParam(ProcedureSym, ParameterNo)) ;
5963 ExpectType := GetSType(Expecting) ;
5964 IF IsUnboundedParam(ProcedureSym, ParameterNo)
5966 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Expecting)))) ;
5967 s2 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(GetSType(ExpectType))))) ;
5968 s := ConCat(s, Mark(Sprintf2(Mark(InitString('%s: {%%kARRAY} {%%kOF} %s')),
5971 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Expecting)))) ;
5972 s2 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(ExpectType)))) ;
5973 s := ConCat(s, Mark(Sprintf2(Mark(InitString('%s: %s')), s1, s2)))
5975 IF ParameterNo<NoOfParam(ProcedureSym)
5977 s := ConCat(s, Mark(InitString('; ... ')))
5980 First := GetDeclaredMod(ProcedureSym) ;
5981 IF NoOfParam(ProcedureSym)>0
5983 s := ConCat(s, Mark(InitString('..')))
5986 ReturnType := GetSType(ProcedureSym) ;
5987 IF ReturnType=NulSym
5989 s := ConCat(s, Sprintf0(Mark(InitString(') ;\n'))))
5991 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(ReturnType)))) ;
5992 s := ConCat(s, Mark(Sprintf1(Mark(InitString(') : %s ;\n')), s1)))
5994 IF IsConstString(Given)
5996 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Given)))) ;
5997 s := ConCat(s, Mark(Sprintf1(Mark(InitString("item being passed is '%s'")),
5999 ELSIF IsTemporary(Given)
6001 s := ConCat(s, Mark(InitString("item being passed has type")))
6003 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Given)))) ;
6004 s := ConCat(s, Mark(Sprintf1(Mark(InitString("item being passed is '%s'")),
6007 s1 := DescribeType(Given) ;
6008 s2 := Mark(InitString(CurrentState)) ;
6009 s := ConCat(s, Mark(Sprintf2(Mark(InitString(': %s\nparameter mismatch: %s')),
6011 MetaErrorStringT0 (tokpos, Dup (s)) ;
6012 MetaErrorStringT0 (First, Dup (s))
6017 ExpectVariable - checks to see whether, sym, is declared as a variable.
6018 If not then it generates an error message.
6022 PROCEDURE ExpectVariable (a: ARRAY OF CHAR; sym: CARDINAL) ;
6025 s1, s2, s3: String ;
6029 e := NewError(GetTokenNo()) ;
6032 s1 := ConCat (InitString (a),
6033 Mark (InitString ('but was given an undeclared symbol {%E1a}'))) ;
6035 ErrorString(e, Sprintf2(Mark(InitString('%s but was given an undeclared symbol %s')), s1, s2))
6037 s1 := Mark(InitString(a)) ;
6038 s2 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(sym)))) ;
6039 s3 := Mark(DescribeType(sym)) ;
6040 ErrorString(e, Sprintf3(Mark(InitString('%s but was given %s: %s')),
6044 END ExpectVariable ;
6049 doIndrX - perform des = *exp with a conversion if necessary.
6052 PROCEDURE doIndrX (tok: CARDINAL;
6053 des, exp: CARDINAL) ;
6057 IF GetDType(des)=GetDType(exp)
6059 GenQuadOtok (tok, IndrXOp, des, GetSType (des), exp, TRUE,
6062 t := MakeTemporary (tok, RightValue) ;
6063 PutVar (t, GetSType (exp)) ;
6064 GenQuadOtok (tok, IndrXOp, t, GetSType (exp), exp, TRUE,
6066 GenQuadOtok (tok, BecomesOp, des, NulSym, doVal (GetSType(des), t), TRUE,
6067 tok, UnknownTokenNo, tok)
6073 MakeRightValue - returns a temporary which will have the RightValue of symbol, Sym.
6074 If Sym is a right value and has type, type, then no quadruples are
6075 generated and Sym is returned. Otherwise a new temporary is created
6076 and an IndrX quadruple is generated.
6079 PROCEDURE MakeRightValue (tok: CARDINAL;
6080 Sym: CARDINAL; type: CARDINAL) : CARDINAL ;
6084 IF GetMode (Sym) = RightValue
6086 IF GetSType(Sym) = type
6088 RETURN Sym (* already a RightValue with desired type *)
6091 type change or mode change, type changes are a pain, but I've
6092 left them here as it is perhaps easier to remove them later.
6094 t := MakeTemporary (tok, RightValue) ;
6096 GenQuadOtok (tok, BecomesOp, t, NulSym, doVal (type, Sym), TRUE,
6101 t := MakeTemporary (tok, RightValue) ;
6103 CheckPointerThroughNil (tok, Sym) ;
6104 doIndrX (tok, t, Sym) ;
6107 END MakeRightValue ;
6111 MakeLeftValue - returns a temporary coresponding to the LeftValue of
6112 symbol, Sym. No quadruple is generated if Sym is already
6113 a LeftValue and has the same type.
6116 PROCEDURE MakeLeftValue (tok: CARDINAL;
6117 Sym: CARDINAL; with: ModeOfAddr; type: CARDINAL) : CARDINAL ;
6121 IF GetMode (Sym) = LeftValue
6123 IF GetSType (Sym) = type
6128 type change or mode change, type changes are a pain, but I've
6129 left them here as it is perhaps easier to remove them later
6131 t := MakeTemporary (tok, with) ;
6133 GenQuadOtok (tok, BecomesOp, t, NulSym, Sym, TRUE,
6134 tok, UnknownTokenNo, tok) ;
6138 t := MakeTemporary (tok, with) ;
6140 GenQuadOtok (tok, AddrOp, t, NulSym, Sym, TRUE,
6141 tok, UnknownTokenNo, tok) ;
6148 ManipulatePseudoCallParameters - manipulates the parameters to a pseudo function or
6149 procedure. It dereferences all LeftValue parameters
6150 and Boolean parameters.
6156 Ptr -> exactly the same
6175 PROCEDURE ManipulatePseudoCallParameters ;
6182 PopT(NoOfParameters) ;
6183 PushT(NoOfParameters) ; (* restored to original state *)
6184 (* Ptr points to the ProcSym *)
6185 ProcSym := OperandT(NoOfParameters+1+1) ;
6188 InternalError ('expecting a pseudo procedure or a type')
6193 pi := NoOfParameters+1 ;
6194 WHILE i<=NoOfParameters DO
6195 IF (GetMode(OperandT(pi))=LeftValue) AND
6196 (Proc#Adr) AND (Proc#Size) AND (Proc#TSize) AND (Proc#High) AND
6197 (* procedures which have first parameter as a VAR param *)
6198 (((Proc#Inc) AND (Proc#Incl) AND (Proc#Dec) AND (Proc#Excl) AND (Proc#New) AND (Proc#Dispose)) OR (i>1))
6200 (* must dereference LeftValue *)
6201 f := PeepAddress(BoolStack, pi) ;
6202 f^.TrueExit := MakeRightValue (GetTokenNo(), OperandT(pi), GetSType(OperandT(pi)))
6207 END ManipulatePseudoCallParameters ;
6211 ManipulateParameters - manipulates the procedure parameters in
6212 preparation for a procedure call.
6213 Prepares Boolean, Unbounded and VAR parameters.
6219 Ptr -> exactly the same
6237 PROCEDURE ManipulateParameters (IsForC: BOOLEAN) ;
6252 PopT(NoOfParameters) ;
6253 ProcSym := OperandT(NoOfParameters+1) ;
6254 tokpos := OperandTtok(NoOfParameters+1) ;
6257 (* Procedure Variable ? *)
6258 Proc := SkipType(OperandF(NoOfParameters+1))
6260 Proc := SkipConst(ProcSym)
6263 IF IsForC AND UsesVarArgs(Proc)
6265 IF NoOfParameters<NoOfParam(Proc)
6267 s := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Proc)))) ;
6268 np := NoOfParam(Proc) ;
6269 ErrorStringAt2(Sprintf3(Mark(InitString('attempting to pass (%d) parameters to procedure (%s) which was declared with varargs but contains at least (%d) parameters')),
6270 NoOfParameters, s, np),
6271 tokpos, GetDeclaredMod(ProcSym))
6273 ELSIF UsesOptArg(Proc)
6275 IF NOT ((NoOfParameters=NoOfParam(Proc)) OR (NoOfParameters+1=NoOfParam(Proc)))
6277 s := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Proc)))) ;
6278 np := NoOfParam(Proc) ;
6279 ErrorStringAt2(Sprintf3(Mark(InitString('attempting to pass (%d) parameters to procedure (%s) which was declared with an optarg with a maximum of (%d) parameters')),
6280 NoOfParameters, s, np),
6281 tokpos, GetDeclaredMod(ProcSym))
6283 ELSIF NoOfParameters#NoOfParam(Proc)
6285 s := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Proc)))) ;
6286 np := NoOfParam(Proc) ;
6287 ErrorStringAt2(Sprintf3(Mark(InitString('attempting to pass (%d) parameters to procedure (%s) which was declared with (%d) parameters')),
6288 NoOfParameters, s, np),
6289 tokpos, GetDeclaredMod(ProcSym))
6292 pi := NoOfParameters ;
6293 WHILE i<=NoOfParameters DO
6294 f := PeepAddress(BoolStack, pi) ;
6295 rw := OperandMergeRW(pi) ;
6296 Assert(IsLegal(rw)) ;
6297 IF i>NoOfParam(Proc)
6299 IF IsForC AND UsesVarArgs(Proc)
6301 IF (GetSType(OperandT(pi))#NulSym) AND IsArray(GetDType(OperandT(pi)))
6303 f^.TrueExit := MakeLeftValue(OperandTok(pi), OperandT(pi), RightValue, Address) ;
6305 ELSIF IsConstString (OperandT (pi))
6307 f^.TrueExit := MakeLeftValue (OperandTok (pi),
6308 MakeConstStringCnul (OperandTok (pi), OperandT (pi)), RightValue, Address) ;
6310 ELSIF (GetSType(OperandT(pi))#NulSym) AND IsUnbounded(GetSType(OperandT(pi)))
6312 MarkAsReadWrite(rw) ;
6313 (* pass the address field of an unbounded variable *)
6314 PushTF(Adr, Address) ;
6315 PushTFAD (f^.TrueExit, f^.FalseExit, f^.Unbounded, f^.Dimension) ;
6319 ELSIF GetMode(OperandT(pi))=LeftValue
6321 MarkAsReadWrite(rw) ;
6322 (* must dereference LeftValue (even if we are passing variable as a vararg) *)
6323 t := MakeTemporary (OperandTok (pi), RightValue) ;
6324 PutVar(t, GetSType (OperandT (pi))) ;
6325 CheckPointerThroughNil (tokpos, OperandT (pi)) ;
6326 doIndrX (OperandTok(pi), t, OperandT (pi)) ;
6330 MetaErrorT2 (tokpos,
6331 'attempting to pass too many parameters to procedure {%1a}, the {%2N} parameter does not exist',
6334 ELSIF IsForC AND IsUnboundedParam(Proc, i) AND
6335 (GetSType(OperandT(pi))#NulSym) AND IsArray(GetDType(OperandT(pi)))
6337 f^.TrueExit := MakeLeftValue(OperandTok(pi), OperandT(pi), RightValue, Address) ;
6339 ELSIF IsForC AND IsUnboundedParam(Proc, i) AND
6340 (GetSType(OperandT(pi))#NulSym) AND IsUnbounded(GetDType(OperandT(pi)))
6342 MarkAsReadWrite(rw) ;
6343 (* pass the address field of an unbounded variable *)
6344 PushTF(Adr, Address) ;
6345 PushTFAD (f^.TrueExit, f^.FalseExit, f^.Unbounded, f^.Dimension) ;
6349 ELSIF IsForC AND IsConstString(OperandT(pi)) AND
6350 (IsUnboundedParam(Proc, i) OR (GetDType(GetParam(Proc, i))=Address))
6352 f^.TrueExit := MakeLeftValue (OperandTok (pi),
6353 MakeConstStringCnul (OperandTok (pi), OperandT (pi)),
6354 RightValue, Address) ;
6355 MarkAsReadWrite (rw)
6356 ELSIF IsUnboundedParam(Proc, i)
6358 (* always pass constant strings with a nul terminator, but leave the HIGH as before. *)
6359 IF IsConstString (OperandT(pi))
6361 (* this is a Modula-2 string which must be nul terminated. *)
6362 f^.TrueExit := MakeConstStringM2nul (OperandTok (pi), OperandT (pi))
6364 t := MakeTemporary (OperandTok (pi), RightValue) ;
6365 UnboundedType := GetSType(GetParam(Proc, i)) ;
6366 PutVar(t, UnboundedType) ;
6367 ParamType := GetSType(UnboundedType) ;
6370 ArraySym := OperandT(pi)
6372 ArraySym := OperandA(pi)
6374 IF IsVarParam(Proc, i)
6376 MarkArrayWritten (OperandT (pi)) ;
6377 MarkArrayWritten (OperandA (pi)) ;
6378 MarkAsReadWrite(rw) ;
6379 AssignUnboundedVar (OperandTtok (pi), OperandT (pi), ArraySym, t, ParamType, OperandD (pi))
6382 AssignUnboundedNonVar (OperandTtok (pi), OperandT (pi), ArraySym, t, ParamType, OperandD (pi))
6385 ELSIF IsVarParam(Proc, i)
6387 (* must reference by address, but we contain the type of the referenced entity *)
6388 MarkArrayWritten(OperandT(pi)) ;
6389 MarkArrayWritten(OperandA(pi)) ;
6390 MarkAsReadWrite(rw) ;
6391 f^.TrueExit := MakeLeftValue(OperandTok(pi), OperandT(pi), LeftValue, GetSType(GetParam(Proc, i)))
6392 ELSIF (NOT IsVarParam(Proc, i)) AND (GetMode(OperandT(pi))=LeftValue)
6394 (* must dereference LeftValue *)
6395 t := MakeTemporary (OperandTok (pi), RightValue) ;
6396 PutVar(t, GetSType(OperandT(pi))) ;
6397 CheckPointerThroughNil (tokpos, OperandT (pi)) ;
6398 doIndrX (OperandTok(pi), t, OperandT(pi)) ;
6407 PushT(NoOfParameters)
6408 END ManipulateParameters ;
6412 CheckParameterOrdinals - check that ordinal values are within type range.
6415 PROCEDURE CheckParameterOrdinals ;
6419 ProcSym : CARDINAL ;
6421 FormalI : CARDINAL ;
6426 PushT (ParamTotal) ; (* Restore stack to origional state *)
6427 ProcSym := OperandT (ParamTotal+1+1) ;
6428 IF IsVar(ProcSym) AND IsProcType(GetDType(ProcSym))
6430 (* Indirect procedure call. *)
6431 Proc := SkipType(OperandF(ParamTotal+1+1))
6433 Proc := SkipConst(ProcSym)
6436 pi := ParamTotal+1 ; (* stack index referencing stacked parameter, i *)
6437 WHILE i<=ParamTotal DO
6438 IF i<=NoOfParam(Proc)
6440 FormalI := GetParam (Proc, i) ;
6441 Actual := OperandT (pi) ;
6442 tokno := OperandTok (pi) ;
6443 IF IsOrdinalType (GetLType (FormalI))
6445 IF NOT IsSet (GetDType (FormalI))
6447 (* tell code generator to test runtime values of assignment so ensure we
6448 catch overflow and underflow *)
6449 BuildRange (InitParameterRangeCheck (tokno, Proc, i, FormalI, Actual))
6456 END CheckParameterOrdinals ;
6460 IsSameUnbounded - returns TRUE if unbounded types, t1, and, t2,
6464 PROCEDURE IsSameUnbounded (t1, t2: CARDINAL) : BOOLEAN ;
6466 Assert(IsUnbounded(t1)) ;
6467 Assert(IsUnbounded(t2)) ;
6468 RETURN( GetDType(t1)=GetDType(t2) )
6469 END IsSameUnbounded ;
6473 AssignUnboundedVar - assigns an Unbounded symbol fields,
6474 ArrayAddress and ArrayHigh, from an array symbol.
6475 UnboundedSym is not a VAR parameter and therefore
6476 this procedure can complete both of the fields.
6477 Sym can be a Variable with type Unbounded.
6478 Sym can be a Variable with type Array.
6479 Sym can be a String Constant.
6481 ParamType is the TYPE of the parameter
6484 PROCEDURE AssignUnboundedVar (tok: CARDINAL;
6485 Sym, ArraySym, UnboundedSym, ParamType: CARDINAL; dim: CARDINAL) ;
6491 MetaErrorT1 (tok, '{%1ad} cannot be passed to a VAR formal parameter', Sym)
6494 Type := GetDType(Sym) ;
6497 MetaErrorT1 (tok, '{%1ad} has no type and cannot be passed to a VAR formal parameter', Sym)
6498 ELSIF IsUnbounded(Type)
6500 IF Type = GetSType (UnboundedSym)
6502 (* Copy Unbounded Symbol ie. UnboundedSym := Sym *)
6503 PushT (UnboundedSym) ;
6505 BuildAssignmentWithoutBounds (tok, FALSE, TRUE)
6506 ELSIF IsSameUnbounded (Type, GetSType (UnboundedSym)) OR
6507 IsGenericSystemType (ParamType)
6509 UnboundedVarLinkToArray (tok, Sym, ArraySym, UnboundedSym, ParamType, dim)
6511 MetaErrorT1 (tok, '{%1ad} cannot be passed to a VAR formal parameter', Sym)
6513 ELSIF IsArray (Type) OR IsGenericSystemType (ParamType)
6515 UnboundedVarLinkToArray (tok, Sym, ArraySym, UnboundedSym, ParamType, dim)
6517 MetaErrorT1 (tok, '{%1ad} cannot be passed to a VAR formal parameter', Sym)
6520 MetaErrorT1 (tok, '{%1ad} cannot be passed to a VAR formal parameter', Sym)
6522 END AssignUnboundedVar ;
6526 AssignUnboundedNonVar - assigns an Unbounded symbol fields,
6527 The difference between this procedure and
6528 AssignUnboundedVar is that this procedure cannot
6529 set the Unbounded.Address since the data from
6530 Sym will be copied because parameter is NOT a VAR
6532 UnboundedSym is not a VAR parameter and therefore
6533 this procedure can only complete the HIGH field
6534 and not the ADDRESS field.
6535 Sym can be a Variable with type Unbounded.
6536 Sym can be a Variable with type Array.
6537 Sym can be a String Constant.
6539 ParamType is the TYPE of the paramater
6542 PROCEDURE AssignUnboundedNonVar (tok: CARDINAL;
6543 Sym, ArraySym, UnboundedSym, ParamType: CARDINAL; dim: CARDINAL) ;
6547 IF IsConst (Sym) (* was IsConstString(Sym) *)
6549 UnboundedNonVarLinkToArray (tok, Sym, ArraySym, UnboundedSym, ParamType, dim)
6552 Type := GetDType (Sym) ;
6555 MetaErrorT1 (tok, '{%1ad} has no type and cannot be passed to a non VAR formal parameter', Sym)
6556 ELSIF IsUnbounded (Type)
6558 UnboundedNonVarLinkToArray (tok, Sym, ArraySym, UnboundedSym, ParamType, dim)
6559 ELSIF IsArray (Type) OR IsGenericSystemType (ParamType)
6561 UnboundedNonVarLinkToArray (tok, Sym, ArraySym, UnboundedSym, ParamType, dim)
6563 MetaErrorT1 (tok, 'illegal type parameter {%1Ead} expecting array or dynamic array', Sym)
6566 MetaErrorT1 (tok, 'illegal parameter {%1Ead} which cannot be passed as {%kVAR} {%kARRAY} {%kOF} {%1tsad}', Sym)
6568 END AssignUnboundedNonVar ;
6572 GenHigh - generates a HighOp but it checks if op3 is a
6573 L value and if so it dereferences it. This
6574 is inefficient, however it is clean and we let the gcc
6575 backend detect these as common subexpressions.
6576 It will also detect that a R value -> L value -> R value
6577 via indirection and eleminate these.
6580 PROCEDURE GenHigh (tok: CARDINAL;
6581 op1, op2, op3: CARDINAL) ;
6585 IF (GetMode(op3)=LeftValue) AND IsUnbounded(GetSType(op3))
6587 sym := MakeTemporary (tok, RightValue) ;
6588 PutVar (sym, GetSType (op3)) ;
6589 doIndrX (tok, sym, op3) ;
6590 GenQuadO (tok, HighOp, op1, op2, sym, TRUE)
6592 GenQuadO (tok, HighOp, op1, op2, op3, TRUE)
6601 PROCEDURE AssignHighField (tok: CARDINAL;
6602 Sym, ArraySym, UnboundedSym, ParamType: CARDINAL;
6603 actuali, formali: CARDINAL) ;
6609 (* Unbounded.ArrayHigh := HIGH(ArraySym) *)
6610 PushTFtok (UnboundedSym, GetSType (UnboundedSym), tok) ;
6611 Field := GetUnboundedHighOffset (GetSType (UnboundedSym), formali) ;
6612 PushTFtok (Field, GetSType (Field), tok) ;
6614 BuildDesignatorRecord (tok) ;
6615 IF IsGenericSystemType (ParamType)
6617 IF IsConstString (Sym)
6619 PushTtok (MakeLengthConst (tok, Sym), tok)
6621 ArrayType := GetSType (Sym) ;
6622 IF IsUnbounded (ArrayType)
6625 * SIZE(parameter) DIV TSIZE(ParamType)
6626 * however in this case parameter
6627 * is an unbounded symbol and therefore we must use
6628 * (HIGH(parameter)+1)*SIZE(unbounded type) DIV TSIZE(ParamType)
6630 * we call upon the function SIZE(ArraySym)
6631 * remember SIZE doubles as
6632 * (HIGH(a)+1) * SIZE(ArrayType) for unbounded symbols
6634 PushTFtok (calculateMultipicand (tok, ArraySym, ArrayType, actuali-1), Cardinal, tok) ;
6635 PushT (DivideTok) ; (* Divide by *)
6636 PushTFtok (TSize, Cardinal, tok) ; (* TSIZE(ParamType) *)
6637 PushTtok (ParamType, tok) ;
6638 PushT (1) ; (* 1 parameter for TSIZE() *)
6639 BuildFunctionCall (FALSE) ;
6642 (* SIZE(parameter) DIV TSIZE(ParamType) *)
6643 PushTFtok (TSize, Cardinal, tok) ; (* TSIZE(ArrayType) *)
6644 PushTtok (ArrayType, tok) ;
6645 PushT (1) ; (* 1 parameter for TSIZE() *)
6646 BuildFunctionCall (TRUE) ;
6647 PushT (DivideTok) ; (* Divide by *)
6648 PushTFtok (TSize, Cardinal, tok) ; (* TSIZE(ParamType) *)
6649 PushTtok (ParamType, tok) ;
6650 PushT (1) ; (* 1 parameter for TSIZE() *)
6651 BuildFunctionCall (TRUE) ;
6654 (* now convert from no of elements into HIGH by subtracting 1 *)
6655 PushT (MinusTok) ; (* -1 *)
6656 PushTtok (MakeConstLit (tok, MakeKey('1'), Cardinal), tok) ;
6660 ReturnVar := MakeTemporary (tok, RightValue) ;
6661 PutVar (ReturnVar, Cardinal) ;
6662 IF (actuali # formali) AND (ArraySym # NulSym) AND IsUnbounded (GetSType (ArraySym))
6664 GenHigh (tok, ReturnVar, actuali, ArraySym)
6666 GenHigh (tok, ReturnVar, formali, Sym)
6668 PushTFtok (ReturnVar, GetSType(ReturnVar), tok)
6670 BuildAssignmentWithoutBounds (tok, FALSE, TRUE)
6671 END AssignHighField ;
6678 PROCEDURE AssignHighFields (tok: CARDINAL;
6679 Sym, ArraySym, UnboundedSym, ParamType: CARDINAL; dim: CARDINAL) ;
6683 actualn, formaln: CARDINAL ;
6685 type := GetDType (Sym) ;
6687 IF (type # NulSym) AND (IsUnbounded (type) OR IsArray (type))
6689 actualn := GetDimension (type)
6691 actuali := dim + 1 ;
6693 formaln := GetDimension (GetDType (UnboundedSym)) ;
6694 WHILE (actuali < actualn) AND (formali < formaln) DO
6695 AssignHighField (tok, Sym, ArraySym, UnboundedSym, NulSym, actuali, formali) ;
6699 AssignHighField (tok, Sym, ArraySym, UnboundedSym, ParamType, actuali, formali)
6700 END AssignHighFields ;
6704 UnboundedNonVarLinkToArray - links an array, ArraySym, to an unbounded
6705 array, UnboundedSym. The parameter is a
6709 PROCEDURE UnboundedNonVarLinkToArray (tok: CARDINAL;
6710 Sym, ArraySym, UnboundedSym, ParamType: CARDINAL; dim: CARDINAL) ;
6713 AddressField: CARDINAL ;
6715 (* Unbounded.ArrayAddress := to be assigned at runtime. *)
6716 PushTFtok (UnboundedSym, GetSType (UnboundedSym), tok) ;
6718 Field := GetUnboundedAddressOffset(GetSType(UnboundedSym)) ;
6719 PushTFtok (Field, GetSType(Field), tok) ;
6721 BuildDesignatorRecord (tok) ;
6722 PopT (AddressField) ;
6724 (* caller saves non var unbounded array contents. *)
6725 GenQuadO (tok, UnboundedOp, AddressField, NulSym, Sym, FALSE) ;
6727 AssignHighFields (tok, Sym, ArraySym, UnboundedSym, ParamType, dim)
6728 END UnboundedNonVarLinkToArray ;
6732 UnboundedVarLinkToArray - links an array, ArraySym, to an unbounded array,
6733 UnboundedSym. The parameter is a VAR variety.
6736 PROCEDURE UnboundedVarLinkToArray (tok: CARDINAL;
6737 Sym, ArraySym, UnboundedSym, ParamType: CARDINAL; dim: CARDINAL) ;
6742 SymType := GetSType (Sym) ;
6743 (* Unbounded.ArrayAddress := ADR(Sym) *)
6744 PushTFtok (UnboundedSym, GetSType (UnboundedSym), tok) ;
6745 Field := GetUnboundedAddressOffset (GetSType (UnboundedSym)) ;
6746 PushTFtok (Field, GetSType (Field), tok) ;
6748 BuildDesignatorRecord (tok) ;
6749 PushTFtok (Adr, Address, tok) ; (* ADR (Sym). *)
6750 IF IsUnbounded (SymType) AND (dim = 0)
6752 PushTFADtok (Sym, SymType, UnboundedSym, dim, tok)
6754 PushTFADtok (Sym, SymType, ArraySym, dim, tok)
6756 PushT (1) ; (* 1 parameter for ADR(). *)
6757 BuildFunctionCall (FALSE) ;
6758 BuildAssignmentWithoutBounds (tok, FALSE, TRUE) ;
6760 AssignHighFields (tok, Sym, ArraySym, UnboundedSym, ParamType, dim)
6761 END UnboundedVarLinkToArray ;
6765 BuildPseudoProcedureCall - builds a pseudo procedure call.
6766 This procedure does not directly alter the
6767 stack, but by calling routines the stack
6768 will change in the following way when this
6790 | ProcSym | Type | Empty
6794 PROCEDURE BuildPseudoProcedureCall (tokno: CARDINAL) ;
6797 ProcSym : CARDINAL ;
6800 ProcSym := OperandT (NoOfParam + 1) ;
6802 (* Compile time stack restored to entry state *)
6805 BuildNewProcedure (tokno)
6806 ELSIF ProcSym = Dispose
6808 BuildDisposeProcedure (tokno)
6815 ELSIF ProcSym = Incl
6818 ELSIF ProcSym = Excl
6821 ELSIF ProcSym = Throw
6825 InternalError ('pseudo procedure not implemented yet')
6827 END BuildPseudoProcedureCall ;
6831 GetItemPointedTo - returns the symbol type that is being pointed to
6835 PROCEDURE GetItemPointedTo (Sym: CARDINAL) : CARDINAL ;
6839 RETURN GetSType (Sym)
6840 ELSIF IsVar (Sym) OR IsType (Sym)
6842 RETURN GetItemPointedTo (GetSType (Sym))
6846 END GetItemPointedTo ;
6850 BuildThrowProcedure - builds the pseudo procedure call M2RTS.Throw.
6870 | ProcSym | Type | Empty
6874 PROCEDURE BuildThrowProcedure ;
6876 functok : CARDINAL ;
6878 NoOfParam: CARDINAL ;
6881 functok := OperandTtok (NoOfParam + 1) ;
6884 op := OperandT (NoOfParam) ;
6885 GenQuadO (functok, ThrowOp, NulSym, NulSym, op, FALSE)
6887 MetaErrorT1 (functok, 'the pseudo procedure %{1Ea} takes one INTEGER parameter', Throw)
6890 END BuildThrowProcedure ;
6894 BuildReThrow - creates a ThrowOp _ _ NulSym, indicating that
6895 the exception needs to be rethrown. The stack
6899 PROCEDURE BuildReThrow (tokenno: CARDINAL) ;
6901 GenQuadO (tokenno, ThrowOp, NulSym, NulSym, NulSym, FALSE)
6906 BuildNewProcedure - builds the pseudo procedure call NEW.
6907 This procedure is traditionally a "macro" for
6908 NEW(x, ...) --> ALLOCATE(x, TSIZE(x^, ...))
6909 One method of implementation is to emulate a "macro"
6910 processor by pushing the relevant input tokens
6911 back onto the input stack.
6912 However this causes two problems:
6914 (i) Unnecessary code is produced for x^
6915 (ii) SIZE must be imported from SYSTEM
6916 Therefore we chose an alternative method of
6918 generate quadruples for ALLOCATE(x, TSIZE(x^, ...))
6919 this, although slightly more efficient,
6920 is more complex and circumvents problems (i) and (ii).
6941 | ProcSym | Type | Empty
6945 PROCEDURE BuildNewProcedure (functok: CARDINAL) ;
6950 ProcSym : CARDINAL ;
6952 combinedtok: CARDINAL ;
6957 ProcSym := RequestSym (functok, MakeKey('ALLOCATE')) ;
6958 IF (ProcSym#NulSym) AND IsProcedure(ProcSym)
6960 PtrSym := OperandT (NoOfParam) ;
6961 paramtok := OperandTtok (1) ;
6962 IF IsReallyPointer(PtrSym)
6964 combinedtok := MakeVirtualTok (functok, functok, paramtok) ;
6966 Build macro: ALLOCATE( PtrSym, SIZE(PtrSym^) )
6968 PushTFtok (TSize, Cardinal, paramtok) ;(* Procedure *)
6970 PushTtok (GetItemPointedTo (PtrSym), paramtok) ;
6971 PushT (1) ; (* One parameter *)
6972 BuildFunctionCall (FALSE) ;
6975 PushTtok (ProcSym, combinedtok) ; (* ALLOCATE *)
6976 PushTtok (PtrSym, paramtok) ; (* x *)
6977 PushTtok (SizeSym, paramtok) ; (* TSIZE(x^) *)
6978 PushT (2) ; (* Two parameters *)
6979 BuildProcedureCall (combinedtok)
6981 MetaErrorT0 (paramtok, 'parameter to {%EkNEW} must be a pointer')
6984 MetaErrorT0 (functok, '{%E}ALLOCATE procedure not found for NEW substitution')
6987 MetaErrorT0 (functok, 'the pseudo procedure {%EkNEW} has one or more parameters')
6990 END BuildNewProcedure ;
6994 BuildDisposeProcedure - builds the pseudo procedure call DISPOSE.
6995 This procedure is traditionally a "macro" for
6996 DISPOSE(x) --> DEALLOCATE(x, TSIZE(x^))
6997 One method of implementation is to emulate a "macro"
6998 processor by pushing the relevant input tokens
6999 back onto the input stack.
7000 However this causes two problems:
7002 (i) Unnecessary code is produced for x^
7003 (ii) TSIZE must be imported from SYSTEM
7004 Therefore we chose an alternative method of
7006 generate quadruples for DEALLOCATE(x, TSIZE(x^))
7007 this, although slightly more efficient,
7008 is more complex and circumvents problems (i)
7030 | ProcSym | Type | Empty
7034 PROCEDURE BuildDisposeProcedure (functok: CARDINAL) ;
7039 ProcSym : CARDINAL ;
7041 paramtok : CARDINAL ;
7046 ProcSym := RequestSym (functok, MakeKey ('DEALLOCATE')) ;
7047 IF (ProcSym # NulSym) AND IsProcedure (ProcSym)
7049 PtrSym := OperandT (NoOfParam) ;
7050 paramtok := OperandTtok (1) ;
7051 IF IsReallyPointer (PtrSym)
7053 combinedtok := MakeVirtualTok (functok, functok, paramtok) ;
7055 Build macro: DEALLOCATE( PtrSym, TSIZE(PtrSym^) )
7057 PushTFtok (TSize, Cardinal, paramtok) ;(* Procedure *)
7059 PushTtok (GetItemPointedTo(PtrSym), paramtok) ;
7060 PushT (1) ; (* One parameter *)
7061 BuildFunctionCall (FALSE) ;
7064 PushTtok (ProcSym, combinedtok) ; (* DEALLOCATE *)
7065 PushTtok (PtrSym, paramtok) ; (* x *)
7066 PushTtok (SizeSym, paramtok) ; (* TSIZE(x^) *)
7067 PushT (2) ; (* Two parameters *)
7068 BuildProcedureCall (combinedtok)
7070 MetaErrorT0 (paramtok, 'argument to {%EkDISPOSE} must be a pointer')
7073 MetaErrorT0 (functok, '{%E}DEALLOCATE procedure not found for DISPOSE substitution')
7076 MetaErrorT0 (functok, 'the pseudo procedure {%EkDISPOSE} has one or more parameters')
7079 END BuildDisposeProcedure ;
7083 CheckRangeIncDec - performs des := des <tok> expr
7084 with range checking (if enabled).
7090 empty | des + expr |
7094 PROCEDURE CheckRangeIncDec (tokenpos: CARDINAL; des, expr: CARDINAL; tok: Name) ;
7096 dtype, etype: CARDINAL ;
7098 dtype := GetDType(des) ;
7099 etype := GetDType(expr) ;
7100 IF WholeValueChecking AND (NOT MustNotCheckBounds)
7104 BuildRange (InitIncRangeCheck (des, expr))
7106 BuildRange (InitDecRangeCheck (des, expr))
7110 IF IsExpressionCompatible (dtype, etype)
7112 (* the easy case simulate a straightforward macro *)
7113 PushTF (des, dtype) ;
7115 PushTF (expr, etype) ;
7116 doBuildBinaryOp (FALSE, TRUE)
7118 IF (IsOrdinalType (dtype) OR (dtype = Address) OR IsPointer (dtype)) AND
7119 (IsOrdinalType (etype) OR (etype = Address) OR IsPointer (etype))
7121 PushTF (des, dtype) ;
7123 PushTF (Convert, NulSym) ;
7126 PushT (2) ; (* Two parameters *)
7127 BuildConvertFunction ;
7128 doBuildBinaryOp (FALSE, TRUE)
7132 MetaError0 ('cannot perform {%EkINC} using non ordinal types')
7134 MetaError0 ('cannot perform {%EkDEC} using non ordinal types')
7136 PushTFtok (MakeConstLit (tokenpos, MakeKey ('0'), NulSym), NulSym, tokenpos)
7139 END CheckRangeIncDec ;
7143 BuildIncProcedure - builds the pseudo procedure call INC.
7144 INC is a procedure which increments a variable.
7145 It takes one or two parameters:
7147 a := a+b or a := a+1
7168 | ProcSym | Type | Empty
7172 PROCEDURE BuildIncProcedure ;
7174 proctok : CARDINAL ;
7179 TempSym : CARDINAL ;
7182 proctok := OperandTtok (NoOfParam + 1) ;
7183 IF (NoOfParam = 1) OR (NoOfParam = 2)
7185 VarSym := OperandT (NoOfParam) ; (* bottom/first parameter *)
7188 dtype := GetDType (VarSym) ;
7191 OperandSym := DereferenceLValue (OperandTok (1), OperandT (1))
7193 PushOne (proctok, dtype, 'the {%EkINC} will cause an overflow {%1ad}') ;
7198 TempSym := DereferenceLValue (OperandTok (NoOfParam), VarSym) ;
7199 CheckRangeIncDec (proctok, TempSym, OperandSym, PlusTok) ; (* TempSym + OperandSym *)
7200 BuildAssignmentWithoutBounds (proctok, FALSE, TRUE) (* VarSym := TempSym + OperandSym *)
7202 MetaErrorT1 (proctok,
7203 'base procedure {%EkINC} expects a variable as a parameter but was given {%1Ed}',
7207 MetaErrorT0 (proctok,
7208 'the base procedure {%EkINC} expects 1 or 2 parameters')
7210 PopN (NoOfParam + 1)
7211 END BuildIncProcedure ;
7215 BuildDecProcedure - builds the pseudo procedure call DEC.
7216 DEC is a procedure which decrements a variable.
7217 It takes one or two parameters:
7219 a := a-b or a := a-1
7240 | ProcSym | Type | Empty
7244 PROCEDURE BuildDecProcedure ;
7251 TempSym : CARDINAL ;
7254 proctok := OperandTtok (NoOfParam + 1) ;
7255 IF (NoOfParam = 1) OR (NoOfParam = 2)
7257 VarSym := OperandT (NoOfParam) ; (* bottom/first parameter *)
7260 dtype := GetDType (VarSym) ;
7263 OperandSym := DereferenceLValue (OperandTok (1), OperandT (1))
7265 PushOne (proctok, dtype, 'the {%EkDEC} will cause an overflow {%1ad}') ;
7270 TempSym := DereferenceLValue (OperandTok (NoOfParam), VarSym) ;
7271 CheckRangeIncDec (proctok, TempSym, OperandSym, MinusTok) ; (* TempSym - OperandSym *)
7272 BuildAssignmentWithoutBounds (proctok, FALSE, TRUE) (* VarSym := TempSym - OperandSym *)
7274 MetaErrorT1 (proctok,
7275 'base procedure {%EkDEC} expects a variable as a parameter but was given {%1Ed}',
7279 MetaErrorT0 (proctok,
7280 'the base procedure {%EkDEC} expects 1 or 2 parameters')
7282 PopN (NoOfParam + 1)
7283 END BuildDecProcedure ;
7287 DereferenceLValue - checks to see whether, operand, is declare as an LValue
7288 and if so it dereferences it.
7291 PROCEDURE DereferenceLValue (tok: CARDINAL; operand: CARDINAL) : CARDINAL ;
7295 IF GetMode (operand) = LeftValue
7297 (* dereference the pointer *)
7298 sym := MakeTemporary (tok, AreConstant(IsConst(operand))) ;
7299 PutVar(sym, GetSType (operand)) ;
7301 PushTtok (sym, tok) ;
7302 PushTtok (operand, tok) ;
7303 BuildAssignmentWithoutBounds (tok, FALSE, TRUE) ;
7308 END DereferenceLValue ;
7312 BuildInclProcedure - builds the pseudo procedure call INCL.
7313 INCL is a procedure which adds bit b into a BITSET a.
7314 It takes two parameters:
7332 | ProcSym | Type | Empty
7336 PROCEDURE BuildInclProcedure ;
7346 proctok := OperandTtok (NoOfParam + 1) ;
7349 VarSym := OperandT (2) ;
7350 MarkArrayWritten (OperandA (2)) ;
7351 OperandSym := OperandT (1) ;
7352 optok := OperandTok (1) ;
7355 IF IsSet (GetDType (VarSym))
7357 DerefSym := DereferenceLValue (optok, OperandSym) ;
7358 BuildRange (InitInclCheck (VarSym, DerefSym)) ;
7359 GenQuadO (proctok, InclOp, VarSym, NulSym, DerefSym, FALSE)
7361 MetaErrorT1 (proctok,
7362 'the first parameter to {%EkINCL} must be a set variable but is {%1Ed}',
7366 MetaErrorT1 (proctok,
7367 'base procedure {%EkINCL} expects a variable as a parameter but is {%1Ed}',
7371 MetaErrorT0 (proctok, 'the base procedure {%EkINCL} expects 1 or 2 parameters')
7373 PopN (NoOfParam + 1)
7374 END BuildInclProcedure ;
7378 BuildExclProcedure - builds the pseudo procedure call EXCL.
7379 INCL is a procedure which removes bit b from SET a.
7380 It takes two parameters:
7398 | ProcSym | Type | Empty
7402 PROCEDURE BuildExclProcedure ;
7412 proctok := OperandTtok (NoOfParam + 1) ;
7415 VarSym := OperandT (2) ;
7416 MarkArrayWritten (OperandA(2)) ;
7417 OperandSym := OperandT (1) ;
7418 optok := OperandTok (1) ;
7421 IF IsSet (GetDType (VarSym))
7423 DerefSym := DereferenceLValue (optok, OperandSym) ;
7424 BuildRange (InitExclCheck (VarSym, DerefSym)) ;
7425 GenQuadO (proctok, ExclOp, VarSym, NulSym, DerefSym, FALSE)
7427 MetaErrorT1 (proctok,
7428 'the first parameter to {%EkEXCL} must be a set variable but is {%1Ed}',
7432 MetaErrorT1 (proctok,
7433 'base procedure {%EkEXCL} expects a variable as a parameter but is {%1Ed}',
7437 MetaErrorT0 (proctok,
7438 'the base procedure {%EkEXCL} expects 1 or 2 parameters')
7440 PopN (NoOfParam + 1)
7441 END BuildExclProcedure ;
7445 CheckBuildFunction - checks to see whether ProcSym is a function
7446 and if so it adds a TempSym value which will
7447 hold the return value once the function finishes.
7448 This procedure also generates an error message
7449 if the user is calling a function and ignoring
7450 the return result. The additional TempSym
7451 is not created if ProcSym is a procedure
7452 and the stack is unaltered.
7463 +----------------+ |----------------|
7464 | ProcSym | Type | | TempSym | Type |
7465 |----------------| |----------------|
7468 PROCEDURE CheckBuildFunction () : BOOLEAN ;
7473 ProcSym, Type: CARDINAL ;
7475 PopTFtok(ProcSym, Type, tokpos) ;
7476 IF IsVar(ProcSym) AND IsProcType(Type)
7478 IF GetSType(Type)#NulSym
7480 TempSym := MakeTemporary (tokpos, RightValue) ;
7481 PutVar(TempSym, GetSType(Type)) ;
7482 PushTFtok(TempSym, GetSType(Type), tokpos) ;
7483 PushTFtok(ProcSym, Type, tokpos) ;
7484 IF NOT IsReturnOptional(Type)
7486 IF IsTemporary(ProcSym)
7488 ErrorFormat0 (NewError (tokpos),
7489 'function is being called but its return value is ignored')
7491 n := GetSymName (ProcSym) ;
7492 ErrorFormat1 (NewError (tokpos),
7493 'function (%a) is being called but its return value is ignored', n)
7498 ELSIF IsProcedure(ProcSym) AND (Type#NulSym)
7500 TempSym := MakeTemporary (tokpos, RightValue) ;
7501 PutVar(TempSym, Type) ;
7502 PushTFtok(TempSym, Type, tokpos) ;
7503 PushTFtok(ProcSym, Type, tokpos) ;
7504 IF NOT IsReturnOptional(ProcSym)
7506 n := GetSymName(ProcSym) ;
7507 ErrorFormat1(NewError(tokpos),
7508 'function (%a) is being called but its return value is ignored', n)
7512 PushTFtok (ProcSym, Type, tokpos) ;
7514 END CheckBuildFunction ;
7518 BuildFunctionCall - builds a function call.
7537 |----------------| +------------+
7538 | ProcSym | Type | | ReturnVar |
7539 |----------------| |------------|
7542 PROCEDURE BuildFunctionCall (ConstExpr: BOOLEAN) ;
7548 ProcSym : CARDINAL ;
7551 functok := OperandTtok (NoOfParam + 1) ;
7552 ProcSym := OperandT (NoOfParam + 1) ;
7553 ProcSym := SkipConst (ProcSym) ;
7555 (* Compile time stack restored to entry state. *)
7556 IF IsUnknown (ProcSym)
7558 paramtok := OperandTtok (1) ;
7559 combinedtok := MakeVirtualTok (functok, functok, paramtok) ;
7560 MetaErrorT1 (functok, 'procedure function {%1Ea} is undefined', ProcSym) ;
7561 PopN (NoOfParam + 2) ;
7562 (* Fake return value to continue compiling. *)
7563 PushT (MakeConstLit (combinedtok, MakeKey ('0'), NulSym))
7564 ELSIF IsAModula2Type (ProcSym)
7566 ManipulatePseudoCallParameters ;
7568 ELSIF IsPseudoSystemFunction (ProcSym) OR
7569 IsPseudoBaseFunction (ProcSym)
7571 ManipulatePseudoCallParameters ;
7572 BuildPseudoFunctionCall
7574 BuildRealFunctionCall (functok, ConstExpr)
7576 END BuildFunctionCall ;
7580 BuildConstFunctionCall - builds a function call and checks that this function can be
7581 called inside a ConstExpression.
7601 |----------------| +------------+
7602 | ProcSym | Type | | ReturnVar |
7603 |----------------| |------------|
7607 PROCEDURE BuildConstFunctionCall ;
7614 ProcSym : CARDINAL ;
7618 ProcSym := OperandT (NoOfParam + 1) ;
7619 functok := OperandTtok (NoOfParam + 1) ;
7620 IF CompilerDebugging
7622 printf2 ('procsym = %d token = %d\n', ProcSym, functok) ;
7623 (* ErrorStringAt (InitString ('constant function'), functok). *)
7626 IF (ProcSym # Convert) AND
7627 (IsPseudoBaseFunction (ProcSym) OR
7628 IsPseudoSystemFunctionConstExpression (ProcSym) OR
7629 (IsProcedure (ProcSym) AND IsProcedureBuiltin (ProcSym)))
7631 BuildFunctionCall (TRUE)
7633 IF IsAModula2Type (ProcSym)
7635 (* Type conversion. *)
7638 ConstExpression := OperandT (NoOfParam + 1) ;
7639 paramtok := OperandTtok (NoOfParam + 1) ;
7640 PopN (NoOfParam + 2) ;
7641 (* Build macro: CONVERT( ProcSym, ConstExpression ). *)
7642 PushTFtok (Convert, NulSym, functok) ;
7643 PushTtok (ProcSym, functok) ;
7644 PushTtok (ConstExpression, paramtok) ;
7645 PushT (2) ; (* Two parameters. *)
7646 BuildConvertFunction
7648 MetaErrorT0 (functok, '{%E}a constant type conversion can only have one argument')
7651 (* Error issue message and fake return stack. *)
7654 MetaErrorT0 (functok, 'the only functions permissible in a constant expression are: {%kCAP}, {%kCHR}, {%kCMPLX}, {%kFLOAT}, {%kHIGH}, {%kIM}, {%kLENGTH}, {%kMAX}, {%kMIN}, {%kODD}, {%kORD}, {%kRE}, {%kSIZE}, {%kTSIZE}, {%kTRUNC}, {%kVAL} and gcc builtins')
7656 MetaErrorT0 (functok, 'the only functions permissible in a constant expression are: {%kCAP}, {%kCHR}, {%kFLOAT}, {%kHIGH}, {%kMAX}, {%kMIN}, {%kODD}, {%kORD}, {%kSIZE}, {%kTSIZE}, {%kTRUNC}, {%kVAL} and gcc builtins')
7660 paramtok := OperandTtok (NoOfParam + 1) ;
7661 combinedtok := MakeVirtualTok (functok, functok, paramtok)
7663 combinedtok := functok
7665 PopN (NoOfParam+2) ;
7666 PushT (MakeConstLit (combinedtok, MakeKey('0'), NulSym)) (* Fake return value to continue compiling. *)
7669 END BuildConstFunctionCall ;
7673 BuildTypeCoercion - builds the type coersion.
7674 MODULA-2 allows types to be coersed with no runtime
7676 It insists that the TSIZE(t1)=TSIZE(t2) where
7677 t2 variable := t2(variable of type t1).
7678 The ReturnVar on the stack is of type t2.
7698 |----------------| +------------+
7699 | ProcSym | Type | | ReturnVar |
7700 |----------------| |------------|
7704 CoerceOp ReturnVar Type Param1
7706 A type coercion will only be legal if the different
7707 types have exactly the same size.
7708 Since we can only decide this after M2Eval has processed
7709 the symbol table then we create a quadruple explaining
7710 the coercion taking place, the code generator can test
7711 this assertion and report an error if the type sizes
7715 PROCEDURE BuildTypeCoercion ;
7724 ProcSym : CARDINAL ;
7727 ProcSym := OperandT (NoOfParam+1) ;
7728 proctok := OperandTok (NoOfParam+1) ;
7729 IF NOT IsAModula2Type (ProcSym)
7731 MetaError1 ('coersion expecting a type, seen {%1Ea} which is {%1Ed}', ProcSym)
7735 PopTrwtok (exp, r, exptok) ;
7737 resulttok := MakeVirtualTok (proctok, proctok, exptok) ;
7738 ReturnVar := MakeTemporary (resulttok, RightValue) ;
7739 PutVar (ReturnVar, ProcSym) ; (* Set ReturnVar's TYPE. *)
7740 PopN (1) ; (* Pop procedure. *)
7741 IF IsConst (exp) OR IsVar (exp)
7743 GenQuad (CoerceOp, ReturnVar, ProcSym, exp)
7745 MetaError2 ('trying to coerse {%1EMRad} which is not a variable or constant into {%2ad}',
7747 MetaError2 ('trying to coerse {%1ECad} which is not a variable or constant into {%2ad}',
7750 PushTFtok (ReturnVar, ProcSym, resulttok)
7752 MetaError0 ('{%E}only one parameter expected in a TYPE coersion')
7754 END BuildTypeCoercion ;
7758 BuildRealFunctionCall - builds a function call.
7777 |----------------| +------------+
7778 | ProcSym | Type | | ReturnVar |
7779 |----------------| |------------|
7782 PROCEDURE BuildRealFunctionCall (tokno: CARDINAL; ConstExpr: BOOLEAN) ;
7785 ProcSym : CARDINAL ;
7789 ProcSym := OperandT (NoOfParam+2) ;
7790 ProcSym := SkipConst (ProcSym) ;
7793 (* Procedure Variable therefore get its type to see if it is a FOR "C" call. *)
7794 ProcSym := SkipType (OperandF (NoOfParam+2))
7796 IF IsDefImp (GetScope (ProcSym)) AND IsDefinitionForC (GetScope (ProcSym))
7798 BuildRealFuncProcCall (tokno, TRUE, TRUE, ConstExpr)
7800 BuildRealFuncProcCall (tokno, TRUE, FALSE, ConstExpr)
7802 END BuildRealFunctionCall ;
7806 BuildPseudoFunctionCall - builds the pseudo function
7825 |----------------| +------------+
7826 | ProcSym | Type | | ReturnVar |
7827 |----------------| |------------|
7831 PROCEDURE BuildPseudoFunctionCall ;
7834 ProcSym : CARDINAL ;
7837 ProcSym := OperandT (NoOfParam+1) ;
7838 ProcSym := SkipConst (ProcSym) ;
7840 (* Compile time stack restored to entry state *)
7844 ELSIF ProcSym = LengthS
7850 ELSIF ProcSym = Size
7853 ELSIF ProcSym = TSize
7856 ELSIF ProcSym = TBitSize
7858 BuildTBitSizeFunction
7859 ELSIF ProcSym = Convert
7861 BuildConvertFunction
7877 ELSIF IsOrd (ProcSym)
7879 BuildOrdFunction (ProcSym)
7880 ELSIF IsInt (ProcSym)
7882 BuildIntFunction (ProcSym)
7883 ELSIF IsTrunc (ProcSym)
7885 BuildTruncFunction (ProcSym)
7886 ELSIF IsFloat (ProcSym)
7888 BuildFloatFunction (ProcSym)
7895 ELSIF ProcSym = AddAdr
7898 ELSIF ProcSym = SubAdr
7901 ELSIF ProcSym = DifAdr
7904 ELSIF ProcSym = Cast
7907 ELSIF ProcSym = Shift
7910 ELSIF ProcSym = Rotate
7913 ELSIF ProcSym = MakeAdr
7915 BuildMakeAdrFunction
7922 ELSIF ProcSym = Cmplx
7926 InternalError ('pseudo function not implemented yet')
7928 END BuildPseudoFunctionCall ;
7932 BuildAddAdrFunction - builds the pseudo procedure call ADDADR.
7934 PROCEDURE ADDADR (addr: ADDRESS; offset: CARDINAL): ADDRESS ;
7936 Which returns address given by (addr + offset),
7937 [ the standard says that it _may_
7938 "raise an exception if this address is not valid."
7939 currently we do not generate any exception code ]
7952 |----------------| +------------+
7953 | ProcSym | Type | | ReturnVar |
7954 |----------------| |------------|
7957 PROCEDURE BuildAddAdrFunction ;
7968 functok := OperandTtok (NoOfParam + 1) ;
7971 VarSym := OperandT (2) ;
7972 OperandSym := OperandT (1) ;
7973 optok := OperandTok (1) ;
7974 combinedtok := MakeVirtualTok (functok, functok, optok) ;
7975 PopN (NoOfParam + 1) ;
7978 IF IsReallyPointer (VarSym) OR (GetSType (VarSym) = Address)
7980 ReturnVar := MakeTemporary (combinedtok, RightValue) ;
7981 PutVar (ReturnVar, Address) ;
7982 GenQuad (AddOp, ReturnVar, VarSym, DereferenceLValue (optok, OperandSym)) ;
7983 PushTFtok (ReturnVar, Address, combinedtok)
7985 MetaErrorT1 (functok,
7986 'the first parameter to ADDADR {%1Ea} must be a variable of type ADDRESS or a {%EkPOINTER}, rather than a {%1Etsd}',
7988 PushTFtok (MakeConstLit (combinedtok, MakeKey('0'), Address), Address, combinedtok)
7991 MetaErrorT0 (functok, '{%E}SYSTEM procedure ADDADR expects a variable of type ADDRESS or POINTER as its first parameter') ;
7992 PushTFtok (MakeConstLit (combinedtok, MakeKey('0'), Address), Address, combinedtok)
7995 MetaErrorT0 (functok, '{%E}SYSTEM procedure ADDADR expects 2 parameters') ;
7996 PopN (NoOfParam + 1) ;
7997 PushTFtok (MakeConstLit (functok, MakeKey ('0'), Address), Address, functok)
7999 END BuildAddAdrFunction ;
8003 BuildSubAdrFunction - builds the pseudo procedure call ADDADR.
8005 PROCEDURE SUBADR (addr: ADDRESS; offset: CARDINAL): ADDRESS ;
8007 Which returns address given by (addr - offset),
8008 [ the standard says that it _may_
8009 "raise an exception if this address is not valid."
8010 currently we do not generate any exception code ]
8023 |----------------| +------------+
8024 | ProcSym | Type | | ReturnVar |
8025 |----------------| |------------|
8028 PROCEDURE BuildSubAdrFunction ;
8040 functok := OperandTtok (NoOfParam + 1) ;
8041 OperandSym := OperandT (1) ;
8042 optok := OperandTok (1) ;
8045 VarSym := OperandT (2) ;
8046 vartok := OperandTok (2) ;
8047 combinedtok := MakeVirtualTok (functok, functok, optok) ;
8048 PopN (NoOfParam + 1) ;
8051 IF IsReallyPointer (VarSym) OR (GetSType (VarSym) = Address)
8053 ReturnVar := MakeTemporary (combinedtok, RightValue) ;
8054 PutVar (ReturnVar, Address) ;
8055 GenQuad (SubOp, ReturnVar, VarSym, DereferenceLValue (optok, OperandSym)) ;
8056 PushTFtok (ReturnVar, Address, combinedtok)
8058 MetaErrorT1 (functok,
8059 'the first parameter to {%EkSUBADR} {%1Ea} must be a variable of type ADDRESS or a {%EkPOINTER}, rather than a {%1Etsd}',
8061 PushTFtok (MakeConstLit (vartok, MakeKey('0'), Address), Address, vartok)
8064 combinedtok := MakeVirtualTok (functok, functok, optok) ;
8065 MetaErrorT0 (combinedtok,
8066 '{%E}SYSTEM procedure {%EkSUBADR} expects a variable of type ADDRESS or POINTER as its first parameter') ;
8067 PushTFtok (MakeConstLit (combinedtok, MakeKey ('0'), Address), Address, combinedtok)
8070 combinedtok := MakeVirtualTok (functok, functok, optok) ;
8071 MetaErrorT0 (functok,
8072 '{%E}SYSTEM procedure {%EkSUBADR} expects 2 parameters') ;
8073 PopN (NoOfParam+1) ;
8074 PushTFtok (MakeConstLit (combinedtok, MakeKey('0'), Address), Address, combinedtok)
8076 END BuildSubAdrFunction ;
8080 BuildDifAdrFunction - builds the pseudo procedure call DIFADR.
8082 PROCEDURE DIFADR (addr1, addr2: ADDRESS): INTEGER ;
8084 Which returns address given by (addr1 - addr2),
8085 [ the standard says that it _may_
8086 "raise an exception if this address is invalid or
8087 address space is non-contiguous."
8088 currently we do not generate any exception code ]
8101 |----------------| +------------+
8102 | ProcSym | Type | | ReturnVar |
8103 |----------------| |------------|
8106 PROCEDURE BuildDifAdrFunction ;
8111 combinedtok: CARDINAL ;
8118 functok := OperandTtok (NoOfParam + 1) ;
8119 OperandSym := OperandT (1) ;
8120 optok := OperandTok (1) ;
8123 VarSym := OperandT (2) ;
8124 vartok := OperandTok (2) ;
8125 combinedtok := MakeVirtualTok (functok, functok, optok) ;
8126 PopN (NoOfParam + 1) ;
8129 IF IsReallyPointer (VarSym) OR (GetSType (VarSym) = Address)
8131 IF IsReallyPointer (OperandSym) OR (GetSType (OperandSym) = Address)
8133 TempVar := MakeTemporary (vartok, RightValue) ;
8134 PutVar (TempVar, Address) ;
8135 GenQuad (SubOp, TempVar, VarSym, DereferenceLValue (optok, OperandSym)) ;
8137 Build macro: CONVERT( INTEGER, TempVar )
8139 PushTFtok (Convert, NulSym, functok) ;
8140 PushTtok (Integer, functok) ;
8141 PushTtok (TempVar, vartok) ;
8142 PushT (2) ; (* Two parameters *)
8143 BuildConvertFunction
8145 MetaError1 ('the second parameter to {%EkDIFADR} {%1Ea} must be a variable of type ADDRESS or a {%EkPOINTER}, rather than a {%1Etsd}',
8147 PushTFtok (MakeConstLit (combinedtok, MakeKey ('0'), Integer), Integer, combinedtok)
8150 MetaErrorT1 (vartok,
8151 'the first parameter to {%EkDIFADR} {%1Ea} must be a variable of type ADDRESS or a {%EkPOINTER}, rather than a {%1Etsd}',
8153 PushTFtok (MakeConstLit (combinedtok, MakeKey ('0'), Integer), Integer, combinedtok)
8156 MetaError0 ('{%E}SYSTEM procedure {%EkDIFADR} expects a variable of type ADDRESS or POINTER as its first parameter') ;
8157 PushTFtok (MakeConstLit (combinedtok, MakeKey('0'), Integer), Integer, combinedtok)
8160 combinedtok := MakeVirtualTok (functok, functok, optok) ;
8161 MetaErrorT0 (functok, '{%E}SYSTEM procedure {%EkDIFADR} expects 2 parameters') ;
8162 PopN (NoOfParam+1) ;
8163 PushTFtok (MakeConstLit (combinedtok, MakeKey('0'), Integer), Integer, combinedtok)
8165 END BuildDifAdrFunction ;
8169 BuildHighFunction - checks the stack in preparation for generating
8170 quadruples which perform HIGH.
8171 This procedure does not alter the stack but
8172 determines whether, a, in HIGH(a) is an ArraySym
8174 Both cases are different and appropriate quadruple
8175 generating routines are called.
8195 |----------------| +------------+
8196 | ProcSym | Type | | ReturnVar |
8197 |----------------| |------------|
8201 PROCEDURE BuildHighFunction ;
8205 paramtok : CARDINAL ;
8212 ProcSym := OperandT (NoOfParam+1) ;
8213 functok := OperandTok (NoOfParam + 1) ;
8214 BuildSizeCheckEnd (ProcSym) ; (* quadruple generation now on *)
8217 Param := OperandT (1) ;
8218 paramtok := OperandTok (1) ;
8219 combinedtok := MakeVirtualTok (paramtok, functok, paramtok) ;
8220 Type := GetDType (Param) ;
8221 (* Restore stack to original form *)
8223 IF (NOT IsVar(Param)) AND (NOT IsConstString(Param)) AND (NOT IsConst(Param))
8225 (* we cannot test for IsConst(Param) AND (GetSType(Param)=Char) as the type might not be assigned yet *)
8226 MetaError1 ('base procedure {%EkHIGH} expects a variable or string constant as its parameter {%1d:rather than {%1d}} {%1asa}', Param)
8227 ELSIF IsUnbounded(Type)
8229 BuildHighFromUnbounded (combinedtok)
8231 BuildConstHighFromSym (combinedtok)
8234 MetaError0 ('base procedure {%EkHIGH} requires one parameter') ;
8236 PushTFtok (MakeConstLit (functok, MakeKey ('0'), Cardinal), Cardinal, functok)
8238 END BuildHighFunction ;
8242 BuildConstHighFromSym - builds the pseudo function HIGH from an Sym.
8243 Sym is a constant or an array which has constant bounds
8244 and therefore it can be calculated at compile time.
8264 |----------------| +------------+
8265 | ProcSym | Type | | ReturnVar |
8266 |----------------| |------------|
8269 PROCEDURE BuildConstHighFromSym (tok: CARDINAL) ;
8272 ReturnVar: CARDINAL ;
8275 ReturnVar := MakeTemporary (tok, ImmediateValue) ;
8276 GenHigh (tok, ReturnVar, 1, OperandT (1)) ;
8277 PopN (NoOfParam+1) ;
8278 PushTtok (ReturnVar, tok)
8279 END BuildConstHighFromSym ;
8283 BuildHighFromUnbounded - builds the pseudo function HIGH from an
8296 |----------------| +------------+
8297 | ProcSym | Type | | ReturnVar |
8298 |----------------| |------------|
8302 PROCEDURE BuildHighFromUnbounded (tok: CARDINAL) ;
8306 ReturnVar: CARDINAL ;
8309 Assert (NoOfParam=1) ;
8310 ReturnVar := MakeTemporary (tok, RightValue) ;
8311 PutVar (ReturnVar, Cardinal) ;
8312 Dim := OperandD (1) ;
8316 GenHigh (tok, ReturnVar, Dim, OperandA(1))
8318 GenHigh (tok, ReturnVar, Dim, OperandT(1))
8321 PushTFtok (ReturnVar, GetSType(ReturnVar), tok)
8322 END BuildHighFromUnbounded ;
8326 GetQualidentImport - returns the symbol as if it were qualified from, module.n.
8327 This is used to reference runtime support procedures and an
8328 error is generated if the symbol cannot be obtained.
8331 PROCEDURE GetQualidentImport (tokno: CARDINAL;
8332 n: Name; module: Name) : CARDINAL ;
8336 ModSym := MakeDefinitionSource (tokno, module) ;
8339 MetaErrorNT2 (tokno,
8340 'module %a cannot be found and is needed to import %a', module, n) ;
8344 Assert(IsDefImp(ModSym)) ;
8345 IF (GetExported (tokno, ModSym, n)=NulSym) OR IsUnknown (GetExported (tokno, ModSym, n))
8347 MetaErrorN2 ('module %a does not export procedure %a which is a necessary component of the runtime system, hint check the path and library/language variant',
8352 RETURN GetExported (tokno, MakeDefinitionSource (tokno, module), n)
8353 END GetQualidentImport ;
8357 MakeLengthConst - creates a constant which contains the length of string, sym.
8360 PROCEDURE MakeLengthConst (tok: CARDINAL; sym: CARDINAL) : CARDINAL ;
8362 RETURN MakeConstant (tok, GetStringLength (sym))
8363 END MakeLengthConst ;
8367 BuildLengthFunction - builds the inline standard function LENGTH.
8379 |----------------| +------------+
8380 | ProcSym | Type | | ReturnVar |
8381 |----------------| |------------|
8385 PROCEDURE BuildLengthFunction ;
8389 functok : CARDINAL ;
8394 ReturnVar : CARDINAL ;
8397 Param := OperandT (1) ;
8398 paramtok := OperandTok (1) ;
8399 functok := OperandTok (NoOfParam + 1) ;
8400 (* Restore stack to origional form *)
8402 Type := GetSType (Param) ; (* get the type from the symbol, not the stack *)
8405 MetaErrorT1 (functok, 'base procedure {%1EkLENGTH} expects 1 parameter, seen {%1n} parameters', NoOfParam)
8409 combinedtok := MakeVirtualTok (paramtok, functok, paramtok) ;
8410 IF IsConst (Param) AND (GetSType (Param) = Char)
8413 PopN (NoOfParam + 1) ;
8414 ReturnVar := MakeConstLit (combinedtok, MakeKey ('1'), Cardinal) ;
8415 PushTtok (ReturnVar, combinedtok)
8416 ELSIF IsConstString (Param)
8419 ReturnVar := MakeLengthConst (combinedtok, OperandT (1)) ;
8420 PopN (NoOfParam + 1) ;
8421 PushTtok (ReturnVar, combinedtok)
8423 ProcSym := GetQualidentImport (functok, MakeKey ('Length'), MakeKey ('M2RTS')) ;
8424 IF (ProcSym # NulSym) AND IsProcedure (ProcSym)
8427 IF IsConst (OperandT (1))
8429 (* we can fold this in M2GenGCC. *)
8430 ReturnVar := MakeTemporary (combinedtok, ImmediateValue) ;
8431 PutVar (ReturnVar, Cardinal) ;
8432 GenQuad (StandardFunctionOp, ReturnVar, ProcSym, OperandT (1)) ;
8433 PopN (NoOfParam + 1) ;
8434 PushTtok (ReturnVar, combinedtok)
8436 (* no we must resolve this at runtime or in the GCC optimizer. *)
8437 PopTF (Param, Type);
8439 PushTtok (ProcSym, functok) ;
8440 PushTFtok (Param, Type, paramtok) ;
8442 BuildRealFunctionCall (functok, FALSE)
8446 PopN (NoOfParam + 1) ;
8447 PushTtok (MakeConstLit (combinedtok, MakeKey ('0'), Cardinal), combinedtok) ;
8448 MetaErrorT0 (functok, 'no procedure Length found for substitution to the standard function {%1EkLENGTH} which is required to calculate non constant string lengths')
8452 (* NoOfParam is _very_ wrong, we flush all outstanding errors *)
8455 END BuildLengthFunction ;
8459 BuildOddFunction - builds the pseudo procedure call ODD.
8460 This procedure is actually a "macro" for
8461 ORD(x) --> VAL(BOOLEAN, x MOD 2)
8462 However we cannot push tokens back onto the input stack
8463 because the compiler is currently building a function
8464 call and expecting a ReturnVar on the stack.
8465 Hence we manipulate the stack and call
8466 BuildConvertFunction.
8487 | ProcSym | Type | Empty
8491 PROCEDURE BuildOddFunction ;
8495 functok : CARDINAL ;
8497 Res, Var : CARDINAL ;
8500 functok := OperandTok (NoOfParam + 1) ;
8503 Var := OperandT (1) ;
8504 optok := OperandTok (1) ;
8505 combinedtok := MakeVirtualTok (functok, functok, optok) ;
8506 IF IsVar(Var) OR IsConst(Var)
8508 PopN (NoOfParam + 1) ;
8510 Build macro: VAL(BOOLEAN, (x MOD 2))
8513 (* compute (x MOD 2) *)
8514 PushTFtok (Var, GetSType (Var), optok) ;
8516 PushTFtok (MakeConstLit (optok, MakeKey ('2'), ZType), ZType, optok) ;
8520 (* compute IF ...=0 *)
8521 PushTtok (Res, optok) ;
8523 PushTFtok (MakeConstLit (optok, MakeKey ('0'), ZType), ZType, optok) ;
8524 BuildRelOp (combinedtok) ;
8527 Res := MakeTemporary (combinedtok, RightValue) ;
8528 PutVar (Res, Boolean) ;
8530 PushTtok (Res, combinedtok) ;
8531 PushTtok (False, combinedtok) ;
8532 BuildAssignment (combinedtok) ;
8534 PushTtok (Res, combinedtok) ;
8535 PushTtok (True, combinedtok) ;
8536 BuildAssignment (combinedtok) ;
8539 PushTtok (Res, combinedtok)
8542 'the parameter to {%1EkODD} must be a variable or constant, seen {%1ad}',
8544 PushTtok (False, combinedtok)
8547 MetaErrorT1 (functok,
8548 'the pseudo procedure {%E1kODD} only has one parameter, seen {%1n} parameters',
8550 PushTtok (False, functok)
8552 END BuildOddFunction ;
8556 BuildAbsFunction - builds a call to the standard function ABS.
8558 We cannot implement it as a macro or inline an
8559 IF THEN statement as the IF THEN ELSE requires
8560 we write the value to the same variable (or constant)
8561 twice. The macro implementation will fail as
8562 the compiler maybe building a function
8563 call and expecting a ReturnVar on the stack.
8564 The only method to implement this is to pass it to the
8586 | ProcSym | Type | Empty
8590 PROCEDURE BuildAbsFunction ;
8594 combinedtok: CARDINAL ;
8597 Res, Var : CARDINAL ;
8600 functok := OperandTok (NoOfParam + 1) ;
8603 Var := OperandT (1) ;
8604 vartok := OperandTok (1) ;
8605 combinedtok := MakeVirtualTok (functok, functok, vartok) ;
8606 IF IsVar(Var) OR IsConst(Var)
8608 ProcSym := OperandT (NoOfParam + 1) ;
8609 PopN (NoOfParam + 1) ;
8611 Res := MakeTemporary (combinedtok, AreConstant (IsConst (Var))) ;
8612 PutVar (Res, GetSType (Var)) ;
8614 GenQuadO (combinedtok, StandardFunctionOp, Res, ProcSym, Var, FALSE) ;
8615 PushTFtok (Res, GetSType (Var), combinedtok)
8617 MetaErrorT1 (vartok,
8618 'the parameter to {%AkABS} must be a variable or constant, seen {%1ad}',
8622 MetaErrorT1 (functok,
8623 'the pseudo procedure {%AkABS} only has one parameter, seen {%1n} parameters',
8626 END BuildAbsFunction ;
8630 BuildCapFunction - builds the pseudo procedure call CAP.
8631 We generate a the following quad:
8634 StandardFunctionOp ReturnVal Cap Param1
8646 |----------------| +-------------+
8647 | ProcSym | Type | | ReturnVal |
8648 |----------------| |-------------|
8651 PROCEDURE BuildCapFunction ;
8655 combinedtok: CARDINAL ;
8658 Res, Var : CARDINAL ;
8661 functok := OperandTok (NoOfParam + 1) ;
8664 Var := OperandT (1) ;
8665 optok := OperandTok (1) ;
8666 IF IsVar (Var) OR IsConst (Var)
8668 ProcSym := OperandT (NoOfParam + 1) ;
8669 PopN (NoOfParam + 1) ;
8671 combinedtok := MakeVirtualTok (functok, functok, optok) ;
8672 Res := MakeTemporary (combinedtok, AreConstant (IsConst (Var))) ;
8673 PutVar (Res, Char) ;
8674 GenQuadO (combinedtok, StandardFunctionOp, Res, ProcSym, Var, FALSE) ;
8675 PushTFtok (Res, Char, combinedtok)
8678 'the parameter to {%AkCAP} must be a variable or constant, seen {%1ad}',
8682 MetaErrorT1 (functok,
8683 'the pseudo procedure {%AkCAP} only has one parameter, seen {%1n} parameters',
8686 END BuildCapFunction ;
8690 BuildChrFunction - builds the pseudo procedure call CHR.
8691 This procedure is actually a "macro" for
8692 CHR(x) --> CONVERT(CHAR, x)
8693 However we cannot push tokens back onto the input stack
8694 because the compiler is currently building a function
8695 call and expecting a ReturnVar on the stack.
8696 Hence we manipulate the stack and call
8697 BuildConvertFunction.
8718 | ProcSym | Type | Empty
8722 PROCEDURE BuildChrFunction ;
8730 functok := OperandTok (NoOfParam + 1) ;
8733 Var := OperandT (1) ;
8734 optok := OperandTok (1) ;
8735 IF IsVar (Var) OR IsConst (Var)
8737 PopN (NoOfParam + 1) ;
8739 Build macro: CONVERT( CHAR, Var )
8741 PushTFtok (Convert, NulSym, functok) ;
8742 PushTtok (Char, functok) ;
8743 PushTtok (Var, optok) ;
8744 PushT (2) ; (* Two parameters *)
8745 BuildConvertFunction
8748 'the parameter to {%AkCHR} must be a variable or constant, seen {%1ad}',
8752 MetaErrorT1 (functok,
8753 'the pseudo procedure {%AkCHR} only has one parameter, seen {%1n} parameters',
8756 END BuildChrFunction ;
8760 BuildOrdFunction - builds the pseudo procedure call ORD.
8761 This procedure is actually a "macro" for
8762 ORD(x) --> CONVERT(GetSType(sym), x)
8763 However we cannot push tokens back onto the input stack
8764 because the compiler is currently building a function
8765 call and expecting a ReturnVar on the stack.
8766 Hence we manipulate the stack and call
8767 BuildConvertFunction.
8788 | ProcSym | Type | Empty
8792 PROCEDURE BuildOrdFunction (Sym: CARDINAL) ;
8797 Type, Var: CARDINAL ;
8800 functok := OperandTok (NoOfParam + 1) ;
8803 Var := OperandT (1) ;
8804 optok := OperandTok (1) ;
8805 IF IsVar (Var) OR IsConst (Var)
8807 Type := GetSType (Sym) ;
8808 PopN (NoOfParam + 1) ;
8810 Build macro: CONVERT( CARDINAL, Var )
8812 PushTFtok (Convert, NulSym, functok) ;
8813 PushTtok (Type, optok) ;
8814 PushTtok (Var, optok) ;
8815 PushT (2) ; (* Two parameters *)
8816 BuildConvertFunction
8819 'the parameter to {%1Aa} must be a variable or constant, seen {%2ad}',
8823 MetaErrorT2 (functok,
8824 'the pseudo procedure {%1Aa} only has one parameter, seen {%2n} parameters',
8827 END BuildOrdFunction ;
8831 BuildIntFunction - builds the pseudo procedure call INT.
8832 This procedure is actually a "macro" for
8833 INT(x) --> CONVERT(INTEGER, x)
8834 However we cannot push tokens back onto the input stack
8835 because the compiler is currently building a function
8836 call and expecting a ReturnVar on the stack.
8837 Hence we manipulate the stack and call
8838 BuildConvertFunction.
8859 | ProcSym | Type | Empty
8863 PROCEDURE BuildIntFunction (Sym: CARDINAL) ;
8869 Type, Var : CARDINAL ;
8872 functok := OperandTok (NoOfParam + 1) ;
8875 Var := OperandT (1) ;
8876 optok := OperandTok (1) ;
8877 IF IsVar (Var) OR IsConst (Var)
8879 Type := GetSType (Sym) ; (* return type of function *)
8880 PopN (NoOfParam + 1) ;
8881 (* Build macro: CONVERT( CARDINAL, Var ). *)
8882 PushTFtok (Convert, NulSym, functok) ;
8883 PushTtok (Type, functok) ;
8884 PushTtok (Var, optok) ;
8885 PushT (2) ; (* Two parameters *)
8886 BuildConvertFunction
8888 combinedtok := MakeVirtualTok (functok, optok, optok) ;
8890 'the parameter to {%1Ea} must be a variable or constant, seen {%2ad}',
8892 PushTtok (combinedtok, MakeConstLit (combinedtok, MakeKey ('0'), ZType))
8895 MetaErrorT2 (functok,
8896 'the pseudo procedure {%1Ea} only has one parameter, seen {%2n} parameters',
8898 PushTtok (functok, MakeConstLit (functok, MakeKey ('0'), ZType))
8900 END BuildIntFunction ;
8904 BuildMakeAdrFunction - builds the pseudo procedure call MAKEADR.
8925 | ProcSym | Type | Empty
8929 PROCEDURE BuildMakeAdrFunction ;
8934 resulttok : CARDINAL ;
8935 AreConst : BOOLEAN ;
8937 NoOfParameters: CARDINAL ;
8938 ReturnVar : CARDINAL ;
8940 PopT (NoOfParameters) ;
8941 functok := OperandTok (NoOfParameters + 1) ;
8944 starttok := OperandTok (NoOfParameters + 1) ; (* ADR token. *)
8945 endtok := OperandTok (1) ; (* last parameter. *)
8946 GenQuad (ParamOp, 0, MakeAdr, MakeAdr) ;
8947 i := NoOfParameters ;
8948 (* stack index referencing stacked parameter, i *)
8951 GenQuadO (OperandTok (pi), ParamOp, i, MakeAdr, OperandT (pi), TRUE) ;
8957 WHILE i <= NoOfParameters DO
8958 IF IsVar (OperandT (i))
8961 ELSIF NOT IsConst (OperandT (i))
8963 MetaError1 ('problem in the {%1EN} argument for {%kMAKEADR}, all arguments to {%kMAKEADR} must be either variables or constants', i)
8967 (* ReturnVar - will have the type of the procedure *)
8968 resulttok := MakeVirtualTok (starttok, starttok, endtok) ;
8969 ReturnVar := MakeTemporary (resulttok, AreConstant(AreConst)) ;
8970 PutVar (ReturnVar, GetSType(MakeAdr)) ;
8971 GenQuadO (resulttok, FunctValueOp, ReturnVar, NulSym, MakeAdr, TRUE) ;
8972 PopN (NoOfParameters+1) ;
8973 PushTFtok (ReturnVar, GetSType (MakeAdr), resulttok)
8975 MetaError1 ('the pseudo procedure {%EkMAKEADR} requires at least one parameter, seen {%1n}', NoOfParameters) ;
8977 PushTFtok (Nil, GetSType (MakeAdr), functok)
8979 END BuildMakeAdrFunction ;
8983 BuildShiftFunction - builds the pseudo procedure call SHIFT.
8985 PROCEDURE SHIFT (val: <any type>;
8986 num: INTEGER): <any type> ;
8988 "Returns a bit sequence obtained from val by
8989 shifting up or down (left or right) by the
8990 absolute value of num, introducing
8991 zeros as necessary. The direction is down if
8992 the sign of num is negative, otherwise the
9006 |----------------| +------------+
9007 | ProcSym | Type | | ReturnVar |
9008 |----------------| |------------|
9011 PROCEDURE BuildShiftFunction ;
9027 paramtok := OperandTok (1) ;
9028 functok := OperandTok (NoOfParam + 1) ;
9031 PopTrwtok (Exp, r, exptok) ;
9033 PopTtok (varSet, vartok) ;
9035 combinedtok := MakeVirtualTok (functok, exptok, vartok) ;
9036 IF (GetSType (varSet) # NulSym) AND IsSet (GetDType (varSet))
9038 derefExp := DereferenceLValue (exptok, Exp) ;
9039 BuildRange (InitShiftCheck (varSet, derefExp)) ;
9040 returnVar := MakeTemporary (combinedtok, RightValue) ;
9041 PutVar (returnVar, GetSType (varSet)) ;
9042 GenQuad (LogicalShiftOp, returnVar, varSet, derefExp) ;
9043 PushTFtok (returnVar, GetSType (varSet), combinedtok)
9045 MetaErrorT1 (vartok,
9046 'SYSTEM procedure {%1EkSHIFT} expects a constant or variable which has a type of SET as its first parameter, seen {%1ad}',
9048 PushTFtok (MakeConstLit (combinedtok, MakeKey ('0'), Cardinal), Cardinal, combinedtok)
9051 combinedtok := MakeVirtualTok (functok, functok, paramtok) ;
9052 MetaErrorT1 (functok,
9053 'the pseudo procedure {%kSHIFT} requires at least two parameters, seen {%1En}',
9055 PopN (NoOfParam + 1) ;
9056 PushTFtok (MakeConstLit (combinedtok, MakeKey ('0'), Cardinal), Cardinal, combinedtok)
9058 END BuildShiftFunction ;
9062 BuildRotateFunction - builds the pseudo procedure call ROTATE.
9064 PROCEDURE ROTATE (val: <any type>;
9065 num: INTEGER): <any type> ;
9067 "Returns a bit sequence obtained from val
9068 by rotating up or down (left or right) by
9069 the absolute value of num. The direction is
9070 down if the sign of num is negative, otherwise
9071 the direction is up."
9084 |----------------| +------------+
9085 | ProcSym | Type | | ReturnVar |
9086 |----------------| |------------|
9089 PROCEDURE BuildRotateFunction ;
9104 functok := OperandTok (NoOfParam + 1) ;
9107 PopTrwtok (Exp, r, exptok) ;
9109 PopTtok (varSet, vartok) ;
9111 IF (GetSType (varSet) # NulSym) AND IsSet (GetDType (varSet))
9113 combinedtok := MakeVirtualTok (functok, functok, exptok) ;
9114 derefExp := DereferenceLValue (exptok, Exp) ;
9115 BuildRange (InitRotateCheck (varSet, derefExp)) ;
9116 returnVar := MakeTemporary (combinedtok, RightValue) ;
9117 PutVar (returnVar, GetSType (varSet)) ;
9118 GenQuadO (combinedtok, LogicalRotateOp, returnVar, varSet, derefExp, TRUE) ;
9119 PushTFtok (returnVar, GetSType (varSet), combinedtok)
9121 MetaErrorT1 (vartok,
9122 'SYSTEM procedure {%EkROTATE} expects a constant or variable which has a type of SET as its first parameter, seen {%1ad}',
9124 PushTFtok (MakeConstLit (functok, MakeKey('0'), Cardinal), Cardinal, functok)
9127 MetaErrorT1 (functok,
9128 'SYSTEM procedure {%EkROTATE} expects 2 parameters and was given {%1n} parameters',
9130 PopN (NoOfParam + 1) ;
9131 PushTFtok (MakeConstLit (functok, MakeKey ('0'), Cardinal), Cardinal, functok)
9133 END BuildRotateFunction ;
9137 BuildValFunction - builds the pseudo procedure call VAL.
9138 This procedure is actually a "macro" for
9139 VAL(Type, x) --> CONVERT(Type, x)
9140 However we cannot push tokens back onto the input stack
9141 because the compiler is currently building a function
9142 call and expecting a ReturnVar on the stack.
9143 Hence we manipulate the stack and call
9144 BuildConvertFunction.
9165 | ProcSym | Type | Empty
9169 PROCEDURE BuildValFunction ;
9171 functok : CARDINAL ;
9174 Exp, Type: CARDINAL ;
9180 functok := OperandTok (NoOfParam + 1) ;
9183 PopTrwtok (Exp, r, exptok) ;
9185 PopTtok (Type, typetok) ;
9186 PopTtok (ProcSym, tok) ;
9189 (* not sensible to try and recover when we dont know the return type. *)
9190 MetaErrorT1 (typetok,
9191 'undeclared type found in builtin procedure function {%AkVAL} {%1ad}',
9193 (* non recoverable error. *)
9194 ELSIF (IsSet (Type) OR IsEnumeration (Type) OR IsSubrange (Type) OR
9195 IsType (Type) OR IsPointer (Type) OR IsProcType (Type)) AND
9196 (IsVar (Exp) OR IsConst (Exp) OR IsProcedure (Exp))
9199 Build macro: CONVERT( Type, Var )
9201 PushTFtok (Convert, NulSym, tok) ;
9202 PushTtok (Type, typetok) ;
9203 PushTtok (Exp, exptok) ;
9204 PushT (2) ; (* Two parameters *)
9205 BuildConvertFunction
9207 (* not sensible to try and recover when we dont know the return type. *)
9208 MetaErrorT0 (functok,
9209 'the builtin procedure {%AkVAL} has the following formal parameter declaration {%kVAL} (type, expression)')
9210 (* non recoverable error. *)
9213 (* not sensible to try and recover when we dont know the return type. *)
9214 MetaErrorT1 (functok,
9215 'the builtin procedure {%AkVAL} expects 2 parameters, a type and an expression, but was given {%1n} parameters', NoOfParam)
9216 (* non recoverable error. *)
9218 END BuildValFunction ;
9222 BuildCastFunction - builds the pseudo procedure call CAST.
9223 This procedure is actually a "macro" for
9224 CAST(Type, x) --> Type(x)
9225 However we cannot push tokens back onto the input stack
9226 because the compiler is currently building a function
9227 call and expecting a ReturnVar on the stack.
9228 Hence we manipulate the stack and call
9229 BuildConvertFunction.
9250 | ProcSym | Type | Empty
9254 PROCEDURE BuildCastFunction ;
9263 Var, Type : CARDINAL ;
9266 functok := OperandTok (NoOfParam + 1) ;
9269 Type := OperandT (2) ;
9270 typetok := OperandTok (2) ;
9271 Var := OperandT (1) ;
9272 vartok := OperandTok (1) ;
9275 n := GetSymName (Type) ;
9276 WriteFormat1 ('undeclared type found in CAST (%a)', n)
9277 ELSIF IsSet (Type) OR IsEnumeration (Type) OR IsSubrange (Type) OR IsType (Type) OR
9278 IsPointer (Type) OR IsArray (Type) OR IsProcType (Type)
9282 PopN (NoOfParam+1) ;
9284 Build macro: Type( Var )
9286 PushTFtok (Type, NulSym, typetok) ;
9287 PushTtok (Var, vartok) ;
9288 PushT (1) ; (* one parameter *)
9290 ELSIF IsVar (Var) OR IsProcedure (Var)
9292 PopN (NoOfParam + 1) ;
9293 combinedtok := MakeVirtualTok (functok, functok, vartok) ;
9294 ReturnVar := MakeTemporary (combinedtok, RightValue) ;
9295 PutVar (ReturnVar, Type) ;
9296 GenQuadO (combinedtok, CastOp, ReturnVar, Type, Var, FALSE) ;
9297 PushTFtok (ReturnVar, Type, combinedtok)
9299 (* not sensible to try and recover when we dont know the return type. *)
9300 MetaErrorT0 (functok,
9301 'the second parameter to the builtin procedure {%AkCAST} must either be a variable, constant or a procedure. The formal parameters to cast are {%kCAST} (type, variable or constant or procedure)')
9302 (* non recoverable error. *)
9305 (* not sensible to try and recover when we dont know the return type. *)
9306 MetaErrorT0 (functok,
9307 'the builtin procedure {%AkCAST} has the following formal parameter declaration {%kCAST} (type, expression)')
9308 (* non recoverable error. *)
9311 (* not sensible to try and recover when we dont know the return type. *)
9312 MetaErrorT1 (functok,
9313 'the builtin procedure {%AkCAST} `expects 2 parameters, a type and an expression, but was given {%1n} parameters', NoOfParam)
9314 (* non recoverable error. *)
9316 END BuildCastFunction ;
9320 BuildConvertFunction - builds the pseudo function CONVERT.
9321 CONVERT( Type, Variable ) ;
9341 |----------------| +---------------------+
9342 | ProcSym | Type | | ReturnVar | Param1 |
9343 |----------------| |---------------------|
9347 ConvertOp ReturnVar Param1 Param2
9349 Converts variable Param2 into a variable Param1
9353 PROCEDURE BuildConvertFunction ;
9363 ReturnVar : CARDINAL ;
9366 functok := OperandTok (NoOfParam + 1) ;
9369 PopTrwtok (Exp, r, exptok) ;
9371 PopTtok (Type, typetok) ;
9375 (* we cannot recover if we dont have a type. *)
9376 MetaErrorT1 (typetok, 'undeclared type {%1Aad} found in {%kCONVERT}', Type)
9377 (* non recoverable error. *)
9378 ELSIF IsUnknown (Exp)
9380 (* we cannot recover if we dont have a type. *)
9381 MetaErrorT1 (typetok, 'unknown {%1Ad} {%1ad} found in {%kCONVERT}', Exp)
9382 (* non recoverable error. *)
9383 ELSIF (IsSet (Type) OR IsEnumeration (Type) OR IsSubrange (Type) OR
9384 IsType (Type) OR IsPointer (Type) OR IsProcType (Type) OR IsRecord (Type)) AND
9385 (IsVar (Exp) OR IsConst (Exp) OR IsProcedure (Exp))
9387 (* firstly dereference Var *)
9388 IF GetMode (Exp) = LeftValue
9390 t := MakeTemporary (exptok, RightValue) ;
9391 PutVar (t, GetSType (Exp)) ;
9392 CheckPointerThroughNil (exptok, Exp) ;
9393 doIndrX (exptok, t, Exp) ;
9397 combinedtok := MakeVirtualTok (functok, functok, exptok) ;
9398 ReturnVar := MakeTemporary (combinedtok, AreConstant (IsConst (Exp))) ;
9399 PutVar (ReturnVar, Type) ;
9400 GenQuadO (combinedtok, ConvertOp, ReturnVar, Type, Exp, TRUE) ;
9401 PushTFtok (ReturnVar, Type, combinedtok)
9403 (* not sensible to try and recover when we dont know the return type. *)
9404 MetaErrorT0 (functok,
9405 'the builtin procedure {%AkCONVERT} has the following formal parameter declaration {%kCONVERT} (type, expression)')
9406 (* non recoverable error. *)
9409 (* not sensible to try and recover when we dont know the return type. *)
9410 MetaErrorT1 (functok,
9411 'the builtin procedure {%AkCONVERT} expects 2 parameters, a type and an expression, but was given {%1n} parameters', NoOfParam)
9412 (* non recoverable error. *)
9414 END BuildConvertFunction ;
9418 CheckBaseTypeValue - checks to see whether the value, min, really exists.
9421 PROCEDURE CheckBaseTypeValue (tok: CARDINAL;
9424 func: CARDINAL) : CARDINAL ;
9426 IF (type = Real) OR (type = LongReal) OR (type = ShortReal)
9429 IF NOT IsValueAndTreeKnown ()
9432 '{%1Ead} ({%2ad}) cannot be calculated at compile time for the target architecture', func, type) ;
9433 RETURN MakeConstLit (tok, MakeKey ('1.0'), RType)
9437 END CheckBaseTypeValue ;
9441 GetTypeMin - returns the minimium value of type.
9444 PROCEDURE GetTypeMin (tok: CARDINAL; func, type: CARDINAL) : CARDINAL ;
9446 min, max: CARDINAL ;
9448 IF IsSubrange (type)
9450 min := MakeTemporary (tok, ImmediateValue) ;
9451 PutVar (min, type) ;
9452 GenQuad (SubrangeLowOp, min, NulSym, type) ;
9454 ELSIF IsSet (SkipType (type))
9456 RETURN GetTypeMin (tok, func, GetSType (SkipType (type)))
9457 ELSIF IsBaseType (type) OR IsEnumeration (type)
9459 GetBaseTypeMinMax (type, min, max) ;
9460 min := CheckBaseTypeValue (tok, type, min, func) ;
9462 ELSIF IsSystemType (type)
9464 GetSystemTypeMinMax (type, min, max) ;
9466 ELSIF GetSType (type) = NulSym
9469 'unable to obtain the {%AkMIN} value for type {%1ad}', type) ;
9470 (* non recoverable error. *)
9471 InternalError ('MetaErrorT1 {%AkMIN} should call abort')
9473 RETURN GetTypeMin (tok, func, GetSType (type))
9479 GetTypeMax - returns the maximum value of type.
9482 PROCEDURE GetTypeMax (tok: CARDINAL; func, type: CARDINAL) : CARDINAL ;
9484 min, max: CARDINAL ;
9486 IF IsSubrange (type)
9488 max := MakeTemporary (tok, ImmediateValue) ;
9489 PutVar (max, type) ;
9490 GenQuad (SubrangeHighOp, max, NulSym, type) ;
9492 ELSIF IsSet (SkipType (type))
9494 RETURN GetTypeMax (tok, func, GetSType (SkipType (type)))
9495 ELSIF IsBaseType (type) OR IsEnumeration (type)
9497 GetBaseTypeMinMax (type, min, max) ;
9498 min := CheckBaseTypeValue (tok, type, min, func) ;
9500 ELSIF IsSystemType (type)
9502 GetSystemTypeMinMax (type, min, max) ;
9504 ELSIF GetSType (type) = NulSym
9507 'unable to obtain the {%AkMAX} value for type {%1ad}', type) ;
9508 (* non recoverable error. *)
9509 InternalError ('MetaErrorT1 {%AkMAX} should call abort')
9511 RETURN GetTypeMax (tok, func, GetSType (type))
9517 BuildMinFunction - builds the pseudo function call Min.
9529 | ProcSym | Type | Empty
9533 PROCEDURE BuildMinFunction ;
9544 func := OperandT (NoOfParam + 1) ;
9545 functok := OperandTtok (NoOfParam + 1) ;
9548 Var := OperandT (1) ;
9549 vartok := OperandTok (1) ;
9550 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9551 combinedtok := MakeVirtualTok (functok, functok, vartok) ;
9552 IF IsAModula2Type (Var)
9554 min := GetTypeMin (vartok, func, Var) ;
9555 PushTFtok (min, GetSType (min), combinedtok)
9558 min := GetTypeMin (vartok, func, GetSType (Var)) ;
9559 PushTFtok (min, GetSType (Var), combinedtok)
9561 (* we dont know the type therefore cannot fake a return. *)
9562 MetaErrorT1 (vartok,
9563 'parameter to {%AkMIN} must be a type or a variable, seen {%1ad}',
9565 (* non recoverable error. *)
9568 (* we dont know the type therefore cannot fake a return. *)
9569 MetaErrorT1 (functok,
9570 'the pseudo builtin procedure function {%AkMIN} only has one parameter, seen {%1n}',
9572 (* non recoverable error. *)
9574 END BuildMinFunction ;
9578 BuildMaxFunction - builds the pseudo function call Max.
9590 | ProcSym | Type | Empty
9594 PROCEDURE BuildMaxFunction ;
9605 func := OperandT (NoOfParam + 1) ;
9606 functok := OperandTtok (NoOfParam + 1) ;
9609 Var := OperandT (1) ;
9610 vartok := OperandTok (1) ;
9611 PopN (NoOfParam + 1) ; (* destroy arguments to this function *)
9612 combinedtok := MakeVirtualTok (functok, functok, vartok) ;
9613 IF IsAModula2Type (Var)
9615 max := GetTypeMax (vartok, func, Var) ;
9616 PushTFtok (max, GetSType (max), combinedtok)
9619 max := GetTypeMax (vartok, func, GetSType (Var)) ;
9620 PushTFtok (max, GetSType (Var), combinedtok)
9622 (* we dont know the type therefore cannot fake a return. *)
9623 MetaErrorT1 (vartok,
9624 'parameter to {%AkMAX} must be a type or a variable, seen {%1ad}',
9626 (* non recoverable error. *) ;
9629 (* we dont know the type therefore cannot fake a return. *)
9630 MetaErrorT1 (functok,
9631 'the pseudo builtin procedure function {%AkMAX} only has one parameter, seen {%1n}',
9633 (* non recoverable error. *)
9635 END BuildMaxFunction ;
9639 BuildTruncFunction - builds the pseudo procedure call TRUNC.
9640 This procedure is actually a "macro" for
9641 TRUNC(x) --> CONVERT(INTEGER, x)
9642 However we cannot push tokens back onto the input stack
9643 because the compiler is currently building a function
9644 call and expecting a ReturnVar on the stack.
9645 Hence we manipulate the stack and call
9646 BuildConvertFunction.
9667 | ProcSym | Type | Empty
9671 PROCEDURE BuildTruncFunction (Sym: CARDINAL) ;
9674 functok : CARDINAL ;
9675 NoOfParam: CARDINAL ;
9681 Assert (IsTrunc (OperandT (NoOfParam+1))) ;
9682 functok := OperandTtok (NoOfParam + 1) ;
9685 ProcSym := RequestSym (functok, MakeKey ('CONVERT')) ;
9686 IF (ProcSym # NulSym) AND IsProcedure (ProcSym)
9688 Var := OperandT (1) ;
9689 vartok := OperandTtok (1) ;
9690 Type := GetSType (Sym) ;
9691 PopN (NoOfParam + 1) ; (* destroy arguments to this function *)
9692 IF IsVar (Var) OR IsConst (Var)
9694 IF IsRealType (GetSType (Var))
9696 (* build macro: CONVERT( INTEGER, Var ). *)
9697 PushTFtok (ProcSym, NulSym, functok) ;
9698 PushTtok (Type, functok) ;
9699 PushTtok (Var, vartok) ;
9700 PushT (2) ; (* two parameters *)
9701 BuildConvertFunction
9703 MetaErrorT1 (functok,
9704 'argument to {%1E%ad} must be a float point type', Sym) ;
9705 PushTFtok (MakeConstLit (functok, MakeKey('0'), Type), Type, functok)
9708 MetaErrorT2 (vartok,
9709 'argument to {%1E%ad} must be a variable or constant, seen {%2ad}',
9711 PushTFtok (MakeConstLit (functok, MakeKey('0'), Type), Type, functok)
9714 InternalError ('CONVERT procedure not found for TRUNC substitution')
9717 (* we dont know the type therefore cannot fake a return. *)
9718 MetaErrorT1 (functok,
9719 'the pseudo builtin procedure function {%AkTRUNC} only has one parameter, seen {%1n}', NoOfParam)
9720 (* non recoverable error. *)
9722 END BuildTruncFunction ;
9726 BuildFloatFunction - builds the pseudo procedure call FLOAT.
9727 This procedure is actually a "macro" for
9728 FLOAT(x) --> CONVERT(REAL, x)
9729 However we cannot push tokens back onto the input stack
9730 because the compiler is currently building a function
9731 call and expecting a ReturnVar on the stack.
9732 Hence we manipulate the stack and call
9733 BuildConvertFunction.
9754 | ProcSym | Type | Empty
9758 PROCEDURE BuildFloatFunction (Sym: CARDINAL) ;
9761 functok : CARDINAL ;
9762 NoOfParam: CARDINAL ;
9765 ProcSym : CARDINAL ;
9768 functok := OperandTtok (NoOfParam + 1) ;
9769 Type := GetSType (Sym) ;
9772 ProcSym := RequestSym (functok, MakeKey ('CONVERT')) ;
9773 IF (ProcSym # NulSym) AND IsProcedure (ProcSym)
9775 Var := OperandT (1) ;
9776 vartok := OperandTtok (1) ;
9777 IF IsVar (Var) OR IsConst (Var)
9779 PopN (NoOfParam + 1) ; (* destroy arguments to this function. *)
9780 (* build macro: CONVERT (REAL, Var). *)
9781 PushTFtok (ProcSym, NulSym, functok) ;
9782 PushTtok (Type, functok) ;
9783 PushTtok (Var, vartok) ;
9784 PushT(2) ; (* two parameters. *)
9785 BuildConvertFunction
9787 MetaErrorT1 (vartok,
9788 'argument to {%1E%ad} must be a variable or constant', ProcSym) ;
9789 PushTFtok (MakeConstLit (functok, MakeKey('0.0'), Type), Type, functok)
9792 InternalError ('CONVERT procedure not found for FLOAT substitution')
9795 MetaErrorT1 (functok,
9796 'the builtin procedure function {%1Ead} only has one parameter',
9798 PushTFtok (MakeConstLit (functok, MakeKey('0.0'), Type), Type, functok)
9800 END BuildFloatFunction ;
9804 BuildReFunction - builds the pseudo procedure call RE.
9825 | ProcSym | Type | Empty
9829 PROCEDURE BuildReFunction ;
9834 functok : CARDINAL ;
9835 NoOfParam : CARDINAL ;
9840 functok := OperandTtok (NoOfParam + 1) ;
9841 func := OperandT (NoOfParam + 1) ;
9844 Var := OperandT (1) ;
9845 vartok := OperandTok (1) ;
9846 combinedtok := MakeVirtualTok (functok, functok, vartok) ;
9847 IF IsVar(Var) OR IsConst(Var)
9849 ReturnVar := MakeTemporary (combinedtok, AreConstant (IsConst (Var))) ;
9850 PutVar (ReturnVar, ComplexToScalar (GetDType (Var))) ;
9851 GenQuadO (combinedtok, StandardFunctionOp, ReturnVar, Re, Var, FALSE) ;
9852 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9853 PushTFtok (ReturnVar, GetSType (ReturnVar), combinedtok)
9855 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9856 PushTFtok (MakeConstLit (combinedtok, MakeKey ('1.0'), RType), RType, combinedtok) ;
9857 MetaErrorT2 (vartok,
9858 'the parameter to the builtin procedure function {%1Ead} must be a constant or a variable, seen {%2ad}',
9862 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9863 PushTFtok (MakeConstLit (functok, MakeKey ('1.0'), RType), RType, functok) ;
9864 MetaErrorT2 (functok,
9865 'the builtin procedure function {%1Ead} only has one parameter, seen {%2n}',
9868 END BuildReFunction ;
9872 BuildImFunction - builds the pseudo procedure call IM.
9893 | ProcSym | Type | Empty
9897 PROCEDURE BuildImFunction ;
9902 functok : CARDINAL ;
9903 NoOfParam : CARDINAL ;
9908 functok := OperandTtok (NoOfParam + 1) ;
9909 func := OperandT (NoOfParam + 1) ;
9912 Var := OperandT (1) ;
9913 vartok := OperandTok (1) ;
9914 combinedtok := MakeVirtualTok (functok, functok, vartok) ;
9915 IF IsVar(Var) OR IsConst(Var)
9917 ReturnVar := MakeTemporary (combinedtok, AreConstant (IsConst (Var))) ;
9918 PutVar (ReturnVar, ComplexToScalar (GetDType (Var))) ;
9919 GenQuadO (combinedtok, StandardFunctionOp, ReturnVar, Im, Var, FALSE) ;
9920 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9921 PushTFtok (ReturnVar, GetSType (ReturnVar), combinedtok)
9923 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9924 PushTFtok (MakeConstLit (combinedtok, MakeKey ('1.0'), RType), RType, combinedtok) ;
9925 MetaErrorT2 (vartok,
9926 'the parameter to the builtin procedure function {%1Ead} must be a constant or a variable, seen {%2ad}',
9930 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9931 PushTFtok (MakeConstLit (functok, MakeKey ('1.0'), RType), RType, functok) ;
9932 MetaErrorT2 (functok,
9933 'the builtin procedure function {%1Ead} only has one parameter, seen {%2n}',
9936 END BuildImFunction ;
9940 BuildCmplxFunction - builds the pseudo procedure call CMPLX.
9961 | ProcSym | Type | Empty
9965 PROCEDURE BuildCmplxFunction ;
9969 combinedtok: CARDINAL ;
9970 NoOfParam : CARDINAL ;
9976 functok := OperandTtok (NoOfParam + 1) ;
9977 func := OperandT (NoOfParam + 1) ;
9982 endtok := OperandTok (1) ;
9983 combinedtok := MakeVirtualTok (functok, functok, endtok) ;
9984 IF (IsVar(l) OR IsConst(l)) AND
9985 (IsVar(r) OR IsConst(r))
9987 CheckExpressionCompatible (combinedtok, GetSType(l), GetSType(r)) ;
9988 ReturnVar := MakeTemporary (combinedtok, AreConstant (IsConst (l) AND IsConst (r))) ;
9989 PutVar (ReturnVar, GetCmplxReturnType (GetDType (l), GetDType (r))) ;
9990 GenQuadO (combinedtok, StandardFunctionOp, ReturnVar, Cmplx, Make2Tuple (l, r), TRUE) ;
9991 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9992 PushTFtok (ReturnVar, GetSType (ReturnVar), combinedtok)
9994 IF IsVar (l) OR IsConst (l)
9996 MetaErrorT2 (functok,
9997 'the builtin procedure {%1Ead} requires two parameters, both must be variables or constants but the second parameter is {%2d}',
10000 MetaErrorT2 (functok,
10001 'the builtin procedure {%1Ead} requires two parameters, both must be variables or constants but the first parameter is {%2d}',
10004 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
10005 PushTFtok (MakeConstLit (combinedtok, MakeKey ('1.0'), CType), CType, combinedtok)
10008 MetaErrorT2 (functok,
10009 'the builtin procedure {%1Ead} requires two parameters, seen {%2n}',
10011 PopN (NoOfParam + 1) ; (* destroy arguments to this function *)
10012 PushTFtok (MakeConstLit (functok, MakeKey ('1.0'), CType), CType, functok)
10014 END BuildCmplxFunction ;
10018 BuildAdrFunction - builds the pseudo function ADR
10037 |----------------| +------------+
10038 | ProcSym | Type | | ReturnVar |
10039 |----------------| |------------|
10043 PROCEDURE BuildAdrFunction ;
10055 Type, rw : CARDINAL ;
10058 PopT (noOfParameters) ;
10059 procSym := OperandT (noOfParameters + 1) ;
10060 procTok := OperandTok (noOfParameters + 1) ; (* token of procedure ADR. *)
10061 endtok := OperandTok (1) ; (* last parameter. *)
10062 combinedTok := MakeVirtualTok (procTok, procTok, endtok) ;
10063 IF noOfParameters # 1
10065 MetaErrorNT0 (combinedTok,
10066 'SYSTEM procedure ADR expects 1 parameter') ;
10067 PopN (noOfParameters + 1) ; (* destroy the arguments and function *)
10068 PushTF (Nil, Address)
10069 ELSIF IsConstString (OperandT (1))
10071 returnVar := MakeLeftValue (combinedTok, OperandT (1), RightValue,
10072 GetSType (procSym)) ;
10073 PopN (noOfParameters + 1) ; (* destroy the arguments and function *)
10074 PushTFtok (returnVar, GetSType (returnVar), combinedTok)
10075 ELSIF (NOT IsVar(OperandT(1))) AND (NOT IsProcedure(OperandT(1)))
10077 MetaErrorNT0 (combinedTok,
10078 'SYSTEM procedure ADR expects a variable, procedure or a constant string as its parameter') ;
10079 PopN (noOfParameters + 1) ; (* destroy the arguments and function *)
10080 PushTFtok (Nil, Address, combinedTok)
10081 ELSIF IsProcedure (OperandT (1))
10083 returnVar := MakeLeftValue (combinedTok, OperandT (1), RightValue,
10084 GetSType (procSym)) ;
10085 PopN (noOfParameters + 1) ; (* destroy the arguments and function *)
10086 PushTFtok (returnVar, GetSType (returnVar), combinedTok)
10088 Type := GetSType (OperandT (1)) ;
10089 Dim := OperandD (1) ;
10090 MarkArrayWritten (OperandT (1)) ;
10091 MarkArrayWritten (OperandA (1)) ;
10092 (* if the operand is an unbounded which has not been indexed
10093 then we will lookup its address from the unbounded record.
10094 Otherwise we obtain the address of the operand.
10096 IF IsUnbounded (Type) AND (Dim = 0)
10098 (* we will reference the address field of the unbounded structure *)
10099 UnboundedSym := OperandT (1) ;
10100 rw := OperandRW (1) ;
10101 PushTFrw (UnboundedSym, GetSType (UnboundedSym), rw) ;
10102 Field := GetUnboundedAddressOffset (GetSType (UnboundedSym)) ;
10103 PushTF (Field, GetSType (Field)) ;
10105 BuildDesignatorRecord (combinedTok) ;
10106 PopTrw (returnVar, rw) ;
10107 IF GetMode (returnVar) = LeftValue
10109 t := MakeTemporary (combinedTok, RightValue) ;
10110 PutVar (t, GetSType (procSym)) ;
10111 doIndrX (combinedTok, t, returnVar) ;
10114 (* we need to cast returnVar into ADDRESS *)
10115 t := MakeTemporary (combinedTok, RightValue) ;
10116 PutVar (t, GetSType (procSym)) ;
10117 GenQuadO (combinedTok, ConvertOp, t, GetSType (procSym), returnVar, FALSE) ;
10121 returnVar := MakeTemporary (combinedTok, RightValue) ;
10122 PutVar (returnVar, GetSType (procSym)) ;
10123 IF GetMode (OperandT (1)) = LeftValue
10125 PutVar (returnVar, GetSType (procSym)) ;
10126 GenQuadO (combinedTok, ConvertOp, returnVar, GetSType (procSym), OperandT (1), FALSE)
10128 GenQuadO (combinedTok, AddrOp, returnVar, NulSym, OperandT (1), FALSE)
10130 PutWriteQuad (OperandT (1), GetMode (OperandT (1)), NextQuad-1) ;
10131 rw := OperandMergeRW (1) ;
10132 Assert (IsLegal (rw))
10134 PopN (noOfParameters + 1) ; (* destroy the arguments and function *)
10135 PushTFrwtok (returnVar, GetSType (returnVar), rw, combinedTok)
10137 END BuildAdrFunction ;
10141 BuildSizeFunction - builds the pseudo function SIZE
10160 |----------------| +------------+
10161 | ProcSym | Type | | ReturnVar |
10162 |----------------| |------------|
10165 PROCEDURE BuildSizeFunction ;
10169 functok : CARDINAL ;
10174 ReturnVar : CARDINAL ;
10177 ProcSym := OperandT (NoOfParam + 1) ;
10178 functok := OperandTtok (NoOfParam + 1) ;
10181 MetaErrorT1 (functok,
10182 '{%E} SYSTEM procedure function {%kSIZE} requires one parameter, seen {%1n}',
10184 resulttok := functok ;
10185 ReturnVar := MakeConstLit (resulttok, MakeKey('0'), Cardinal)
10186 ELSIF IsAModula2Type (OperandT (1))
10188 paramtok := OperandTok (1) ;
10189 resulttok := MakeVirtualTok (functok, functok, paramtok) ;
10190 BuildSizeCheckEnd (ProcSym) ; (* Quadruple generation now on. *)
10191 ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
10192 GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, OperandT(1), TRUE)
10193 ELSIF IsVar (OperandT (1))
10195 BuildSizeCheckEnd (ProcSym) ; (* Quadruple generation now on. *)
10196 Type := GetSType (OperandT (1)) ;
10197 paramtok := OperandTok (1) ;
10198 resulttok := MakeVirtualTok (functok, functok, paramtok) ;
10199 IF IsUnbounded (Type)
10201 (* Eg. SIZE(a) ; where a is unbounded dereference HIGH and multiply by the TYPE. *)
10202 dim := OperandD (1) ;
10205 ReturnVar := calculateMultipicand (resulttok, OperandT (1), Type, dim)
10207 ReturnVar := calculateMultipicand (resulttok, OperandA (1), Type, dim)
10210 ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
10213 MetaErrorT1 (resulttok,
10214 'cannot get the type and size of {%1Ead}', OperandT (1))
10216 GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, Type, TRUE)
10219 resulttok := functok ;
10220 MetaErrorT1 (resulttok,
10221 '{%E}SYSTEM procedure {%kSIZE} expects a variable as its parameter, seen {%1Ed}',
10223 ReturnVar := MakeConstLit (resulttok, MakeKey('0'), Cardinal)
10225 PopN (NoOfParam+1) ; (* Destroy the arguments and function. *)
10226 PushTFtok (ReturnVar, GetSType(ProcSym), resulttok)
10227 END BuildSizeFunction ;
10231 BuildTSizeFunction - builds the pseudo function TSIZE
10250 |----------------| +------------+
10251 | ProcSym | Type | | ReturnVar |
10252 |----------------| |------------|
10256 PROCEDURE BuildTSizeFunction ;
10260 functok : CARDINAL ;
10261 NoOfParam: CARDINAL ;
10264 ReturnVar: CARDINAL ;
10267 ProcSym := OperandT (NoOfParam + 1) ;
10268 functok := OperandTtok (NoOfParam) ;
10269 BuildSizeCheckEnd (ProcSym) ; (* quadruple generation now on *)
10272 paramtok := OperandTtok (1) ;
10273 resulttok := MakeVirtualTok (functok, functok, paramtok) ;
10274 IF IsAModula2Type (OperandT (1))
10276 ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
10277 GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, OperandT (1), FALSE)
10278 ELSIF IsVar (OperandT (1))
10280 ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
10281 GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, GetSType (OperandT (1)), FALSE)
10283 MetaErrorT1 (resulttok,
10284 '{%E}SYSTEM procedure function {%kTSIZE} expects a variable as its first parameter, seen {%1Ed}',
10286 ReturnVar := MakeConstLit (resulttok, MakeKey ('0'), Cardinal)
10288 ELSIF NoOfParam = 0
10290 resulttok := functok ;
10291 MetaErrorT0 (resulttok,
10292 '{%E}SYSTEM procedure function {%kTSIZE} expects either one or two parameters, seen none') ;
10293 ReturnVar := MakeConstLit (resulttok, MakeKey ('0'), Cardinal)
10295 Record := OperandT (NoOfParam) ;
10296 paramtok := OperandTtok (1) ;
10297 resulttok := OperandTtok (NoOfParam) ;
10298 IF IsRecord (Record)
10300 paramtok := OperandTtok (1) ;
10301 resulttok := MakeVirtualTok (functok, functok, paramtok) ;
10302 ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
10303 GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, Record, FALSE)
10305 resulttok := MakeVirtualTok (functok, functok, paramtok) ;
10306 MetaErrorT1 (resulttok,
10307 '{%E}SYSTEM procedure function {%kTSIZE} expects the first parameter to be a record type, seen {%1d}',
10309 ReturnVar := MakeConstLit (resulttok, MakeKey ('0'), Cardinal)
10312 PopN (NoOfParam+1) ; (* destroy the arguments and function *)
10313 PushTFtok (ReturnVar, GetSType (ProcSym), resulttok)
10314 END BuildTSizeFunction ;
10318 BuildTBitSizeFunction - builds the pseudo function TBITSIZE
10337 |----------------| +------------+
10338 | ProcSym | Type | | ReturnVar |
10339 |----------------| |------------|
10343 PROCEDURE BuildTBitSizeFunction ;
10347 functok : CARDINAL ;
10348 NoOfParam: CARDINAL ;
10351 ReturnVar: CARDINAL ;
10354 ProcSym := OperandT (NoOfParam + 1) ;
10355 functok := OperandTtok (NoOfParam) ;
10356 BuildSizeCheckEnd (ProcSym) ; (* quadruple generation now on *)
10359 paramtok := OperandTtok (1) ;
10360 resulttok := MakeVirtualTok (functok, functok, paramtok) ;
10361 IF IsAModula2Type (OperandT (1))
10363 ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
10364 GenQuadO (resulttok, StandardFunctionOp, ReturnVar, ProcSym, OperandT (1), FALSE)
10365 ELSIF IsVar (OperandT (1))
10367 ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
10368 GenQuadO (resulttok, StandardFunctionOp, ReturnVar, ProcSym, OperandT(1), FALSE)
10370 MetaErrorT1 (resulttok,
10371 '{%E}SYSTEM procedure function {%kTBITSIZE} expects a variable as its first parameter, seen {%1d}',
10373 ReturnVar := MakeConstLit (resulttok, MakeKey ('0'), Cardinal)
10375 ELSIF NoOfParam = 0
10377 resulttok := functok ;
10378 MetaErrorT0 (functok,
10379 '{%E}SYSTEM procedure function {%kTBITSIZE} expects either one or two parameters, seen none') ;
10380 ReturnVar := MakeConstLit (functok, MakeKey ('0'), Cardinal)
10382 Record := OperandT (NoOfParam) ;
10383 paramtok := OperandTtok (1) ;
10384 resulttok := OperandTtok (NoOfParam) ;
10385 IF IsRecord (Record)
10387 paramtok := OperandTtok (1) ;
10388 resulttok := MakeVirtualTok (functok, functok, paramtok) ;
10389 ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
10390 GenQuad(StandardFunctionOp, ReturnVar, ProcSym, OperandT(1)) ;
10392 resulttok := MakeVirtualTok (functok, functok, paramtok) ;
10393 MetaErrorT1 (resulttok,
10394 '{%E}SYSTEM procedure function {%kTBITSIZE} expects the first parameter to be a record type, seen {%1d}',
10396 ReturnVar := MakeConstLit (resulttok, MakeKey ('0'), Cardinal)
10399 PopN (NoOfParam + 1) ; (* destroy the arguments and function *)
10400 PushTFtok (ReturnVar, GetSType (ProcSym), resulttok)
10401 END BuildTBitSizeFunction ;
10405 ExpectingParameterType -
10408 PROCEDURE ExpectingParameterType (BlockSym, Type: CARDINAL) ;
10410 IF NOT IsAModula2Type (Type)
10412 IF (Type = NulSym) OR IsPartialUnbounded (Type) OR IsUnknown (Type)
10414 MetaError1 ('the type used in the formal parameter declaration in {%1Md} {%1a} is unknown',
10417 MetaError2 ('the type {%1Ead} used in the formal parameter declaration in {%2Md} {%2a} was not declared as a type',
10421 END ExpectingParameterType ;
10425 ExpectingVariableType -
10428 PROCEDURE ExpectingVariableType (BlockSym, Type: CARDINAL) ;
10430 IF NOT IsAModula2Type(Type)
10434 MetaError1 ('the type used during the variable declaration section in procedure {%1EMad} is unknown',
10436 MetaError1 ('the type used during the variable declaration section in procedure {%1Ead} is unknown',
10438 ELSIF IsPartialUnbounded(Type) OR IsUnknown(Type)
10440 MetaError2 ('the type {%1EMad} used during variable declaration section in procedure {%2ad} is unknown',
10442 MetaError2 ('the type {%1Ead} used during variable declaration section in procedure {%2Mad} is unknown',
10445 MetaError2 ('the {%1d} {%1Ea} is not a type and therefore cannot be used to declare a variable in {%2d} {%2a}',
10449 END ExpectingVariableType ;
10453 CheckVariablesAndParameterTypesInBlock - checks to make sure that block, BlockSym, has
10454 parameters types and variable types which are legal.
10457 PROCEDURE CheckVariablesAndParameterTypesInBlock (BlockSym: CARDINAL) ;
10460 ParamNo: CARDINAL ;
10462 IF IsProcedure(BlockSym)
10464 ParamNo := NoOfParam(BlockSym)
10470 n := GetNth(BlockSym, i) ;
10471 IF (n#NulSym) AND (NOT IsTemporary(n)) AND
10472 (IsProcedure(BlockSym) OR ((IsDefImp(BlockSym) AND (GetMainModule()=BlockSym)) OR IsModule(BlockSym)))
10476 (* n is a parameter *)
10477 ExpectingParameterType(BlockSym, GetSType(n))
10479 (* n is a local variable *)
10480 ExpectingVariableType(BlockSym, GetSType(n))
10485 END CheckVariablesAndParameterTypesInBlock ;
10489 BuildProcedureStart - Builds start of the procedure. Generates a
10490 quadruple which indicated the start of
10491 this procedure declarations scope.
10492 The Stack is expected to contain:
10499 +------------+ +-----------+
10500 | ProcSym | | ProcSym |
10501 |------------| |-----------|
10503 |------------| |-----------|
10508 q ProcedureScopeOp Line# Scope ProcSym
10511 PROCEDURE BuildProcedureStart ;
10513 ProcSym: CARDINAL ;
10516 Assert(IsProcedure(ProcSym)) ;
10517 PutProcedureScopeQuad(ProcSym, NextQuad) ;
10518 GenQuad(ProcedureScopeOp, GetPreviousTokenLineNo(), GetScope(ProcSym), ProcSym) ;
10520 END BuildProcedureStart ;
10524 BuildProcedureBegin - determines the start of the BEGIN END block of
10526 The Stack is expected to contain:
10533 +------------+ +-----------+
10534 | ProcSym | | ProcSym |
10535 |------------| |-----------|
10537 |------------| |-----------|
10542 q NewLocalVarOp TokenNo(BEGIN) _ ProcSym
10545 PROCEDURE BuildProcedureBegin ;
10547 ProcSym: CARDINAL ;
10550 Assert(IsProcedure(ProcSym)) ;
10551 PutProcedureStartQuad(ProcSym, NextQuad) ;
10552 PutProcedureBegin(ProcSym, GetTokenNo()) ;
10553 GenQuad(NewLocalVarOp, GetTokenNo(), GetScope(ProcSym), ProcSym) ;
10554 CurrentProc := ProcSym ;
10555 PushWord(ReturnStack, 0) ;
10557 CheckVariablesAt(ProcSym) ;
10558 CheckNeedPriorityBegin(GetTokenNo(), ProcSym, GetCurrentModule()) ;
10559 PushWord(TryStack, NextQuad) ;
10560 PushWord(CatchStack, 0) ;
10561 IF HasExceptionBlock(ProcSym)
10563 GenQuad(TryOp, NulSym, NulSym, 0)
10565 END BuildProcedureBegin ;
10569 BuildProcedureEnd - Builds end of the procedure. Destroys space for
10570 the local variables.
10571 The Stack is expected to contain:
10578 +------------+ +-----------+
10579 | ProcSym | | ProcSym |
10580 |------------| |-----------|
10582 |------------| |-----------|
10587 q KillLocalVarOp TokenNo(END) _ ProcSym
10590 PROCEDURE BuildProcedureEnd ;
10593 ProcSym: CARDINAL ;
10595 PopTtok(ProcSym, tok) ;
10596 IF HasExceptionBlock(ProcSym)
10598 BuildRTExceptLeave(tok, TRUE) ;
10599 GenQuad(CatchEndOp, NulSym, NulSym, NulSym)
10601 IF GetSType(ProcSym)#NulSym
10603 BuildError(InitNoReturnRangeCheck())
10605 BackPatch(PopWord(ReturnStack), NextQuad) ;
10606 CheckNeedPriorityEnd(tok, ProcSym, GetCurrentModule()) ;
10607 CurrentProc := NulSym ;
10608 PutProcedureEnd(ProcSym, GetTokenNo()-1) ; (* --fixme-- *)
10609 GenQuad(KillLocalVarOp, GetTokenNo()-1, NulSym, ProcSym) ;
10610 PutProcedureEndQuad(ProcSym, NextQuad) ;
10611 GenQuad(ReturnOp, NulSym, NulSym, ProcSym) ;
10612 CheckFunctionReturn(ProcSym) ;
10613 CheckVariablesInBlock(ProcSym) ;
10614 RemoveTop (CatchStack) ;
10615 RemoveTop (TryStack) ;
10617 END BuildProcedureEnd ;
10621 IsNeverAltered - returns TRUE if variable, sym, is never altered
10622 between quadruples: Start..End
10625 PROCEDURE IsNeverAltered (sym: CARDINAL; Start, End: CARDINAL) : BOOLEAN ;
10627 WriteStart, WriteEnd: CARDINAL ;
10629 GetWriteLimitQuads (sym, GetMode (sym), Start, End, WriteStart, WriteEnd) ;
10630 RETURN( (WriteStart = 0) AND (WriteEnd = 0) )
10631 END IsNeverAltered ;
10635 IsConditionVariable - returns TRUE if the condition at quadruple, q, is variable.
10638 PROCEDURE IsConditionVariable (q: CARDINAL; Start, End: CARDINAL) : BOOLEAN ;
10640 op : QuadOperator ;
10641 op1, op2, op3: CARDINAL ;
10643 RightFixed : BOOLEAN ;
10645 GetQuad (q, op, op1, op2, op3) ;
10650 LeftFixed := IsConst(op1) ;
10651 RightFixed := IsConst(op2) ;
10654 LeftFixed := IsNeverAltered(op1, Start, End)
10658 RightFixed := IsNeverAltered(op2, Start, End)
10660 RETURN( NOT (LeftFixed AND RightFixed) )
10662 END IsConditionVariable ;
10666 IsInfiniteLoop - returns TRUE if an infinite loop is found.
10667 Given a backwards jump at, End, it returns a BOOLEAN which depends on
10668 whether a jump is found to jump beyond, End. If a conditonal jump is found
10669 to pass over, End, the condition is tested for global variables, procedure variables and
10673 variables - tested to see whether they are altered inside the loop
10674 global variable - the procedure tests to see whether it is altered as above
10675 but will also test to see whether this loop calls a procedure
10676 in which case it believes the loop NOT to be infinite
10677 (as this procedure call might alter the global variable)
10679 Note that this procedure can easily be fooled by the user altering variables
10683 PROCEDURE IsInfiniteLoop (End: CARDINAL) : BOOLEAN ;
10686 IsGlobal : BOOLEAN ;
10689 op : QuadOperator ;
10690 op1, op2, op3: CARDINAL ;
10692 SeenCall := FALSE ;
10693 IsGlobal := FALSE ;
10694 GetQuad(End, op, op1, op2, Start) ;
10696 WHILE Current#End DO
10697 GetQuad(Current, op, op1, op2, op3) ;
10698 (* remember that this function is only called once we have optimized the redundant gotos and conditionals *)
10699 IF IsConditional(Current) AND (NOT IsGlobal)
10701 IsGlobal := (IsVar(op1) AND (NOT IsProcedure(GetVarScope(op1)))) OR
10702 (IsVar(op2) AND (NOT IsProcedure(GetVarScope(op2))))
10708 IF (op=GotoOp) OR (IsConditional(Current) AND IsConditionVariable(Current, Start, End))
10710 IF (op3>End) OR (op3<Start)
10712 RETURN( FALSE ) (* may jump out of this loop, good *)
10715 Current := GetNextQuad(Current)
10717 GetQuad(End, op, op1, op2, op3) ;
10718 IF IsConditional(End)
10720 IF IsConditionVariable(End, Start, End)
10726 IsGlobal := (IsVar(op1) AND (NOT IsProcedure(GetVarScope(op1)))) OR
10727 (IsVar(op2) AND (NOT IsProcedure(GetVarScope(op2))))
10731 (* we have found a likely infinite loop if no conditional uses a global and no procedure call was seen *)
10732 RETURN( NOT (IsGlobal AND SeenCall) )
10733 END IsInfiniteLoop ;
10737 LoopAnalysis - checks whether an infinite loop exists.
10740 PROCEDURE LoopAnalysis (Scope: CARDINAL; Current, End: CARDINAL) ;
10742 op : QuadOperator ;
10743 op1, op2, op3: CARDINAL ;
10747 WHILE (Current<=End) AND (Current#0) DO
10748 GetQuad(Current, op, op1, op2, op3) ;
10749 IF (op=GotoOp) OR IsConditional(Current)
10753 (* found a loop - ie a branch which goes back in quadruple numbers *)
10754 IF IsInfiniteLoop(Current)
10756 MetaErrorT1 (QuadToTokenNo(op3),
10757 'it is very likely (although not absolutely certain) that the top of an infinite loop exists here in {%1Wad}',
10759 MetaErrorT1 (QuadToTokenNo(Current),
10760 'and the bottom of the infinite loop is ends here in {%1Wad} or alternatively a component of this loop is never executed',
10763 WarnStringAt(InitString('it is very likely (although not absolutely certain) that the top of an infinite loop is here'),
10764 QuadToTokenNo(op3)) ;
10765 WarnStringAt(InitString('and the bottom of the infinite loop is ends here or alternatively a component of this loop is never executed'),
10766 QuadToTokenNo(Current))
10771 Current := GetNextQuad(Current)
10778 CheckVariablesInBlock - given a block, BlockSym, check whether all variables are used.
10781 PROCEDURE CheckVariablesInBlock (BlockSym: CARDINAL) ;
10783 CheckVariablesAndParameterTypesInBlock (BlockSym)
10784 END CheckVariablesInBlock ;
10788 CheckFunctionReturn - checks to see that a RETURN statement was present in a function.
10791 PROCEDURE CheckFunctionReturn (ProcSym: CARDINAL) ;
10793 Op : QuadOperator ;
10796 Start, End : CARDINAL ;
10798 IF GetSType(ProcSym)#NulSym
10800 (* yes it is a function *)
10801 GetProcedureQuads(ProcSym, Scope, Start, End) ;
10802 GetQuad(Start, Op, Op1, Op2, Op3) ;
10805 InternalError ('incorrect start quad')
10807 WHILE (Start#End) AND (Op#ReturnValueOp) AND (Op#InlineOp) DO
10808 Start := GetNextQuad(Start) ;
10809 GetQuad(Start, Op, Op1, Op2, Op3)
10811 IF (Op#ReturnValueOp) AND (Op#InlineOp)
10813 (* an InlineOp can always be used to emulate a RETURN *)
10814 MetaError1 ('procedure function {%1Ea} does not RETURN a value', ProcSym)
10817 END CheckFunctionReturn ;
10821 CheckReturnType - checks to see that the return type from currentProc is
10822 assignment compatible with actualType.
10825 PROCEDURE CheckReturnType (tokno: CARDINAL; currentProc, actualVal, actualType: CARDINAL) ;
10827 procType: CARDINAL ;
10831 procType := GetSType (currentProc) ;
10832 IF procType = NulSym
10834 MetaError1 ('attempting to RETURN a value from procedure {%1Ea} which was not a declared as a procedure function', currentProc)
10835 ELSIF AssignmentRequiresWarning (actualType, GetSType (currentProc))
10837 MetaError2 ('attempting to RETURN a value {%1Wa} with an incompatible type {%1Wtsa} from a procedure function {%1a} which returns {%1tsa}', actualVal, currentProc)
10838 ELSIF NOT IsAssignmentCompatible (actualType, procType)
10840 n1 := GetSymName(actualType) ;
10841 n2 := GetSymName(procType) ;
10842 WriteFormat2('attempting to RETURN a value with an incompatible type (%a) from a function which returns (%a)',
10844 ELSIF IsProcedure(actualVal) AND (NOT IsAssignmentCompatible(actualVal, procType))
10847 MetaWarnings2('attempting to RETURN a value with an incompatible type {%1ad} from function {%2a} which returns {%2ta}',
10848 actualVal, currentProc)
10850 --fixme-- introduce MetaWarning, MetaWarning2, MetaWarning3 into M2MetaError
10852 s1 := InitStringCharStar(KeyToCharStar(GetSymName(actualVal))) ;
10853 s2 := InitStringCharStar(KeyToCharStar(GetSymName(procType))) ;
10854 ErrorString(NewWarning(GetTokenNo()),
10855 Sprintf2(Mark(InitString('attempting to RETURN a value with a (possibly on other targets) incompatible type (%s) from a function which returns (%s)')),
10857 ELSIF IsProcedure(actualVal) AND (NOT IsAssignmentCompatible(actualVal, GetSType(CurrentProc)))
10859 n1 := GetSymName(actualVal) ;
10860 n2 := GetSymName(GetSType(currentProc)) ;
10861 WriteFormat2('attempting to RETURN a value with an incompatible type (%a) from a function which returns (%a)',
10864 (* this checks the types are compatible, not the data contents. *)
10865 BuildRange (InitTypesAssignmentCheck (tokno, currentProc, actualVal))
10867 END CheckReturnType ;
10871 BuildReturn - Builds the Return part of the procedure.
10872 tokreturn is the location of the RETURN keyword.
10873 The Stack is expected to contain:
10885 PROCEDURE BuildReturn (tokreturn: CARDINAL) ;
10888 tokexpr : CARDINAL ;
10896 PopBooltok (t, f, tokexpr) ;
10897 (* Des will be a boolean type *)
10898 Des := MakeTemporary (tokexpr, RightValue) ;
10899 PutVar (Des, Boolean) ;
10900 PushTFtok (Des, Boolean, tokexpr) ;
10901 PushBooltok (t, f, tokexpr) ;
10902 BuildAssignmentWithoutBounds (tokreturn, FALSE, TRUE) ;
10903 PushTFtok (Des, Boolean, tokexpr)
10905 PopTFtok (e1, t1, tokexpr) ;
10906 tokcombined := MakeVirtualTok (tokreturn, tokreturn, tokexpr) ;
10909 (* this will check that the type returned is compatible with
10910 the formal return type of the procedure. *)
10911 CheckReturnType (tokcombined, CurrentProc, e1, t1) ;
10912 (* dereference LeftValue if necessary *)
10913 IF GetMode (e1) = LeftValue
10915 t2 := GetSType (CurrentProc) ;
10916 e2 := MakeTemporary (tokexpr, RightValue) ;
10918 CheckPointerThroughNil (tokexpr, e1) ;
10919 doIndrX (tokexpr, e2, e1) ;
10920 (* here we check the data contents to ensure no overflow. *)
10921 BuildRange (InitReturnRangeCheck (tokcombined, CurrentProc, e2)) ;
10922 GenQuadOtok (tokcombined, ReturnValueOp, e2, NulSym, CurrentProc, FALSE,
10923 tokcombined, UnknownTokenNo, GetDeclaredMod (CurrentProc))
10925 (* here we check the data contents to ensure no overflow. *)
10926 BuildRange (InitReturnRangeCheck (tokcombined, CurrentProc, e1)) ;
10927 GenQuadOtok (tokcombined, ReturnValueOp, e1, NulSym, CurrentProc, FALSE,
10928 tokcombined, UnknownTokenNo, GetDeclaredMod (CurrentProc))
10931 GenQuadO (tokcombined, GotoOp, NulSym, NulSym, PopWord (ReturnStack), FALSE) ;
10932 PushWord (ReturnStack, NextQuad-1)
10937 IsReadOnly - a helper procedure function to detect constants.
10940 PROCEDURE IsReadOnly (sym: CARDINAL) : BOOLEAN ;
10942 RETURN IsConst (sym) OR (IsVar (sym) AND IsVarConst (sym))
10947 BuildDesignatorRecord - Builds the record referencing.
10948 The Stack is expected to contain:
10964 | fldn | typen | <- Ptr
10965 |--------------| +-------------+
10966 | Sym | Type | | S | type1|
10967 |--------------| |-------------|
10970 PROCEDURE BuildDesignatorRecord (dottok: CARDINAL) ;
10974 combinedtok: CARDINAL ;
10982 RecordSym := OperandT (n+1) ;
10983 (* RecordType could be found by: SkipType (OperandF (n+1)). *)
10984 RecordTok := OperandTok (n+1) ;
10985 rw := OperandMergeRW (n+1) ;
10986 Assert (IsLegal (rw)) ;
10987 Field := OperandT (n) ;
10988 FieldType := SkipType (OperandF (n)) ;
10989 FieldTok := OperandTok (n) ;
10990 combinedtok := MakeVirtualTok (dottok, RecordTok, FieldTok) ;
10993 InternalError ('not expecting to see n>1')
10995 IF IsUnused (Field)
10997 MetaErrors1 ('record field {%1Dad} was declared as unused by a pragma',
10998 'record field {%1ad} is being used after being declared as unused by a pragma', Field)
11000 Res := MakeComponentRef (MakeComponentRecord (combinedtok,
11001 RightValue, RecordSym), Field) ;
11002 PutVarConst (Res, IsReadOnly (RecordSym)) ;
11003 GenQuadO (combinedtok, RecordFieldOp, Res, RecordSym, Field, FALSE) ;
11005 PushTFrwtok (Res, FieldType, rw, combinedtok)
11006 END BuildDesignatorRecord ;
11010 BuildDesignatorError - removes the designator from the stack and replaces
11011 it with an error symbol.
11014 PROCEDURE BuildDesignatorError (message: ARRAY OF CHAR) ;
11018 exprTok : CARDINAL ;
11023 PopTtok (e, exprTok) ;
11024 PopTFDtok (Sym, Type, d, arrayTok) ;
11025 combinedTok := MakeVirtualTok (arrayTok, arrayTok, exprTok) ;
11026 error := MakeError (combinedTok, MakeKey (message)) ;
11027 PushTFDtok (error, Type, d, arrayTok)
11028 END BuildDesignatorError ;
11033 BuildDesignatorArray - Builds the array referencing.
11034 The purpose of this procedure is to work out
11035 whether the DesignatorArray is a static or
11036 dynamic array and to call the appropriate
11039 The Stack is expected to contain:
11048 |--------------| +------------+
11049 | Sym | Type | | S | T |
11050 |--------------| |------------|
11053 PROCEDURE BuildDesignatorArray ;
11057 exprTok : CARDINAL ;
11063 IF IsConst (OperandT (2))
11065 type := GetDType (OperandT (2)) ;
11068 InternalError ('constant type should have been resolved')
11069 ELSIF IsArray (type)
11071 PopTtok (e, exprTok) ;
11072 PopTFDtok (Sym, Type, dim, arrayTok) ;
11073 result := MakeTemporary (exprTok, RightValue) ;
11074 PutVar (result, Type) ;
11075 PushTFtok (result, GetSType (result), exprTok) ;
11076 PushTtok (Sym, arrayTok) ;
11077 combinedTok := MakeVirtualTok (arrayTok, arrayTok, exprTok) ;
11078 PutVarConst (result, TRUE) ;
11079 BuildAssignConstant (combinedTok) ;
11080 PushTFDtok (result, GetDType (result), dim, arrayTok) ;
11081 PushTtok (e, exprTok)
11084 IF (NOT IsVar (OperandT (2))) AND (NOT IsTemporary (OperandT (2)))
11086 MetaErrorT1 (OperandTtok (2),
11087 'can only access arrays using variables or formal parameters not {%1Ead}',
11089 BuildDesignatorError ('bad array access')
11091 Sym := OperandT (2) ;
11092 Type := GetDType (Sym) ;
11093 arrayTok := OperandTtok (2) ;
11096 IF (arrayTok = UnknownTokenNo) OR (arrayTok = BuiltinTokenNo)
11098 arrayTok := GetTokenNo ()
11100 MetaErrorT0 (arrayTok, "type of array is undefined") ;
11101 BuildDesignatorError ('bad array access')
11102 ELSIF IsUnbounded (Type)
11105 ELSIF IsArray (Type)
11109 MetaErrorT1 (arrayTok,
11110 'can only index static or dynamic arrays, {%1Ead} is not an array but a {%tad}',
11112 BuildDesignatorError ('bad array access')
11114 END BuildDesignatorArray ;
11118 BuildStaticArray - Builds the array referencing for static arrays.
11119 The Stack is expected to contain:
11128 |--------------| +------------+
11129 | Sym | Type | | S | T |
11130 |--------------| |------------|
11133 PROCEDURE BuildStaticArray ;
11137 arrayTok : CARDINAL ;
11143 Type, Adr : CARDINAL ;
11145 Index := OperandT (1) ;
11146 indexTok := OperandTtok (1) ;
11147 Array := OperandT (2) ;
11148 arrayTok := OperandTtok (2) ;
11149 Type := SkipType (OperandF (2)) ;
11150 rw := OperandMergeRW (2) ;
11151 Assert (IsLegal (rw)) ;
11152 Dim := OperandD (2) ;
11154 IF GetMode (Index)=LeftValue
11156 Index := MakeRightValue (indexTok, Index, GetSType (Index))
11158 BuildRange (InitStaticArraySubscriptRangeCheck (GetArraySubscript (Type), Index, Dim)) ;
11160 (* now make Adr point to the address of the indexed element *)
11161 combinedTok := MakeVirtualTok (arrayTok, arrayTok, indexTok) ;
11162 Adr := MakeTemporary (combinedTok, LeftValue) ;
11165 (* BuildDesignatorArray may have detected des is a constant. *)
11166 PutVarConst (Adr, IsVarConst (Array))
11168 PutVarArrayRef (Adr, TRUE) ;
11170 From now on it must reference the array element by its lvalue
11171 - so we create the type of the referenced entity
11174 BackEndType := MakePointer (combinedTok, NulName) ;
11175 PutPointer (BackEndType, GetDType (Type)) ;
11176 (* PutVar(Adr, BackEndType) ; *)
11177 PutLeftValueFrontBackType (Adr, GetDType (Type), BackEndType) ;
11179 GenQuadO (combinedTok, ArrayOp, Adr, Index, Array, TRUE) ;
11180 PopN (2) ; (* remove all parameters to this procedure *)
11181 PushTFDrwtok (Adr, GetSType (Adr), Dim, rw, combinedTok)
11182 END BuildStaticArray ;
11186 calculateMultipicand - generates quadruples which calculate the
11187 multiplicand for the array at dimension, dim.
11190 PROCEDURE calculateMultipicand (tok: CARDINAL;
11191 arraySym, arrayType: CARDINAL; dim: CARDINAL) : CARDINAL ;
11193 ti, tj, tk, tl: CARDINAL ;
11195 IF dim = GetDimension (arrayType)
11197 (* ti has no type since constant *)
11198 ti := MakeTemporary (tok, ImmediateValue) ;
11199 PutVar (ti, Cardinal) ;
11200 GenQuadO (tok, ElementSizeOp, ti, arrayType, 1, TRUE)
11203 tk := MakeTemporary (tok, RightValue) ;
11204 PutVar (tk, Cardinal) ;
11205 GenHigh (tok, tk, dim, arraySym) ;
11206 tl := MakeTemporary (tok, RightValue) ;
11207 PutVar (tl, Cardinal) ;
11208 GenQuadO (tok, AddOp, tl, tk, MakeConstLit (tok, MakeKey ('1'), Cardinal), TRUE) ;
11209 tj := calculateMultipicand (tok, arraySym, arrayType, dim) ;
11210 ti := MakeTemporary (tok, RightValue) ;
11211 PutVar (ti, Cardinal) ;
11212 GenQuadO (tok, MultOp, ti, tj, tl, TRUE)
11215 END calculateMultipicand ;
11219 BuildDynamicArray - Builds the array referencing for dynamic arrays.
11220 The Stack is expected to contain:
11227 +-----------------------+
11229 |-----------------------| +---------------------------+
11230 | ArraySym | Type | Dim | | S | T | ArraySym | Dim+1 |
11231 |-----------------------| |---------------------------|
11236 S := base of ArraySym + TSIZE(Type)*Index
11238 S := S + TSIZE(Type)*Index
11242 PROCEDURE BuildDynamicArray ;
11246 indexTok : CARDINAL ;
11255 ti, tj, tk : CARDINAL ;
11258 Sym := OperandT (2) ;
11259 Type := SkipType (OperandF (2)) ;
11260 arrayTok := OperandTok (2) ;
11261 indexTok := OperandTok (1) ;
11262 combinedTok := MakeVirtualTok (arrayTok, arrayTok, indexTok) ;
11263 Dim := OperandD (2) ;
11264 rw := OperandMergeRW (2) ;
11265 Assert (IsLegal (rw)) ;
11270 Base has type address since
11271 BuildDesignatorRecord references by address.
11273 Build a record for retrieving the address of dynamic array.
11274 BuildDesignatorRecord will generate the required quadruples,
11275 therefore build sets up the stack for BuildDesignatorRecord
11276 which will generate the quads to access the record.
11279 UnboundedType := GetUnboundedRecordType (GetSType (Sym)) ;
11280 PushTFrwtok (Sym, UnboundedType, rw, arrayTok) ;
11281 PushTF (GetUnboundedAddressOffset (GetSType (Sym)),
11282 GetSType (GetUnboundedAddressOffset (GetSType (Sym)))) ;
11283 PushT (1) ; (* One record field to dereference *)
11284 BuildDesignatorRecord (combinedTok) ;
11287 (* Now actually copy Unbounded.ArrayAddress into base *)
11288 IF GetMode(PtrToBase) = LeftValue
11290 Base := MakeTemporary (arrayTok, RightValue) ;
11291 PutVar (Base, Address) ; (* has type ADDRESS *)
11292 CheckPointerThroughNil (arrayTok, PtrToBase) ;
11293 GenQuad (IndrXOp, Base, Address, PtrToBase) (* Base = *PtrToBase *)
11295 Assert (GetMode (PtrToBase) # ImmediateValue) ;
11299 (* Base already calculated previously and pushed to stack *)
11300 UnboundedType := SkipType (OperandF (2)) ;
11302 ArraySym := OperandA (2)
11304 Assert (GetSType (Sym) = Type) ;
11305 ti := calculateMultipicand (indexTok, Sym, Type, Dim) ;
11306 idx := OperandT (1) ;
11309 (* tj has no type since constant *)
11310 tj := MakeTemporary (indexTok, ImmediateValue) ;
11311 tk := MakeTemporary (indexTok, ImmediateValue) ;
11312 PutVar (tj, Cardinal) ;
11313 PutVar (tk, Cardinal)
11315 (* tj has Cardinal type since we have multiplied array indices *)
11316 tj := MakeTemporary (indexTok, RightValue) ;
11317 IF GetSType (idx) # Cardinal
11319 PushTF (RequestSym (indexTok, MakeKey ('CONVERT')), NulSym) ;
11321 PushTtok (idx, indexTok) ;
11322 PushT(2) ; (* Two parameters *)
11323 BuildConvertFunction ;
11326 PutVar (tj, Cardinal) ;
11327 tk := MakeTemporary (indexTok, RightValue) ;
11328 PutVar (tk, Cardinal)
11330 BuildRange (InitDynamicArraySubscriptRangeCheck (ArraySym, idx, Dim)) ;
11332 PushTtok (tj, indexTok) ;
11333 PushTtok (idx, indexTok) ;
11334 BuildAssignmentWithoutBounds (indexTok, FALSE, TRUE) ;
11336 GenQuad (MultOp, tk, ti, tj) ;
11337 Adr := MakeTemporary (combinedTok, LeftValue) ;
11338 PutVarArrayRef (Adr, TRUE) ;
11340 Ok must reference by address
11341 - but we contain the type of the referenced entity
11343 BackEndType := MakePointer (combinedTok, NulName) ;
11344 PutPointer (BackEndType, GetSType (Type)) ;
11346 IF Dim = GetDimension (Type)
11348 PutLeftValueFrontBackType (Adr, GetSType(Type), BackEndType) ;
11350 GenQuad (AddOp, Adr, Base, tk) ;
11352 PushTFADrwtok (Adr, GetSType(Adr), ArraySym, Dim, rw, combinedTok)
11354 (* more to index *)
11355 PutLeftValueFrontBackType (Adr, Type, BackEndType) ;
11357 GenQuad (AddOp, Adr, Base, tk) ;
11359 PushTFADrwtok (Adr, GetSType(Adr), ArraySym, Dim, rw, combinedTok)
11361 END BuildDynamicArray ;
11368 PROCEDURE DebugLocation (tok: CARDINAL; message: ARRAY OF CHAR) ;
11372 WarnStringAt (InitString (message), tok)
11374 END DebugLocation ;
11378 BuildDesignatorPointer - Builds a pointer reference.
11379 The Stack is expected to contain:
11386 +--------------+ +--------------+
11387 | Sym1 | Type1| | Sym2 | Type2|
11388 |--------------| |--------------|
11391 PROCEDURE BuildDesignatorPointer (ptrtok: CARDINAL) ;
11394 exprtok : CARDINAL ;
11397 Sym2, Type2: CARDINAL ;
11399 PopTFrwtok (Sym1, Type1, rw, exprtok) ;
11400 DebugLocation (exprtok, "expression") ;
11402 Type1 := SkipType (Type1) ;
11405 MetaErrorT1 (ptrtok, '{%1ad} has no type and therefore cannot be dereferenced by ^', Sym1)
11406 ELSIF IsUnknown (Sym1)
11408 MetaError1 ('{%1EMad} is undefined and therefore {%1ad}^ cannot be resolved', Sym1)
11409 ELSIF IsPointer (Type1)
11411 Type2 := GetSType (Type1) ;
11412 Sym2 := MakeTemporary (ptrtok, LeftValue) ;
11414 Ok must reference by address
11415 - but we contain the type of the referenced entity
11418 PutVarPointerCheck (Sym1, TRUE) ;
11419 CheckPointerThroughNil (ptrtok, Sym1) ;
11420 IF GetMode (Sym1) = LeftValue
11423 PutLeftValueFrontBackType (Sym2, Type2, Type1) ;
11424 GenQuadO (ptrtok, IndrXOp, Sym2, Type1, Sym1, FALSE) (* Sym2 := *Sym1 *)
11426 PutLeftValueFrontBackType (Sym2, Type2, NulSym) ;
11427 GenQuadO (ptrtok, BecomesOp, Sym2, NulSym, Sym1, FALSE) (* Sym2 := Sym1 *)
11429 PutVarPointerCheck (Sym2, TRUE) ; (* we should check this for *)
11430 (* Sym2 later on (pointer via NIL) *)
11431 combinedtok := MakeVirtualTok (exprtok, exprtok, ptrtok) ;
11432 PushTFrwtok (Sym2, Type2, rw, combinedtok) ;
11433 DebugLocation (combinedtok, "pointer expression")
11435 MetaError2 ('{%1ad} is not a pointer type but a {%2d}', Sym1, Type1)
11437 END BuildDesignatorPointer ;
11441 StartBuildWith - performs the with statement.
11447 | Sym | Type | Empty
11451 PROCEDURE StartBuildWith (withTok: CARDINAL) ;
11457 DebugLocation (withtok, "with") ;
11458 BuildStmtNoteTok (withTok) ;
11460 PopTFtok (Sym, Type, tok) ;
11461 DebugLocation (tok, "expression") ;
11462 Type := SkipType (Type) ;
11464 Ref := MakeTemporary (tok, LeftValue) ;
11465 PutVar (Ref, Type) ;
11466 IF GetMode (Sym) = LeftValue
11468 (* Copy LeftValue. *)
11469 GenQuadO (tok, BecomesOp, Ref, NulSym, Sym, TRUE)
11471 (* Calculate the address of Sym. *)
11472 GenQuadO (tok, AddrOp, Ref, NulSym, Sym, TRUE)
11475 PushWith (Sym, Type, Ref, tok) ;
11476 DebugLocation (tok, "with ref") ;
11479 MetaError1 ('{%1Ea} {%1d} has a no type, the {%kWITH} statement requires a variable or parameter of a {%kRECORD} type',
11481 ELSIF NOT IsRecord(Type)
11483 MetaError1 ('the {%kWITH} statement requires that {%1Ea} {%1d} be of a {%kRECORD} {%1tsa:type rather than {%1tsa}}',
11488 END StartBuildWith ;
11492 EndBuildWith - terminates the innermost with scope.
11495 PROCEDURE EndBuildWith ;
11505 PushWith - pushes sym and type onto the with stack. It checks for
11506 previous declaration of this record type.
11509 PROCEDURE PushWith (Sym, Type, Ref, Tok: CARDINAL) ;
11516 n := NoOfItemsInStackAddress(WithStack) ;
11517 i := 1 ; (* Top of the stack. *)
11519 (* Search for other declarations of the with using Type. *)
11520 f := PeepAddress(WithStack, i) ;
11521 IF f^.RecordSym=Type
11524 'cannot have nested {%kWITH} statements referencing the same {%kRECORD} {%1Ead}',
11526 MetaErrorT1 (f^.RecordTokPos,
11527 'cannot have nested {%kWITH} statements referencing the same {%kRECORD} {%1Ead}',
11536 RecordType := Type ;
11539 RecordTokPos := Tok
11541 PushAddress (WithStack, f)
11545 PROCEDURE PopWith ;
11549 f := PopAddress (WithStack) ;
11555 CheckWithReference - performs the with statement.
11560 +------------+ +------------+
11561 | Sym | Type | | Sym | Type |
11562 |------------| |------------|
11565 PROCEDURE CheckWithReference ;
11570 Sym, Type: CARDINAL ;
11572 n := NoOfItemsInStackAddress(WithStack) ;
11573 IF (n>0) AND (NOT SuppressWith)
11575 PopTFrwtok (Sym, Type, rw, tokpos) ;
11576 Assert (tokpos # UnknownTokenNo) ;
11577 (* inner WITH always has precidence *)
11578 i := 1 ; (* top of stack *)
11580 (* WriteString('Checking for a with') ; *)
11581 f := PeepAddress (WithStack, i) ;
11583 IF IsRecordField (Sym) AND (GetRecord (GetParent (Sym)) = RecordType)
11587 MetaError1('record field {%1Dad} was declared as unused by a pragma', Sym)
11589 (* Fake a RecordSym.op *)
11590 PushTFrwtok (RecordRef, RecordType, rw, RecordTokPos) ;
11591 PushTFtok (Sym, Type, tokpos) ;
11592 BuildAccessWithField ;
11593 PopTFrw (Sym, Type, rw) ;
11594 i := n+1 (* Finish loop. *)
11600 PushTFrwtok (Sym, Type, rw, tokpos)
11602 END CheckWithReference ;
11606 BuildAccessWithField - similar to BuildDesignatorRecord except it
11607 does not perform the address operation.
11608 The address will have been computed at the
11609 beginning of the WITH statement.
11610 It also stops the GenQuad procedure from examining the
11619 | Field | Type1| <- Ptr
11620 |-------|------| +-------------+
11621 | Adr | Type2| | Sym | Type1|
11622 |--------------| |-------------|
11625 PROCEDURE BuildAccessWithField ;
11627 rectok, fieldtok : CARDINAL ;
11628 OldSuppressWith : BOOLEAN ;
11631 Record, RecordType,
11634 OldSuppressWith := SuppressWith ;
11635 SuppressWith := TRUE ;
11637 now the WITH cannot look at the stack of outstanding WITH records.
11639 PopTFtok (Field, FieldType, fieldtok) ;
11640 PopTFrwtok (Record, RecordType, rw, rectok) ;
11642 Ref := MakeComponentRef (MakeComponentRecord (fieldtok,
11643 RightValue, Record), Field) ;
11644 PutVarConst (Ref, IsReadOnly (Record)) ;
11645 GenQuadO (fieldtok,
11646 RecordFieldOp, Ref, Record, Field, TRUE) ;
11648 PushTFrwtok (Ref, FieldType, rw, fieldtok) ;
11649 SuppressWith := OldSuppressWith
11650 END BuildAccessWithField ;
11654 BuildNulExpression - Builds a nul expression on the stack.
11660 Empty +------------+
11665 PROCEDURE BuildNulExpression ;
11668 END BuildNulExpression ;
11672 BuildTypeForConstructor - pushes the type implied by the current constructor.
11673 If no constructor is currently being built then
11674 it Pushes a Bitset type.
11677 PROCEDURE BuildTypeForConstructor ;
11679 c: ConstructorFrame ;
11681 IF NoOfItemsInStackAddress(ConstructorStack)=0
11685 c := PeepAddress(ConstructorStack, 1) ;
11687 IF IsArray(type) OR IsSet(type)
11689 PushT(GetSType(type))
11690 ELSIF IsRecord(type)
11692 PushT(GetSType(GetNth(type, index)))
11694 MetaError1('{%1ad} is not a set, record or array type which is expected when constructing an aggregate entity',
11699 END BuildTypeForConstructor ;
11703 BuildSetStart - Pushes a Bitset type on the stack.
11711 Empty +--------------+
11716 PROCEDURE BuildSetStart ;
11719 END BuildSetStart ;
11723 BuildSetEnd - pops the set value and type from the stack
11724 and pushes the value,type pair.
11730 | Set Value | <- Ptr
11731 |--------------| +--------------+
11732 | Set Type | | Value | Type |
11733 |--------------| |--------------|
11736 PROCEDURE BuildSetEnd ;
11748 BuildEmptySet - Builds an empty set on the stack.
11756 +-----------+ |-------------|
11757 | SetType | | SetType |
11758 |-----------| |-------------|
11762 PROCEDURE BuildEmptySet ;
11769 PopT(Type) ; (* type of set we are building *)
11770 tok := GetTokenNo () ;
11771 IF (Type=NulSym) AND Pim
11773 (* allowed generic {} in PIM Modula-2 *)
11774 ELSIF IsUnknown(Type)
11776 n := GetSymName(Type) ;
11777 WriteFormat1('set type %a is undefined', n) ;
11779 ELSIF NOT IsSet(SkipType(Type))
11781 n := GetSymName(Type) ;
11782 WriteFormat1('expecting a set type %a', n) ;
11785 Type := SkipType(Type) ;
11786 Assert((Type#NulSym))
11788 NulSet := MakeTemporary(tok, ImmediateValue) ;
11789 PutVar(NulSet, Type) ;
11790 PutConstSet(NulSet) ;
11791 IF CompilerDebugging
11793 n := GetSymName(Type) ;
11794 printf1('set type = %a\n', n)
11796 PushNulSet(Type) ; (* onto the ALU stack *)
11797 PopValue(NulSet) ; (* ALU -> symbol table *)
11799 (* and now construct the M2Quads stack as defined by the comments above *)
11802 IF CompilerDebugging
11804 n := GetSymName(Type) ;
11805 printf2('Type = %a (%d) built empty set\n', n, Type) ;
11806 DisplayStack (* Debugging info *)
11808 END BuildEmptySet ;
11812 BuildInclRange - includes a set range with a set.
11824 |------------| +-------------------+
11825 | Set Value | | Value + {El1..El2}|
11826 |------------| |-------------------|
11828 No quadruples produced as the range info is contained within
11832 PROCEDURE BuildInclRange ;
11841 IF NOT IsConstSet(value)
11843 n := GetSymName(el1) ;
11844 WriteFormat1('can only add bit ranges to a constant set, %a is not a constant set', n)
11846 IF IsConst(el1) AND IsConst(el2)
11848 PushValue(value) ; (* onto ALU stack *)
11849 AddBitRange(GetTokenNo(), el1, el2) ;
11850 PopValue(value) (* ALU -> symboltable *)
11852 IF NOT IsConst(el1)
11854 n := GetSymName(el1) ;
11855 WriteFormat1('must use constants as ranges when defining a set constant, problem with the low value %a', n)
11857 IF NOT IsConst(el2)
11859 n := GetSymName(el2) ;
11860 WriteFormat1('must use constants as ranges when defining a set constant, problem with the high value %a', n)
11864 END BuildInclRange ;
11868 BuildInclBit - includes a bit into the set.
11877 |------------| +------------+
11878 | Value | | Value |
11879 |------------| |------------|
11883 PROCEDURE BuildInclBit ;
11886 el, value, t: CARDINAL ;
11890 tok := GetTokenNo () ;
11893 PushValue(value) ; (* onto ALU stack *)
11895 PopValue(value) (* ALU -> symboltable *)
11897 IF GetMode(el)=LeftValue
11899 t := MakeTemporary(tok, RightValue) ;
11900 PutVar(t, GetSType(el)) ;
11901 CheckPointerThroughNil (tok, el) ;
11902 doIndrX(tok, t, el) ;
11907 (* move constant into a variable to achieve the include *)
11908 t := MakeTemporary(tok, RightValue) ;
11909 PutVar(t, GetSType(value)) ;
11910 GenQuad(BecomesOp, t, NulSym, value) ;
11913 GenQuad(InclOp, value, NulSym, el)
11923 PROCEDURE PushConstructor (sym: CARDINAL) ;
11925 c: ConstructorFrame ;
11929 type := SkipType(sym) ;
11932 PushAddress(ConstructorStack, c)
11933 END PushConstructor ;
11937 PopConstructor - removes the top constructor from the top of stack.
11940 PROCEDURE PopConstructor ;
11942 c: ConstructorFrame ;
11944 c := PopAddress (ConstructorStack) ;
11946 END PopConstructor ;
11950 NextConstructorField - increments the top of constructor stacks index by one.
11953 PROCEDURE NextConstructorField ;
11955 c: ConstructorFrame ;
11957 c := PeepAddress(ConstructorStack, 1) ;
11959 END NextConstructorField ;
11963 SilentBuildConstructor - places NulSym into the constructor fifo queue.
11966 PROCEDURE SilentBuildConstructor ;
11968 PutConstructorIntoFifoQueue (NulSym)
11969 END SilentBuildConstructor ;
11973 BuildConstructor - builds a constructor.
11984 PROCEDURE BuildConstructor (tokcbrpos: CARDINAL) ;
11990 PopTtok (type, tok) ;
11991 constValue := MakeTemporary (tok, ImmediateValue) ;
11992 PutVar (constValue, type) ;
11993 PutConstructor (constValue) ;
11994 PushValue (constValue) ;
11997 MetaErrorT0 (tokcbrpos,
11998 '{%E}constructor requires a type before the opening {')
12000 ChangeToConstructor (tok, type) ;
12001 PutConstructorFrom (constValue, type) ;
12002 PopValue (constValue) ;
12003 PutConstructorIntoFifoQueue (constValue)
12005 PushConstructor (type)
12006 END BuildConstructor ;
12010 SilentBuildConstructorStart - removes an entry from the constructor fifo queue.
12013 PROCEDURE SilentBuildConstructorStart ;
12015 constValue: CARDINAL ;
12017 GetConstructorFromFifoQueue (constValue)
12018 END SilentBuildConstructorStart ;
12022 BuildConstructorStart - builds a constructor.
12028 +------------+ +----------------+
12029 | Type | | ConstructorSym |
12030 |------------+ |----------------|
12033 PROCEDURE BuildConstructorStart (cbratokpos: CARDINAL) ;
12038 PopT (type) ; (* we ignore the type as we already have the constructor symbol from pass C *)
12039 GetConstructorFromFifoQueue (constValue) ;
12040 IF type # GetSType (constValue)
12042 MetaErrorT3 (cbratokpos,
12043 '{%E}the constructor type is {%1ad} and this is different from the constant {%2ad} which has a type {%2tad}',
12044 type, constValue, constValue)
12046 PushTtok (constValue, cbratokpos) ;
12047 PushConstructor (type)
12048 END BuildConstructorStart ;
12052 BuildConstructorEnd - removes the current constructor frame from the
12053 constructor stack (it does not effect the quad
12059 +------------+ +------------+
12060 | const | | const |
12061 |------------| |------------|
12064 PROCEDURE BuildConstructorEnd (cbratokpos: CARDINAL) ;
12067 value, valtok: CARDINAL ;
12069 PopTtok (value, valtok) ;
12074 typetok := OperandTtok (1)
12076 valtok := MakeVirtualTok (typetok, typetok, cbratokpos) ;
12077 PutDeclared (valtok, value) ;
12078 PushTtok (value, valtok) ; (* Use valtok as we now know it was a constructor. *)
12080 (* ; ErrorStringAt (Mark (InitString ('aggregate constant')), valtok) *)
12081 END BuildConstructorEnd ;
12085 AddFieldTo - adds field, e, to, value.
12088 PROCEDURE AddFieldTo (value, e: CARDINAL) : CARDINAL ;
12090 IF IsSet(GetDType(value))
12092 PutConstSet(value) ;
12099 AddField(GetTokenNo(), e) ;
12107 BuildComponentValue - builds a component value.
12114 +------------+ +------------+
12115 | const | | const |
12116 |------------| |------------|
12119 PROCEDURE BuildComponentValue ;
12122 e1, e2 : CARDINAL ;
12130 IF nuldotdot=NulTok
12134 PushT(AddFieldTo(const, e1))
12140 AddBitRange(GetTokenNo(), e1, e2) ;
12147 IF nuldotdot=NulTok
12152 AddElements(GetTokenNo(), e2, e1) ;
12159 WriteFormat0('the constant must be an array constructor or a set constructor but not both') ;
12163 END BuildComponentValue ;
12167 RecordOp - Records the operator passed on the stack.
12168 Checks for AND operator or OR operator
12169 if either of these operators are found then BackPatching
12171 The Expected Stack:
12176 +-------------+ +-------------+
12177 | OperatorTok | | OperatorTok |
12178 |-------------| |-------------|
12179 | t | f | | t | f |
12180 |-------------| |-------------|
12183 If OperatorTok=AndTok
12185 BackPatch(f, NextQuad)
12186 Elsif OperatorTok=OrTok
12188 BackPatch(t, NextQuad)
12192 PROCEDURE RecordOp ;
12198 PopTtok(Op, tokno) ;
12199 IF (Op=AndTok) OR (Op=AmbersandTok)
12203 BackPatch(t, NextQuad) ;
12209 BackPatch(f, NextQuad) ;
12212 PushTtok(Op, tokno)
12217 CheckLogicalOperator - returns a logical operator if the operands imply
12218 a logical operation should be performed.
12221 PROCEDURE CheckLogicalOperator (Tok: Name; left, lefttype: CARDINAL) : Name ;
12223 IF (Tok=PlusTok) OR (Tok=TimesTok) OR (Tok=DivideTok) OR (Tok=MinusTok)
12225 (* --fixme-- when we add complex arithmetic, we must check constructor is not a complex constant. *)
12226 IF ((lefttype#NulSym) AND IsSet(SkipType(lefttype))) OR
12227 IsConstSet(left) OR IsConstructor(left)
12231 RETURN( LogicalOrTok )
12232 ELSIF Tok=DivideTok
12234 RETURN( LogicalXorTok )
12237 RETURN( LogicalAndTok )
12240 RETURN( LogicalDifferenceTok )
12245 END CheckLogicalOperator ;
12249 doCheckGenericNulSet - checks to see whether e1 is a generic nul set and if so it alters it
12250 to the nul set of t2.
12254 PROCEDURE doCheckGenericNulSet (e1: CARDINAL; VAR t1: CARDINAL; t2: CARDINAL) ;
12260 MetaError2 ('incompatibility between a set constant {%1Ea} of type {%1tsa} and an object of type {%2sa}',
12264 IF IsGenericNulSet ()
12272 END doCheckGenericNulSet ;
12277 CheckGenericNulSet - if e1 or e2 is the generic nul set then
12278 alter it to the nul set of the other operands type.
12282 PROCEDURE CheckGenericNulSet (e1, e2: CARDINAL; VAR t1, t2: CARDINAL) ;
12286 doCheckGenericNulSet(e1, t1, t2) ;
12287 doCheckGenericNulSet(e2, t2, t1)
12289 END CheckGenericNulSet ;
12294 CheckDivModRem - initiates calls to check the divisor for DIV, MOD, REM
12298 PROCEDURE CheckDivModRem (TokPos: CARDINAL; tok: Name; d, e: CARDINAL) ;
12302 BuildRange (InitWholeZeroDivisionCheck (TokPos, d, e))
12305 BuildRange (InitWholeZeroDivisionCheck (TokPos, d, e))
12308 BuildRange (InitWholeZeroRemainderCheck (TokPos, d, e))
12310 END CheckDivModRem ;
12314 doConvert - convert, sym, to a new symbol with, type.
12315 Return the new symbol.
12318 PROCEDURE doConvert (type: CARDINAL; sym: CARDINAL) : CARDINAL ;
12320 IF GetSType(sym)#type
12322 PushTF(Convert, NulSym) ;
12325 PushT(2) ; (* Two parameters *)
12326 BuildConvertFunction ;
12334 BuildBinaryOp - Builds a binary operation from the quad stack.
12335 Be aware that this procedure will check for
12336 the overloading of the bitset operators + - \ *.
12337 So do NOT call this procedure if you are building
12338 a reference to an array which has a bitset type or
12339 the address arithmetic will be wrongly coersed into
12342 The Stack is expected to contain:
12352 | Operator | <- Ptr
12353 |------------| +------------+
12354 | Sym2 | | Temporary |
12355 |------------| |------------|
12358 Quadruples Produced
12360 q Operator Temporary Sym1 Sym2
12374 |------------| +------------+
12375 | T2 | F2 | | T1+T2| F1 |
12376 |------------| |------------|
12379 Quadruples Produced
12383 PROCEDURE BuildBinaryOp ;
12385 doBuildBinaryOp (TRUE, TRUE)
12386 END BuildBinaryOp ;
12390 doBuildBinaryOp - build the binary op, with or without type
12394 PROCEDURE doBuildBinaryOp (checkTypes, checkOverflow: BOOLEAN) ;
12404 lefttype, righttype,
12406 leftpos, rightpos : CARDINAL ;
12409 Operator := OperandT (2) ;
12410 IF Operator = OrTok
12414 PopTtok (Operator, OperatorPos) ;
12417 PushBool (Merge (t1, t2), f1)
12418 ELSIF (Operator = AndTok) OR (Operator = AmbersandTok)
12422 PopTtok (Operator, OperatorPos) ;
12425 PushBool (t1, Merge (f1, f2))
12427 PopTFrwtok (right, righttype, rightrw, rightpos) ;
12428 PopTtok (Operator, OperatorPos) ;
12429 PopTFrwtok (left, lefttype, leftrw, leftpos) ;
12430 MarkAsRead (rightrw) ;
12431 MarkAsRead (leftrw) ;
12432 NewOp := CheckLogicalOperator (Operator, (* right, righttype, *) left, lefttype) ;
12433 IF NewOp = Operator
12436 BinaryOps and UnaryOps only work with immediate and
12437 offset addressing. This is fine for calculating
12438 array and record offsets but we need to get the real
12439 values to perform normal arithmetic. Not address
12442 However the set operators will dereference LValues
12443 (to optimize large set arithemetic)
12445 IF GetMode (right) = LeftValue
12447 value := MakeTemporary (rightpos, RightValue) ;
12448 PutVar (value, righttype) ;
12449 CheckPointerThroughNil (rightpos, right) ;
12450 doIndrX (rightpos, value, right) ;
12453 IF GetMode (left) = LeftValue
12455 value := MakeTemporary (leftpos, RightValue) ;
12456 PutVar (value, lefttype) ;
12457 CheckPointerThroughNil (leftpos, left) ;
12458 doIndrX (leftpos, value, left) ;
12462 (* CheckForGenericNulSet(e1, e2, t1, t2) *)
12464 IF (Operator = PlusTok) AND IsConstString(left) AND IsConstString(right)
12466 (* handle special addition for constant strings *)
12467 s := InitStringCharStar (KeyToCharStar (GetString (left))) ;
12468 s := ConCat (s, Mark (InitStringCharStar (KeyToCharStar (GetString (right))))) ;
12469 value := MakeConstLitString (OperatorPos, makekey (string (s))) ;
12470 s := KillString (s)
12472 OldPos := OperatorPos ;
12473 OperatorPos := MakeVirtualTok (OperatorPos, leftpos, rightpos) ;
12476 BuildRange (InitTypesExpressionCheck (OperatorPos, left, right, FALSE, FALSE))
12478 value := MakeTemporaryFromExpressions (OperatorPos,
12480 AreConstant (IsConst (left) AND IsConst (right))) ;
12482 CheckDivModRem (OperatorPos, NewOp, value, right) ;
12486 s := InitStringCharStar (KeyToCharStar (GetTokenName (Operator))) ;
12487 WarnStringAt (s, OldPos) ;
12488 s := InitString ('left') ;
12489 WarnStringAt (s, leftpos) ;
12490 s := InitString ('right') ;
12491 WarnStringAt (s, rightpos) ;
12492 s := InitString ('caret') ;
12493 WarnStringAt (s, OldPos) ;
12494 s := InitString ('combined') ;
12495 WarnStringAt (s, OperatorPos) ;
12496 (* MetaErrorT1 (GetDeclaredMod (t), 'in binary with a {%1a}', t) *)
12498 GenQuadOtok (OperatorPos, MakeOp (NewOp), value, left, right, checkOverflow,
12499 OperatorPos, leftpos, rightpos)
12501 PushTFtok (value, GetSType (value), OperatorPos)
12503 END doBuildBinaryOp ;
12507 BuildUnaryOp - Builds a unary operation from the quad stack.
12508 The Stack is expected to contain:
12517 |------------| +------------+
12518 | Operator | | Temporary | <- Ptr
12519 |------------| |------------|
12522 Quadruples Produced
12524 q Operator Temporary _ Sym
12528 PROCEDURE BuildUnaryOp ;
12531 tokpos : CARDINAL ;
12535 SymT, r, t: CARDINAL ;
12537 PopTrwtok (Sym, r, sympos) ;
12538 PopTtok (Tok, tokpos) ;
12542 type := NegateType (GetSType (Sym) (* , sympos *) ) ;
12543 tokpos := MakeVirtualTok (tokpos, tokpos, sympos) ;
12545 t := MakeTemporary (tokpos, AreConstant(IsConst(Sym))) ;
12549 variables must have a type and REAL/LONGREAL constants must
12553 IF NOT IsConst(Sym)
12555 IF (type#NulSym) AND IsSet(SkipType(type))
12557 (* do not dereference set variables *)
12558 ELSIF GetMode(Sym)=LeftValue
12560 (* dereference symbols which are not sets and which are variables *)
12562 SymT := MakeTemporary (sympos, RightValue) ;
12563 PutVar (SymT, GetSType (Sym)) ;
12564 CheckPointerThroughNil (sympos, Sym) ;
12565 doIndrX (sympos, SymT, Sym) ;
12569 GenQuadO (tokpos, NegateOp, t, NulSym, Sym, TRUE) ;
12570 PushTtok (t, tokpos)
12573 tokpos := MakeVirtualTok (tokpos, tokpos, sympos) ;
12574 PushTrwtok (Sym, r, tokpos)
12576 MetaErrorNT1 (tokpos,
12577 'expecting an unary operator, seen {%Ek%a}', Tok)
12583 AreConstant - returns immediate addressing mode if b is true else
12584 offset mode is returned. b determines whether the
12585 operands are all constant - in which case we can use
12586 a constant temporary variable.
12589 PROCEDURE AreConstant (b: BOOLEAN) : ModeOfAddr ;
12593 RETURN ImmediateValue
12601 ConvertBooleanToVariable - converts a BoolStack(i) from a Boolean True|False
12602 exit pair into a variable containing the value TRUE or
12603 FALSE. The parameter, i, is relative to the top
12607 PROCEDURE ConvertBooleanToVariable (tok: CARDINAL; i: CARDINAL) ;
12612 Assert (IsBoolean (i)) ;
12614 need to convert it to a variable containing the result.
12615 Des will be a boolean type
12617 Des := MakeTemporary (tok, RightValue) ;
12618 PutVar (Des, Boolean) ;
12619 PushTtok (Des, tok) ; (* we have just increased the stack so we must use i+1 *)
12620 f := PeepAddress (BoolStack, i+1) ;
12621 PushBool (f^.TrueExit, f^.FalseExit) ;
12622 BuildAssignmentWithoutBounds (tok, FALSE, TRUE) ; (* restored stack *)
12623 f := PeepAddress (BoolStack, i) ;
12625 TrueExit := Des ; (* alter Stack(i) to contain the variable *)
12626 FalseExit := Boolean ;
12627 BooleanOp := FALSE ; (* no longer a Boolean True|False pair *)
12628 Unbounded := NulSym ;
12630 ReadWrite := NulSym ;
12632 Annotation := KillString (Annotation) ;
12633 Annotation := InitString ('%1s(%1d)|%2s(%2d)||boolean var|type')
12635 END ConvertBooleanToVariable ;
12639 BuildBooleanVariable - tests to see whether top of stack is a boolean
12640 conditional and if so it converts it into a boolean
12644 PROCEDURE BuildBooleanVariable ;
12648 ConvertBooleanToVariable (OperandTtok (1), 1)
12650 END BuildBooleanVariable ;
12654 BuildRelOpFromBoolean - builds a relational operator sequence of quadruples
12655 instead of using a temporary boolean variable.
12656 This function can only be used when we perform
12657 the following translation:
12659 (a=b) # (c=d) alternatively (a=b) = (c=d)
12662 it only allows # = to be used as >= <= > < all
12663 assume a particular value for TRUE and FALSE.
12664 (In which case the user should specify ORD)
12671 q+2 if r2 op3 op4 t1
12674 after (in case of =)
12676 q if r1 op1 op2 q+2
12678 q+2 if r2 op3 op4 t
12680 q+4 if r2 op3 op4 f
12683 after (in case of #)
12685 q if r1 op1 op2 q+2
12687 q+2 if r2 op3 op4 f
12689 q+4 if r2 op3 op4 t
12692 The Stack is expected to contain:
12702 | Operator | <- Ptr
12703 |------------| +------------+
12704 | t2 | f2 | | t | f |
12705 |------------| |------------|
12710 PROCEDURE BuildRelOpFromBoolean (tokpos: CARDINAL) ;
12717 Assert (IsBoolean (1) AND IsBoolean (3)) ;
12718 IF OperandT (2) = EqualTok
12720 (* are the two boolean expressions the same? *)
12724 (* give the false exit a second chance *)
12725 BackPatch (t2, t1) ; (* q if _ _ q+2 *)
12726 BackPatch (f2, NextQuad) ; (* q+1 if _ _ q+4 *)
12727 Assert (NextQuad = f1+1) ;
12730 GenQuadO (tokpos, Operator, Operand1, Operand2, 0, FALSE)
12732 GenQuadO (tokpos, GotoOp, NulSym, NulSym, 0, FALSE) ;
12733 PushBool (Merge (NextQuad-1, t1), Merge (NextQuad-2, f1))
12734 ELSIF (OperandT (2) = HashTok) OR (OperandT (2) = LessGreaterTok)
12736 (* are the two boolean expressions the different? *)
12740 (* give the false exit a second chance *)
12741 BackPatch (t2, t1) ; (* q if _ _ q+2 *)
12742 BackPatch (f2, NextQuad) ; (* q+1 if _ _ q+4 *)
12743 Assert (NextQuad = f1+1) ;
12746 GenQuadO (tokpos, Operator, Operand1, Operand2, 0, FALSE)
12748 GenQuadO (tokpos, GotoOp, NulSym, NulSym, 0, FALSE) ;
12749 PushBool (Merge (NextQuad-2, f1), Merge (NextQuad-1, t1))
12751 MetaError0 ('only allowed to use the relation operators {%Ek=} {%Ek#} rather than {%Ek<} or {%Ek>} on {%EkBOOLEAN} expressions as these do not imply an ordinal value for {%kTRUE} or {%kFALSE}')
12753 END BuildRelOpFromBoolean ;
12757 CheckVariableOrConstantOrProcedure - checks to make sure sym is a variable, constant or procedure.
12760 PROCEDURE CheckVariableOrConstantOrProcedure (tokpos: CARDINAL; sym: CARDINAL) ;
12764 type := GetSType (sym) ;
12767 MetaErrorT1 (tokpos, '{%1EUad} has not been declared', sym) ;
12768 UnknownReported (sym)
12769 ELSIF IsPseudoSystemFunction (sym) OR IsPseudoBaseFunction (sym)
12771 MetaErrorT1 (tokpos,
12772 '{%1Ead} expected a variable, procedure, constant or expression, not an intrinsic procedure function',
12774 ELSIF (NOT IsConst(sym)) AND (NOT IsVar(sym)) AND
12775 (NOT IsProcedure(sym)) AND
12776 (NOT IsTemporary(sym)) AND (NOT MustNotCheckBounds)
12778 MetaErrorsT1 (tokpos,
12779 '{%1Ead} expected a variable, procedure, constant or expression',
12780 'and it was declared as a {%1Dd}', sym) ;
12781 ELSIF (type#NulSym) AND IsArray(type)
12783 MetaErrorsT1 (tokpos,
12784 '{%1EU} not expecting an array variable as an operand for either comparison or binary operation',
12785 'it was declared as a {%1Dd}', sym)
12786 ELSIF IsConstString(sym) AND (GetStringLength(sym)>1)
12788 MetaErrorT1 (tokpos,
12789 '{%1EU} not expecting a string constant as an operand for either comparison or binary operation',
12792 END CheckVariableOrConstantOrProcedure ;
12796 BuildRelOp - Builds a relative operation from the quad stack.
12797 The Stack is expected to contain:
12806 |------------| <- Ptr
12808 |------------| +------------+
12810 |------------| |------------|
12813 Quadruples Produced
12815 q IFOperator e2 e1 TrueExit ; e2 e1 since
12816 q+1 GotoOp FalseExit ; relation > etc
12820 PROCEDURE BuildRelOp (optokpos: CARDINAL) ;
12824 leftpos : CARDINAL ;
12827 rightType, leftType,
12828 right, left : CARDINAL ;
12831 IF CompilerDebugging
12833 DisplayStack (* Debugging info *)
12835 IF IsBoolean (1) AND IsBoolean (3)
12838 we allow # and = to be used with Boolean expressions.
12839 we do not allow > < >= <= though
12841 BuildRelOpFromBoolean (optokpos)
12845 ConvertBooleanToVariable (OperandTtok (1), 1)
12849 ConvertBooleanToVariable (OperandTtok (3), 3)
12851 PopTFtok (right, rightType, rightpos) ;
12853 PopTFtok (left, leftType, leftpos) ;
12855 CheckVariableOrConstantOrProcedure (rightpos, right) ;
12856 CheckVariableOrConstantOrProcedure (leftpos, left) ;
12857 combinedTok := MakeVirtualTok (optokpos, leftpos, rightpos) ;
12859 IF (left#NulSym) AND (right#NulSym)
12861 (* BuildRange will check the expression later on once gcc knows about all data types. *)
12862 BuildRange (InitTypesExpressionCheck (combinedTok, left, right, TRUE,
12866 (* Must dereference LeftValue operands. *)
12867 IF GetMode(right) = LeftValue
12869 t := MakeTemporary (rightpos, RightValue) ;
12870 PutVar(t, GetSType(right)) ;
12871 CheckPointerThroughNil (rightpos, right) ;
12872 doIndrX (rightpos, t, right) ;
12875 IF GetMode(left) = LeftValue
12877 t := MakeTemporary (leftpos, RightValue) ;
12878 PutVar (t, GetSType (left)) ;
12879 CheckPointerThroughNil (leftpos, left) ;
12880 doIndrX (leftpos, t, left) ;
12886 s := InitStringCharStar (KeyToCharStar (GetTokenName (Op))) ;
12887 WarnStringAt (s, optokpos) ;
12888 s := InitString ('left') ;
12889 WarnStringAt (s, leftpos) ;
12890 s := InitString ('right') ;
12891 WarnStringAt (s, rightpos) ;
12892 s := InitString ('caret') ;
12893 WarnStringAt (s, optokpos) ;
12894 s := InitString ('combined') ;
12895 WarnStringAt (s, combinedTok)
12898 GenQuadOtok (combinedTok, MakeOp (Op), left, right, 0, FALSE,
12899 leftpos, rightpos, UnknownTokenNo) ; (* True Exit *)
12900 GenQuadO (combinedTok, GotoOp, NulSym, NulSym, 0, FALSE) ; (* False Exit *)
12901 PushBool (NextQuad-2, NextQuad-1)
12907 BuildNot - Builds a NOT operation from the quad stack.
12908 The Stack is expected to contain:
12915 +------------+ +------------+
12916 | t | f | | f | t |
12917 |------------| |------------|
12920 PROCEDURE BuildNot (notTokPos: CARDINAL) ;
12923 exprTokPos : CARDINAL ;
12927 PopBooltok (t, f, exprTokPos) ;
12928 combinedTok := MakeVirtualTok (notTokPos, notTokPos, exprTokPos) ;
12929 PushBooltok (f, t, combinedTok)
12934 MakeOp - returns the equalent quadruple operator to a token, t.
12937 PROCEDURE MakeOp (t: Name) : QuadOperator ;
12953 RETURN( DivTruncOp )
12956 RETURN( ModTruncOp )
12965 RETURN( IfNotEquOp )
12966 ELSIF t=LessGreaterTok
12968 RETURN( IfNotEquOp )
12969 ELSIF t=GreaterEqualTok
12971 RETURN( IfGreEquOp )
12972 ELSIF t=LessEqualTok
12974 RETURN( IfLessEquOp )
12987 ELSIF t=LogicalOrTok
12989 RETURN( LogicalOrOp )
12990 ELSIF t=LogicalAndTok
12992 RETURN( LogicalAndOp )
12993 ELSIF t=LogicalXorTok
12995 RETURN( LogicalXorOp )
12996 ELSIF t=LogicalDifferenceTok
12998 RETURN( LogicalDiffOp )
13000 InternalError('binary operation not implemented yet')
13006 GenQuadO - generate a quadruple with Operation, Op1, Op2, Op3, overflow.
13009 PROCEDURE GenQuadO (TokPos: CARDINAL;
13010 Operation: QuadOperator;
13011 Op1, Op2, Op3: CARDINAL; overflow: BOOLEAN) ;
13013 GenQuadOTrash (TokPos, Operation, Op1, Op2, Op3, overflow, NulSym)
13018 GenQuadOTrash - generate a quadruple with Operation, Op1, Op2, Op3, overflow.
13021 PROCEDURE GenQuadOTrash (TokPos: CARDINAL;
13022 Operation: QuadOperator;
13023 Op1, Op2, Op3: CARDINAL;
13024 overflow: BOOLEAN; trash: CARDINAL) ;
13028 (* WriteString('Potential Quad: ') ; *)
13029 IF QuadrupleGeneration
13033 f := GetQF (NextQuad-1) ;
13034 f^.Next := NextQuad
13036 PutQuadO (NextQuad, Operation, Op1, Op2, Op3, overflow) ;
13037 f := GetQF (NextQuad) ;
13041 LineNo := GetLineNo () ;
13042 IF TokPos = UnknownTokenNo
13044 TokenNo := GetTokenNo ()
13049 IF NextQuad=BreakAtQuad
13053 (* DisplayQuad(NextQuad) ; *)
13056 END GenQuadOTrash ;
13060 GetQuadTrash - return the symbol associated with the trashed operand.
13063 PROCEDURE GetQuadTrash (quad: CARDINAL) : CARDINAL ;
13067 f := GetQF (quad) ;
13068 LastQuadNo := quad ;
13074 GenQuad - Generate a quadruple with Operation, Op1, Op2, Op3.
13077 PROCEDURE GenQuad (Operation: QuadOperator;
13078 Op1, Op2, Op3: CARDINAL) ;
13080 GenQuadO (UnknownTokenNo, Operation, Op1, Op2, Op3, TRUE)
13085 GenQuadOtok - generate a quadruple with Operation, Op1, Op2, Op3, overflow.
13088 PROCEDURE GenQuadOtok (TokPos: CARDINAL;
13089 Operation: QuadOperator;
13090 Op1, Op2, Op3: CARDINAL; overflow: BOOLEAN;
13091 Op1Pos, Op2Pos, Op3Pos: CARDINAL) ;
13095 (* WriteString('Potential Quad: ') ; *)
13096 IF QuadrupleGeneration
13100 f := GetQF (NextQuad-1) ;
13101 f^.Next := NextQuad
13103 PutQuadO (NextQuad, Operation, Op1, Op2, Op3, overflow) ;
13104 f := GetQF (NextQuad) ;
13107 LineNo := GetLineNo () ;
13108 IF TokPos = UnknownTokenNo
13110 TokenNo := GetTokenNo ()
13118 IF NextQuad=BreakAtQuad
13122 (* DisplayQuad(NextQuad) ; *)
13129 DisplayQuadList - displays all quads.
13132 PROCEDURE DisplayQuadList ;
13137 printf0('Quadruples:\n') ;
13144 END DisplayQuadList ;
13148 DisplayQuadRange - displays all quads in list range, start..end.
13151 PROCEDURE DisplayQuadRange (scope: CARDINAL; start, end: CARDINAL) ;
13155 printf1 ('Quadruples for scope: %d\n', scope) ;
13156 WHILE (start <= end) AND (start # 0) DO
13157 DisplayQuad (start) ;
13158 f := GetQF (start) ;
13161 END DisplayQuadRange ;
13165 BackPatch - Makes each of the quadruples on the list pointed to by
13166 StartQuad, take quadruple Value as a target.
13169 PROCEDURE BackPatch (QuadNo, Value: CARDINAL) ;
13174 IF QuadrupleGeneration
13177 f := GetQF (QuadNo) ;
13179 i := Operand3 ; (* Next Link along the BackPatch *)
13180 ManipulateReference (QuadNo, Value) (* Filling in the BackPatch. *)
13189 Merge - joins two quad lists, QuadList2 to the end of QuadList1.
13190 A QuadList of value zero is a nul list.
13193 PROCEDURE Merge (QuadList1, QuadList2: CARDINAL) : CARDINAL ;
13200 RETURN( QuadList2 )
13203 RETURN( QuadList1 )
13211 ManipulateReference(j, QuadList2) ;
13212 RETURN( QuadList1 )
13218 Annotate - annotate the top of stack.
13221 PROCEDURE Annotate (a: ARRAY OF CHAR) ;
13225 IF DebugStackOn AND CompilerDebugging AND (NoOfItemsInStackAddress(BoolStack)>0)
13227 f := PeepAddress(BoolStack, 1) ; (* top of stack *)
13231 Annotation := KillString(Annotation)
13233 Annotation := InitString(a)
13240 OperandAnno - returns the annotation string associated with the
13241 position, n, on the stack.
13244 PROCEDURE OperandAnno (n: CARDINAL) : String ;
13248 f := PeepAddress (BoolStack, n) ;
13249 RETURN f^.Annotation
13254 DisplayStack - displays the compile time symbol stack.
13257 PROCEDURE DisplayStack ;
13259 IF DebugStackOn AND CompilerDebugging
13261 DebugStack (NoOfItemsInStackAddress (BoolStack),
13262 OperandTno, OperandFno, OperandA,
13263 OperandD, OperandRW, OperandTok, OperandAnno)
13269 ds - tiny procedure name, useful for calling from the gdb shell.
13281 DisplayQuad - displays a quadruple, QuadNo.
13284 PROCEDURE DisplayQuad (QuadNo: CARDINAL) ;
13287 printf1('%4d ', QuadNo) ; WriteQuad(QuadNo) ; printf0('\n') ;
13293 DisplayProcedureAttributes -
13296 PROCEDURE DisplayProcedureAttributes (proc: CARDINAL) ;
13300 printf0 (" (ctor)")
13304 printf0 (" (public)")
13308 printf0 (" (extern)")
13310 IF IsMonoName (proc)
13312 printf0 (" (mononame)")
13314 END DisplayProcedureAttributes ;
13318 WriteQuad - Writes out the Quad BufferQuad.
13321 PROCEDURE WriteQuad (BufferQuad: CARDINAL) ;
13328 f := GetQF(BufferQuad) ;
13330 WriteOperator(Operator) ;
13331 printf1(' [%d] ', NoOfTimesReferenced) ;
13334 HighOp : WriteOperand(Operand1) ;
13335 printf1(' %4d ', Operand2) ;
13336 WriteOperand(Operand3) |
13349 AddrOp : WriteOperand(Operand1) ;
13351 WriteOperand(Operand3) |
13360 IfGreEquOp : WriteOperand(Operand1) ;
13362 WriteOperand(Operand2) ;
13363 printf1(' %4d', Operand3) |
13368 GotoOp : printf1('%4d', Operand3) |
13370 StatementNoteOp : l := TokenToLineNo(Operand3, 0) ;
13371 n := GetTokenName (Operand3) ;
13372 printf4('%a:%d:%a (tokenno %d)', Operand1, l, n, Operand3) |
13373 LineNumberOp : printf2('%a:%d', Operand1, Operand3) |
13375 EndFileOp : n1 := GetSymName(Operand3) ;
13376 printf1('%a', n1) |
13381 KillLocalVarOp : WriteOperand(Operand3) |
13383 ProcedureScopeOp : n1 := GetSymName(Operand2) ;
13384 n2 := GetSymName(Operand3) ;
13385 printf3(' %4d %a %a', Operand1, n1, n2) ;
13386 DisplayProcedureAttributes (Operand3) |
13391 InitStartOp : n1 := GetSymName(Operand2) ;
13392 n2 := GetSymName(Operand3) ;
13393 printf3(' %4d %a %a', Operand1, n1, n2) |
13396 StartModFileOp : n1 := GetSymName(Operand3) ;
13397 printf4('%a:%d %a(%d)', Operand2, Operand1, n1, Operand3) |
13399 StartDefFileOp : n1 := GetSymName(Operand3) ;
13400 printf2(' %4d %a', Operand1, n1) |
13403 ParamOp : printf1('%4d ', Operand1) ;
13404 WriteOperand(Operand2) ;
13406 WriteOperand(Operand3) |
13432 DivTruncOp : WriteOperand(Operand1) ;
13434 WriteOperand(Operand2) ;
13436 WriteOperand(Operand3) |
13444 BuiltinConstOp : WriteOperand(Operand1) ;
13445 printf1(' %a', Operand3) |
13446 BuiltinTypeInfoOp : WriteOperand(Operand1) ;
13447 printf1(' %a', Operand2) ;
13448 printf1(' %a', Operand3) |
13449 StandardFunctionOp: WriteOperand(Operand1) ;
13451 WriteOperand(Operand2) ;
13453 WriteOperand(Operand3) |
13458 ErrorOp : WriteRangeCheck(Operand3) |
13460 RestoreExceptionOp: WriteOperand(Operand1) ;
13462 WriteOperand(Operand3)
13465 InternalError ('quadruple not recognised')
13472 WriteOperator - writes the name of the quadruple operator.
13475 PROCEDURE WriteOperator (Operator: QuadOperator) ;
13479 ArithAddOp : printf0('Arith + ') |
13480 InitAddressOp : printf0('InitAddress ') |
13481 LogicalOrOp : printf0('Or ') |
13482 LogicalAndOp : printf0('And ') |
13483 LogicalXorOp : printf0('Xor ') |
13484 LogicalDiffOp : printf0('Ldiff ') |
13485 LogicalShiftOp : printf0('Shift ') |
13486 LogicalRotateOp : printf0('Rotate ') |
13487 BecomesOp : printf0('Becomes ') |
13488 IndrXOp : printf0('IndrX ') |
13489 XIndrOp : printf0('XIndr ') |
13490 ArrayOp : printf0('Array ') |
13491 ElementSizeOp : printf0('ElementSize ') |
13492 RecordFieldOp : printf0('RecordField ') |
13493 AddrOp : printf0('Addr ') |
13494 SizeOp : printf0('Size ') |
13495 IfInOp : printf0('If IN ') |
13496 IfNotInOp : printf0('If NOT IN ') |
13497 IfNotEquOp : printf0('If <> ') |
13498 IfEquOp : printf0('If = ') |
13499 IfLessEquOp : printf0('If <= ') |
13500 IfGreEquOp : printf0('If >= ') |
13501 IfGreOp : printf0('If > ') |
13502 IfLessOp : printf0('If < ') |
13503 GotoOp : printf0('Goto ') |
13504 DummyOp : printf0('Dummy ') |
13505 ModuleScopeOp : printf0('ModuleScopeOp ') |
13506 StartDefFileOp : printf0('StartDefFile ') |
13507 StartModFileOp : printf0('StartModFile ') |
13508 EndFileOp : printf0('EndFileOp ') |
13509 InitStartOp : printf0('InitStart ') |
13510 InitEndOp : printf0('InitEnd ') |
13511 FinallyStartOp : printf0('FinallyStart ') |
13512 FinallyEndOp : printf0('FinallyEnd ') |
13513 RetryOp : printf0('Retry ') |
13514 TryOp : printf0('Try ') |
13515 ThrowOp : printf0('Throw ') |
13516 CatchBeginOp : printf0('CatchBegin ') |
13517 CatchEndOp : printf0('CatchEnd ') |
13518 AddOp : printf0('+ ') |
13519 SubOp : printf0('- ') |
13520 DivM2Op : printf0('DIV M2 ') |
13521 ModM2Op : printf0('MOD M2 ') |
13522 DivCeilOp : printf0('DIV ceil ') |
13523 ModCeilOp : printf0('MOD ceil ') |
13524 DivFloorOp : printf0('DIV floor ') |
13525 ModFloorOp : printf0('MOD floor ') |
13526 DivTruncOp : printf0('DIV trunc ') |
13527 ModTruncOp : printf0('MOD trunc ') |
13528 MultOp : printf0('* ') |
13529 NegateOp : printf0('Negate ') |
13530 InclOp : printf0('Incl ') |
13531 ExclOp : printf0('Excl ') |
13532 ReturnOp : printf0('Return ') |
13533 ReturnValueOp : printf0('ReturnValue ') |
13534 FunctValueOp : printf0('FunctValue ') |
13535 CallOp : printf0('Call ') |
13536 ParamOp : printf0('Param ') |
13537 OptParamOp : printf0('OptParam ') |
13538 NewLocalVarOp : printf0('NewLocalVar ') |
13539 KillLocalVarOp : printf0('KillLocalVar ') |
13540 ProcedureScopeOp : printf0('ProcedureScope ') |
13541 UnboundedOp : printf0('Unbounded ') |
13542 CoerceOp : printf0('Coerce ') |
13543 ConvertOp : printf0('Convert ') |
13544 CastOp : printf0('Cast ') |
13545 HighOp : printf0('High ') |
13546 CodeOnOp : printf0('CodeOn ') |
13547 CodeOffOp : printf0('CodeOff ') |
13548 ProfileOnOp : printf0('ProfileOn ') |
13549 ProfileOffOp : printf0('ProfileOff ') |
13550 OptimizeOnOp : printf0('OptimizeOn ') |
13551 OptimizeOffOp : printf0('OptimizeOff ') |
13552 InlineOp : printf0('Inline ') |
13553 StatementNoteOp : printf0('StatementNote ') |
13554 LineNumberOp : printf0('LineNumber ') |
13555 BuiltinConstOp : printf0('BuiltinConst ') |
13556 BuiltinTypeInfoOp : printf0('BuiltinTypeInfo ') |
13557 StandardFunctionOp : printf0('StandardFunction ') |
13558 SavePriorityOp : printf0('SavePriority ') |
13559 RestorePriorityOp : printf0('RestorePriority ') |
13560 RangeCheckOp : printf0('RangeCheck ') |
13561 ErrorOp : printf0('Error ') |
13562 SaveExceptionOp : printf0('SaveException ') |
13563 RestoreExceptionOp : printf0('RestoreException ')
13566 InternalError ('operator not expected')
13568 END WriteOperator ;
13572 WriteOperand - displays the operands name, symbol id and mode of addressing.
13575 PROCEDURE WriteOperand (Sym: CARDINAL) ;
13581 printf0 ('<nulsym>')
13583 n := GetSymName (Sym) ;
13584 printf1 ('%a', n) ;
13585 IF IsVar (Sym) OR IsConst (Sym)
13587 printf0 ('[') ; WriteMode (GetMode (Sym)) ; printf0(']')
13589 printf1 ('(%d)', Sym)
13594 PROCEDURE WriteMode (Mode: ModeOfAddr) ;
13598 ImmediateValue: printf0('i') |
13599 NoValue : printf0('n') |
13600 RightValue : printf0('r') |
13601 LeftValue : printf0('l')
13604 InternalError ('unrecognised mode')
13610 GetQuadOp - returns the operator for quad.
13613 PROCEDURE GetQuadOp (quad: CARDINAL) : QuadOperator ;
13617 f := GetQF (quad) ;
13623 GetM2OperatorDesc - returns the Modula-2 string associated with the quad operator
13624 (if possible). It returns NIL if no there is not an obvious match
13625 in Modula-2. It is assummed that the string will be used during
13626 construction of error messages and therefore keywords are
13627 wrapped with a format specifier.
13630 PROCEDURE GetM2OperatorDesc (op: QuadOperator) : String ;
13634 NegateOp : RETURN InitString ('-') |
13635 AddOp : RETURN InitString ('+') |
13636 SubOp : RETURN InitString ('-') |
13637 MultOp : RETURN InitString ('*') |
13641 DivTruncOp : RETURN InitString ('{%kDIV}') |
13644 ModFloorOp : RETURN InitString ('{%kMOD}') |
13645 ModTruncOp : RETURN InitString ('{%kREM}') |
13646 LogicalOrOp : RETURN InitString ('{%kOR}') |
13647 LogicalAndOp: RETURN InitString ('{%kAND}') |
13648 InclOp : RETURN InitString ('{%kINCL}') |
13649 ExclOp : RETURN InitString ('{%kEXCL}') |
13650 IfEquOp : RETURN InitString ('=') |
13651 IfLessEquOp : RETURN InitString ('<=') |
13652 IfGreEquOp : RETURN InitString ('>=') |
13653 IfGreOp : RETURN InitString ('>') |
13654 IfLessOp : RETURN InitString ('<') |
13655 IfNotEquOp : RETURN InitString ('#') |
13656 IfInOp : RETURN InitString ('IN') |
13657 IfNotInOp : RETURN InitString ('NOT IN')
13662 END GetM2OperatorDesc ;
13667 PushExit - pushes the exit value onto the EXIT stack.
13670 PROCEDURE PushExit (Exit: CARDINAL) ;
13672 PushWord(ExitStack, Exit)
13677 PopExit - pops the exit value from the EXIT stack.
13680 PROCEDURE PopExit() : WORD ;
13682 RETURN( PopWord(ExitStack) )
13687 PushFor - pushes the exit value onto the FOR stack.
13690 PROCEDURE PushFor (Exit: CARDINAL) ;
13692 PushWord(ForStack, Exit)
13697 PopFor - pops the exit value from the FOR stack.
13700 PROCEDURE PopFor() : WORD ;
13702 RETURN( PopWord(ForStack) )
13707 OperandTno - returns the ident operand stored in the true position
13708 on the boolean stack. This is exactly the same as
13709 OperandT but it has no IsBoolean checking.
13712 PROCEDURE OperandTno (pos: CARDINAL) : WORD ;
13717 f := PeepAddress(BoolStack, pos) ;
13718 RETURN( f^.TrueExit )
13723 OperandFno - returns the ident operand stored in the false position
13724 on the boolean stack. This is exactly the same as
13725 OperandF but it has no IsBoolean checking.
13728 PROCEDURE OperandFno (pos: CARDINAL) : WORD ;
13733 f := PeepAddress (BoolStack, pos) ;
13734 RETURN f^.FalseExit
13739 OperandTtok - returns the token associated with the position, pos
13740 on the boolean stack.
13743 PROCEDURE OperandTtok (pos: CARDINAL) : CARDINAL ;
13748 f := PeepAddress (BoolStack, pos) ;
13754 PopBooltok - Pops a True and a False exit quad number from the True/False
13758 PROCEDURE PopBooltok (VAR True, False: CARDINAL; VAR tokno: CARDINAL) ;
13762 f := PopAddress (BoolStack) ;
13765 False := FalseExit ;
13774 PushBooltok - Push a True and a False exit quad numbers onto the
13778 PROCEDURE PushBooltok (True, False: CARDINAL; tokno: CARDINAL) ;
13782 Assert (True<=NextQuad) ;
13783 Assert (False<=NextQuad) ;
13784 f := newBoolFrame () ;
13787 FalseExit := False ;
13788 BooleanOp := TRUE ;
13792 PushAddress (BoolStack, f) ;
13793 Annotate ('<q%1d>|<q%2d>||true quad|false quad')
13798 PopBool - Pops a True and a False exit quad number from the True/False
13802 PROCEDURE PopBool (VAR True, False: CARDINAL) ;
13806 PopBooltok (True, False, tokno)
13811 PushBool - Push a True and a False exit quad numbers onto the
13815 PROCEDURE PushBool (True, False: CARDINAL) ;
13817 PushBooltok (True, False, UnknownTokenNo)
13822 IsBoolean - returns true is the Stack position pos contains a Boolean
13823 Exit. False is returned if an Ident is stored.
13826 PROCEDURE IsBoolean (pos: CARDINAL) : BOOLEAN ;
13831 f := PeepAddress(BoolStack, pos) ;
13832 RETURN( f^.BooleanOp )
13837 OperandD - returns possible array dimension associated with the ident
13838 operand stored on the boolean stack.
13841 PROCEDURE OperandD (pos: CARDINAL) : WORD ;
13846 Assert(NOT IsBoolean (pos)) ;
13847 f := PeepAddress(BoolStack, pos) ;
13848 RETURN( f^.Dimension )
13853 OperandA - returns possible array symbol associated with the ident
13854 operand stored on the boolean stack.
13857 PROCEDURE OperandA (pos: CARDINAL) : WORD ;
13862 Assert(NOT IsBoolean (pos)) ;
13863 f := PeepAddress(BoolStack, pos) ;
13864 RETURN( f^.Unbounded )
13869 OperandT - returns the ident operand stored in the true position on the boolean stack.
13872 PROCEDURE OperandT (pos: CARDINAL) : WORD ;
13874 Assert(NOT IsBoolean (pos)) ;
13875 RETURN( OperandTno(pos) )
13880 OperandF - returns the ident operand stored in the false position on the boolean stack.
13883 PROCEDURE OperandF (pos: CARDINAL) : WORD ;
13885 Assert(NOT IsBoolean (pos)) ;
13886 RETURN( OperandFno(pos) )
13891 OperandRW - returns the rw operand stored on the boolean stack.
13894 PROCEDURE OperandRW (pos: CARDINAL) : WORD ;
13899 Assert(NOT IsBoolean (pos)) ;
13900 f := PeepAddress(BoolStack, pos) ;
13901 RETURN( f^.ReadWrite )
13906 OperandMergeRW - returns the rw operand if not NulSym else it
13910 PROCEDURE OperandMergeRW (pos: CARDINAL) : WORD ;
13912 IF OperandRW (pos) = NulSym
13914 RETURN OperandT (pos)
13916 RETURN OperandRW (pos)
13918 END OperandMergeRW ;
13922 OperandTok - returns the token associated with pos, on the stack.
13925 PROCEDURE OperandTok (pos: CARDINAL) : WORD ;
13927 Assert (NOT IsBoolean (pos)) ;
13928 RETURN OperandTtok (pos)
13933 BuildCodeOn - generates a quadruple declaring that code should be
13934 emmitted from henceforth.
13936 The Stack is unnaffected.
13939 PROCEDURE BuildCodeOn ;
13941 GenQuad(CodeOnOp, NulSym, NulSym, NulSym)
13946 BuildCodeOff - generates a quadruple declaring that code should not be
13947 emmitted from henceforth.
13949 The Stack is unnaffected.
13952 PROCEDURE BuildCodeOff ;
13954 GenQuad(CodeOffOp, NulSym, NulSym, NulSym)
13959 BuildProfileOn - generates a quadruple declaring that profile timings
13960 should be emmitted from henceforth.
13962 The Stack is unnaffected.
13965 PROCEDURE BuildProfileOn ;
13967 GenQuad(ProfileOnOp, NulSym, NulSym, NulSym)
13968 END BuildProfileOn ;
13972 BuildProfileOn - generates a quadruple declaring that profile timings
13973 should be emmitted from henceforth.
13975 The Stack is unnaffected.
13978 PROCEDURE BuildProfileOff ;
13980 GenQuad(ProfileOffOp, NulSym, NulSym, NulSym)
13981 END BuildProfileOff ;
13985 BuildOptimizeOn - generates a quadruple declaring that optimization
13986 should occur from henceforth.
13988 The Stack is unnaffected.
13991 PROCEDURE BuildOptimizeOn ;
13993 GenQuad(OptimizeOnOp, NulSym, NulSym, NulSym)
13994 END BuildOptimizeOn ;
13998 BuildOptimizeOff - generates a quadruple declaring that optimization
13999 should not occur from henceforth.
14001 The Stack is unnaffected.
14004 PROCEDURE BuildOptimizeOff ;
14006 GenQuad (OptimizeOffOp, NulSym, NulSym, NulSym)
14007 END BuildOptimizeOff ;
14011 BuildAsm - builds an Inline pseudo quadruple operator.
14012 The inline interface, Sym, is stored as the operand
14013 to the operator InlineOp.
14015 The stack is expected to contain:
14027 PROCEDURE BuildAsm (tok: CARDINAL) ;
14032 GenQuadO (tok, InlineOp, NulSym, NulSym, Sym, FALSE)
14037 BuildLineNo - builds a LineNumberOp pseudo quadruple operator.
14038 This quadruple indicates which source line has been
14039 processed, these quadruples are only generated if we
14040 are producing runtime debugging information.
14042 The stack is not affected, read or altered in any way.
14051 PROCEDURE BuildLineNo ;
14056 IF (NextQuad#Head) AND (GenerateLineDebug OR GenerateDebugging) AND FALSE
14058 filename := makekey (string (GetFileName ())) ;
14059 f := GetQF (NextQuad-1) ;
14060 IF NOT ((f^.Operator = LineNumberOp) AND (f^.Operand1 = WORD (filename)))
14062 GenQuad (LineNumberOp, WORD (filename), NulSym, WORD (GetLineNo ()))
14069 UseLineNote - uses the line note and returns it to the free list.
14072 PROCEDURE UseLineNote (l: LineNote) ;
14077 f := GetQF (NextQuad-1) ;
14078 IF (f^.Operator = LineNumberOp) AND (f^.Operand1 = WORD (File))
14084 GenQuad (LineNumberOp, WORD (File), NulSym, WORD (Line))
14087 Next := FreeLineList
14094 PopLineNo - pops a line note from the line stack.
14097 PROCEDURE PopLineNo () : LineNote ;
14101 l := PopAddress(LineStack) ;
14104 InternalError ('no line note available')
14111 InitLineNote - creates a line note and initializes it to
14112 contain, file, line.
14115 PROCEDURE InitLineNote (file: Name; line: CARDINAL) : LineNote ;
14119 IF FreeLineList=NIL
14123 l := FreeLineList ;
14124 FreeLineList := FreeLineList^.Next
14138 PROCEDURE PushLineNote (l: LineNote) ;
14140 PushAddress(LineStack, l)
14145 PushLineNo - pushes the current file and line number to the stack.
14148 PROCEDURE PushLineNo ;
14150 PushLineNote(InitLineNote(makekey(string(GetFileName())), GetLineNo()))
14155 BuildStmtNote - builds a StatementNoteOp pseudo quadruple operator.
14156 This quadruple indicates which source line has been
14157 processed and it represents the start of a statement
14159 It differs from LineNumberOp in that multiple successive
14160 LineNumberOps will be removed and the final one is attached to
14161 the next real GCC tree. Whereas a StatementNoteOp is always left
14162 alone. Depending upon the debugging level it will issue a nop
14163 instruction to ensure that the gdb single step will step into
14164 this line. Practically it allows pedalogical debugging to
14165 occur when there is syntax sugar such as:
14171 a := 1 ; (* step *)
14176 The stack is not affected, read or altered in any way.
14185 PROCEDURE BuildStmtNote (offset: INTEGER) ;
14191 tokenno := offset ;
14192 INC (tokenno, GetTokenNo ()) ;
14193 BuildStmtNoteTok (VAL(CARDINAL, tokenno))
14195 END BuildStmtNote ;
14199 BuildStmtNoteTok - adds a nop (with an assigned tokenno location) to the code.
14202 PROCEDURE BuildStmtNoteTok (tokenno: CARDINAL) ;
14207 f := GetQF (NextQuad-1) ;
14208 (* no need to have multiple notes at the same position. *)
14209 IF (f^.Operator # StatementNoteOp) OR (f^.Operand3 # tokenno)
14211 filename := makekey (string (GetFileName ())) ;
14212 GenQuad (StatementNoteOp, WORD (filename), NulSym, tokenno)
14214 END BuildStmtNoteTok ;
14218 AddRecordToList - adds the record held on the top of stack to the
14219 list of records and varient fields.
14222 PROCEDURE AddRecordToList ;
14228 Assert(IsRecord(r) OR IsFieldVarient(r)) ;
14230 r might be a field varient if the declaration consists of nested
14231 varients. However ISO TSIZE can only utilise record types, we store
14232 a varient field anyway as the next pass would not know whether to
14233 ignore a varient field.
14235 PutItemIntoList (VarientFields, r) ;
14238 n := NoOfItemsInList(VarientFields) ;
14241 printf2('in list: record %d is %d\n', n, r)
14243 printf2('in list: varient field %d is %d\n', n, r)
14246 END AddRecordToList ;
14250 AddVarientToList - adds varient held on the top of stack to the list.
14253 PROCEDURE AddVarientToList ;
14258 Assert(IsVarient(v)) ;
14259 PutItemIntoList(VarientFields, v) ;
14262 n := NoOfItemsInList(VarientFields) ;
14263 printf2('in list: varient %d is %d\n', n, v)
14265 END AddVarientToList ;
14269 AddVarientFieldToList - adds varient field, f, to the list of all varient
14273 PROCEDURE AddVarientFieldToList (f: CARDINAL) ;
14277 Assert(IsFieldVarient(f)) ;
14278 PutItemIntoList(VarientFields, f) ;
14281 n := NoOfItemsInList(VarientFields) ;
14282 printf2('in list: varient field %d is %d\n', n, f)
14284 END AddVarientFieldToList ;
14291 PROCEDURE GetRecordOrField () : CARDINAL ;
14295 INC(VarientFieldNo) ;
14296 f := GetItemFromList(VarientFields, VarientFieldNo) ;
14301 printf2('out list: record %d is %d\n', VarientFieldNo, f)
14303 printf2('out list: varient field %d is %d\n', VarientFieldNo, f)
14307 END GetRecordOrField ;
14311 BeginVarient - begin a varient record.
14314 PROCEDURE BeginVarient ;
14318 r := GetRecordOrField() ;
14319 Assert(IsRecord(r) OR IsFieldVarient(r)) ;
14320 v := GetRecordOrField() ;
14321 Assert(IsVarient(v)) ;
14322 BuildRange(InitCaseBounds(PushCase(r, v, NulSym)))
14327 EndVarient - end a varient record.
14330 PROCEDURE EndVarient ;
14337 ElseVarient - associate an ELSE clause with a varient record.
14340 PROCEDURE ElseVarient ;
14344 f := GetRecordOrField() ;
14345 Assert(IsFieldVarient(f)) ;
14352 BeginVarientList - begin an ident list containing ranges belonging to a
14356 PROCEDURE BeginVarientList ;
14360 f := GetRecordOrField() ;
14361 Assert(IsFieldVarient(f)) ;
14363 END BeginVarientList ;
14367 EndVarientList - end a range list for a varient field.
14370 PROCEDURE EndVarientList ;
14373 END EndVarientList ;
14377 AddVarientRange - creates a range from the top two contant expressions
14378 on the stack which are recorded with the current
14379 varient field. The stack is unaltered.
14382 PROCEDURE AddVarientRange ;
14388 AddRange(r1, r2, GetTokenNo())
14389 END AddVarientRange ;
14393 AddVarientEquality - adds the contant expression on the top of the stack
14394 to the current varient field being recorded.
14395 The stack is unaltered.
14398 PROCEDURE AddVarientEquality ;
14403 AddRange(r1, NulSym, GetTokenNo())
14404 END AddVarientEquality ;
14408 BuildAsmElement - the stack is expected to contain:
14415 +------------------+
14417 |------------------|
14419 |------------------|
14421 |------------------| +------------------+
14422 | CurrentInterface | | CurrentInterface |
14423 |------------------| |------------------|
14424 | CurrentAsm | | CurrentAsm |
14425 |------------------| |------------------|
14427 |------------------| |------------------|
14430 PROCEDURE BuildAsmElement (input, output: BOOLEAN) ;
14432 DebugAsmTokPos = FALSE ;
14435 n, str, expr, tokpos,
14437 CurrentAsm, name : CARDINAL ;
14439 PopTtok (expr, tokpos) ;
14442 PopT (CurrentInterface) ;
14443 PopT (CurrentAsm) ;
14444 Assert (IsGnuAsm (CurrentAsm) OR IsGnuAsmVolatile (CurrentAsm)) ;
14447 IF CurrentInterface = NulSym
14449 CurrentInterface := MakeRegInterface ()
14453 PutRegInterface (tokpos, CurrentInterface, n, name, str, expr,
14457 s := InitString ('input expression') ;
14458 WarnStringAt (s, tokpos)
14463 PutRegInterface (tokpos, CurrentInterface, n, name, str, expr,
14467 s := InitString ('output expression') ;
14468 WarnStringAt (s, tokpos)
14472 PushT (CurrentAsm) ;
14473 PushT (CurrentInterface)
14474 END BuildAsmElement ;
14478 BuildAsmTrash - the stack is expected to contain:
14485 +------------------+
14487 |------------------| +------------------+
14488 | CurrentInterface | | CurrentInterface |
14489 |------------------| |------------------|
14490 | CurrentAsm | | CurrentAsm |
14491 |------------------| |------------------|
14493 |------------------| |------------------|
14496 PROCEDURE BuildAsmTrash ;
14500 CurrentAsm : CARDINAL ;
14502 PopTtok (expr, tokpos) ;
14503 PopT (CurrentInterface) ;
14504 PopT (CurrentAsm) ;
14505 Assert (IsGnuAsm (CurrentAsm) OR IsGnuAsmVolatile (CurrentAsm)) ;
14508 IF CurrentInterface = NulSym
14510 CurrentInterface := MakeRegInterface ()
14512 PutRegInterface (tokpos, CurrentInterface, n, NulName, NulSym, expr,
14515 PushT (CurrentAsm) ;
14516 PushT (CurrentInterface)
14517 END BuildAsmTrash ;
14521 IncOperandD - increment the dimension number associated with symbol
14522 at, pos, on the boolean stack.
14526 PROCEDURE IncOperandD (pos: CARDINAL) ;
14530 f := PeepAddress(BoolStack, pos) ;
14537 PushTFA - Push True, False, Array, numbers onto the
14538 True/False stack. True and False are assumed to
14539 contain Symbols or Ident etc.
14542 PROCEDURE PushTFA (True, False, Array: WORD) ;
14546 f := newBoolFrame () ;
14549 FalseExit := False ;
14552 PushAddress(BoolStack, f)
14557 PushTFAD - Push True, False, Array, Dim, numbers onto the
14558 True/False stack. True and False are assumed to
14559 contain Symbols or Ident etc.
14562 PROCEDURE PushTFAD (True, False, Array, Dim: WORD) ;
14566 f := newBoolFrame () ;
14569 FalseExit := False ;
14570 Unbounded := Array ;
14573 PushAddress(BoolStack, f)
14578 PushTFADtok - Push True, False, Array, Dim, numbers onto the
14579 True/False stack. True and False are assumed to
14580 contain Symbols or Ident etc.
14583 PROCEDURE PushTFADtok (True, False, Array, Dim: WORD; tokno: CARDINAL) ;
14587 f := newBoolFrame () ;
14590 FalseExit := False ;
14591 Unbounded := Array ;
14595 PushAddress (BoolStack, f)
14600 PushTFADrwtok - Push True, False, Array, Dim, rw, numbers onto the
14601 True/False stack. True and False are assumed to
14602 contain Symbols or Ident etc.
14605 PROCEDURE PushTFADrwtok (True, False, Array, Dim, rw: WORD; Tok: CARDINAL) ;
14609 f := newBoolFrame () ;
14612 FalseExit := False ;
14613 Unbounded := Array ;
14618 PushAddress (BoolStack, f)
14619 END PushTFADrwtok ;
14623 PopTFrwtok - Pop a True and False number from the True/False stack.
14624 True and False are assumed to contain Symbols or Ident etc.
14627 PROCEDURE PopTFrwtok (VAR True, False, rw: WORD; VAR tokno: CARDINAL) ;
14631 f := PopAddress(BoolStack) ;
14634 False := FalseExit ;
14635 Assert(NOT BooleanOp) ;
14644 PushTFrwtok - Push an item onto the stack in the T (true) position,
14645 it is assummed to be a token and its token location is recorded.
14648 PROCEDURE PushTFrwtok (True, False, rw: WORD; tokno: CARDINAL) ;
14652 f := newBoolFrame () ;
14655 FalseExit := False ;
14659 PushAddress(BoolStack, f)
14664 PushTFDtok - Push True, False, Dim, numbers onto the
14665 True/False stack. True and False are assumed to
14666 contain Symbols or Ident etc.
14669 PROCEDURE PushTFDtok (True, False, Dim: WORD; Tok: CARDINAL) ;
14673 f := newBoolFrame () ;
14676 FalseExit := False ;
14680 PushAddress (BoolStack, f)
14685 PopTFDtok - Pop a True, False, Dim number from the True/False stack.
14686 True and False are assumed to contain Symbols or Ident etc.
14689 PROCEDURE PopTFDtok (VAR True, False, Dim: WORD; VAR Tok: CARDINAL) ;
14693 f := PopAddress(BoolStack) ;
14696 False := FalseExit ;
14699 Assert(NOT BooleanOp)
14706 PushTFDrwtok - Push True, False, Dim, numbers onto the
14707 True/False stack. True and False are assumed to
14708 contain Symbols or Ident etc.
14711 PROCEDURE PushTFDrwtok (True, False, Dim, rw: WORD; Tok: CARDINAL) ;
14715 f := newBoolFrame () ;
14718 FalseExit := False ;
14723 PushAddress (BoolStack, f)
14728 PushTFrw - Push a True and False numbers onto the True/False stack.
14729 True and False are assumed to contain Symbols or Ident etc.
14730 It also pushes the higher level symbol which is associated
14731 with the True symbol. Eg record variable or array variable.
14734 PROCEDURE PushTFrw (True, False: WORD; rw: CARDINAL) ;
14738 f := newBoolFrame () ;
14741 FalseExit := False ;
14744 PushAddress(BoolStack, f)
14749 PopTFrw - Pop a True and False number from the True/False stack.
14750 True and False are assumed to contain Symbols or Ident etc.
14753 PROCEDURE PopTFrw (VAR True, False, rw: WORD) ;
14757 f := PopAddress(BoolStack) ;
14760 False := FalseExit ;
14761 Assert(NOT BooleanOp) ;
14769 PushTF - Push a True and False numbers onto the True/False stack.
14770 True and False are assumed to contain Symbols or Ident etc.
14773 PROCEDURE PushTF (True, False: WORD) ;
14777 f := newBoolFrame () ;
14782 PushAddress(BoolStack, f)
14787 PopTF - Pop a True and False number from the True/False stack.
14788 True and False are assumed to contain Symbols or Ident etc.
14791 PROCEDURE PopTF (VAR True, False: WORD) ;
14795 f := PopAddress(BoolStack) ;
14798 False := FalseExit ;
14799 Assert(NOT BooleanOp)
14806 newBoolFrame - creates a new BoolFrame with all fields initialised to their defaults.
14809 PROCEDURE newBoolFrame () : BoolFrame ;
14817 Unbounded := NulSym ;
14818 BooleanOp := FALSE ;
14820 ReadWrite := NulSym ;
14822 Annotation := NIL ;
14823 tokenno := UnknownTokenNo
14830 PushTtok - Push an item onto the stack in the T (true) position,
14831 it is assummed to be a token and its token location is recorded.
14834 PROCEDURE PushTtok (True: WORD; tokno: CARDINAL) ;
14838 (* PrintTokenNo (tokno) ; *)
14839 f := newBoolFrame () ;
14844 PushAddress (BoolStack, f)
14849 PushT - Push an item onto the stack in the T (true) position.
14852 PROCEDURE PushT (True: WORD) ;
14856 f := newBoolFrame () ;
14860 PushAddress (BoolStack, f)
14865 PopT - Pops the T value from the stack.
14868 PROCEDURE PopT (VAR True: WORD) ;
14872 f := PopAddress (BoolStack) ;
14875 Assert(NOT BooleanOp)
14882 PopTtok - Pops the T value from the stack and token position.
14885 PROCEDURE PopTtok (VAR True: WORD; VAR tok: CARDINAL) ;
14889 f := PopAddress(BoolStack) ;
14893 Assert(NOT BooleanOp)
14900 PushTrw - Push an item onto the True/False stack. The False value will be zero.
14904 PROCEDURE PushTrw (True: WORD; rw: WORD) ;
14908 f := newBoolFrame () ;
14913 PushAddress(BoolStack, f)
14919 PushTrwtok - Push an item onto the True/False stack. The False value will be zero.
14922 PROCEDURE PushTrwtok (True: WORD; rw: WORD; tok: CARDINAL) ;
14926 f := newBoolFrame () ;
14932 PushAddress(BoolStack, f)
14937 PopTrw - Pop a True field and rw symbol from the stack.
14940 PROCEDURE PopTrw (VAR True, rw: WORD) ;
14944 f := PopAddress(BoolStack) ;
14947 Assert(NOT BooleanOp) ;
14955 PopTrwtok - Pop a True field and rw symbol from the stack.
14958 PROCEDURE PopTrwtok (VAR True, rw: WORD; VAR tok: CARDINAL) ;
14962 f := PopAddress(BoolStack) ;
14965 Assert(NOT BooleanOp) ;
14974 PushTFn - Push a True and False numbers onto the True/False stack.
14975 True and False are assumed to contain Symbols or Ident etc.
14978 PROCEDURE PushTFn (True, False, n: WORD) ;
14982 f := newBoolFrame () ;
14985 FalseExit := False ;
14988 PushAddress(BoolStack, f)
14993 PushTFntok - Push a True and False numbers onto the True/False stack.
14994 True and False are assumed to contain Symbols or Ident etc.
14997 PROCEDURE PushTFntok (True, False, n: WORD; tokno: CARDINAL) ;
15001 f := newBoolFrame () ;
15004 FalseExit := False ;
15008 PushAddress (BoolStack, f)
15013 PopTFn - Pop a True and False number from the True/False stack.
15014 True and False are assumed to contain Symbols or Ident etc.
15017 PROCEDURE PopTFn (VAR True, False, n: WORD) ;
15021 f := PopAddress(BoolStack) ;
15024 False := FalseExit ;
15026 Assert(NOT BooleanOp)
15033 PopNothing - pops the top element on the boolean stack.
15036 PROCEDURE PopNothing ;
15040 f := PopAddress(BoolStack) ;
15046 PopN - pops multiple elements from the BoolStack.
15049 PROCEDURE PopN (n: CARDINAL) ;
15059 PushTFtok - Push an item onto the stack in the T (true) position,
15060 it is assummed to be a token and its token location is recorded.
15063 PROCEDURE PushTFtok (True, False: WORD; tokno: CARDINAL) ;
15067 f := newBoolFrame () ;
15070 FalseExit := False ;
15073 PushAddress(BoolStack, f)
15078 PopTFtok - Pop T/F/tok from the stack.
15081 PROCEDURE PopTFtok (VAR True, False: WORD; VAR tokno: CARDINAL) ;
15085 f := PopAddress(BoolStack) ;
15088 False := FalseExit ;
15095 PushTFAtok - Push T/F/A/tok to the stack.
15098 PROCEDURE PushTFAtok (True, False, Array: WORD; tokno: CARDINAL) ;
15102 f := newBoolFrame () ;
15105 FalseExit := False ;
15106 Unbounded := Array ;
15109 PushAddress(BoolStack, f)
15114 Top - returns the no of items held in the stack.
15117 PROCEDURE Top () : CARDINAL ;
15119 RETURN( NoOfItemsInStackAddress(BoolStack) )
15124 PushAutoOn - push the auto flag and then set it to TRUE.
15125 Any call to ident in the parser will result in the token being pushed.
15128 PROCEDURE PushAutoOn ;
15130 PushWord(AutoStack, IsAutoOn) ;
15136 PushAutoOff - push the auto flag and then set it to FALSE.
15139 PROCEDURE PushAutoOff ;
15141 PushWord(AutoStack, IsAutoOn) ;
15147 IsAutoPushOn - returns the value of the current Auto ident push flag.
15150 PROCEDURE IsAutoPushOn () : BOOLEAN ;
15157 PopAuto - restores the previous value of the Auto flag.
15160 PROCEDURE PopAuto ;
15162 IsAutoOn := PopWord(AutoStack)
15167 PushInConstExpression - push the InConstExpression flag and then set it to TRUE.
15170 PROCEDURE PushInConstExpression ;
15172 PushWord(ConstStack, InConstExpression) ;
15173 InConstExpression := TRUE
15174 END PushInConstExpression ;
15178 PopInConstExpression - restores the previous value of the InConstExpression.
15181 PROCEDURE PopInConstExpression ;
15183 InConstExpression := PopWord(ConstStack)
15184 END PopInConstExpression ;
15188 IsInConstExpression - returns the value of the InConstExpression.
15191 PROCEDURE IsInConstExpression () : BOOLEAN ;
15193 RETURN( InConstExpression )
15194 END IsInConstExpression ;
15198 MustCheckOverflow - returns TRUE if the quadruple should test for overflow.
15201 PROCEDURE MustCheckOverflow (q: CARDINAL) : BOOLEAN ;
15206 RETURN( f^.CheckOverflow )
15207 END MustCheckOverflow ;
15215 PROCEDURE StressStack ;
15219 n, i, j: CARDINAL ;
15224 FOR n := 1 TO Maxtries DO
15225 FOR i := n TO 1 BY -1 DO
15228 FOR i := n TO 1 BY -1 DO
15229 Assert(OperandT(i)=i)
15232 Assert(OperandT(i)=i)
15234 FOR i := 1 TO n BY 10 DO
15235 Assert(OperandT(i)=i)
15237 IF (n>1) AND (n MOD 2 = 0)
15239 FOR i := 1 TO n DIV 2 DO
15243 FOR i := n DIV 2 TO 1 BY -1 DO
15257 Init - initialize the M2Quads module, all the stacks, all the lists
15258 and the quads list.
15263 LogicalOrTok := MakeKey('_LOR') ;
15264 LogicalAndTok := MakeKey('_LAND') ;
15265 LogicalXorTok := MakeKey('_LXOR') ;
15266 LogicalDifferenceTok := MakeKey('_LDIFF') ;
15267 ArithPlusTok := MakeKey ('_ARITH_+') ;
15268 QuadArray := InitIndex (1) ;
15270 NewQuad(NextQuad) ;
15271 Assert(NextQuad=1) ;
15272 BoolStack := InitStackAddress() ;
15273 ExitStack := InitStackWord() ;
15274 RepeatStack := InitStackWord() ;
15275 WhileStack := InitStackWord() ;
15276 ForStack := InitStackWord() ;
15277 WithStack := InitStackAddress() ;
15278 ReturnStack := InitStackWord() ;
15279 LineStack := InitStackAddress() ;
15280 PriorityStack := InitStackWord() ;
15281 TryStack := InitStackWord() ;
15282 CatchStack := InitStackWord() ;
15283 ExceptStack := InitStackWord() ;
15284 ConstructorStack := InitStackAddress() ;
15285 ConstStack := InitStackWord() ;
15286 (* StressStack ; *)
15287 SuppressWith := FALSE ;
15290 MustNotCheckBounds := FALSE ;
15292 GrowInitialization := 0 ;
15293 ForInfo := InitIndex (1) ;
15294 QuadrupleGeneration := TRUE ;
15295 BuildingHigh := FALSE ;
15296 BuildingSize := FALSE ;
15297 AutoStack := InitStackWord() ;
15299 InConstExpression := FALSE ;
15300 FreeLineList := NIL ;
15301 InitList(VarientFields) ;
15302 VarientFieldNo := 0 ;