1 (* M2Quads.mod generates quadruples.
3 Copyright (C) 2001-2023 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,
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,
88 IsVarParam, IsProcedure, IsPointer, IsParameter,
89 IsUnboundedParam, IsEnumeration, IsDefinitionForC,
90 IsVarAParam, IsVarient, IsLegal,
91 UsesVarArgs, UsesOptArg,
97 HasExceptionBlock, PutExceptionBlock,
98 HasExceptionFinally, PutExceptionFinally,
99 GetParent, GetRecord, IsRecordField, IsFieldVarient, IsRecord,
101 IsVar, IsProcType, IsType, IsSubrange, IsExported,
102 IsConst, IsConstString, IsModule, IsDefImp,
103 IsArray, IsUnbounded, IsProcedureNested,
104 IsParameterUnbounded,
105 IsPartialUnbounded, IsProcedureBuiltin,
106 IsSet, IsConstSet, IsConstructor, PutConst,
107 PutConstructor, PutConstructorFrom,
109 MakeComponentRecord, MakeComponentRef,
113 PutLeftValueFrontBackType,
114 PushSize, PushValue, PopValue,
115 GetVariableAtAddress, IsVariableAtAddress,
116 MakeError, UnknownReported,
119 IsImportStatement, IsImport, GetImportModule, GetImportDeclared,
120 GetImportStatementList,
121 GetModuleDefImportStatementList, GetModuleModImportStatementList,
122 IsCtor, IsPublic, IsExtern, IsMonoName,
124 GetUnboundedRecordType,
125 GetUnboundedAddressOffset,
126 GetUnboundedHighOffset,
128 ForeachFieldEnumerationDo, ForeachLocalSymDo,
129 GetExported, PutImported, GetSym,
133 FROM M2Batch IMPORT MakeDefinitionSource ;
134 FROM M2GCCDeclare IMPORT PutToBeSolvedByQuads ;
136 FROM FifoQueue IMPORT GetConstFromFifoQueue,
137 PutConstructorIntoFifoQueue, GetConstructorFromFifoQueue ;
139 FROM M2Comp IMPORT CompilingImplementationModule,
140 CompilingProgramModule ;
142 FROM M2LexBuf IMPORT currenttoken, UnknownTokenNo, BuiltinTokenNo,
143 GetToken, MakeVirtualTok,
144 GetFileName, TokenToLineNo, GetTokenName,
145 GetTokenNo, GetLineNo, GetPreviousTokenLineNo, PrintTokenNo ;
147 FROM M2Error IMPORT Error,
149 WriteFormat0, WriteFormat1, WriteFormat2, WriteFormat3,
150 NewError, NewWarning, ErrorFormat0, ErrorFormat1,
151 ErrorFormat2, ErrorFormat3, FlushErrors, ChainError,
153 ErrorStringAt, ErrorStringAt2, ErrorStringsAt2,
154 WarnStringAt, WarnStringAt2, WarnStringsAt2 ;
156 FROM M2Printf IMPORT printf0, printf1, printf2, printf3, printf4 ;
158 FROM M2Reserved IMPORT PlusTok, MinusTok, TimesTok, DivTok, ModTok,
160 OrTok, AndTok, AmbersandTok,
161 EqualTok, LessEqualTok, GreaterEqualTok,
162 LessTok, GreaterTok, HashTok, LessGreaterTok,
164 UpArrowTok, RParaTok, LParaTok, CommaTok,
166 SemiColonTok, toktype ;
168 FROM M2Base IMPORT True, False, Boolean, Cardinal, Integer, Char,
169 Real, LongReal, ShortReal, Nil,
172 NegateType, ComplexToScalar, GetCmplxReturnType,
173 IsAssignmentCompatible, IsExpressionCompatible,
174 AssignmentRequiresWarning,
175 CannotCheckTypeInPass3, ScalarToComplex, MixTypes,
176 CheckAssignmentCompatible, CheckExpressionCompatible,
177 High, LengthS, New, Dispose, Inc, Dec, Incl, Excl,
179 IsOrd, Chr, Convert, Val, IsFloat, IsTrunc,
181 IsPseudoBaseProcedure, IsPseudoBaseFunction,
182 IsMathType, IsOrdinalType, IsRealType,
183 IsBaseType, GetBaseTypeMinMax, ActivationPointer ;
185 FROM M2System IMPORT IsPseudoSystemFunction, IsPseudoSystemProcedure,
186 IsSystemType, GetSystemTypeMinMax,
187 IsPseudoSystemFunctionConstExpression,
189 Adr, TSize, TBitSize, AddAdr, SubAdr, DifAdr, Cast,
190 Shift, Rotate, MakeAdr, Address, Byte, Word, Loc, Throw ;
192 FROM M2Size IMPORT Size ;
193 FROM M2Bitset IMPORT Bitset ;
195 FROM M2ALU IMPORT PushInt, Gre, Less, PushNulSet, AddBitRange, AddBit,
196 IsGenericNulSet, IsValueAndTreeKnown, AddField,
197 AddElements, ChangeToConstructor ;
199 FROM Lists IMPORT List, InitList, GetItemFromList, NoOfItemsInList, PutItemIntoList,
200 IsItemInList, KillList, IncludeItemIntoList ;
202 FROM M2Options IMPORT NilChecking,
203 WholeDivChecking, WholeValueChecking,
204 IndexChecking, RangeChecking,
205 CaseElseChecking, ReturnChecking,
206 UnusedVariableChecking, UnusedParameterChecking,
207 Iso, Pim, Pim2, Pim3, Pim4, PositiveModFloorDiv,
208 Pedantic, CompilerDebugging, GenerateDebugging,
209 GenerateLineDebug, Exceptions,
210 Profiling, Coding, Optimizing,
211 ScaffoldDynamic, ScaffoldStatic, cflag,
212 ScaffoldMain, SharedFlag, WholeProgram ;
214 FROM M2Pass IMPORT IsPassCodeGeneration, IsNoPass ;
216 FROM M2StackAddress IMPORT StackOfAddress, InitStackAddress, KillStackAddress,
217 PushAddress, PopAddress, PeepAddress,
218 IsEmptyAddress, NoOfItemsInStackAddress ;
220 FROM M2StackWord IMPORT StackOfWord, InitStackWord, KillStackWord,
221 PushWord, PopWord, PeepWord, RemoveTop,
222 IsEmptyWord, NoOfItemsInStackWord ;
224 FROM Indexing IMPORT Index, InitIndex, GetIndice, PutIndice, InBounds, HighIndice, IncludeIndiceIntoIndex ;
226 FROM M2Range IMPORT InitAssignmentRangeCheck,
227 InitReturnRangeCheck,
228 InitSubrangeRangeCheck,
229 InitStaticArraySubscriptRangeCheck,
230 InitDynamicArraySubscriptRangeCheck,
237 InitTypesAssignmentCheck,
238 InitTypesExpressionCheck,
239 InitTypesParameterCheck,
240 InitForLoopBeginRangeCheck,
241 InitForLoopToRangeCheck,
242 InitForLoopEndRangeCheck,
243 InitPointerRangeCheck,
244 InitNoReturnRangeCheck,
245 InitNoElseRangeCheck,
247 InitWholeZeroDivisionCheck,
248 InitWholeZeroRemainderCheck,
249 InitParameterRangeCheck,
250 (* CheckRangeAddVariableRead, *)
251 (* CheckRangeRemoveVariableRead, *)
254 FROM M2CaseList IMPORT PushCase, PopCase, AddRange, BeginCaseList, EndCaseList, ElseCase ;
255 FROM PCSymBuild IMPORT SkipConst ;
256 FROM m2builtins IMPORT GetBuiltinTypeInfoType ;
262 DebugStackOn = TRUE ;
263 DebugVarients = FALSE ;
265 DebugTokPos = FALSE ;
268 ConstructorFrame = POINTER TO constructorFrame ;
269 constructorFrame = RECORD
274 BoolFrame = POINTER TO RECORD
275 TrueExit : CARDINAL ;
276 FalseExit : CARDINAL ;
277 Unbounded : CARDINAL ;
278 BooleanOp : BOOLEAN ;
279 Dimension : CARDINAL ;
280 ReadWrite : CARDINAL ;
286 QuadFrame = POINTER TO RECORD
287 Operator : QuadOperator ;
288 Operand1 : CARDINAL ;
289 Operand2 : CARDINAL ;
290 Operand3 : CARDINAL ;
291 Next : CARDINAL ; (* Next quadruple *)
292 LineNo : CARDINAL ; (* Line No of source text *)
293 TokenNo : CARDINAL ; (* Token No of source text *)
294 NoOfTimesReferenced: CARDINAL ; (* No of times quad is referenced *)
295 CheckOverflow : BOOLEAN ; (* should backend check overflow *)
298 op3pos : CARDINAL ; (* token position of operands. *)
301 WithFrame = POINTER TO RECORD
302 RecordSym : CARDINAL ;
303 RecordType : CARDINAL ;
304 RecordRef : CARDINAL ;
305 rw : CARDINAL ; (* The record variable. *)
306 RecordTokPos: CARDINAL ; (* Token of the record. *)
309 ForLoopInfo = POINTER TO RECORD
311 StartOfForLoop, (* we keep a list of all for *)
312 EndOfForLoop, (* loops so we can check index *)
314 IndexTok : CARDINAL ; (* variables are not abused *)
317 LineNote = POINTER TO RECORD
326 WithStack : StackOfAddress ;
336 ReturnStack : StackOfWord ; (* Return quadruple of the procedure. *)
337 PriorityStack : StackOfWord ; (* temporary variable holding old priority *)
338 SuppressWith : BOOLEAN ;
340 NextQuad : CARDINAL ; (* Next quadruple number to be created. *)
341 FreeList : CARDINAL ; (* FreeList of quadruples. *)
342 CurrentProc : CARDINAL ; (* Current procedure being compiled, used *)
343 (* to determine which procedure a RETURN *)
344 (* ReturnValueOp must have as its 3rd op. *)
345 InitQuad : CARDINAL ; (* Initial Quad BackPatch that starts the *)
346 (* suit of Modules. *)
347 LastQuadNo : CARDINAL ; (* Last Quadruple accessed by GetQuad. *)
348 LogicalOrTok, (* Internal _LOR token. *)
349 LogicalAndTok, (* Internal _LAND token. *)
350 LogicalXorTok, (* Internal _LXOR token. *)
351 LogicalDifferenceTok : Name ; (* Internal _LDIFF token. *)
353 IsAutoOn, (* should parser automatically push idents *)
354 MustNotCheckBounds : BOOLEAN ;
355 ForInfo : Index ; (* start and end of all FOR loops *)
356 GrowInitialization : CARDINAL ; (* upper limit of where the initialized *)
360 QuadrupleGeneration : BOOLEAN ; (* should we be generating quadruples? *)
361 FreeLineList : LineNote ; (* free list of line notes *)
362 VarientFields : List ; (* the list of all varient fields created *)
363 VarientFieldNo : CARDINAL ; (* used to retrieve the VarientFields *)
365 NoOfQuads : CARDINAL ; (* Number of used quadruples. *)
366 Head : CARDINAL ; (* Head of the list of quadruples *)
370 Rules for file and initialization quadruples:
372 StartModFileOp - indicates that this file (module) has produced the
374 StartDefFileOp - indicates that this definition module has produced
376 EndFileOp - indicates that a module has finished
377 InitStartOp - the start of the initialization code of a module
378 InitEndOp - the end of the above
379 FinallyStartOp - the start of the finalization code of a module
380 FinallyEndOp - the end of the above
385 #define InitString(X) InitStringDB(X, __FILE__, __LINE__)
386 #define InitStringCharStar(X) InitStringCharStarDB(X, __FILE__, __LINE__)
387 #define InitStringChar(X) InitStringCharDB(X, __FILE__, __LINE__)
388 #define Mult(X,Y) MultDB(X, Y, __FILE__, __LINE__)
389 #define Dup(X) DupDB(X, __FILE__, __LINE__)
390 #define Slice(X,Y,Z) SliceDB(X, Y, Z, __FILE__, __LINE__)
399 PROCEDURE doDSdbEnter ;
410 PROCEDURE doDSdbExit (s: String) ;
412 s := PopAllocationExemption(TRUE, s)
420 PROCEDURE DSdbEnter ;
435 #define DBsbEnter doDBsbEnter
436 #define DBsbExit doDBsbExit
441 SetOptionProfiling - builds a profile quadruple if the profiling
442 option was given to the compiler.
445 PROCEDURE SetOptionProfiling (b: BOOLEAN) ;
457 END SetOptionProfiling ;
461 SetOptionCoding - builds a code quadruple if the profiling
462 option was given to the compiler.
465 PROCEDURE SetOptionCoding (b: BOOLEAN) ;
477 END SetOptionCoding ;
481 SetOptionOptimizing - builds a quadruple to say that the optimization option
482 has been found in a comment.
485 PROCEDURE SetOptionOptimizing (b: BOOLEAN) ;
493 END SetOptionOptimizing ;
497 GetQF - returns the QuadFrame associated with, q.
500 PROCEDURE GetQF (q: CARDINAL) : QuadFrame ;
502 RETURN QuadFrame (GetIndice (QuadArray, q))
507 Opposite - returns the opposite comparison operator.
510 PROCEDURE Opposite (Operator: QuadOperator) : QuadOperator ;
516 IfNotEquOp : Op := IfEquOp |
517 IfEquOp : Op := IfNotEquOp |
518 IfLessEquOp: Op := IfGreOp |
519 IfGreOp : Op := IfLessEquOp |
520 IfGreEquOp : Op := IfLessOp |
521 IfLessOp : Op := IfGreEquOp |
522 IfInOp : Op := IfNotInOp |
523 IfNotInOp : Op := IfInOp
526 InternalError ('unexpected operator')
533 IsReferenced - returns true if QuadNo is referenced by another quadruple.
536 PROCEDURE IsReferenced (QuadNo: CARDINAL) : BOOLEAN ;
542 RETURN( (Operator=ProcedureScopeOp) OR (Operator=NewLocalVarOp) OR
543 (NoOfTimesReferenced>0) )
549 IsBackReference - returns TRUE if quadruple, q, is referenced from a quad further on.
552 PROCEDURE IsBackReference (q: CARDINAL) : BOOLEAN ;
556 op1, op2, op3: CARDINAL ;
560 GetQuad (i, op, op1, op2, op3) ;
571 StartModFileOp: RETURN( FALSE ) | (* run into end of procedure or module *)
589 InternalError ('fix this for the sake of efficiency..')
590 END IsBackReference ;
594 IsUnConditional - returns true if QuadNo is an unconditional jump.
597 PROCEDURE IsUnConditional (QuadNo: CARDINAL) : BOOLEAN ;
609 GotoOp : RETURN( TRUE )
615 END IsUnConditional ;
619 IsConditional - returns true if QuadNo is a conditional jump.
622 PROCEDURE IsConditional (QuadNo: CARDINAL) : BOOLEAN ;
637 IfGreEquOp : RETURN( TRUE )
647 IsBackReferenceConditional - returns TRUE if quadruple, q, is referenced from
648 a conditional quad further on.
651 PROCEDURE IsBackReferenceConditional (q: CARDINAL) : BOOLEAN ;
655 op1, op2, op3: CARDINAL ;
659 GetQuad (i, op, op1, op2, op3) ;
670 StartModFileOp: RETURN( FALSE ) | (* run into end of procedure or module *)
682 IfNotInOp : IF (op3=q) AND IsConditional(q)
690 InternalError ('fix this for the sake of efficiency..')
691 END IsBackReferenceConditional ;
695 IsQuadA - returns true if QuadNo is a op.
698 PROCEDURE IsQuadA (QuadNo: CARDINAL; op: QuadOperator) : BOOLEAN ;
704 RETURN( Operator=op )
710 IsCall - returns true if QuadNo is a call operation.
713 PROCEDURE IsCall (QuadNo: CARDINAL) : BOOLEAN ;
715 RETURN( IsQuadA(QuadNo, CallOp) )
720 IsReturn - returns true if QuadNo is a return operation.
723 PROCEDURE IsReturn (QuadNo: CARDINAL) : BOOLEAN ;
725 RETURN( IsQuadA(QuadNo, ReturnOp) )
730 IsNewLocalVar - returns true if QuadNo is a NewLocalVar operation.
733 PROCEDURE IsNewLocalVar (QuadNo: CARDINAL) : BOOLEAN ;
735 RETURN( IsQuadA(QuadNo, NewLocalVarOp) )
740 IsKillLocalVar - returns true if QuadNo is a KillLocalVar operation.
743 PROCEDURE IsKillLocalVar (QuadNo: CARDINAL) : BOOLEAN ;
745 RETURN( IsQuadA(QuadNo, KillLocalVarOp) )
750 IsProcedureScope - returns true if QuadNo is a ProcedureScope operation.
753 PROCEDURE IsProcedureScope (QuadNo: CARDINAL) : BOOLEAN ;
755 RETURN( IsQuadA(QuadNo, ProcedureScopeOp) )
756 END IsProcedureScope ;
760 IsCatchBegin - returns true if QuadNo is a catch begin quad.
763 PROCEDURE IsCatchBegin (QuadNo: CARDINAL) : BOOLEAN ;
765 RETURN( IsQuadA(QuadNo, CatchBeginOp) )
770 IsCatchEnd - returns true if QuadNo is a catch end quad.
773 PROCEDURE IsCatchEnd (QuadNo: CARDINAL) : BOOLEAN ;
775 RETURN( IsQuadA(QuadNo, CatchEndOp) )
780 IsInitStart - returns true if QuadNo is a init start quad.
783 PROCEDURE IsInitStart (QuadNo: CARDINAL) : BOOLEAN ;
785 RETURN( IsQuadA(QuadNo, InitStartOp) )
790 IsInitEnd - returns true if QuadNo is a init end quad.
793 PROCEDURE IsInitEnd (QuadNo: CARDINAL) : BOOLEAN ;
795 RETURN( IsQuadA(QuadNo, InitEndOp) )
800 IsFinallyStart - returns true if QuadNo is a finally start quad.
803 PROCEDURE IsFinallyStart (QuadNo: CARDINAL) : BOOLEAN ;
805 RETURN( IsQuadA(QuadNo, FinallyStartOp) )
810 IsFinallyEnd - returns true if QuadNo is a finally end quad.
813 PROCEDURE IsFinallyEnd (QuadNo: CARDINAL) : BOOLEAN ;
815 RETURN( IsQuadA(QuadNo, FinallyEndOp) )
820 IsInitialisingConst - returns TRUE if the quadruple is setting
821 a const (op1) with a value.
824 PROCEDURE IsInitialisingConst (QuadNo: CARDINAL) : BOOLEAN ;
827 op1, op2, op3: CARDINAL ;
829 GetQuad (QuadNo, op, op1, op2, op3) ;
865 RestoreExceptionOp: RETURN( IsConst(op1) )
870 END IsInitialisingConst ;
874 IsOptimizeOn - returns true if the Optimize flag was true at QuadNo.
877 PROCEDURE IsOptimizeOn (QuadNo: CARDINAL) : BOOLEAN ;
886 WHILE (q#0) AND (q#QuadNo) DO
889 IF Operator=OptimizeOnOp
892 ELSIF Operator=OptimizeOffOp
905 IsProfileOn - returns true if the Profile flag was true at QuadNo.
908 PROCEDURE IsProfileOn (QuadNo: CARDINAL) : BOOLEAN ;
917 WHILE (q#0) AND (q#QuadNo) DO
920 IF Operator=ProfileOnOp
923 ELSIF Operator=ProfileOffOp
936 IsCodeOn - returns true if the Code flag was true at QuadNo.
939 PROCEDURE IsCodeOn (QuadNo: CARDINAL) : BOOLEAN ;
948 WHILE (q#0) AND (q#QuadNo) DO
954 ELSIF Operator=CodeOffOp
967 IsDefOrModFile - returns TRUE if QuadNo is a start of Module or Def file
971 PROCEDURE IsDefOrModFile (QuadNo: CARDINAL) : BOOLEAN ;
977 RETURN( (Operator=StartDefFileOp) OR (Operator=StartModFileOp) )
983 IsPseudoQuad - returns true if QuadNo is a compiler directive.
984 ie code, profile and optimize.
988 PROCEDURE IsPseudoQuad (QuadNo: CARDINAL) : BOOLEAN ;
994 RETURN( (Operator=CodeOnOp) OR (Operator=CodeOffOp) OR
995 (Operator=ProfileOnOp) OR (Operator=ProfileOffOp) OR
996 (Operator=OptimizeOnOp) OR (Operator=OptimizeOffOp) OR
997 (Operator=EndFileOp) OR
998 (Operator=StartDefFileOp) OR (Operator=StartModFileOp)
1005 GetLastFileQuad - returns the Quadruple number of the last StartDefFile or
1006 StartModFile quadruple.
1009 PROCEDURE GetLastFileQuad (QuadNo: CARDINAL) : CARDINAL ;
1013 FileQuad: CARDINAL ;
1020 IF (Operator=StartModFileOp) OR (Operator=StartDefFileOp)
1027 UNTIL (i=QuadNo) OR (i=0) ;
1029 Assert(FileQuad#0) ;
1031 END GetLastFileQuad ;
1035 GetLastQuadNo - returns the last quadruple number referenced
1039 PROCEDURE GetLastQuadNo () : CARDINAL ;
1041 RETURN( LastQuadNo )
1046 QuadToLineNo - Converts a QuadNo into the approprate line number of the
1047 source file, the line number is returned.
1049 This may be used to yield an idea where abouts in the
1050 source file the code generetion is
1054 PROCEDURE QuadToLineNo (QuadNo: CARDINAL) : CARDINAL ;
1058 IF ((LastQuadNo=0) AND (NOT IsNoPass()) AND (NOT IsPassCodeGeneration())) OR
1059 (NOT InBounds(QuadArray, QuadNo))
1063 f := GetQF(QuadNo) ;
1070 QuadToTokenNo - Converts a QuadNo into the approprate token number of the
1071 source file, the line number is returned.
1073 This may be used to yield an idea where abouts in the
1074 source file the code generetion is
1078 PROCEDURE QuadToTokenNo (QuadNo: CARDINAL) : CARDINAL ;
1082 IF ((LastQuadNo=0) AND (NOT IsNoPass()) AND (NOT IsPassCodeGeneration())) OR
1083 (NOT InBounds(QuadArray, QuadNo))
1087 f := GetQF(QuadNo) ;
1088 RETURN( f^.TokenNo )
1094 GetQuad - returns the Quadruple QuadNo.
1097 PROCEDURE GetQuad (QuadNo: CARDINAL;
1098 VAR Op: QuadOperator;
1099 VAR Oper1, Oper2, Oper3: CARDINAL) ;
1103 f := GetQF(QuadNo) ;
1104 LastQuadNo := QuadNo ;
1115 GetQuadtok - returns the Quadruple QuadNo.
1118 PROCEDURE GetQuadtok (QuadNo: CARDINAL;
1119 VAR Op: QuadOperator;
1120 VAR Oper1, Oper2, Oper3: CARDINAL;
1121 VAR Op1Pos, Op2Pos, Op3Pos: CARDINAL) ;
1125 f := GetQF(QuadNo) ;
1126 LastQuadNo := QuadNo ;
1140 GetQuadOtok - returns the Quadruple QuadNo.
1143 PROCEDURE GetQuadOtok (QuadNo: CARDINAL;
1145 VAR Op: QuadOperator;
1146 VAR Oper1, Oper2, Oper3: CARDINAL;
1147 VAR Op1Pos, Op2Pos, Op3Pos: CARDINAL) ;
1151 f := GetQF(QuadNo) ;
1152 LastQuadNo := QuadNo ;
1167 AddQuadInformation - adds variable analysis and jump analysis to the new quadruple.
1170 PROCEDURE AddQuadInformation (QuadNo: CARDINAL;
1172 Oper1, Oper2, Oper3: CARDINAL) ;
1183 IfGreEquOp : ManipulateReference(QuadNo, Oper3) ;
1184 CheckAddVariableRead(Oper1, FALSE, QuadNo) ;
1185 CheckAddVariableRead(Oper2, FALSE, QuadNo) |
1189 GotoOp : ManipulateReference(QuadNo, Oper3) |
1191 (* variable references *)
1194 ExclOp : CheckConst(Oper1) ;
1195 CheckAddVariableRead(Oper3, FALSE, QuadNo) ;
1196 CheckAddVariableWrite(Oper1, TRUE, QuadNo) |
1202 SizeOp : CheckConst(Oper1) ;
1203 CheckAddVariableWrite(Oper1, FALSE, QuadNo) ;
1204 CheckAddVariableRead(Oper3, FALSE, QuadNo) |
1205 AddrOp : CheckConst(Oper1) ;
1206 CheckAddVariableWrite(Oper1, FALSE, QuadNo) ;
1207 (* CheckAddVariableReadLeftValue(Oper3, QuadNo) *)
1208 (* the next line is a kludge and assumes we _will_
1209 write to the variable as we have taken its address *)
1210 CheckRemoveVariableWrite(Oper1, TRUE, QuadNo) |
1211 ReturnValueOp : CheckAddVariableRead(Oper1, FALSE, QuadNo) |
1215 CallOp : CheckAddVariableRead(Oper3, TRUE, QuadNo) |
1217 ParamOp : CheckAddVariableRead(Oper2, FALSE, QuadNo) ;
1218 CheckAddVariableRead(Oper3, FALSE, QuadNo) ;
1219 IF (Oper1>0) AND (Oper1<=NoOfParam(Oper2)) AND
1220 IsVarParam(Oper2, Oper1)
1222 (* _may_ also write to a var parameter, although we dont know *)
1223 CheckAddVariableWrite(Oper3, TRUE, QuadNo)
1245 DivTruncOp : CheckConst(Oper1) ;
1246 CheckAddVariableWrite(Oper1, FALSE, QuadNo) ;
1247 CheckAddVariableRead(Oper2, FALSE, QuadNo) ;
1248 CheckAddVariableRead(Oper3, FALSE, QuadNo) |
1250 XIndrOp : CheckConst(Oper1) ;
1251 CheckAddVariableWrite(Oper1, TRUE, QuadNo) ;
1252 CheckAddVariableRead(Oper3, FALSE, QuadNo) |
1254 IndrXOp : CheckConst(Oper1) ;
1255 CheckAddVariableWrite(Oper1, FALSE, QuadNo) ;
1256 CheckAddVariableRead(Oper3, TRUE, QuadNo) |
1258 (* RangeCheckOp : CheckRangeAddVariableRead(Oper3, QuadNo) | *)
1259 SaveExceptionOp : CheckConst(Oper1) ;
1260 CheckAddVariableWrite(Oper1, FALSE, QuadNo) |
1261 RestoreExceptionOp: CheckAddVariableRead(Oper1, FALSE, QuadNo)
1265 END AddQuadInformation ;
1268 PROCEDURE stop ; BEGIN END stop ;
1272 PutQuadO - alters a quadruple QuadNo with Op, Oper1, Oper2, Oper3, and
1273 sets a boolean to determinine whether overflow should be checked.
1276 PROCEDURE PutQuadO (QuadNo: CARDINAL;
1278 Oper1, Oper2, Oper3: CARDINAL;
1279 overflow: BOOLEAN) ;
1283 IF QuadNo = BreakAtQuad
1287 IF QuadrupleGeneration
1289 EraseQuad (QuadNo) ;
1290 AddQuadInformation (QuadNo, Op, Oper1, Oper2, Oper3) ;
1291 f := GetQF (QuadNo) ;
1297 CheckOverflow := overflow
1304 PutQuad - overwrites a quadruple QuadNo with Op, Oper1, Oper2, Oper3
1307 PROCEDURE PutQuad (QuadNo: CARDINAL;
1309 Oper1, Oper2, Oper3: CARDINAL) ;
1311 PutQuadO (QuadNo, Op, Oper1, Oper2, Oper3, TRUE)
1319 PROCEDURE UndoReadWriteInfo (QuadNo: CARDINAL;
1321 Oper1, Oper2, Oper3: CARDINAL) ;
1325 (* jumps, calls and branches *)
1333 IfGreEquOp : RemoveReference(QuadNo) ;
1334 CheckRemoveVariableRead(Oper1, FALSE, QuadNo) ;
1335 CheckRemoveVariableRead(Oper2, FALSE, QuadNo) |
1339 GotoOp : RemoveReference(QuadNo) |
1341 (* variable references *)
1344 ExclOp : CheckRemoveVariableRead(Oper1, FALSE, QuadNo) ;
1345 CheckRemoveVariableWrite(Oper1, TRUE, QuadNo) |
1352 SizeOp : CheckRemoveVariableWrite(Oper1, FALSE, QuadNo) ;
1353 CheckRemoveVariableRead(Oper3, FALSE, QuadNo) |
1354 AddrOp : CheckRemoveVariableWrite(Oper1, FALSE, QuadNo) ;
1355 (* CheckRemoveVariableReadLeftValue(Oper3, QuadNo) ; *)
1356 (* the next line is a kludge and assumes we _will_
1357 write to the variable as we have taken its address *)
1358 CheckRemoveVariableWrite(Oper1, TRUE, QuadNo) |
1359 ReturnValueOp : CheckRemoveVariableRead(Oper1, FALSE, QuadNo) |
1364 ParamOp : CheckRemoveVariableRead(Oper2, FALSE, QuadNo) ;
1365 CheckRemoveVariableRead(Oper3, FALSE, QuadNo) ;
1366 IF (Oper1>0) AND (Oper1<=NoOfParam(Oper2)) AND
1367 IsVarParam(Oper2, Oper1)
1369 (* _may_ also write to a var parameter, although we dont know *)
1370 CheckRemoveVariableWrite(Oper3, TRUE, QuadNo)
1392 DivTruncOp : CheckRemoveVariableWrite(Oper1, FALSE, QuadNo) ;
1393 CheckRemoveVariableRead(Oper2, FALSE, QuadNo) ;
1394 CheckRemoveVariableRead(Oper3, FALSE, QuadNo) |
1396 XIndrOp : CheckRemoveVariableWrite(Oper1, TRUE, QuadNo) ;
1397 CheckRemoveVariableRead(Oper3, FALSE, QuadNo) |
1399 IndrXOp : CheckRemoveVariableWrite(Oper1, FALSE, QuadNo) ;
1400 CheckRemoveVariableRead(Oper3, TRUE, QuadNo) |
1402 (* RangeCheckOp : CheckRangeRemoveVariableRead(Oper3, QuadNo) | *)
1403 SaveExceptionOp : CheckRemoveVariableWrite(Oper1, FALSE, QuadNo) |
1404 RestoreExceptionOp: CheckRemoveVariableRead(Oper1, FALSE, QuadNo)
1408 END UndoReadWriteInfo ;
1412 EraseQuad - erases a quadruple QuadNo, the quadruple is still in the list
1416 PROCEDURE EraseQuad (QuadNo: CARDINAL) ;
1420 f := GetQF(QuadNo) ;
1422 UndoReadWriteInfo(QuadNo, Operator, Operand1, Operand2, Operand3) ;
1423 Operator := DummyOp ; (* finally blank it out *)
1427 op1pos := UnknownTokenNo ;
1428 op2pos := UnknownTokenNo ;
1429 op3pos := UnknownTokenNo
1435 CheckAddVariableReadLeftValue -
1439 PROCEDURE CheckAddVariableReadLeftValue (sym: CARDINAL; q: CARDINAL) ;
1443 PutReadQuad(sym, LeftValue, q)
1445 END CheckAddVariableReadLeftValue ;
1450 CheckRemoveVariableReadLeftValue -
1454 PROCEDURE CheckRemoveVariableReadLeftValue (sym: CARDINAL; q: CARDINAL) ;
1458 RemoveReadQuad(sym, LeftValue, q)
1460 END CheckRemoveVariableReadLeftValue ;
1465 CheckAddVariableRead - checks to see whether symbol, Sym, is a variable or
1466 a parameter and if so it then adds this quadruple
1467 to the variable list.
1470 PROCEDURE CheckAddVariableRead (Sym: CARDINAL; canDereference: BOOLEAN; Quad: CARDINAL) ;
1474 PutReadQuad(Sym, GetMode(Sym), Quad) ;
1475 IF (GetMode(Sym)=LeftValue) AND canDereference
1477 PutReadQuad(Sym, RightValue, Quad)
1480 END CheckAddVariableRead ;
1484 CheckRemoveVariableRead - checks to see whether, Sym, is a variable or
1485 a parameter and if so then it removes the
1486 quadruple from the variable list.
1489 PROCEDURE CheckRemoveVariableRead (Sym: CARDINAL; canDereference: BOOLEAN; Quad: CARDINAL) ;
1493 RemoveReadQuad(Sym, GetMode(Sym), Quad) ;
1494 IF (GetMode(Sym)=LeftValue) AND canDereference
1496 RemoveReadQuad(Sym, RightValue, Quad)
1499 END CheckRemoveVariableRead ;
1503 CheckAddVariableWrite - checks to see whether symbol, Sym, is a variable and
1504 if so it then adds this quadruple to the variable list.
1507 PROCEDURE CheckAddVariableWrite (Sym: CARDINAL; canDereference: BOOLEAN; Quad: CARDINAL) ;
1511 IF (GetMode(Sym)=LeftValue) AND canDereference
1513 PutReadQuad(Sym, LeftValue, Quad) ;
1514 PutWriteQuad(Sym, RightValue, Quad)
1516 PutWriteQuad(Sym, GetMode(Sym), Quad)
1519 END CheckAddVariableWrite ;
1523 CheckRemoveVariableWrite - checks to see whether, Sym, is a variable and
1524 if so then it removes the quadruple from the
1528 PROCEDURE CheckRemoveVariableWrite (Sym: CARDINAL; canDereference: BOOLEAN; Quad: CARDINAL) ;
1532 IF (GetMode(Sym)=LeftValue) AND canDereference
1534 RemoveReadQuad(Sym, LeftValue, Quad) ;
1535 RemoveWriteQuad(Sym, RightValue, Quad)
1537 RemoveWriteQuad(Sym, GetMode(Sym), Quad)
1540 END CheckRemoveVariableWrite ;
1547 PROCEDURE CheckConst (sym: CARDINAL) ;
1551 PutToBeSolvedByQuads(sym)
1557 GetFirstQuad - returns the first quadruple.
1560 PROCEDURE GetFirstQuad () : CARDINAL ;
1567 GetNextQuad - returns the Quadruple number following QuadNo.
1570 PROCEDURE GetNextQuad (QuadNo: CARDINAL) : CARDINAL ;
1574 f := GetQF(QuadNo) ;
1580 SubQuad - subtracts a quadruple QuadNo from a list Head.
1583 PROCEDURE SubQuad (QuadNo: CARDINAL) ;
1588 f := GetQF(QuadNo) ;
1590 AlterReference(Head, QuadNo, f^.Next) ;
1591 UndoReadWriteInfo(QuadNo, Operator, Operand1, Operand2, Operand3)
1599 WHILE g^.Next#QuadNo DO
1605 f^.Operator := DummyOp ;
1611 GetRealQuad - returns the Quadruple number of the real quadruple
1612 at QuadNo or beyond.
1615 PROCEDURE GetRealQuad (QuadNo: CARDINAL) : CARDINAL ;
1620 IF InBounds(QuadArray, QuadNo)
1622 f := GetQF(QuadNo) ;
1624 IF (NOT IsPseudoQuad(QuadNo)) AND
1625 (Operator#DummyOp) AND (Operator#LineNumberOp) AND (Operator#StatementNoteOp)
1640 AlterReference - alters all references from OldQuad, to NewQuad in a
1641 quadruple list Head.
1644 PROCEDURE AlterReference (Head, OldQuad, NewQuad: CARDINAL) ;
1649 f := GetQF(OldQuad) ;
1650 WHILE (f^.NoOfTimesReferenced>0) AND (Head#0) DO
1665 GotoOp : IF Operand3=OldQuad
1667 ManipulateReference(Head, NewQuad)
1676 END AlterReference ;
1680 GrowQuads - grows the list of quadruples to the quadruple, to.
1683 PROCEDURE GrowQuads (to: CARDINAL) ;
1688 IF (to#0) AND (to>GrowInitialization)
1690 i := GrowInitialization+1 ;
1692 IF InBounds(QuadArray, i)
1694 Assert(GetIndice(QuadArray, i)#NIL)
1699 InternalError ('out of memory error when trying to allocate a quadruple')
1701 PutIndice(QuadArray, i, f) ;
1702 f^.NoOfTimesReferenced := 0
1706 GrowInitialization := to
1712 ManipulateReference - manipulates the quadruple, q, so that it now points to quad, to.
1715 PROCEDURE ManipulateReference (q: CARDINAL; to: CARDINAL) ;
1719 Assert((GrowInitialization>=q) OR (to=0)) ;
1721 RemoveReference(q) ;
1727 INC(f^.NoOfTimesReferenced)
1729 END ManipulateReference ;
1733 RemoveReference - remove the reference by quadruple, q, to wherever
1737 PROCEDURE RemoveReference (q: CARDINAL) ;
1742 IF (f^.Operand3#0) AND (f^.Operand3<NextQuad)
1744 g := GetQF(f^.Operand3) ;
1745 Assert(g^.NoOfTimesReferenced#0) ;
1746 DEC(g^.NoOfTimesReferenced)
1748 END RemoveReference ;
1752 CountQuads - returns the number of quadruples.
1755 PROCEDURE CountQuads () : CARDINAL ;
1762 NewQuad - sets QuadNo to a new quadruple.
1765 PROCEDURE NewQuad (VAR QuadNo: CARDINAL) ;
1769 QuadNo := FreeList ;
1770 IF InBounds (QuadArray, QuadNo) AND (GetIndice (QuadArray, QuadNo) # NIL)
1772 f := GetIndice (QuadArray, QuadNo)
1777 InternalError ('out of memory error trying to allocate a quadruple')
1780 PutIndice (QuadArray, QuadNo, f) ;
1781 f^.NoOfTimesReferenced := 0
1785 Operator := DummyOp ;
1790 IF GrowInitialization < FreeList
1792 GrowInitialization := FreeList
1798 CheckVariableAt - checks to see whether, sym, was declared at a particular address.
1801 PROCEDURE CheckVariableAt (sym: CARDINAL) ;
1803 IF IsVar (sym) AND IsVariableAtAddress (sym)
1805 IF GetMode (sym) = LeftValue
1807 GenQuad (InitAddressOp, sym, NulSym, GetVariableAtAddress (sym))
1809 InternalError ('expecting lvalue for this variable which is declared at an explicit address')
1812 END CheckVariableAt ;
1816 CheckVariablesAt - checks to see whether we need to initialize any pointers
1817 which point to variable declared at addresses.
1820 PROCEDURE CheckVariablesAt (scope: CARDINAL) ;
1822 ForeachLocalSymDo (scope, CheckVariableAt)
1823 END CheckVariablesAt ;
1827 GetTurnInterrupts - returns the TurnInterrupts procedure function.
1830 PROCEDURE GetTurnInterrupts (tok: CARDINAL) : CARDINAL ;
1834 RETURN GetQualidentImport (tok,
1835 MakeKey ('TurnInterrupts'), MakeKey ('COROUTINES'))
1837 RETURN GetQualidentImport (tok,
1838 MakeKey ('TurnInterrupts'), MakeKey ('SYSTEM'))
1840 END GetTurnInterrupts ;
1844 GetProtection - returns the PROTECTION data type.
1847 PROCEDURE GetProtection (tok: CARDINAL) : CARDINAL ;
1851 RETURN GetQualidentImport (tok,
1852 MakeKey ('PROTECTION'), MakeKey ('COROUTINES'))
1854 RETURN GetQualidentImport (tok,
1855 MakeKey ('PROTECTION'), MakeKey ('SYSTEM'))
1861 CheckNeedPriorityBegin - checks to see whether we need to save the old
1862 module priority and change to another module
1864 The current module initialization or procedure
1865 being built is defined by, scope. The module whose
1866 priority will be used is defined by, module.
1869 PROCEDURE CheckNeedPriorityBegin (tok: CARDINAL; scope, module: CARDINAL) ;
1871 ProcSym, old: CARDINAL ;
1873 IF GetPriority (module) # NulSym
1875 (* module has been given a priority *)
1876 ProcSym := GetTurnInterrupts (tok) ;
1879 old := MakeTemporary (tok, RightValue) ;
1880 PutVar (old, GetProtection (tok)) ;
1882 GenQuadO (tok, SavePriorityOp, old, scope, ProcSym, FALSE) ;
1883 PushWord (PriorityStack, old)
1886 END CheckNeedPriorityBegin ;
1890 CheckNeedPriorityEnd - checks to see whether we need to restore the old
1892 The current module initialization or procedure
1893 being built is defined by, scope.
1896 PROCEDURE CheckNeedPriorityEnd (tok: CARDINAL;
1897 scope, module: CARDINAL) ;
1899 ProcSym, old: CARDINAL ;
1901 IF GetPriority (module) # NulSym
1903 (* module has been given a priority *)
1904 ProcSym := GetTurnInterrupts (tok) ;
1907 old := PopWord (PriorityStack) ;
1908 GenQuad (RestorePriorityOp, old, scope, ProcSym)
1911 END CheckNeedPriorityEnd ;
1915 StartBuildDefFile - generates a StartFileDefOp quadruple indicating the file
1916 that has produced the subsequent quadruples.
1917 The code generator uses the StartDefFileOp quadruples
1918 to relate any error to the appropriate file.
1926 +------------+ +------------+
1927 | ModuleName | | ModuleName |
1928 |------------| |------------|
1933 q StartDefFileOp _ _ ModuleSym
1936 PROCEDURE StartBuildDefFile (tok: CARDINAL) ;
1941 PushT (ModuleName) ;
1942 GenQuadO (tok, StartDefFileOp, tok, NulSym, GetModule (ModuleName), FALSE)
1943 END StartBuildDefFile ;
1947 StartBuildModFile - generates a StartModFileOp quadruple indicating the file
1948 that has produced the subsequent quadruples.
1949 The code generator uses the StartModFileOp quadruples
1950 to relate any error to the appropriate file.
1958 +------------+ +------------+
1959 | ModuleName | | ModuleName |
1960 |------------| |------------|
1965 q StartModFileOp lineno filename ModuleSym
1968 PROCEDURE StartBuildModFile (tok: CARDINAL) ;
1970 GenQuadO (tok, StartModFileOp, tok,
1971 WORD (makekey (string (GetFileName ()))),
1972 GetFileModule (), FALSE)
1973 END StartBuildModFile ;
1977 EndBuildFile - generates an EndFileOp quadruple indicating the file
1978 that has produced the previous quadruples has ended.
1985 +------------+ +------------+
1986 | ModuleName | | ModuleName |
1987 |------------| |------------|
1992 q EndFileOp _ _ ModuleSym
1995 PROCEDURE EndBuildFile (tok: CARDINAL) ;
1999 ModuleName := OperandT (1) ;
2000 GenQuadO (tok, EndFileOp, NulSym, NulSym, GetModule (ModuleName), FALSE)
2005 StartBuildInit - Sets the start of initialization code of the
2006 current module to the next quadruple.
2009 PROCEDURE StartBuildInit (tok: CARDINAL) ;
2012 ModuleSym: CARDINAL ;
2015 ModuleSym := GetCurrentModule() ;
2016 Assert(IsModule(ModuleSym) OR IsDefImp(ModuleSym)) ;
2017 Assert(GetSymName(ModuleSym)=name) ;
2018 PutModuleStartQuad(ModuleSym, NextQuad) ;
2019 GenQuad(InitStartOp, tok, GetFileModule(), ModuleSym) ;
2020 PushWord(ReturnStack, 0) ;
2022 CheckVariablesAt(ModuleSym) ;
2023 CheckNeedPriorityBegin(tok, ModuleSym, ModuleSym) ;
2024 PushWord(TryStack, NextQuad) ;
2025 PushWord(CatchStack, 0) ;
2026 IF HasExceptionBlock(ModuleSym)
2028 GenQuad(TryOp, NulSym, NulSym, 0)
2030 END StartBuildInit ;
2034 EndBuildInit - Sets the end initialization code of a module.
2037 PROCEDURE EndBuildInit (tok: CARDINAL) ;
2039 IF HasExceptionBlock(GetCurrentModule())
2041 BuildRTExceptLeave (tok, TRUE) ;
2042 GenQuadO (tok, CatchEndOp, NulSym, NulSym, NulSym, FALSE)
2044 BackPatch (PopWord (ReturnStack), NextQuad) ;
2045 CheckNeedPriorityEnd (tok, GetCurrentModule(), GetCurrentModule()) ;
2046 PutModuleEndQuad (GetCurrentModule(), NextQuad) ;
2047 CheckVariablesInBlock (GetCurrentModule()) ;
2048 GenQuadO (tok, InitEndOp, tok, GetFileModule(), GetCurrentModule(), FALSE)
2053 StartBuildFinally - Sets the start of finalization code of the
2054 current module to the next quadruple.
2057 PROCEDURE StartBuildFinally (tok: CARDINAL) ;
2060 ModuleSym: CARDINAL ;
2063 ModuleSym := GetCurrentModule() ;
2064 Assert(IsModule(ModuleSym) OR IsDefImp(ModuleSym)) ;
2065 Assert(GetSymName(ModuleSym)=name) ;
2066 PutModuleFinallyStartQuad(ModuleSym, NextQuad) ;
2067 GenQuadO (tok, FinallyStartOp, tok, GetFileModule(), ModuleSym, FALSE) ;
2068 PushWord (ReturnStack, 0) ;
2070 (* CheckVariablesAt(ModuleSym) ; *)
2071 CheckNeedPriorityBegin (tok, ModuleSym, ModuleSym) ;
2072 PushWord (TryStack, NextQuad) ;
2073 PushWord (CatchStack, 0) ;
2074 IF HasExceptionFinally (ModuleSym)
2076 GenQuadO (tok, TryOp, NulSym, NulSym, 0, FALSE)
2078 END StartBuildFinally ;
2082 EndBuildFinally - Sets the end finalization code of a module.
2085 PROCEDURE EndBuildFinally (tok: CARDINAL) ;
2087 IF HasExceptionFinally(GetCurrentModule())
2089 BuildRTExceptLeave (tok, TRUE) ;
2090 GenQuadO (tok, CatchEndOp, NulSym, NulSym, NulSym, FALSE)
2092 BackPatch (PopWord (ReturnStack), NextQuad) ;
2093 CheckNeedPriorityEnd (tok, GetCurrentModule (), GetCurrentModule ()) ;
2094 PutModuleFinallyEndQuad(GetCurrentModule (), NextQuad) ;
2095 CheckVariablesInBlock (GetCurrentModule ()) ;
2096 GenQuadO (tok, FinallyEndOp, tok, GetFileModule (),
2097 GetCurrentModule(), FALSE)
2098 END EndBuildFinally ;
2102 BuildRTExceptEnter - informs RTExceptions that we are about to enter the except state.
2105 PROCEDURE BuildRTExceptEnter (tok: CARDINAL) ;
2112 (* now inform the Modula-2 runtime we are in the exception state *)
2113 ProcSym := GetQualidentImport (tok,
2114 MakeKey('SetExceptionState'), MakeKey('RTExceptions')) ;
2118 '{%W}no procedure SetExceptionState found in RTExceptions which is needed to implement exception handling')
2120 old := MakeTemporary (tok, RightValue) ;
2121 PutVar (old, Boolean) ;
2122 GenQuadO (tok, SaveExceptionOp, old, NulSym, ProcSym, FALSE) ;
2123 PushWord (ExceptStack, old)
2127 '{%E}cannot use {%kEXCEPT} blocks with the -fno-exceptions flag')
2129 END BuildRTExceptEnter ;
2133 BuildRTExceptLeave - informs RTExceptions that we are about to leave the except state.
2134 If, destroy, is TRUE then pop the ExceptStack.
2137 PROCEDURE BuildRTExceptLeave (tok: CARDINAL; destroy: BOOLEAN) ;
2144 (* now inform the Modula-2 runtime we are in the exception state *)
2145 ProcSym := GetQualidentImport (tok,
2146 MakeKey('SetExceptionState'), MakeKey('RTExceptions')) ;
2151 old := PopWord (ExceptStack)
2153 old := PeepWord (ExceptStack, 1)
2155 GenQuadO (tok, RestoreExceptionOp, old, NulSym, ProcSym, FALSE)
2158 (* no need for an error message here as it will be generated in the Enter procedure above *)
2160 END BuildRTExceptLeave ;
2164 BuildExceptInitial - adds an CatchBeginOp, CatchEndOp quadruple
2165 in the current block.
2168 PROCEDURE BuildExceptInitial (tok: CARDINAL) ;
2170 previous: CARDINAL ;
2172 (* we have finished the 'try' block, so now goto the return
2173 section which will tidy up (any) priorities before returning.
2175 GenQuadO (tok, GotoOp, NulSym, NulSym, PopWord(ReturnStack), FALSE) ;
2176 PushWord (ReturnStack, NextQuad-1) ;
2178 this is the 'catch' block.
2180 BackPatch (PeepWord (TryStack, 1), NextQuad) ;
2181 GenQuadO (tok, CatchBeginOp, NulSym, NulSym, NulSym, FALSE) ;
2182 previous := PopWord (CatchStack) ;
2186 '{%E}only allowed one EXCEPT statement in a procedure or module')
2188 PushWord (CatchStack, NextQuad-1) ;
2189 BuildRTExceptEnter (tok)
2190 END BuildExceptInitial ;
2194 BuildExceptFinally - adds an ExceptOp quadruple in a modules
2198 PROCEDURE BuildExceptFinally (tok: CARDINAL) ;
2200 BuildExceptInitial (tok)
2201 END BuildExceptFinally ;
2205 BuildExceptProcedure - adds an ExceptOp quadruple in a procedure
2209 PROCEDURE BuildExceptProcedure (tok: CARDINAL) ;
2211 BuildExceptInitial (tok)
2212 END BuildExceptProcedure ;
2216 BuildRetry - adds an RetryOp quadruple.
2219 PROCEDURE BuildRetry (tok: CARDINAL);
2221 IF PeepWord (CatchStack, 1) = 0
2224 '{%E}the {%kRETRY} statement must occur after an {%kEXCEPT} statement in the same module or procedure block')
2226 BuildRTExceptLeave (tok, FALSE) ;
2227 GenQuadO (tok, RetryOp, NulSym, NulSym, PeepWord (TryStack, 1), FALSE)
2233 SafeRequestSym - only used during scaffold to get argc, argv, envp.
2234 It attempts to get symbol name from the current scope(s) and if
2235 it fails then it falls back onto default constants.
2238 PROCEDURE SafeRequestSym (tok: CARDINAL; name: Name) : CARDINAL ;
2242 sym := GetSym (name) ;
2245 IF name = MakeKey ('argc')
2247 RETURN MakeConstLit (tok, MakeKey ('0'), ZType)
2248 ELSIF (name = MakeKey ('argv')) OR (name = MakeKey ('envp'))
2252 InternalError ('not expecting this parameter name') ;
2257 END SafeRequestSym ;
2261 callRequestDependant - create a call:
2262 RequestDependant (GetSymName (modulesym), GetSymName (depModuleSym));
2265 PROCEDURE callRequestDependant (tokno: CARDINAL;
2266 moduleSym, depModuleSym: CARDINAL;
2267 requestDep: CARDINAL) ;
2269 Assert (requestDep # NulSym) ;
2270 PushTtok (requestDep, tokno) ;
2271 PushTF (Adr, Address) ;
2272 PushTtok (MakeConstLitString (tokno, GetSymName (moduleSym)), tokno) ;
2276 IF depModuleSym = NulSym
2278 PushTF (Nil, Address)
2280 PushTF (Adr, Address) ;
2281 PushTtok (MakeConstLitString (tokno, GetSymName (depModuleSym)), tokno) ;
2287 BuildProcedureCall (tokno)
2288 END callRequestDependant ;
2292 ForeachImportInDepDo -
2295 PROCEDURE ForeachImportInDepDo (importStatements: List; moduleSym, requestDep: CARDINAL) ;
2303 IF importStatements # NIL
2306 n := NoOfItemsInList (importStatements) ;
2308 stmt := GetItemFromList (importStatements, i) ;
2309 Assert (IsImportStatement (stmt)) ;
2310 l := GetImportStatementList (stmt) ;
2312 m := NoOfItemsInList (l) ;
2314 imported := GetItemFromList (l, j) ;
2315 Assert (IsImport (imported)) ;
2316 callRequestDependant (GetImportDeclared (imported),
2317 moduleSym, GetImportModule (imported),
2324 END ForeachImportInDepDo ;
2328 ForeachImportedModuleDo -
2331 PROCEDURE ForeachImportedModuleDo (moduleSym, requestDep: CARDINAL) ;
2333 importStatements: List ;
2335 importStatements := GetModuleModImportStatementList (moduleSym) ;
2336 ForeachImportInDepDo (importStatements, moduleSym, requestDep) ;
2337 importStatements := GetModuleDefImportStatementList (moduleSym) ;
2338 ForeachImportInDepDo (importStatements, moduleSym, requestDep)
2339 END ForeachImportedModuleDo ;
2343 BuildM2DepFunction - creates the dependency graph procedure using IR:
2347 M2RTS_RequestDependant (module_name, "b");
2348 M2RTS_RequestDependant (module_name, NULL);
2352 PROCEDURE BuildM2DepFunction (tokno: CARDINAL; moduleSym: CARDINAL) ;
2355 ctor, init, fini, dep: CARDINAL ;
2359 (* Scaffold required and dynamic dependency graph should be produced. *)
2360 GetModuleCtors (moduleSym, ctor, init, fini, dep) ;
2362 BuildProcedureStart ;
2363 BuildProcedureBegin ;
2365 requestDep := GetQualidentImport (tokno,
2366 MakeKey ("RequestDependant"),
2367 MakeKey ("M2RTS")) ;
2368 IF requestDep # NulSym
2370 ForeachImportedModuleDo (moduleSym, requestDep) ;
2371 callRequestDependant (tokno, moduleSym, NulSym, requestDep)
2377 END BuildM2DepFunction ;
2381 BuildM2LinkFunction - creates the _M2_link procedure which will
2382 cause the linker to pull in all the module ctors.
2385 PROCEDURE BuildM2LinkFunction (tokno: CARDINAL) ;
2389 IF linkFunction # NulSym
2394 for each module in uselist do
2395 PROC foo_%d = _M2_module_ctor
2398 PushT (linkFunction) ;
2399 BuildProcedureStart ;
2400 BuildProcedureBegin ;
2401 StartScope (linkFunction) ;
2402 PopulateCtorArray (tokno) ;
2408 END BuildM2LinkFunction ;
2412 BuildTry - build the try statement for main.
2415 PROCEDURE BuildTry (tokno: CARDINAL) ;
2419 PushWord (TryStack, NextQuad) ;
2420 PushWord (CatchStack, 0) ;
2421 GenQuadO (tokno, TryOp, NulSym, NulSym, 0, FALSE)
2427 BuildExcept - build the except block for main.
2430 PROCEDURE BuildExcept (tokno: CARDINAL) ;
2432 catchProcedure: CARDINAL ;
2436 BuildExceptInitial (tokno) ;
2437 catchProcedure := GetQualidentImport (tokno,
2438 MakeKey ('DefaultErrorCatch'),
2439 MakeKey ('RTExceptions')) ;
2440 IF catchProcedure # NulSym
2442 PushTtok (catchProcedure, tokno) ;
2444 BuildProcedureCall (tokno)
2446 BuildRTExceptLeave (tokno, TRUE) ;
2447 GenQuadO (tokno, CatchEndOp, NulSym, NulSym, NulSym, FALSE)
2453 BuildM2MainFunction - creates the main function with appropriate calls to the scaffold.
2456 PROCEDURE BuildM2MainFunction (tokno: CARDINAL) ;
2458 IF (ScaffoldDynamic OR ScaffoldStatic) AND (NOT SharedFlag)
2460 (* Scaffold required and main should be produced. *)
2463 main (int argc, char *argv[], char *envp[])
2466 _M2_init (argc, argv, envp);
2467 _M2_fini (argc, argv, envp);
2471 RTExceptions_DefaultErrorCatch ();
2475 PushT (mainFunction) ;
2476 BuildProcedureStart ;
2477 BuildProcedureBegin ;
2478 StartScope (mainFunction) ;
2480 (* _M2_init (argc, argv, envp); *)
2481 PushTtok (initFunction, tokno) ;
2482 PushTtok (RequestSym (tokno, MakeKey ("argc")), tokno) ;
2483 PushTtok (RequestSym (tokno, MakeKey ("argv")), tokno) ;
2484 PushTtok (RequestSym (tokno, MakeKey ("envp")), tokno) ;
2486 BuildProcedureCall (tokno) ;
2488 (* _M2_fini (argc, argv, envp); *)
2489 PushTtok (finiFunction, tokno) ;
2490 PushTtok (RequestSym (tokno, MakeKey ("argc")), tokno) ;
2491 PushTtok (RequestSym (tokno, MakeKey ("argv")), tokno) ;
2492 PushTtok (RequestSym (tokno, MakeKey ("envp")), tokno) ;
2494 BuildProcedureCall (tokno) ;
2496 PushZero (tokno, Integer) ;
2497 BuildReturn (tokno) ;
2498 BuildExcept (tokno) ;
2503 END BuildM2MainFunction ;
2507 BuildM2InitFunction -
2510 PROCEDURE BuildM2InitFunction (tok: CARDINAL; moduleSym: CARDINAL) ;
2512 constructModules: CARDINAL ;
2514 IF ScaffoldDynamic OR ScaffoldStatic
2516 (* Scaffold required and main should be produced. *)
2518 _M2_init (int argc, char *argv[], char *envp[])
2520 M2RTS_ConstructModules (module_name, argc, argv, envp);
2522 PushT (initFunction) ;
2523 BuildProcedureStart ;
2524 BuildProcedureBegin ;
2525 StartScope (initFunction) ;
2528 IF linkFunction # NulSym
2531 PushTtok (linkFunction, tok) ;
2533 BuildProcedureCall (tok)
2536 (* Lookup ConstructModules and call it. *)
2537 constructModules := GetQualidentImport (tok,
2538 MakeKey ("ConstructModules"),
2539 MakeKey ("M2RTS")) ;
2540 IF constructModules # NulSym
2542 (* ConstructModules (module_name, argc, argv, envp); *)
2543 PushTtok (constructModules, tok) ;
2545 PushTF(Adr, Address) ;
2546 PushTtok (MakeConstLitString (tok, GetSymName (moduleSym)), tok) ;
2550 PushTtok (SafeRequestSym (tok, MakeKey ("argc")), tok) ;
2551 PushTtok (SafeRequestSym (tok, MakeKey ("argv")), tok) ;
2552 PushTtok (SafeRequestSym (tok, MakeKey ("envp")), tok) ;
2554 BuildProcedureCall (tok) ;
2556 ELSIF ScaffoldStatic
2558 ForeachModuleCallInit (tok,
2559 SafeRequestSym (tok, MakeKey ("argc")),
2560 SafeRequestSym (tok, MakeKey ("argv")),
2561 SafeRequestSym (tok, MakeKey ("envp")))
2567 END BuildM2InitFunction ;
2571 BuildM2FiniFunction -
2574 PROCEDURE BuildM2FiniFunction (tok: CARDINAL; moduleSym: CARDINAL) ;
2576 deconstructModules: CARDINAL ;
2578 IF ScaffoldDynamic OR ScaffoldStatic
2580 (* Scaffold required and main should be produced. *)
2581 PushT (finiFunction) ;
2582 BuildProcedureStart ;
2583 BuildProcedureBegin ;
2584 StartScope (finiFunction) ;
2588 _M2_finish (int argc, char *argv[], char *envp[])
2590 M2RTS_DeconstructModules (module_name, argc, argv, envp);
2592 deconstructModules := GetQualidentImport (tok,
2593 MakeKey ("DeconstructModules"),
2594 MakeKey ("M2RTS")) ;
2595 IF deconstructModules # NulSym
2597 (* DeconstructModules (module_name, argc, argv, envp); *)
2598 PushTtok (deconstructModules, tok) ;
2600 PushTF(Adr, Address) ;
2601 PushTtok (MakeConstLitString (tok, GetSymName (moduleSym)), tok) ;
2605 PushTtok (SafeRequestSym (tok, MakeKey ("argc")), tok) ;
2606 PushTtok (SafeRequestSym (tok, MakeKey ("argv")), tok) ;
2607 PushTtok (SafeRequestSym (tok, MakeKey ("envp")), tok) ;
2609 BuildProcedureCall (tok)
2611 ELSIF ScaffoldStatic
2613 ForeachModuleCallFinish (tok,
2614 SafeRequestSym (tok, MakeKey ("argc")),
2615 SafeRequestSym (tok, MakeKey ("argv")),
2616 SafeRequestSym (tok, MakeKey ("envp")))
2622 END BuildM2FiniFunction ;
2626 BuildM2CtorFunction - create a constructor function associated with moduleSym.
2631 M2RTS_RegisterModule (GetSymName (moduleSym),
2632 init, fini, dependencies);
2636 PROCEDURE BuildM2CtorFunction (tok: CARDINAL; moduleSym: CARDINAL) ;
2638 RegisterModule : CARDINAL ;
2639 ctor, init, fini, dep: CARDINAL ;
2643 GetModuleCtors (moduleSym, ctor, init, fini, dep) ;
2646 Assert (IsProcedure (ctor)) ;
2648 BuildProcedureStart ;
2649 BuildProcedureBegin ;
2651 RegisterModule := GetQualidentImport (tok,
2652 MakeKey ("RegisterModule"),
2653 MakeKey ("M2RTS")) ;
2654 IF RegisterModule # NulSym
2656 (* RegisterModule (module_name, init, fini, dependencies); *)
2657 PushTtok (RegisterModule, tok) ;
2659 PushTF (Adr, Address) ;
2660 PushTtok (MakeConstLitString (tok, GetSymName (moduleSym)), tok) ;
2664 PushTtok (init, tok) ;
2665 PushTtok (fini, tok) ;
2666 PushTtok (dep, tok) ;
2668 BuildProcedureCall (tok)
2675 END BuildM2CtorFunction ;
2679 BuildScaffold - generate the main, init, finish functions if
2680 no -c and this is the application module.
2683 PROCEDURE BuildScaffold (tok: CARDINAL; moduleSym: CARDINAL) ;
2685 IF GetMainModule () = moduleSym
2687 DeclareScaffold (tok) ;
2688 IF (ScaffoldMain OR (NOT cflag))
2690 (* There are module init/fini functions and
2691 application init/fini functions.
2692 Here we create the application pair. *)
2693 BuildM2LinkFunction (tok) ;
2694 BuildM2MainFunction (tok) ;
2695 BuildM2InitFunction (tok, moduleSym) ; (* Application init. *)
2696 BuildM2FiniFunction (tok, moduleSym) ; (* Application fini. *)
2698 BuildM2DepFunction (tok, moduleSym) ; (* Per module dependency. *)
2699 (* Each module needs a ctor to register the module
2700 init/finish/dep with M2RTS. *)
2701 BuildM2CtorFunction (tok, moduleSym)
2704 DeclareScaffold (tok) ;
2705 BuildM2DepFunction (tok, moduleSym) ; (* Per module dependency. *)
2706 (* Each module needs a ctor to register the module
2707 init/finish/dep with M2RTS. *)
2708 BuildM2CtorFunction (tok, moduleSym)
2714 BuildModuleStart - starts current module scope.
2717 PROCEDURE BuildModuleStart (tok: CARDINAL) ;
2721 WORD (makekey (string (GetFileName ()))), GetCurrentModule (), FALSE)
2722 END BuildModuleStart ;
2726 StartBuildInnerInit - Sets the start of initialization code of the
2727 inner module to the next quadruple.
2730 PROCEDURE StartBuildInnerInit (tok: CARDINAL) ;
2732 PutModuleStartQuad (GetCurrentModule(), NextQuad) ;
2733 GenQuadO (tok, InitStartOp, tok, NulSym, GetCurrentModule(), FALSE) ;
2734 PushWord (ReturnStack, 0) ;
2735 CheckNeedPriorityBegin (tok, GetCurrentModule(), GetCurrentModule()) ;
2736 PushWord (TryStack, NextQuad) ;
2737 PushWord (CatchStack, 0) ;
2738 IF HasExceptionFinally (GetCurrentModule())
2740 GenQuadO (tok, TryOp, NulSym, NulSym, 0, FALSE)
2742 END StartBuildInnerInit ;
2746 EndBuildInnerInit - Sets the end initialization code of a module.
2749 PROCEDURE EndBuildInnerInit (tok: CARDINAL) ;
2751 IF HasExceptionBlock (GetCurrentModule())
2753 BuildRTExceptLeave (tok, TRUE) ;
2754 GenQuadO (tok, CatchEndOp, NulSym, NulSym, NulSym, FALSE)
2756 PutModuleEndQuad (GetCurrentModule(), NextQuad) ;
2757 CheckVariablesInBlock (GetCurrentModule ()) ;
2758 BackPatch (PopWord (ReturnStack), NextQuad) ;
2759 CheckNeedPriorityEnd (tok, GetCurrentModule (), GetCurrentModule ()) ;
2760 GenQuadO (tok, InitEndOp, tok, NulSym, GetCurrentModule (), FALSE)
2761 END EndBuildInnerInit ;
2765 BuildModulePriority - assigns the current module with a priority
2766 from the top of stack.
2778 PROCEDURE BuildModulePriority ;
2780 Priority: CARDINAL ;
2783 PutPriority (GetCurrentModule (), Priority)
2784 END BuildModulePriority ;
2788 ForLoopAnalysis - checks all the FOR loops for index variable manipulation
2789 and dangerous usage outside the loop.
2792 PROCEDURE ForLoopAnalysis ;
2795 forDesc: ForLoopInfo ;
2799 n := HighIndice (ForInfo) ;
2802 forDesc := GetIndice (ForInfo, i) ;
2803 CheckForIndex (forDesc) ;
2807 END ForLoopAnalysis ;
2811 AddForInfo - adds the description of the FOR loop into the record list.
2812 This is used if -pedantic is turned on to check index variable
2816 PROCEDURE AddForInfo (Start, End, IncQuad: CARDINAL; Sym: CARDINAL; idtok: CARDINAL) ;
2818 forDesc: ForLoopInfo ;
2824 IncrementQuad := IncQuad ;
2825 StartOfForLoop := Start ;
2826 EndOfForLoop := End ;
2827 ForLoopIndex := Sym ;
2830 IncludeIndiceIntoIndex (ForInfo, forDesc)
2836 CheckForIndex - checks the quadruples: Start..End to see whether a
2837 for loop index is manipulated by the programmer.
2838 It generates a warning if this is the case.
2839 It also checks to see whether the IndexSym is read
2840 immediately outside the loop in which case a warning
2844 PROCEDURE CheckForIndex (forDesc: ForLoopInfo) ;
2847 WriteStart, WriteEnd: CARDINAL ;
2849 GetWriteLimitQuads (forDesc^.ForLoopIndex, RightValue, forDesc^.StartOfForLoop, forDesc^.EndOfForLoop, WriteStart, WriteEnd) ;
2850 IF (WriteStart < forDesc^.IncrementQuad) AND (WriteStart > forDesc^.StartOfForLoop)
2852 MetaErrorT1 (forDesc^.IndexTok,
2853 '{%kFOR} loop index variable {%1Wad} is being manipulated inside the loop',
2854 forDesc^.ForLoopIndex) ;
2855 MetaErrorT1 (QuadToTokenNo (WriteStart),
2856 '{%kFOR} loop index variable {%1Wad} is being manipulated, this is considered bad practice and may cause unknown program behaviour',
2857 forDesc^.ForLoopIndex)
2859 GetWriteLimitQuads (forDesc^.ForLoopIndex, RightValue, forDesc^.EndOfForLoop, 0, WriteStart, WriteEnd) ;
2860 GetReadLimitQuads (forDesc^.ForLoopIndex, RightValue, forDesc^.EndOfForLoop, 0, ReadStart, ReadEnd) ;
2861 IF (ReadStart#0) AND ((ReadStart < WriteStart) OR (WriteStart = 0))
2863 MetaErrorT1 (forDesc^.IndexTok,
2864 '{%kFOR} loop index variable {%1Wad} is being read outside the FOR loop (without being reset)',
2865 forDesc^.ForLoopIndex) ;
2866 MetaErrorT1 (QuadToTokenNo (ReadStart),
2867 '{%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',
2868 forDesc^.ForLoopIndex)
2874 GetCurrentFunctionName - returns the name for the current __FUNCTION__
2878 PROCEDURE GetCurrentFunctionName () : Name ;
2883 IF CurrentProc=NulSym
2885 s := InitStringCharStar(KeyToCharStar(GetSymName(GetCurrentModule()))) ;
2886 s := Sprintf1(Mark(InitString('module %s initialization')), s) ;
2887 n := makekey(string(s)) ;
2888 s := KillString(s) ;
2891 RETURN( GetSymName(CurrentProc) )
2893 END GetCurrentFunctionName ;
2898 BuildRange - generates a RangeCheckOp quad with, r, as its operand.
2901 PROCEDURE BuildRange (r: CARDINAL) ;
2903 GenQuad (RangeCheckOp, WORD (GetLineNo ()), NulSym, r)
2908 BuildError - generates a ErrorOp quad, indicating that if this
2909 quadruple is reachable, then a runtime error would
2913 PROCEDURE BuildError (r: CARDINAL) ;
2915 GenQuad (ErrorOp, WORD (GetLineNo ()), NulSym, r)
2920 CheckPointerThroughNil - builds a range quadruple, providing, sym, is
2921 a candidate for checking against NIL.
2922 This range quadruple is only expanded into
2923 code during the code generation phase
2924 thus allowing limited compile time checking.
2927 PROCEDURE CheckPointerThroughNil (tokpos: CARDINAL; sym: CARDINAL) ;
2929 IF IsVar (sym) AND GetVarPointerCheck (sym)
2931 (* PutVarPointerCheck(sym, FALSE) ; (* so we do not detect this again *) *)
2932 BuildRange (InitPointerRangeCheck (tokpos, sym, GetMode (sym) = LeftValue))
2934 END CheckPointerThroughNil ;
2938 CollectLow - returns the low of the subrange value.
2941 PROCEDURE CollectLow (sym: CARDINAL) : CARDINAL ;
2943 low, high: CARDINAL ;
2947 GetSubrange (sym, high, low) ;
2950 InternalError ('expecting Subrange symbol')
2956 CollectHigh - returns the high of the subrange value, sym.
2959 PROCEDURE CollectHigh (sym: CARDINAL) : CARDINAL ;
2961 low, high: CARDINAL ;
2965 GetSubrange (sym, high, low) ;
2968 InternalError ('expecting Subrange symbol')
2974 BackPatchSubrangesAndOptParam - runs through all the quadruples and finds SubrangeLow or SubrangeHigh
2975 quadruples and replaces it by an assignment to the Low or High component
2976 of the subrange type.
2979 SubrangeLow op1 op3 (* op3 is a subrange *)
2985 SubrangeHigh op1 op3 (* op3 is a subrange *)
2991 OptParam op1 op2 op3
2994 Param op1 op2 GetOptArgInit(op3)
2997 PROCEDURE BackPatchSubrangesAndOptParam ;
3002 q := GetFirstQuad () ;
3010 SubrangeLowOp : Operand3 := CollectLow (Operand3) ;
3011 Operator := BecomesOp |
3012 SubrangeHighOp: Operand3 := CollectHigh (Operand3) ;
3013 Operator := BecomesOp |
3014 OptParamOp : Operand3 := GetOptArgInit (Operand3) ;
3023 END BackPatchSubrangesAndOptParam ;
3027 CheckCompatibleWithBecomes - checks to see that symbol, sym, is
3028 compatible with the := operator.
3031 PROCEDURE CheckCompatibleWithBecomes (des, expr,
3032 destok, exprtok: CARDINAL) ;
3036 MetaErrorT1 (destok,
3037 'an assignment cannot assign a value to a type {%1a}', des)
3038 ELSIF IsProcedure (des)
3040 MetaErrorT1 (destok,
3041 'an assignment cannot assign a value to a procedure {%1a}', des)
3042 ELSIF IsFieldEnumeration (des)
3044 MetaErrorT1 (destok,
3045 'an assignment cannot assign a value to an enumeration field {%1a}', des)
3047 IF IsPseudoBaseProcedure (expr) OR IsPseudoBaseFunction (expr)
3049 MetaErrorT1 (exprtok,
3050 'an assignment cannot assign a {%1d} {%1a}', expr)
3052 END CheckCompatibleWithBecomes ;
3056 BuildAssignmentWithoutBounds - calls BuildAssignment but makes sure we do not
3060 PROCEDURE BuildAssignmentWithoutBounds (tok: CARDINAL; checkTypes, checkOverflow: BOOLEAN) ;
3064 old := MustNotCheckBounds ;
3065 MustNotCheckBounds := TRUE ;
3066 doBuildAssignment (tok, checkTypes, checkOverflow) ;
3067 MustNotCheckBounds := old
3068 END BuildAssignmentWithoutBounds ;
3072 MarkArrayWritten - marks, Array, as being written.
3075 PROCEDURE MarkArrayWritten (Array: CARDINAL) ;
3077 IF (Array#NulSym) AND IsVarAParam(Array)
3079 PutVarWritten(Array, TRUE)
3081 END MarkArrayWritten ;
3085 MarkAsReadWrite - marks the variable or parameter as being
3089 PROCEDURE MarkAsReadWrite (sym: CARDINAL) ;
3091 IF (sym#NulSym) AND IsVar(sym)
3093 PutReadQuad (sym, RightValue, NextQuad) ;
3094 PutWriteQuad (sym, RightValue, NextQuad)
3096 END MarkAsReadWrite ;
3100 MarkAsRead - marks the variable or parameter as being read.
3103 PROCEDURE MarkAsRead (sym: CARDINAL) ;
3105 IF (sym#NulSym) AND IsVar(sym)
3107 PutReadQuad (sym, RightValue, NextQuad)
3113 MarkAsWrite - marks the variable or parameter as being written.
3116 PROCEDURE MarkAsWrite (sym: CARDINAL) ;
3118 IF (sym#NulSym) AND IsVar(sym)
3120 PutWriteQuad(sym, RightValue, NextQuad)
3126 doVal - return an expression which is VAL(type, expr). If
3127 expr is a constant then return expr.
3130 PROCEDURE doVal (type, expr: CARDINAL) : CARDINAL ;
3132 IF (NOT IsConst(expr)) AND (SkipType(type)#GetDType(expr))
3134 PushTF(Convert, NulSym) ;
3135 PushT(SkipType(type)) ;
3137 PushT(2) ; (* Two parameters *)
3138 BuildConvertFunction ;
3149 PROCEDURE MoveWithMode (tokno: CARDINAL;
3150 Des, Exp, Array: CARDINAL;
3151 destok, exptok: CARDINAL;
3152 checkOverflow: BOOLEAN) ;
3156 IF IsConstString(Exp) AND IsConst(Des)
3158 GenQuadOtok (tokno, BecomesOp, Des, NulSym, Exp, TRUE,
3159 tokno, destok, exptok) ;
3160 PutConstString (tokno, Des, GetString (Exp))
3162 IF GetMode(Des)=RightValue
3164 IF GetMode(Exp)=LeftValue
3166 CheckPointerThroughNil (tokno, Exp) ; (* Des = *Exp *)
3167 doIndrX (tokno, Des, Exp)
3169 GenQuadOtok (tokno, BecomesOp, Des, NulSym, Exp, TRUE,
3170 tokno, destok, exptok)
3172 ELSIF GetMode(Des)=LeftValue
3174 MarkArrayWritten (Array) ;
3175 IF GetMode(Exp) = LeftValue
3177 t := MakeTemporary (tokno, RightValue) ;
3178 PutVar(t, GetSType(Exp)) ;
3179 CheckPointerThroughNil (tokno, Exp) ;
3180 doIndrX (tokno, t, Exp) ;
3181 CheckPointerThroughNil (tokno, Des) ; (* *Des = Exp *)
3182 GenQuadO (tokno, XIndrOp, Des, GetSType (Des), doVal (GetSType (Des), t),
3185 CheckPointerThroughNil (tokno, Des) ; (* *Des = Exp *)
3186 GenQuadO (tokno, XIndrOp, Des, GetSType (Des), doVal (GetSType (Des), Exp),
3190 GenQuadOtok (tokno, BecomesOp, Des, NulSym, Exp, TRUE,
3191 tokno, destok, exptok)
3198 BuildBuiltinConst - makes reference to a builtin constant within gm2.
3203 +------------+ +------------+
3205 |------------| |------------|
3209 q Sym BuiltinConstOp Ident
3212 PROCEDURE BuildBuiltinConst ;
3218 PopTtok (Id, idtok) ;
3219 Sym := MakeTemporary (idtok, ImmediateValue) ;
3220 PutVar (Sym, Integer) ;
3222 CASE GetBuiltinConstType(KeyToCharStar(Name(Id))) OF
3224 0: ErrorFormat1(NewError(GetTokenNo()),
3225 '%a unrecognised builtin constant', Id) |
3226 1: PutVar(Sym, Integer) |
3227 2: PutVar(Sym, Real)
3230 InternalError ('unrecognised value')
3233 GenQuadO (idtok, BuiltinConstOp, Sym, NulSym, Id, FALSE) ;
3234 PushTtok (Sym, idtok)
3235 END BuildBuiltinConst ;
3239 BuildBuiltinTypeInfo - make reference to a builtin typeinfo function
3247 |-------------| +------------+
3249 |-------------| |------------|
3253 q Sym BuiltinTypeInfoOp Type Ident
3256 PROCEDURE BuildBuiltinTypeInfo ;
3263 PopTtok (Ident, idtok) ;
3265 Sym := MakeTemporary (BuiltinTokenNo, ImmediateValue) ;
3266 CASE GetBuiltinTypeInfoType (KeyToCharStar (Name (Ident))) OF
3268 0: ErrorFormat1 (NewError(idtok),
3269 '%a unrecognised builtin constant', Ident) |
3270 1: PutVar (Sym, Boolean) |
3271 2: PutVar (Sym, ZType) |
3272 3: PutVar (Sym, RType)
3275 InternalError ('unrecognised value')
3277 GenQuadO (idtok, BuiltinTypeInfoOp, Sym, Type, Ident, FALSE) ;
3278 PushTtok (Sym, idtok)
3279 END BuildBuiltinTypeInfo ;
3283 CheckBecomesMeta - checks to make sure that we are not
3284 assigning a variable to a constant.
3285 Also check we are not assigning to an
3289 PROCEDURE CheckBecomesMeta (Des, Exp: CARDINAL; combinedtok, destok, exprtok: CARDINAL) ;
3291 IF IsConst (Des) AND IsVar (Exp)
3293 MetaErrorsT2 (combinedtok,
3294 'in assignment, cannot assign a variable {%2a} to a constant {%1a}',
3295 'designator {%1Da} is declared as a {%kCONST}', Des, Exp)
3297 IF (GetDType(Des) # NulSym) AND IsVar (Des) AND IsUnbounded (GetDType (Des))
3299 MetaErrorT1 (destok,
3300 'in assignment, cannot assign to an unbounded array {%1ad}', Des)
3302 IF (GetDType(Exp) # NulSym) AND IsVar (Exp) AND IsUnbounded (GetDType (Exp))
3304 MetaErrorT1 (exprtok,
3305 'in assignment, cannot assign from an unbounded array {%1ad}', Exp)
3307 END CheckBecomesMeta ;
3311 BuildAssignment - Builds an assignment from the values given on the
3312 quad stack. Either an assignment to an
3313 arithmetic expression or an assignment to a
3314 boolean expression. This procedure should not
3315 be called in CONST declarations.
3316 The Stack is expected to contain:
3329 |------------| +------------+
3331 |------------| |------------|
3336 q BecomesOp Designator _ Expression
3348 |------------| +------------+
3350 |------------| |------------|
3355 q BecomesOp Designator _ TRUE
3357 q+2 BecomesOp Designator _ FALSE
3361 PROCEDURE BuildAssignment (becomesTokNo: CARDINAL) ;
3363 des, exp : CARDINAL ;
3366 combinedtok: CARDINAL ;
3368 des := OperandT (2) ;
3371 destok := OperandTok (2) ;
3372 exptok := OperandTok (1) ;
3373 exp := OperandT (1) ;
3376 MetaErrorT1 (destok, 'destok {%1Ead}', des) ;
3377 MetaErrorT1 (exptok, 'exptok {%1Ead}', exp)
3379 combinedtok := MakeVirtualTok (becomesTokNo, destok, exptok) ;
3382 MetaErrorT1 (combinedtok, 'combined {%1Ead}', des)
3386 MetaErrorT1 (combinedtok,
3387 'cannot assign expression to a constant designator {%1Ead}', des)
3389 exp := OperandT (1) ;
3390 MetaErrorT2 (combinedtok,
3391 'cannot assign a constant designator {%1Ead} with an expression {%2Ead}',
3394 PopN (2) (* Remove both parameters. *)
3397 PopN (2) (* Remove both parameters. *)
3399 doBuildAssignment (becomesTokNo, TRUE, TRUE)
3401 END BuildAssignment ;
3405 BuildAssignConstant - used to create constant in the CONST declaration.
3406 The stack is expected to contain:
3418 |------------| +------------+
3420 |------------| |------------|
3425 q BecomesOp Designator _ Expression
3437 |------------| +------------+
3439 |------------| |------------|
3444 q BecomesOp Designator _ TRUE
3446 q+2 BecomesOp Designator _ FALSE
3449 PROCEDURE BuildAssignConstant (equalsTokNo: CARDINAL) ;
3451 doBuildAssignment (equalsTokNo, TRUE, TRUE)
3452 END BuildAssignConstant ;
3456 doBuildAssignment - subsiduary procedure of BuildAssignment.
3457 It builds the assignment and optionally
3458 checks the types are compatible.
3461 PROCEDURE doBuildAssignment (becomesTokNo: CARDINAL; checkTypes, checkOverflow: BOOLEAN) ;
3466 Des, Exp : CARDINAL ;
3468 destok, exptok: CARDINAL ;
3474 PopTtok (Des, destok) ;
3475 (* Conditional Boolean Assignment. *)
3476 BackPatch (t, NextQuad) ;
3477 IF GetMode (Des) = RightValue
3479 GenQuadO (becomesTokNo, BecomesOp, Des, NulSym, True, checkOverflow)
3481 CheckPointerThroughNil (destok, Des) ;
3482 GenQuadO (destok, XIndrOp, Des, Boolean, True, checkOverflow)
3484 GenQuadO (destok, GotoOp, NulSym, NulSym, NextQuad+2, checkOverflow) ;
3485 BackPatch (f, NextQuad) ;
3486 IF GetMode (Des) = RightValue
3488 GenQuadO (becomesTokNo, BecomesOp, Des, NulSym, False, checkOverflow)
3490 CheckPointerThroughNil (destok, Des) ;
3491 GenQuadO (destok, XIndrOp, Des, Boolean, False, checkOverflow)
3494 PopTrwtok (Exp, r, exptok) ;
3498 MetaError0 ('{%E}unknown expression found during assignment') ;
3501 Array := OperandA (1) ;
3502 PopTrwtok (Des, w, destok) ;
3504 CheckCompatibleWithBecomes (Des, Exp, destok, exptok) ;
3505 combinedtok := MakeVirtualTok (becomesTokNo, destok, exptok) ;
3506 IF (GetSType (Des) # NulSym) AND (NOT IsSet (GetDType (Des)))
3508 (* Tell code generator to test runtime values of assignment so ensure we
3509 catch overflow and underflow. *)
3510 BuildRange (InitAssignmentRangeCheck (combinedtok, Des, Exp))
3514 CheckBecomesMeta (Des, Exp, combinedtok, destok, exptok)
3516 (* Traditional Assignment. *)
3517 MoveWithMode (becomesTokNo, Des, Exp, Array, destok, exptok, checkOverflow) ;
3521 IF (CannotCheckTypeInPass3 (Des) OR CannotCheckTypeInPass3 (Exp))
3523 (* We must do this after the assignment to allow the Designator to be
3524 resolved (if it is a constant) before the type checking is done. *)
3525 (* Prompt post pass 3 to check the assignment once all types are resolved. *)
3526 BuildRange (InitTypesAssignmentCheck (combinedtok, Des, Exp))
3529 (* BuildRange (InitTypesAssignmentCheck (combinedtok, Des, Exp)) ; *)
3530 CheckAssignCompatible (Des, Exp, combinedtok, destok, exptok)
3534 END doBuildAssignment ;
3538 CheckAssignCompatible - checks to see that an assignment is compatible.
3539 It performs limited checking - thorough checking
3540 is done in pass 3. But we do what we can here
3541 given knowledge so far.
3544 PROCEDURE CheckAssignCompatible (Des, Exp: CARDINAL; combinedtok, destok, exprtok: CARDINAL) ;
3546 DesT, ExpT, DesL: CARDINAL ;
3548 DesT := GetSType(Des) ;
3549 ExpT := GetSType(Exp) ;
3550 DesL := GetLType(Des) ;
3551 IF IsProcedure(Exp) AND
3552 ((DesT#NulSym) AND (NOT IsProcType(DesT))) AND
3553 ((DesL#NulSym) AND (NOT IsProcType(DesL)))
3555 MetaErrorT1 (destok,
3556 'incorrectly assigning a procedure to a designator {%1Ead} (designator is not a procedure type, {%1ast})', Des)
3557 ELSIF IsProcedure (Exp) AND IsProcedureNested (Exp)
3559 MetaErrorT1 (exprtok,
3560 'cannot call nested procedure {%1Ead} indirectly as the outer scope will not be known', Exp)
3561 ELSIF IsConstString(Exp)
3563 ELSIF (DesT#NulSym) AND (IsUnbounded(DesT))
3565 ELSIF (ExpT#NulSym) AND (IsUnbounded(ExpT))
3567 ELSIF (DesL#NulSym) AND IsArray(DesL)
3569 ELSIF IsConstructor(Exp)
3573 (* ignore type checking *)
3574 ELSIF (DesT=NulSym) AND IsConst(Des) AND (IsConstructor(Des) OR IsConstSet(Des))
3577 ELSIF NOT IsAssignmentCompatible(DesT, ExpT)
3579 MetaErrorT1 (combinedtok,
3580 'constructor expression is not compatible during assignment to {%1Ead}', Des)
3582 ELSIF (DesT#NulSym) AND IsSet(DesT) AND IsConst(Exp)
3584 (* We ignore checking of these types in pass 3 - but we do check them thoroughly post pass 3 *)
3585 ELSIF IsConst(Exp) AND (ExpT#Address) AND (NOT IsConst(Des)) AND
3586 (DesL#NulSym) AND ((DesL=Cardinal) OR (NOT IsSubrange(DesL))) AND
3587 (NOT IsEnumeration(DesL))
3589 IF (IsBaseType(DesL) OR IsSystemType(DesL))
3591 CheckAssignmentCompatible (combinedtok, ExpT, DesT)
3593 MetaErrorT2 (combinedtok,
3594 '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)
3597 IF (DesT#NulSym) AND IsProcType(DesT) AND IsProcedure(Exp)
3599 DesT := GetSType(DesT) ; (* we can at least check RETURN values of procedure variables *)
3600 (* remember that thorough assignment checking is done post pass 3 *)
3601 CheckAssignmentCompatible (combinedtok, ExpT, DesT)
3604 END CheckAssignCompatible ;
3608 CheckBooleanId - Checks to see if the top operand is a boolean.
3609 If the operand is not a boolean then it is tested
3610 with true and a boolean is generated.
3616 +------------+ +------------+
3618 |------------| |------------|
3626 PROCEDURE CheckBooleanId ;
3630 IF NOT IsBoolean (1)
3632 tok := OperandTok (1) ;
3633 IF IsVar (OperandT (1))
3635 IF GetSType (OperandT (1)) # Boolean
3637 MetaError1 ('{%1Ua:is not a boolean expression}' +
3638 '{!%1Ua:boolean expression expected}', OperandT (1))
3645 END CheckBooleanId ;
3649 BuildAlignment - builds an assignment to an alignment constant.
3651 The Stack is expected to contain:
3662 |---------------| empty
3665 PROCEDURE BuildAlignment (tokno: CARDINAL) ;
3673 IF name # MakeKey ('bytealignment')
3675 MetaError1 ('expecting bytealignment identifier, rather than {%1Ea}',
3676 MakeError (tokno, name))
3678 GetConstFromFifoQueue (align) ;
3681 BuildAssignConstant (tokno)
3682 END BuildAlignment ;
3686 BuildBitLength - builds an assignment to a bit length constant.
3688 The Stack is expected to contain:
3697 |------------| empty
3700 PROCEDURE BuildBitLength (tokno: CARDINAL) ;
3706 GetConstFromFifoQueue (length) ;
3709 BuildAssignConstant (tokno)
3710 END BuildBitLength ;
3714 BuildDefaultFieldAlignment - builds an assignment to an alignment constant.
3716 The Stack is expected to contain:
3725 |------------| empty
3728 PROCEDURE BuildDefaultFieldAlignment ;
3736 IF name # MakeKey ('bytealignment')
3738 MetaError0 ('{%E}only allowed to use the attribute {%kbytealignment} in the default record field alignment pragma')
3740 GetConstFromFifoQueue (align) ;
3743 BuildAssignConstant (GetTokenNo ())
3744 END BuildDefaultFieldAlignment ;
3748 BuildPragmaField - builds an assignment to an alignment constant.
3750 The Stack is expected to contain:
3759 |------------| empty
3762 PROCEDURE BuildPragmaField ;
3770 IF (name # MakeKey ('unused')) AND (name # MakeKey ('bytealignment'))
3772 MetaError0 ('only allowed to use the attribute {%Ekbytealignment} in the default record field alignment pragma')
3776 GetConstFromFifoQueue (const) ;
3779 BuildAssignConstant (GetTokenNo ())
3781 END BuildPragmaField ;
3785 BuildRepeat - Builds the repeat statement from the quad stack.
3786 The Stack is expected to contain:
3801 PROCEDURE BuildRepeat ;
3808 BuildUntil - Builds the until part of the repeat statement
3809 from the quad stack.
3810 The Stack is expected to contain:
3820 | RepeatQuad | Empty
3824 PROCEDURE BuildUntil ;
3832 BackPatch(f, Repeat) ; (* If False then keep on repeating *)
3833 BackPatch(t, NextQuad) ; (* If True then exit repeat *)
3838 BuildWhile - Builds the While part of the While statement
3839 from the quad stack.
3840 The Stack is expected to contain:
3852 PROCEDURE BuildWhile ;
3859 BuildDoWhile - Builds the Do part of the while statement
3860 from the quad stack.
3861 The Stack is expected to contain:
3868 +------------+ +------------+
3870 |------------| |------------|
3871 | WhileQuad | | WhileQuad |
3872 |------------| |------------|
3876 BackPatch t exit to the NextQuad
3879 PROCEDURE BuildDoWhile ;
3885 BackPatch(t, NextQuad) ;
3891 BuildEndWhile - Builds the end part of the while statement
3892 from the quad stack.
3893 The Stack is expected to contain:
3909 False exit is backpatched with q+1
3912 PROCEDURE BuildEndWhile ;
3920 GenQuad(GotoOp, NulSym, NulSym, While) ;
3921 BackPatch(f, NextQuad)
3926 BuildLoop - Builds the Loop part of the Loop statement
3927 from the quad stack.
3928 The Stack is expected to contain:
3935 Empty +------------+
3940 PROCEDURE BuildLoop ;
3943 PushExit(0) (* Seperate Exit Stack for loop end *)
3948 BuildExit - Builds the Exit part of the Loop statement.
3951 PROCEDURE BuildExit ;
3953 IF IsEmptyWord(ExitStack)
3955 MetaError0 ('{%EkEXIT} is only allowed in a {%kLOOP} statement')
3957 GenQuad(GotoOp, NulSym, NulSym, 0) ;
3958 PushExit(Merge(PopExit(), NextQuad-1))
3964 BuildEndLoop - Builds the End part of the Loop statement
3965 from the quad stack.
3966 The Stack is expected to contain:
3982 PROCEDURE BuildEndLoop ;
3987 GenQuad(GotoOp, NulSym, NulSym, Loop) ;
3988 BackPatch(PopExit(), NextQuad)
3993 BuildThenIf - Builds the Then part of the If statement
3994 from the quad stack.
3995 The Stack is expected to contain:
4002 +------------+ +------------+
4004 |------------| |------------|
4008 The true exit is BackPatched to point to
4012 PROCEDURE BuildThenIf ;
4018 BackPatch(t, NextQuad) ;
4024 BuildElse - Builds the Else part of the If statement
4025 from the quad stack.
4026 The Stack is expected to contain:
4033 +------------+ +------------+
4034 | t | f | | t+q | 0 |
4035 |------------| |------------|
4040 q+1 <- BackPatched from f
4043 PROCEDURE BuildElse ;
4047 GenQuad(GotoOp, NulSym, NulSym, 0) ;
4049 BackPatch(f, NextQuad) ;
4050 PushBool(Merge(t, NextQuad-1), 0) (* NextQuad-1 = Goto Quad *)
4055 BuildEndIf - Builds the End part of the If statement
4056 from the quad stack.
4057 The Stack is expected to contain:
4070 Both t and f are backpatched to point to the NextQuad
4073 PROCEDURE BuildEndIf ;
4078 BackPatch(t, NextQuad) ;
4079 BackPatch(f, NextQuad)
4084 BuildElsif1 - Builds the Elsif part of the If statement
4085 from the quad stack.
4086 The Stack is expected to contain:
4093 +------------+ +------------+
4094 | t | f | | t+q | 0 |
4095 |------------| |------------|
4100 q+1 <- BackPatched from f
4103 PROCEDURE BuildElsif1 ;
4107 GenQuad(GotoOp, NulSym, NulSym, 0) ;
4109 BackPatch(f, NextQuad) ;
4110 PushBool(Merge(t, NextQuad-1), 0) (* NextQuad-1 = Goto Quad *)
4115 BuildElsif2 - Builds the Elsif until part of the If statement
4116 from the quad stack.
4117 The Stack is expected to contain:
4126 |--------------| +---------------+
4127 | t2 | f2 | | t2 | f1+f2 |
4128 |--------------| |---------------|
4131 PROCEDURE BuildElsif2 ;
4139 PushBool(t2, Merge(f1, f2))
4144 PushOne - pushes the value one to the stack.
4145 The Stack is changed:
4157 PROCEDURE PushOne (tok: CARDINAL; type: CARDINAL; message: ARRAY OF CHAR) ;
4161 PushTF (MakeConstLit (tok, MakeKey('1'), NulSym), NulSym)
4162 ELSIF IsEnumeration (type)
4164 IF NoOfElements (type) = 0
4166 MetaErrorString1 (ConCat (InitString ('enumeration type only has one element {%1Dad} and therefore '),
4167 Mark (InitString (message))),
4169 PushZero (tok, type)
4171 PushTF (Convert, NulSym) ;
4173 PushT (MakeConstLit (tok, MakeKey ('1'), ZType)) ;
4174 PushT (2) ; (* Two parameters *)
4175 BuildConvertFunction
4178 PushTF (MakeConstLit (tok, MakeKey ('1'), type), type)
4184 PushZero - pushes the value zero to the stack.
4185 The Stack is changed:
4197 PROCEDURE PushZero (tok: CARDINAL; type: CARDINAL) ;
4201 PushTFtok (MakeConstLit (tok, MakeKey ('0'), NulSym), NulSym, tok)
4202 ELSIF IsEnumeration (type)
4204 PushTFtok (Convert, NulSym, tok) ;
4205 PushTtok (type, tok) ;
4206 PushTtok (MakeConstLit (tok, MakeKey ('0'), ZType), tok) ;
4207 PushT (2) ; (* Two parameters *)
4208 BuildConvertFunction
4210 PushTFtok (MakeConstLit (tok, MakeKey ('0'), type), type, tok)
4216 BuildPseudoBy - Builds the Non existant part of the By
4217 clause of the For statement
4218 from the quad stack.
4219 The Stack is expected to contain:
4227 Ptr -> | BySym | t |
4228 +------------+ |------------|
4230 |------------| |------------|
4233 PROCEDURE BuildPseudoBy ;
4235 e, t, dotok: CARDINAL ;
4237 PopTFtok (e, t, dotok) ; (* as there is no BY token this position is the DO at the end of the last expression. *)
4238 PushTFtok (e, t, dotok) ;
4243 PushOne (dotok, t, 'the implied FOR loop increment will cause an overflow {%1ad}')
4248 BuildForLoopToRangeCheck - builds the range check to ensure that the id
4249 does not exceed the limits of its type.
4252 PROCEDURE BuildForLoopToRangeCheck ;
4259 BuildRange (InitForLoopToRangeCheck (d, e)) ;
4262 END BuildForLoopToRangeCheck ;
4266 BuildForToByDo - Builds the For To By Do part of the For statement
4267 from the quad stack.
4268 The Stack is expected to contain:
4276 +----------------+ |----------------|
4277 | BySym | ByType | | ForQuad |
4278 |----------------| |----------------|
4279 | e2 | | LastValue |
4280 |----------------| |----------------|
4281 | e1 | | BySym | ByType |
4282 |----------------| |----------------|
4283 | Ident | | IdentSym |
4284 |----------------| |----------------|
4288 LASTVALUE := ((e2-e1) DIV BySym) * BySym + e1
4312 q BecomesOp IdentSym _ e1
4313 q+ LastValue := ((e1-e2) DIV by) * by + e1
4314 q+1 if >= by 0 q+..2
4320 q+..2 If >= e2 e1 q+..4
4324 The For Loop is regarded:
4326 For ident := e1 To e2 By by Do
4331 PROCEDURE BuildForToByDo ;
4354 PopTFtok (BySym, ByType, bytok) ;
4355 PopTtok (e2, e2tok) ;
4356 PopTtok (e1, e1tok) ;
4357 PopTtok (Id, idtok) ;
4358 IdSym := RequestSym (idtok, Id) ;
4359 IF NOT IsExpressionCompatible (GetSType (e1), GetSType (e2))
4361 MetaError2 ('incompatible types found in {%EkFOR} loop header, initial expression {%E1tsad} and final expression {%E2tsad}',
4363 CheckExpressionCompatible (idtok, GetSType (e1), GetSType (e2))
4365 IF NOT IsExpressionCompatible( GetSType (e1), ByType)
4367 MetaError2 ('incompatible types found in {%EkFOR} loop header, initial expression {%E1tsad} and {%kBY} {%E2tsad}',
4369 CheckExpressionCompatible (e1tok, GetSType (e1), ByType)
4370 ELSIF NOT IsExpressionCompatible (GetSType (e2), ByType)
4372 MetaError2 ('incompatible types found in {%EkFOR} loop header, final expression {%E1tsad} and {%kBY} {%E2tsad}',
4374 CheckExpressionCompatible (e1tok, GetSType (e2), ByType)
4376 BuildRange (InitForLoopBeginRangeCheck (IdSym, e1)) ;
4377 PushTtok (IdSym, idtok) ;
4378 PushTtok (e1, e1tok) ;
4379 BuildAssignmentWithoutBounds (idtok, TRUE, TRUE) ;
4382 FinalValue := MakeTemporary (e2tok,
4383 AreConstant (IsConst (e1) AND IsConst (e2) AND
4385 PutVar (FinalValue, GetSType (IdSym)) ;
4386 etype := MixTypes (GetSType (e1), GetSType (e2), e2tok) ;
4387 e1 := doConvert (etype, e1) ;
4388 e2 := doConvert (etype, e2) ;
4390 PushTF (FinalValue, GetSType(FinalValue)) ;
4391 PushTFtok (e2, GetSType(e2), e2tok) ; (* FinalValue := ((e1-e2) DIV By) * By + e1 *)
4393 PushTFtok (e1, GetSType(e1), e1tok) ;
4394 doBuildBinaryOp (TRUE, FALSE) ;
4396 PushTFtok (BySym, ByType, bytok) ;
4397 doBuildBinaryOp (FALSE, FALSE) ;
4399 PushTFtok (BySym, ByType, bytok) ;
4400 doBuildBinaryOp (FALSE, FALSE) ;
4402 PushTFtok (e1, GetSType (e1), e1tok) ;
4403 doBuildBinaryOp (FALSE, FALSE) ;
4404 BuildForLoopToRangeCheck ;
4405 BuildAssignmentWithoutBounds (e1tok, FALSE, FALSE) ;
4407 (* q+1 if >= by 0 q+..2 *)
4408 (* q+2 GotoOp q+3 *)
4409 PushTFtok (BySym, ByType, bytok) ; (* BuildRelOp 1st parameter *)
4410 PushT (GreaterEqualTok) ; (* 2nd parameter *)
4412 PushZero (bytok, ByType) ;
4414 BuildRelOp (e2tok) ; (* choose final expression position. *)
4416 BackPatch(f, NextQuad) ;
4417 (* q+3 If >= e1 e2 q+5 *)
4418 (* q+4 GotoOp Exit *)
4419 PushTFtok (e1, GetSType (e1), e1tok) ; (* BuildRelOp 1st parameter *)
4420 PushT (GreaterEqualTok) ; (* 2nd parameter *)
4421 PushTFtok (e2, GetSType (e2), e2tok) ; (* 3rd parameter *)
4422 BuildRelOp (e2tok) ; (* choose final expression position. *)
4423 PopBool (t1, exit1) ;
4424 BackPatch (t1, NextQuad) ;
4425 PushFor (Merge (PopFor(), exit1)) ; (* merge exit1 *)
4427 GenQuad (GotoOp, NulSym, NulSym, 0) ;
4428 ForLoop := NextQuad-1 ;
4432 BackPatch (t, NextQuad) ;
4433 PushTFtok (e2, GetSType(e2), e2tok) ; (* BuildRelOp 1st parameter *)
4434 PushT (GreaterEqualTok) ; (* 2nd parameter *)
4435 PushTFtok (e1, GetSType(e1), e1tok) ; (* 3rd parameter *)
4436 BuildRelOp (e2tok) ;
4437 PopBool (t1, exit1) ;
4438 BackPatch (t1, NextQuad) ;
4439 PushFor (Merge (PopFor (), exit1)) ; (* merge exit1 *)
4441 BackPatch(ForLoop, NextQuad) ; (* fixes the start of the for loop *)
4442 ForLoop := NextQuad ;
4444 (* and set up the stack *)
4446 PushTFtok (IdSym, GetSym (IdSym), idtok) ;
4447 PushTFtok (BySym, ByType, bytok) ;
4448 PushTFtok (FinalValue, GetSType (FinalValue), e2tok) ;
4450 END BuildForToByDo ;
4454 BuildEndFor - Builds the End part of the For statement
4455 from the quad stack.
4456 The Stack is expected to contain:
4474 PROCEDURE BuildEndFor (endpostok: CARDINAL) ;
4489 PopTFtok (BySym, ByType, bytok) ;
4490 PopTtok (IdSym, idtok) ;
4492 (* IF IdSym=LastSym THEN exit END *)
4493 PushTF(IdSym, GetSType (IdSym)) ;
4495 PushTF (LastSym, GetSType (LastSym)) ;
4496 BuildRelOp (endpostok) ;
4499 BackPatch (t, NextQuad) ;
4500 GenQuad (GotoOp, NulSym, NulSym, 0) ;
4501 PushFor (Merge (PopFor (), NextQuad-1)) ;
4502 BackPatch (f, NextQuad) ;
4503 IF GetMode (IdSym) = LeftValue
4505 (* index variable is a LeftValue, therefore we must dereference it *)
4506 tsym := MakeTemporary (idtok, RightValue) ;
4507 PutVar (tsym, GetSType (IdSym)) ;
4508 CheckPointerThroughNil (idtok, IdSym) ;
4509 doIndrX (endpostok, tsym, IdSym) ;
4510 BuildRange (InitForLoopEndRangeCheck (tsym, BySym)) ; (* --fixme-- pass endpostok. *)
4511 IncQuad := NextQuad ;
4512 (* we have explicitly checked using the above and also
4513 this addition can legally overflow if a cardinal type
4514 is counting down. The above test will generate a more
4515 precise error message, so we suppress overflow detection
4517 GenQuadO (bytok, AddOp, tsym, tsym, BySym, FALSE) ;
4518 CheckPointerThroughNil (idtok, IdSym) ;
4519 GenQuadO (idtok, XIndrOp, IdSym, GetSType (IdSym), tsym, FALSE)
4521 BuildRange (InitForLoopEndRangeCheck (IdSym, BySym)) ;
4522 IncQuad := NextQuad ;
4523 (* we have explicitly checked using the above and also
4524 this addition can legally overflow if a cardinal type
4525 is counting down. The above test will generate a more
4526 precise error message, so we suppress overflow detection
4528 GenQuadO (idtok, AddOp, IdSym, IdSym, BySym, FALSE)
4530 GenQuadO (endpostok, GotoOp, NulSym, NulSym, ForQuad, FALSE) ;
4531 BackPatch (PopFor (), NextQuad) ;
4532 AddForInfo (ForQuad, NextQuad-1, IncQuad, IdSym, idtok)
4537 BuildCaseStart - starts the case statement.
4538 It initializes a backpatch list on the compile
4539 time stack, the list is used to contain all
4540 case break points. The list is later backpatched
4541 and contains all positions of the case statement
4542 which jump to the end of the case statement.
4543 The stack also contains room for a boolean
4544 expression, this is needed to allow , operator
4545 in the CaseField alternatives.
4547 The Stack is expected to contain:
4561 PROCEDURE BuildCaseStart ;
4563 BuildRange (InitCaseBounds (PushCase (NulSym, NulSym))) ;
4564 PushBool (0, 0) ; (* BackPatch list initialized *)
4565 PushBool (0, 0) (* Room for a boolean expression *)
4566 END BuildCaseStart ;
4570 BuildCaseStartStatementSequence - starts the statement sequence
4571 inside a case clause.
4572 BackPatches the true exit to the
4579 +-----------+ +------------+
4581 |-----------| |------------|
4584 PROCEDURE BuildCaseStartStatementSequence ;
4589 BackPatch (t, NextQuad) ;
4591 END BuildCaseStartStatementSequence ;
4595 BuildCaseEndStatementSequence - ends the statement sequence
4596 inside a case clause.
4597 BackPatches the false exit f1 to the
4599 Asserts that t1 and f2 is 0
4611 +-----------+ +------------+
4612 | t1 | f1 | | 0 | 0 |
4613 |-----------| |------------|
4614 | t2 | f2 | | t2+q | 0 |
4615 |-----------| |------------|
4618 PROCEDURE BuildCaseEndStatementSequence ;
4623 GenQuad (GotoOp, NulSym, NulSym, 0) ;
4625 PopBool (t2, f2) ; (* t2 contains the break list for the case *)
4626 BackPatch (f1, NextQuad) ; (* f1 no longer needed *)
4629 PushBool (Merge (t2, NextQuad-1), 0) ; (* NextQuad-1 = Goto Quad *)
4630 PushBool (0, 0) (* Room for boolean expression *)
4631 END BuildCaseEndStatementSequence ;
4635 BuildCaseRange - builds the range testing quaruples for
4638 IF (e1>=ce1) AND (e1<=ce2)
4650 |-----------| +-----------+
4652 |-----------| |-----------|
4653 | t1 | f1 | | t1 | f1 |
4654 |-----------| |-----------|
4655 | t2 | f2 | | t2 | f2 |
4656 |-----------| |-----------|
4658 |-----------| |-----------|
4661 PROCEDURE BuildCaseRange ;
4672 PopTtok (ce2, ce2tok) ;
4673 PopTtok (ce1, ce1tok) ;
4674 combinedtok := MakeVirtualTok (ce2tok, ce2tok, ce1tok) ;
4675 AddRange (ce1, ce2, combinedtok) ;
4678 PopTtok (e1, e1tok) ;
4679 PushTtok (e1, e1tok) ; (* leave e1 on bottom of stack when exit procedure *)
4681 PushBool (t1, f1) ; (* also leave t1 and f1 on the bottom of the stack *)
4682 PushTtok (e1, e1tok) ;
4683 PushT (GreaterEqualTok) ;
4684 PushTtok (ce1, ce1tok) ;
4685 BuildRelOp (combinedtok) ;
4688 PushTtok (e1, e1tok) ;
4689 PushT (LessEqualTok) ;
4690 PushTtok (ce2, ce2tok) ;
4691 BuildRelOp (combinedtok) ;
4693 END BuildCaseRange ;
4697 BuildCaseEquality - builds the range testing quadruples for
4710 +-----------+ +-----------+
4712 |-----------| |-----------|
4713 | t1 | f1 | | t1 | f1 |
4714 |-----------| |-----------|
4715 | t2 | f2 | | t2 | f2 |
4716 |-----------| |-----------|
4718 |-----------| |-----------|
4721 PROCEDURE BuildCaseEquality ;
4729 PopTtok (ce1, ce1tok) ;
4730 AddRange (ce1, NulSym, ce1tok) ;
4733 PopTtok (e1, e1tok) ;
4734 PushTtok (e1, e1tok) ; (* leave e1 on bottom of stack when exit procedure *)
4735 PushBool (t2, f2) ; (* also leave t2 and f2 on the bottom of the stack *)
4737 PushTtok (e1, e1tok) ;
4739 PushTtok (ce1, ce1tok) ;
4741 END BuildCaseEquality ;
4745 BuildCaseList - merges two case tests into one
4754 |-----------| +-------------+
4755 | t1 | f1 | | t1+t2| f1+f2|
4756 |-----------| |-------------|
4759 PROCEDURE BuildCaseList ;
4766 PushBool (Merge (t1, t2), Merge (f1, f2))
4771 BuildCaseOr - builds the , in the case clause.
4778 +-----------+ +------------+
4780 |-----------| |------------|
4783 PROCEDURE BuildCaseOr ;
4788 BackPatch (f, NextQuad) ;
4794 BuildCaseElse - builds the else of case clause.
4801 +-----------+ +------------+
4803 |-----------| |------------|
4806 PROCEDURE BuildCaseElse ;
4811 BackPatch (f, NextQuad) ;
4817 BuildCaseEnd - builds the end of case clause.
4833 PROCEDURE BuildCaseEnd ;
4839 BackPatch (f, NextQuad) ;
4840 BackPatch (t, NextQuad) ;
4842 BackPatch (f, NextQuad) ;
4843 BackPatch (t, NextQuad) ;
4850 BuildCaseCheck - builds the case checking code to ensure that
4851 the program does not need an else clause at runtime.
4852 The stack is unaltered.
4855 PROCEDURE BuildCaseCheck ;
4857 BuildError (InitNoElseRangeCheck ())
4858 END BuildCaseCheck ;
4862 BuildNulParam - Builds a nul parameter on the stack.
4868 Empty +------------+
4873 PROCEDURE BuildNulParam ;
4880 BuildSizeCheckStart - switches off all quadruple generation if the function SIZE or HIGH
4881 is being "called". This should be done as SIZE only requires the
4882 actual type of the expression, not its value. Consider the problem of
4883 SIZE(UninitializedPointer^) which is quite legal and it must
4885 ISO Modula-2 also allows HIGH(a[0]) for a two dimensional array
4886 and there is no need to compute a[0], we just need to follow the
4887 type and count dimensions. However if SIZE(a) or HIGH(a) occurs
4888 and, a, is an unbounded array then we turn on quadruple generation.
4890 The Stack is expected to contain:
4897 +----------------------+ +----------------------+
4898 | ProcSym | Type | tok | | ProcSym | Type | tok |
4899 |----------------------| |----------------------|
4902 PROCEDURE BuildSizeCheckStart ;
4904 ProcSym, Type, tok: CARDINAL ;
4906 PopTFtok (ProcSym, Type, tok) ;
4907 IF (ProcSym=Size) OR (ProcSym=TSize) OR (ProcSym=TBitSize)
4909 QuadrupleGeneration := FALSE ;
4910 BuildingSize := TRUE
4913 QuadrupleGeneration := FALSE ;
4914 BuildingHigh := TRUE
4916 PushTFtok (ProcSym, Type, tok)
4917 END BuildSizeCheckStart ;
4921 BuildSizeCheckEnd - checks to see whether the function "called" was in fact SIZE.
4922 If so then we restore quadruple generation.
4925 PROCEDURE BuildSizeCheckEnd (ProcSym: CARDINAL) ;
4927 IF (ProcSym=Size) OR (ProcSym=TSize) OR (ProcSym=TBitSize)
4929 QuadrupleGeneration := TRUE ;
4930 BuildingSize := FALSE
4933 QuadrupleGeneration := TRUE ;
4934 BuildingHigh := FALSE
4936 END BuildSizeCheckEnd ;
4940 BuildProcedureCall - builds a procedure call.
4941 Although this procedure does not directly
4942 destroy the procedure parameters, it calls
4943 routine which will manipulate the stack and
4944 so the entry and exit states of the stack are shown.
4965 | ProcSym | Type | Empty
4969 PROCEDURE BuildProcedureCall (tokno: CARDINAL) ;
4972 ProcSym : CARDINAL ;
4975 ProcSym := OperandT (NoOfParam+1) ;
4976 PushT (NoOfParam) ; (* Compile time stack restored to entry state *)
4977 IF IsPseudoBaseProcedure (ProcSym) OR IsPseudoSystemProcedure (ProcSym)
4980 ManipulatePseudoCallParameters ;
4982 BuildPseudoProcedureCall (tokno) ;
4984 ELSIF IsUnknown (ProcSym)
4986 MetaError1 ('{%1Ua} is not recognised as a procedure, check declaration or import', ProcSym) ;
4987 PopN (NoOfParam + 2)
4990 BuildRealProcedureCall (tokno) ;
4993 END BuildProcedureCall ;
4997 BuildRealProcedureCall - builds a real procedure call.
5017 | ProcSym | Type | Empty
5021 PROCEDURE BuildRealProcedureCall (tokno: CARDINAL) ;
5023 NoOfParam: CARDINAL ;
5024 ProcSym : CARDINAL ;
5028 ProcSym := OperandT (NoOfParam+2) ;
5029 ProcSym := SkipConst (ProcSym) ;
5030 (* tokno := OperandTtok (NoOfParam+2) ; *) (* --checkme-- *)
5033 (* Procedure Variable ? *)
5034 ProcSym := SkipType (OperandF (NoOfParam+2))
5036 IF IsDefImp (GetScope (ProcSym)) AND IsDefinitionForC (GetScope (ProcSym))
5038 BuildRealFuncProcCall (tokno, FALSE, TRUE)
5040 BuildRealFuncProcCall (tokno, FALSE, FALSE)
5042 END BuildRealProcedureCall ;
5046 BuildRealFuncProcCall - builds a real procedure or function call.
5066 | ProcSym | Type | Empty
5070 PROCEDURE BuildRealFuncProcCall (tokno: CARDINAL; IsFunc, IsForC: BOOLEAN) ;
5073 ParamConstant : BOOLEAN ;
5083 CheckProcedureParameters (IsForC) ;
5084 PopT (NoOfParameters) ;
5085 PushT (NoOfParameters) ; (* Restore stack to original state. *)
5086 ProcSym := OperandT (NoOfParameters+2) ;
5087 proctok := tokno ; (* OperandTtok (NoOfParameters+2) ; *)
5088 IF proctok = UnknownTokenNo
5090 proctok := GetTokenNo ()
5092 paramtok := proctok ;
5093 ProcSym := SkipConst (ProcSym) ;
5094 ForcedFunc := FALSE ;
5097 (* Procedure Variable ? *)
5098 Proc := SkipType (OperandF (NoOfParameters+2)) ;
5099 ParamConstant := FALSE
5102 ParamConstant := IsProcedureBuiltin (Proc)
5106 IF GetSType (Proc) = NulSym
5108 MetaErrors1 ('procedure {%1a} cannot be used as a function',
5109 'procedure {%1Da} does not have a return type',
5113 (* is being called as a procedure *)
5114 IF GetSType (Proc) # NulSym
5116 (* however it was declared as a procedure function *)
5117 IF NOT IsReturnOptional (Proc)
5119 MetaErrors1 ('function {%1a} is being called but its return value is ignored',
5120 'function {%1Da} return a type {%1ta:of {%1ta}}',
5127 ManipulateParameters (IsForC) ;
5128 CheckParameterOrdinals ;
5129 PopT(NoOfParameters) ;
5132 GenQuad (ParamOp, 0, Proc, ProcSym) (* Space for return value *)
5134 IF (NoOfParameters+1=NoOfParam(Proc)) AND UsesOptArg(Proc)
5136 GenQuad (OptParamOp, NoOfParam(Proc), Proc, Proc)
5138 i := NoOfParameters ;
5139 pi := 1 ; (* stack index referencing stacked parameter, i *)
5141 paramtok := OperandTtok (pi) ;
5142 GenQuadO (paramtok, ParamOp, i, Proc, OperandT (pi), TRUE) ;
5143 IF NOT IsConst (OperandT (pi))
5145 ParamConstant := FALSE
5150 GenQuadO (proctok, CallOp, NulSym, NulSym, ProcSym, TRUE) ;
5151 PopN (NoOfParameters+1) ; (* Destroy arguments and procedure call *)
5154 (* ReturnVar - will have the type of the procedure *)
5155 resulttok := MakeVirtualTok (proctok, proctok, paramtok) ;
5156 ReturnVar := MakeTemporary (resulttok, AreConstant(ParamConstant)) ;
5157 PutVar (ReturnVar, GetSType(Proc)) ;
5158 GenQuadO (resulttok, FunctValueOp, ReturnVar, NulSym, Proc, TRUE) ;
5161 PushTFtok (ReturnVar, GetSType (Proc), resulttok)
5164 END BuildRealFuncProcCall ;
5168 CheckProcedureParameters - Checks the parameters which are being passed to
5177 +----------------+ +----------------+
5178 | NoOfParam | | NoOfParam |
5179 |----------------| |----------------|
5180 | Param 1 | | Param 1 |
5181 |----------------| |----------------|
5182 | Param 2 | | Param 2 |
5183 |----------------| |----------------|
5187 |----------------| |----------------|
5188 | Param # | | Param # |
5189 |----------------| |----------------|
5190 | ProcSym | Type | | ProcSym | Type |
5191 |----------------| |----------------|
5195 PROCEDURE CheckProcedureParameters (IsForC: BOOLEAN) ;
5198 paramtok : CARDINAL ;
5211 PushT(ParamTotal) ; (* Restore stack to origional state *)
5212 ProcSym := OperandT(ParamTotal+1+1) ;
5213 proctok := OperandTtok(ParamTotal+1+1) ;
5214 IF IsVar(ProcSym) AND IsProcType(GetDType(ProcSym))
5216 (* Procedure Variable ? *)
5217 Proc := SkipType(OperandF(ParamTotal+1+1))
5219 Proc := SkipConst(ProcSym)
5221 IF NOT (IsProcedure(Proc) OR IsProcType(Proc))
5225 MetaError1('{%1Ua} is not recognised as a procedure, check declaration or import', Proc)
5227 MetaErrors1('{%1a} is not recognised as a procedure, check declaration or import',
5228 '{%1Ua} is not recognised as a procedure, check declaration or import',
5232 IF CompilerDebugging
5234 n1 := GetSymName(Proc) ;
5235 printf1(' %a ( ', n1)
5239 s := InitString ('procedure') ;
5240 WarnStringAt (s, proctok)
5244 pi := ParamTotal+1 ; (* stack index referencing stacked parameter, i *)
5245 WHILE i<=ParamTotal DO
5246 IF i<=NoOfParam(Proc)
5248 FormalI := GetParam(Proc, i) ;
5249 IF CompilerDebugging
5251 n1 := GetSymName(FormalI) ;
5252 n2 := GetSymName(GetSType(FormalI)) ;
5253 printf2('%a: %a', n1, n2)
5255 Actual := OperandT(pi) ;
5256 Dim := OperandD(pi) ;
5257 paramtok := OperandTtok(pi) ;
5260 s := InitString ('actual') ;
5261 WarnStringAt (s, paramtok)
5264 BuildRange(InitTypesParameterCheck(Proc, i, FormalI, Actual)) ;
5267 IF IsVarParam(Proc, i)
5269 FailParameter (paramtok,
5270 'trying to pass a constant to a VAR parameter',
5271 Actual, FormalI, Proc, i)
5272 ELSIF IsConstString (Actual)
5274 IF (GetStringLength (Actual) = 0) (* if = 0 then it maybe unknown at this time *)
5276 (* dont check this yet *)
5277 ELSIF IsArray(GetDType(FormalI)) AND (GetSType(GetDType(FormalI))=Char)
5279 (* allow string literals to be passed to ARRAY [0..n] OF CHAR *)
5280 ELSIF (GetStringLength(Actual) = 1) (* if = 1 then it maybe treated as a char *)
5282 CheckParameter (paramtok, Actual, Dim, FormalI, Proc, i, NIL)
5283 ELSIF NOT IsUnboundedParam(Proc, i)
5285 IF IsForC AND (GetSType(FormalI)=Address)
5287 FailParameter (paramtok,
5288 'a string constant can either be passed to an ADDRESS parameter or an ARRAY OF CHAR',
5289 Actual, FormalI, Proc, i)
5291 FailParameter (paramtok,
5292 'cannot pass a string constant to a non unbounded array parameter',
5293 Actual, FormalI, Proc, i)
5298 CheckParameter (paramtok, Actual, Dim, FormalI, Proc, i, NIL)
5301 IF IsForC AND UsesVarArgs(Proc)
5303 (* these are varargs, therefore we don't check them *)
5306 MetaErrorT2 (proctok, 'too many parameters, {%2n} passed to {%1a} ', Proc, i)
5311 IF CompilerDebugging
5321 END CheckProcedureParameters ;
5325 CheckProcTypeAndProcedure - checks the ProcType with the call.
5328 PROCEDURE CheckProcTypeAndProcedure (ProcType: CARDINAL; call: CARDINAL) ;
5331 i, n, t : CARDINAL ;
5332 CheckedProcedure: CARDINAL ;
5335 n := NoOfParam(ProcType) ;
5336 IF IsVar(call) OR IsTemporary(call) OR IsParameter(call)
5338 CheckedProcedure := GetDType(call)
5340 CheckedProcedure := call
5342 IF n#NoOfParam(CheckedProcedure)
5344 e := NewError(GetDeclaredMod(ProcType)) ;
5345 n1 := GetSymName(call) ;
5346 n2 := GetSymName(ProcType) ;
5347 ErrorFormat2(e, 'procedure (%a) is a parameter being passed as variable (%a) but they are declared with different number of parameters',
5349 e := ChainError(GetDeclaredMod(call), e) ;
5350 t := NoOfParam(CheckedProcedure) ;
5353 ErrorFormat3(e, 'procedure (%a) is being called incorrectly with (%d) parameter, declared with (%d)',
5356 ErrorFormat3(e, 'procedure (%a) is being called incorrectly with (%d) parameters, declared with (%d)',
5362 IF IsVarParam(ProcType, i) # IsVarParam(CheckedProcedure, i)
5364 MetaError3('parameter {%3n} in {%1dD} causes a mismatch it was declared as a {%2d}', ProcType, GetNth(ProcType, i), i) ;
5365 MetaError3('parameter {%3n} in {%1dD} causes a mismatch it was declared as a {%2d}', call, GetNth(call, i), i)
5367 BuildRange(InitTypesParameterCheck(CheckedProcedure, i,
5368 GetParam(CheckedProcedure, i),
5369 GetParam(ProcType, i))) ;
5370 (* CheckParameter(tokpos, GetParam(CheckedProcedure, i), 0, GetParam(ProcType, i), call, i, TypeList) ; *)
5374 END CheckProcTypeAndProcedure ;
5378 IsReallyPointer - returns TRUE is sym is a pointer, address or a type declared
5379 as a pointer or address.
5382 PROCEDURE IsReallyPointer (Sym: CARDINAL) : BOOLEAN ;
5386 Sym := GetSType(Sym)
5388 Sym := SkipType(Sym) ;
5389 RETURN( IsPointer(Sym) OR (Sym=Address) )
5390 END IsReallyPointer ;
5394 LegalUnboundedParam - returns TRUE if the parameter, Actual, can legally be
5395 passed to ProcSym, i, the, Formal, parameter.
5398 PROCEDURE LegalUnboundedParam (tokpos: CARDINAL; ProcSym, i, ActualType, Actual, Dimension, Formal: CARDINAL) : BOOLEAN ;
5400 FormalType: CARDINAL ;
5403 ActualType := SkipType(ActualType) ;
5404 FormalType := GetDType(Formal) ;
5405 FormalType := GetSType(FormalType) ; (* type of the unbounded ARRAY *)
5406 IF IsArray(ActualType)
5408 m := GetDimension(Formal) ;
5410 WHILE IsArray(ActualType) DO
5412 ActualType := GetDType(ActualType) ;
5413 IF (m=n) AND (ActualType=FormalType)
5420 (* now we fall though and test ActualType against FormalType *)
5422 IF IsGenericSystemType(FormalType)
5426 FailParameter(tokpos,
5427 'attempting to pass an array with the incorrect number dimenisons to an unbounded formal parameter of different dimensions',
5428 Actual, Formal, ProcSym, i) ;
5432 ELSIF IsUnbounded(ActualType)
5434 IF (Dimension=0) AND (GetDimension(Formal)=GetDimension(Actual))
5436 (* now we fall though and test ActualType against FormalType *)
5437 ActualType := GetSType(ActualType)
5439 IF IsGenericSystemType(FormalType)
5443 IF GetDimension(Actual)-Dimension = GetDimension(Formal)
5445 ActualType := GetSType(ActualType)
5447 FailParameter(tokpos,
5448 'attempting to pass an unbounded array with the incorrect number dimenisons to an unbounded formal parameter of different dimensions',
5449 Actual, Formal, ProcSym, i) ;
5455 IF IsGenericSystemType (FormalType) OR
5456 IsGenericSystemType (ActualType) OR
5457 IsAssignmentCompatible (FormalType, ActualType)
5459 (* we think it is legal, but we ask post pass 3 to check as
5460 not all types are known at this point *)
5463 FailParameter(tokpos,
5464 'identifier with an incompatible type is being passed to this procedure',
5465 Actual, Formal, ProcSym, i) ;
5468 END LegalUnboundedParam ;
5472 CheckParameter - checks that types ActualType and FormalType are compatible for parameter
5473 passing. ProcSym is the procedure and i is the parameter number.
5475 We obey the following rules:
5477 (1) we allow WORD, BYTE, LOC to be compitable with any like sized
5479 (2) we allow ADDRESS to be compatible with any pointer type.
5480 (3) we relax INTEGER and CARDINAL checking for Temporary variables.
5482 Note that type sizes are checked during the code generation pass.
5485 PROCEDURE CheckParameter (tokpos: CARDINAL;
5486 Actual, Dimension, Formal, ProcSym: CARDINAL;
5487 i: CARDINAL; TypeList: List) ;
5490 ActualType, FormalType: CARDINAL ;
5492 FormalType := GetDType(Formal) ;
5493 IF IsConstString(Actual) AND (GetStringLength(Actual) = 1) (* if = 1 then it maybe treated as a char *)
5496 ELSIF Actual=Boolean
5498 ActualType := Actual
5500 ActualType := GetDType(Actual)
5509 IF IsItemInList(TypeList, ActualType)
5511 (* no need to check *)
5514 IncludeItemIntoList(TypeList, ActualType) ;
5515 IF IsProcType(FormalType)
5517 IF (NOT IsProcedure(Actual)) AND ((ActualType=NulSym) OR (NOT IsProcType(SkipType(ActualType))))
5519 FailParameter(tokpos,
5520 'expecting a procedure or procedure variable as a parameter',
5521 Actual, Formal, ProcSym, i) ;
5524 IF IsProcedure(Actual) AND IsProcedureNested(Actual)
5526 MetaError2 ('cannot pass a nested procedure {%1Ea} seen in the {%2N} parameter as the outer scope will be unknown at runtime', Actual, i)
5528 (* we can check the return type of both proc types *)
5529 IF (ActualType#NulSym) AND IsProcType(ActualType)
5531 IF ((GetSType(ActualType)#NulSym) AND (GetSType(FormalType)=NulSym))
5533 FailParameter(tokpos,
5534 'the item being passed is a function whereas the formal procedure parameter is a procedure',
5535 Actual, Formal, ProcSym, i) ;
5537 ELSIF ((GetSType(ActualType)=NulSym) AND (GetSType(FormalType)#NulSym))
5539 FailParameter(tokpos,
5540 'the item being passed is a procedure whereas the formal procedure parameter is a function',
5541 Actual, Formal, ProcSym, i) ;
5543 ELSIF AssignmentRequiresWarning(GetSType(ActualType), GetSType(FormalType))
5545 WarnParameter(tokpos,
5546 'the return result of the procedure variable parameter may not be compatible on other targets with the return result of the item being passed',
5547 Actual, Formal, ProcSym, i) ;
5549 ELSIF IsGenericSystemType (GetSType(FormalType)) OR
5550 IsGenericSystemType (GetSType(ActualType)) OR
5551 IsAssignmentCompatible(GetSType(ActualType), GetSType(FormalType))
5555 FailParameter(tokpos,
5556 'the return result of the procedure variable parameter is not compatible with the return result of the item being passed',
5557 Actual, Formal, ProcSym, i) ;
5561 (* now to check each parameter of the proc type *)
5562 CheckProcTypeAndProcedure (FormalType, Actual)
5563 ELSIF (ActualType#FormalType) AND (ActualType#NulSym)
5565 IF IsUnknown(FormalType)
5567 FailParameter(tokpos,
5568 'procedure parameter type is undeclared',
5569 Actual, Formal, ProcSym, i) ;
5572 IF IsUnbounded(ActualType) AND (NOT IsUnboundedParam(ProcSym, i))
5574 FailParameter(tokpos,
5575 'attempting to pass an unbounded array to a NON unbounded parameter',
5576 Actual, Formal, ProcSym, i) ;
5578 ELSIF IsUnboundedParam(ProcSym, i)
5580 IF NOT LegalUnboundedParam(tokpos, ProcSym, i, ActualType, Actual, Dimension, Formal)
5584 ELSIF ActualType#FormalType
5586 IF AssignmentRequiresWarning(FormalType, ActualType)
5588 WarnParameter (tokpos,
5589 'identifier being passed to this procedure may contain a possibly incompatible type when compiling for a different target',
5590 Actual, Formal, ProcSym, i)
5591 ELSIF IsGenericSystemType (FormalType) OR
5592 IsGenericSystemType (ActualType) OR
5593 IsAssignmentCompatible (ActualType, FormalType)
5595 (* so far we know it is legal, but not all types have been resolved
5596 and so this is checked later on in another pass. *)
5598 FailParameter (tokpos,
5599 'identifier with an incompatible type is being passed to this procedure',
5600 Actual, Formal, ProcSym, i)
5608 END CheckParameter ;
5612 DescribeType - returns a String describing a symbol, Sym, name and its type.
5615 PROCEDURE DescribeType (Sym: CARDINAL) : String ;
5624 IF IsConstString(Sym)
5626 IF (GetStringLength(Sym) = 1) (* if = 1 then it maybe treated as a char *)
5628 s := InitString('(constant string) or {%kCHAR}')
5630 s := InitString('(constant string)')
5634 s := InitString('(constant)')
5635 ELSIF IsUnknown(Sym)
5637 s := InitString('(unknown)')
5639 Type := GetSType(Sym) ;
5642 s := InitString('(unknown)')
5643 ELSIF IsUnbounded(Type)
5645 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(GetSType(Type))))) ;
5646 s := Sprintf1(Mark(InitString('{%%kARRAY} {%%kOF} %s')), s1)
5649 s := InitString('{%kARRAY} [') ;
5650 Subscript := GetArraySubscript(Type) ;
5653 Assert(IsSubscript(Subscript)) ;
5654 Subrange := GetSType(Subscript) ;
5655 IF NOT IsSubrange(Subrange)
5657 MetaError3 ('error in definition of array {%1Ead} in the {%2N} subscript which has no subrange, instead type given is {%3a}',
5658 Sym, Subscript, Subrange)
5660 Assert(IsSubrange(Subrange)) ;
5661 GetSubrange(Subrange, High, Low) ;
5662 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Low)))) ;
5663 s2 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(High)))) ;
5664 s := ConCat(s, Mark(Sprintf2(Mark(InitString('%s..%s')),
5667 s1 := Mark(DescribeType(Type)) ;
5668 s := ConCat(ConCat(s, Mark(InitString('] OF '))), s1)
5672 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Type)))) ;
5673 s := Sprintf1(Mark(InitString('%s (currently unknown, check declaration or import)')),
5676 s := InitStringCharStar(KeyToCharStar(GetSymName(Type)))
5685 FailParameter - generates an error message indicating that a parameter
5686 declaration has failed.
5690 CurrentState - string describing the current failing state.
5691 Given - the token that the source code provided.
5692 Expecting - token or identifier that was expected.
5693 ParameterNo - parameter number that has failed.
5694 ProcedureSym - procedure symbol where parameter has failed.
5696 If any parameter is Nul then it is ignored.
5699 PROCEDURE FailParameter (tokpos : CARDINAL;
5700 CurrentState : ARRAY OF CHAR;
5702 Expecting : CARDINAL;
5703 ProcedureSym : CARDINAL;
5704 ParameterNo : CARDINAL) ;
5707 ExpectType: CARDINAL ;
5708 s, s1, s2 : String ;
5710 MetaError2 ('parameter mismatch between the {%2N} parameter of procedure {%1Ead}',
5711 ProcedureSym, ParameterNo) ;
5712 s := InitString ('{%kPROCEDURE} {%1Eau} (') ;
5713 IF NoOfParam(ProcedureSym)>=ParameterNo
5717 s := ConCat(s, Mark(InitString('.., ')))
5719 IF IsVarParam(ProcedureSym, ParameterNo)
5721 s := ConCat(s, Mark(InitString('{%kVAR} ')))
5724 First := GetDeclaredMod(GetNthParam(ProcedureSym, ParameterNo)) ;
5725 ExpectType := GetSType(Expecting) ;
5726 IF IsUnboundedParam(ProcedureSym, ParameterNo)
5728 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Expecting)))) ;
5729 s2 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(GetSType(ExpectType))))) ;
5730 s := ConCat(s, Mark(Sprintf2(Mark(InitString('%s: {%%kARRAY} {%%kOF} %s')),
5733 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Expecting)))) ;
5734 s2 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(ExpectType)))) ;
5735 s := ConCat(s, Mark(Sprintf2(Mark(InitString('%s: %s')), s1, s2)))
5737 IF ParameterNo<NoOfParam(ProcedureSym)
5739 s := ConCat(s, Mark(InitString('; ... ')))
5742 First := GetDeclaredMod(ProcedureSym) ;
5743 IF NoOfParam(ProcedureSym)>0
5745 s := ConCat(s, Mark(InitString('..')))
5748 s := ConCat (s, Mark (InitString ('){%1Tau:% : {%1Tau}} ;'))) ;
5749 MetaErrorStringT1 (First, Dup (s), ProcedureSym) ;
5750 MetaErrorStringT1 (tokpos, s, ProcedureSym) ;
5751 MetaError1 ('item being passed is {%1EDda} {%1Dad} of type {%1Dtsd}', Given)
5756 WarnParameter - generates a warning message indicating that a parameter
5757 use might cause problems on another target.
5761 CurrentState - string describing the current failing state.
5762 Given - the token that the source code provided.
5763 Expecting - token or identifier that was expected.
5764 ParameterNo - parameter number that has failed.
5765 ProcedureSym - procedure symbol where parameter has failed.
5767 If any parameter is Nul then it is ignored.
5770 PROCEDURE WarnParameter (tokpos : CARDINAL;
5771 CurrentState : ARRAY OF CHAR;
5773 Expecting : CARDINAL;
5774 ProcedureSym : CARDINAL;
5775 ParameterNo : CARDINAL) ;
5779 ReturnType: CARDINAL ;
5780 s, s1, s2 : String ;
5782 s := InitString('{%W}') ;
5783 IF CompilingImplementationModule()
5785 s := ConCat(s, Sprintf0(Mark(InitString('warning issued while compiling the implementation module\n'))))
5786 ELSIF CompilingProgramModule()
5788 s := ConCat(s, Sprintf0(Mark(InitString('warning issued while compiling the program module\n'))))
5790 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(ProcedureSym)))) ;
5791 s := ConCat(s, Mark(Sprintf2(Mark(InitString('problem in parameter %d, PROCEDURE %s (')),
5794 IF NoOfParam(ProcedureSym)>=ParameterNo
5798 s := ConCat(s, Mark(InitString('.., ')))
5800 IF IsVarParam(ProcedureSym, ParameterNo)
5802 s := ConCat(s, Mark(InitString('{%kVAR} ')))
5805 First := GetDeclaredMod(GetNthParam(ProcedureSym, ParameterNo)) ;
5806 ExpectType := GetSType(Expecting) ;
5807 IF IsUnboundedParam(ProcedureSym, ParameterNo)
5809 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Expecting)))) ;
5810 s2 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(GetSType(ExpectType))))) ;
5811 s := ConCat(s, Mark(Sprintf2(Mark(InitString('%s: {%%kARRAY} {%%kOF} %s')),
5814 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Expecting)))) ;
5815 s2 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(ExpectType)))) ;
5816 s := ConCat(s, Mark(Sprintf2(Mark(InitString('%s: %s')), s1, s2)))
5818 IF ParameterNo<NoOfParam(ProcedureSym)
5820 s := ConCat(s, Mark(InitString('; ... ')))
5823 First := GetDeclaredMod(ProcedureSym) ;
5824 IF NoOfParam(ProcedureSym)>0
5826 s := ConCat(s, Mark(InitString('..')))
5829 ReturnType := GetSType(ProcedureSym) ;
5830 IF ReturnType=NulSym
5832 s := ConCat(s, Sprintf0(Mark(InitString(') ;\n'))))
5834 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(ReturnType)))) ;
5835 s := ConCat(s, Mark(Sprintf1(Mark(InitString(') : %s ;\n')), s1)))
5837 IF IsConstString(Given)
5839 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Given)))) ;
5840 s := ConCat(s, Mark(Sprintf1(Mark(InitString("item being passed is '%s'")),
5842 ELSIF IsTemporary(Given)
5844 s := ConCat(s, Mark(InitString("item being passed has type")))
5846 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Given)))) ;
5847 s := ConCat(s, Mark(Sprintf1(Mark(InitString("item being passed is '%s'")),
5850 s1 := DescribeType(Given) ;
5851 s2 := Mark(InitString(CurrentState)) ;
5852 s := ConCat(s, Mark(Sprintf2(Mark(InitString(': %s\nparameter mismatch: %s')),
5854 MetaErrorStringT0 (tokpos, Dup (s)) ;
5855 MetaErrorStringT0 (First, Dup (s))
5860 ExpectVariable - checks to see whether, sym, is declared as a variable.
5861 If not then it generates an error message.
5865 PROCEDURE ExpectVariable (a: ARRAY OF CHAR; sym: CARDINAL) ;
5868 s1, s2, s3: String ;
5872 e := NewError(GetTokenNo()) ;
5875 s1 := ConCat (InitString (a),
5876 Mark (InitString ('but was given an undeclared symbol {%E1a}'))) ;
5878 ErrorString(e, Sprintf2(Mark(InitString('%s but was given an undeclared symbol %s')), s1, s2))
5880 s1 := Mark(InitString(a)) ;
5881 s2 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(sym)))) ;
5882 s3 := Mark(DescribeType(sym)) ;
5883 ErrorString(e, Sprintf3(Mark(InitString('%s but was given %s: %s')),
5887 END ExpectVariable ;
5892 doIndrX - perform des = *exp with a conversion if necessary.
5895 PROCEDURE doIndrX (tok: CARDINAL;
5896 des, exp: CARDINAL) ;
5900 IF GetDType(des)=GetDType(exp)
5902 GenQuadO (tok, IndrXOp, des, GetSType(des), exp, TRUE)
5904 t := MakeTemporary (tok, RightValue) ;
5905 PutVar (t, GetSType (exp)) ;
5906 GenQuadO (tok, IndrXOp, t, GetSType (exp), exp, TRUE) ;
5907 GenQuadO (tok, BecomesOp, des, NulSym, doVal (GetSType(des), t), TRUE)
5913 MakeRightValue - returns a temporary which will have the RightValue of symbol, Sym.
5914 If Sym is a right value and has type, type, then no quadruples are
5915 generated and Sym is returned. Otherwise a new temporary is created
5916 and an IndrX quadruple is generated.
5919 PROCEDURE MakeRightValue (tok: CARDINAL;
5920 Sym: CARDINAL; type: CARDINAL) : CARDINAL ;
5924 IF GetMode (Sym) = RightValue
5926 IF GetSType(Sym) = type
5928 RETURN Sym (* already a RightValue with desired type *)
5931 type change or mode change, type changes are a pain, but I've
5932 left them here as it is perhaps easier to remove them later.
5934 t := MakeTemporary (tok, RightValue) ;
5936 GenQuadO (tok, BecomesOp, t, NulSym, doVal(type, Sym), TRUE) ;
5940 t := MakeTemporary (tok, RightValue) ;
5942 CheckPointerThroughNil (tok, Sym) ;
5943 doIndrX (tok, t, Sym) ;
5946 END MakeRightValue ;
5950 MakeLeftValue - returns a temporary coresponding to the LeftValue of
5951 symbol, Sym. No quadruple is generated if Sym is already
5952 a LeftValue and has the same type.
5955 PROCEDURE MakeLeftValue (tok: CARDINAL;
5956 Sym: CARDINAL; with: ModeOfAddr; type: CARDINAL) : CARDINAL ;
5960 IF GetMode (Sym) = LeftValue
5962 IF GetSType (Sym) = type
5967 type change or mode change, type changes are a pain, but I've
5968 left them here as it is perhaps easier to remove them later
5970 t := MakeTemporary (tok, with) ;
5972 GenQuadO (tok, BecomesOp, t, NulSym, Sym, TRUE) ;
5976 t := MakeTemporary (tok, with) ;
5978 GenQuadO (tok, AddrOp, t, NulSym, Sym, TRUE) ;
5985 ManipulatePseudoCallParameters - manipulates the parameters to a pseudo function or
5986 procedure. It dereferences all LeftValue parameters
5987 and Boolean parameters.
5993 Ptr -> exactly the same
6012 PROCEDURE ManipulatePseudoCallParameters ;
6019 PopT(NoOfParameters) ;
6020 PushT(NoOfParameters) ; (* restored to original state *)
6021 (* Ptr points to the ProcSym *)
6022 ProcSym := OperandT(NoOfParameters+1+1) ;
6025 InternalError ('expecting a pseudo procedure or a type')
6030 pi := NoOfParameters+1 ;
6031 WHILE i<=NoOfParameters DO
6032 IF (GetMode(OperandT(pi))=LeftValue) AND
6033 (Proc#Adr) AND (Proc#Size) AND (Proc#TSize) AND (Proc#High) AND
6034 (* procedures which have first parameter as a VAR param *)
6035 (((Proc#Inc) AND (Proc#Incl) AND (Proc#Dec) AND (Proc#Excl) AND (Proc#New) AND (Proc#Dispose)) OR (i>1))
6037 (* must dereference LeftValue *)
6038 f := PeepAddress(BoolStack, pi) ;
6039 f^.TrueExit := MakeRightValue (GetTokenNo(), OperandT(pi), GetSType(OperandT(pi)))
6044 END ManipulatePseudoCallParameters ;
6048 ManipulateParameters - manipulates the procedure parameters in
6049 preparation for a procedure call.
6050 Prepares Boolean, Unbounded and VAR parameters.
6056 Ptr -> exactly the same
6074 PROCEDURE ManipulateParameters (IsForC: BOOLEAN) ;
6089 PopT(NoOfParameters) ;
6090 ProcSym := OperandT(NoOfParameters+1) ;
6091 tokpos := OperandTtok(NoOfParameters+1) ;
6094 (* Procedure Variable ? *)
6095 Proc := SkipType(OperandF(NoOfParameters+1))
6097 Proc := SkipConst(ProcSym)
6100 IF IsForC AND UsesVarArgs(Proc)
6102 IF NoOfParameters<NoOfParam(Proc)
6104 s := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Proc)))) ;
6105 np := NoOfParam(Proc) ;
6106 ErrorStringAt2(Sprintf3(Mark(InitString('attempting to pass (%d) parameters to procedure (%s) which was declared with varargs but contains at least (%d) parameters')),
6107 NoOfParameters, s, np),
6108 tokpos, GetDeclaredMod(ProcSym))
6110 ELSIF UsesOptArg(Proc)
6112 IF NOT ((NoOfParameters=NoOfParam(Proc)) OR (NoOfParameters+1=NoOfParam(Proc)))
6114 s := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Proc)))) ;
6115 np := NoOfParam(Proc) ;
6116 ErrorStringAt2(Sprintf3(Mark(InitString('attempting to pass (%d) parameters to procedure (%s) which was declared with an optarg with a maximum of (%d) parameters')),
6117 NoOfParameters, s, np),
6118 tokpos, GetDeclaredMod(ProcSym))
6120 ELSIF NoOfParameters#NoOfParam(Proc)
6122 s := Mark(InitStringCharStar(KeyToCharStar(GetSymName(Proc)))) ;
6123 np := NoOfParam(Proc) ;
6124 ErrorStringAt2(Sprintf3(Mark(InitString('attempting to pass (%d) parameters to procedure (%s) which was declared with (%d) parameters')),
6125 NoOfParameters, s, np),
6126 tokpos, GetDeclaredMod(ProcSym))
6129 pi := NoOfParameters ;
6130 WHILE i<=NoOfParameters DO
6131 f := PeepAddress(BoolStack, pi) ;
6132 rw := OperandMergeRW(pi) ;
6133 Assert(IsLegal(rw)) ;
6134 IF i>NoOfParam(Proc)
6136 IF IsForC AND UsesVarArgs(Proc)
6138 IF (GetSType(OperandT(pi))#NulSym) AND IsArray(GetDType(OperandT(pi)))
6140 f^.TrueExit := MakeLeftValue(OperandTok(pi), OperandT(pi), RightValue, Address) ;
6142 ELSIF IsConstString (OperandT (pi))
6144 f^.TrueExit := MakeLeftValue (OperandTok (pi),
6145 MakeConstStringCnul (OperandTok (pi), OperandT (pi)), RightValue, Address) ;
6147 ELSIF (GetSType(OperandT(pi))#NulSym) AND IsUnbounded(GetSType(OperandT(pi)))
6149 MarkAsReadWrite(rw) ;
6150 (* pass the address field of an unbounded variable *)
6151 PushTF(Adr, Address) ;
6152 PushTFAD (f^.TrueExit, f^.FalseExit, f^.Unbounded, f^.Dimension) ;
6156 ELSIF GetMode(OperandT(pi))=LeftValue
6158 MarkAsReadWrite(rw) ;
6159 (* must dereference LeftValue (even if we are passing variable as a vararg) *)
6160 t := MakeTemporary (OperandTok (pi), RightValue) ;
6161 PutVar(t, GetSType (OperandT (pi))) ;
6162 CheckPointerThroughNil (tokpos, OperandT (pi)) ;
6163 doIndrX (OperandTok(pi), t, OperandT (pi)) ;
6167 MetaErrorT2 (tokpos,
6168 'attempting to pass too many parameters to procedure {%1a}, the {%2N} parameter does not exist',
6171 ELSIF IsForC AND IsUnboundedParam(Proc, i) AND
6172 (GetSType(OperandT(pi))#NulSym) AND IsArray(GetDType(OperandT(pi)))
6174 f^.TrueExit := MakeLeftValue(OperandTok(pi), OperandT(pi), RightValue, Address) ;
6176 ELSIF IsForC AND IsUnboundedParam(Proc, i) AND
6177 (GetSType(OperandT(pi))#NulSym) AND IsUnbounded(GetDType(OperandT(pi)))
6179 MarkAsReadWrite(rw) ;
6180 (* pass the address field of an unbounded variable *)
6181 PushTF(Adr, Address) ;
6182 PushTFAD (f^.TrueExit, f^.FalseExit, f^.Unbounded, f^.Dimension) ;
6186 ELSIF IsForC AND IsConstString(OperandT(pi)) AND
6187 (IsUnboundedParam(Proc, i) OR (GetDType(GetParam(Proc, i))=Address))
6189 f^.TrueExit := MakeLeftValue (OperandTok (pi),
6190 MakeConstStringCnul (OperandTok (pi), OperandT (pi)),
6191 RightValue, Address) ;
6192 MarkAsReadWrite (rw)
6193 ELSIF IsUnboundedParam(Proc, i)
6195 (* always pass constant strings with a nul terminator, but leave the HIGH as before. *)
6196 IF IsConstString (OperandT(pi))
6198 (* this is a Modula-2 string which must be nul terminated. *)
6199 f^.TrueExit := MakeConstStringM2nul (OperandTok (pi), OperandT (pi))
6201 t := MakeTemporary (OperandTok (pi), RightValue) ;
6202 UnboundedType := GetSType(GetParam(Proc, i)) ;
6203 PutVar(t, UnboundedType) ;
6204 ParamType := GetSType(UnboundedType) ;
6207 ArraySym := OperandT(pi)
6209 ArraySym := OperandA(pi)
6211 IF IsVarParam(Proc, i)
6213 MarkArrayWritten (OperandT (pi)) ;
6214 MarkArrayWritten (OperandA (pi)) ;
6215 MarkAsReadWrite(rw) ;
6216 AssignUnboundedVar (OperandTtok (pi), OperandT (pi), ArraySym, t, ParamType, OperandD (pi))
6219 AssignUnboundedNonVar (OperandTtok (pi), OperandT (pi), ArraySym, t, ParamType, OperandD (pi))
6222 ELSIF IsVarParam(Proc, i)
6224 (* must reference by address, but we contain the type of the referenced entity *)
6225 MarkArrayWritten(OperandT(pi)) ;
6226 MarkArrayWritten(OperandA(pi)) ;
6227 MarkAsReadWrite(rw) ;
6228 f^.TrueExit := MakeLeftValue(OperandTok(pi), OperandT(pi), LeftValue, GetSType(GetParam(Proc, i)))
6229 ELSIF (NOT IsVarParam(Proc, i)) AND (GetMode(OperandT(pi))=LeftValue)
6231 (* must dereference LeftValue *)
6232 t := MakeTemporary (OperandTok (pi), RightValue) ;
6233 PutVar(t, GetSType(OperandT(pi))) ;
6234 CheckPointerThroughNil (tokpos, OperandT (pi)) ;
6235 doIndrX (OperandTok(pi), t, OperandT(pi)) ;
6244 PushT(NoOfParameters)
6245 END ManipulateParameters ;
6249 CheckParameterOrdinals - check that ordinal values are within type range.
6252 PROCEDURE CheckParameterOrdinals ;
6255 ProcSym : CARDINAL ;
6257 FormalI : CARDINAL ;
6262 PushT (ParamTotal) ; (* Restore stack to origional state *)
6263 ProcSym := OperandT (ParamTotal+1+1) ;
6264 IF IsVar(ProcSym) AND IsProcType(GetDType(ProcSym))
6266 (* Indirect procedure call. *)
6267 Proc := SkipType(OperandF(ParamTotal+1+1))
6269 Proc := SkipConst(ProcSym)
6272 pi := ParamTotal+1 ; (* stack index referencing stacked parameter, i *)
6273 WHILE i<=ParamTotal DO
6274 IF i<=NoOfParam(Proc)
6276 FormalI := GetParam (Proc, i) ;
6277 Actual := OperandT (pi) ;
6278 IF IsOrdinalType (GetLType (FormalI))
6280 IF NOT IsSet (GetDType (FormalI))
6282 (* tell code generator to test runtime values of assignment so ensure we
6283 catch overflow and underflow *)
6284 BuildRange (InitParameterRangeCheck (Proc, i, FormalI, Actual))
6291 END CheckParameterOrdinals ;
6295 IsSameUnbounded - returns TRUE if unbounded types, t1, and, t2,
6299 PROCEDURE IsSameUnbounded (t1, t2: CARDINAL) : BOOLEAN ;
6301 Assert(IsUnbounded(t1)) ;
6302 Assert(IsUnbounded(t2)) ;
6303 RETURN( GetDType(t1)=GetDType(t2) )
6304 END IsSameUnbounded ;
6308 AssignUnboundedVar - assigns an Unbounded symbol fields,
6309 ArrayAddress and ArrayHigh, from an array symbol.
6310 UnboundedSym is not a VAR parameter and therefore
6311 this procedure can complete both of the fields.
6312 Sym can be a Variable with type Unbounded.
6313 Sym can be a Variable with type Array.
6314 Sym can be a String Constant.
6316 ParamType is the TYPE of the parameter
6319 PROCEDURE AssignUnboundedVar (tok: CARDINAL;
6320 Sym, ArraySym, UnboundedSym, ParamType: CARDINAL; dim: CARDINAL) ;
6326 MetaErrorT1 (tok, '{%1ad} cannot be passed to a VAR formal parameter', Sym)
6329 Type := GetDType(Sym) ;
6330 IF IsUnbounded(Type)
6332 IF Type = GetSType (UnboundedSym)
6334 (* Copy Unbounded Symbol ie. UnboundedSym := Sym *)
6335 PushT (UnboundedSym) ;
6337 BuildAssignmentWithoutBounds (tok, FALSE, TRUE)
6338 ELSIF IsSameUnbounded (Type, GetSType (UnboundedSym)) OR
6339 IsGenericSystemType (ParamType)
6341 UnboundedVarLinkToArray (tok, Sym, ArraySym, UnboundedSym, ParamType, dim)
6343 MetaErrorT1 (tok, '{%1ad} cannot be passed to a VAR formal parameter', Sym)
6345 ELSIF IsArray (Type) OR IsGenericSystemType (ParamType)
6347 UnboundedVarLinkToArray (tok, Sym, ArraySym, UnboundedSym, ParamType, dim)
6349 MetaErrorT1 (tok, '{%1ad} cannot be passed to a VAR formal parameter', Sym)
6352 MetaErrorT1 (tok, '{%1ad} cannot be passed to a VAR formal parameter', Sym)
6354 END AssignUnboundedVar ;
6358 AssignUnboundedNonVar - assigns an Unbounded symbol fields,
6359 The difference between this procedure and
6360 AssignUnboundedVar is that this procedure cannot
6361 set the Unbounded.Address since the data from
6362 Sym will be copied because parameter is NOT a VAR
6364 UnboundedSym is not a VAR parameter and therefore
6365 this procedure can only complete the HIGH field
6366 and not the ADDRESS field.
6367 Sym can be a Variable with type Unbounded.
6368 Sym can be a Variable with type Array.
6369 Sym can be a String Constant.
6371 ParamType is the TYPE of the paramater
6374 PROCEDURE AssignUnboundedNonVar (tok: CARDINAL;
6375 Sym, ArraySym, UnboundedSym, ParamType: CARDINAL; dim: CARDINAL) ;
6379 IF IsConst (Sym) (* was IsConstString(Sym) *)
6381 UnboundedNonVarLinkToArray (tok, Sym, ArraySym, UnboundedSym, ParamType, dim)
6384 Type := GetDType (Sym) ;
6385 IF IsUnbounded (Type)
6387 UnboundedNonVarLinkToArray (tok, Sym, ArraySym, UnboundedSym, ParamType, dim)
6388 ELSIF IsArray (Type) OR IsGenericSystemType (ParamType)
6390 UnboundedNonVarLinkToArray (tok, Sym, ArraySym, UnboundedSym, ParamType, dim)
6392 MetaErrorT1 (tok, 'illegal type parameter {%1Ead} expecting array or dynamic array', Sym)
6395 MetaErrorT1 (tok, 'illegal parameter {%1Ead} which cannot be passed as {%kVAR} {%kARRAY} {%kOF} {%1tsad}', Sym)
6397 END AssignUnboundedNonVar ;
6401 GenHigh - generates a HighOp but it checks if op3 is a
6402 L value and if so it dereferences it. This
6403 is inefficient, however it is clean and we let the gcc
6404 backend detect these as common subexpressions.
6405 It will also detect that a R value -> L value -> R value
6406 via indirection and eleminate these.
6409 PROCEDURE GenHigh (tok: CARDINAL;
6410 op1, op2, op3: CARDINAL) ;
6414 IF (GetMode(op3)=LeftValue) AND IsUnbounded(GetSType(op3))
6416 sym := MakeTemporary (tok, RightValue) ;
6417 PutVar (sym, GetSType (op3)) ;
6418 doIndrX (tok, sym, op3) ;
6419 GenQuadO (tok, HighOp, op1, op2, sym, TRUE)
6421 GenQuadO (tok, HighOp, op1, op2, op3, TRUE)
6430 PROCEDURE AssignHighField (tok: CARDINAL;
6431 Sym, ArraySym, UnboundedSym, ParamType: CARDINAL;
6432 actuali, formali: CARDINAL) ;
6438 (* Unbounded.ArrayHigh := HIGH(ArraySym) *)
6439 PushTFtok (UnboundedSym, GetSType (UnboundedSym), tok) ;
6440 Field := GetUnboundedHighOffset (GetSType (UnboundedSym), formali) ;
6441 PushTFtok (Field, GetSType (Field), tok) ;
6443 BuildDesignatorRecord (tok) ;
6444 IF IsGenericSystemType (ParamType)
6446 IF IsConstString (Sym)
6448 PushTtok (MakeLengthConst (tok, Sym), tok)
6450 ArrayType := GetSType (Sym) ;
6451 IF IsUnbounded (ArrayType)
6454 * SIZE(parameter) DIV TSIZE(ParamType)
6455 * however in this case parameter
6456 * is an unbounded symbol and therefore we must use
6457 * (HIGH(parameter)+1)*SIZE(unbounded type) DIV TSIZE(ParamType)
6459 * we call upon the function SIZE(ArraySym)
6460 * remember SIZE doubles as
6461 * (HIGH(a)+1) * SIZE(ArrayType) for unbounded symbols
6463 PushTFtok (calculateMultipicand (tok, ArraySym, ArrayType, actuali-1), Cardinal, tok) ;
6464 PushT (DivideTok) ; (* Divide by *)
6465 PushTFtok (TSize, Cardinal, tok) ; (* TSIZE(ParamType) *)
6466 PushTtok (ParamType, tok) ;
6467 PushT (1) ; (* 1 parameter for TSIZE() *)
6471 (* SIZE(parameter) DIV TSIZE(ParamType) *)
6472 PushTFtok (TSize, Cardinal, tok) ; (* TSIZE(ArrayType) *)
6473 PushTtok (ArrayType, tok) ;
6474 PushT (1) ; (* 1 parameter for TSIZE() *)
6476 PushT (DivideTok) ; (* Divide by *)
6477 PushTFtok (TSize, Cardinal, tok) ; (* TSIZE(ParamType) *)
6478 PushTtok (ParamType, tok) ;
6479 PushT (1) ; (* 1 parameter for TSIZE() *)
6483 (* now convert from no of elements into HIGH by subtracting 1 *)
6484 PushT (MinusTok) ; (* -1 *)
6485 PushTtok (MakeConstLit (tok, MakeKey('1'), Cardinal), tok) ;
6489 ReturnVar := MakeTemporary (tok, RightValue) ;
6490 PutVar (ReturnVar, Cardinal) ;
6491 IF (actuali # formali) AND (ArraySym # NulSym) AND IsUnbounded (GetSType (ArraySym))
6493 GenHigh (tok, ReturnVar, actuali, ArraySym)
6495 GenHigh (tok, ReturnVar, formali, Sym)
6497 PushTFtok (ReturnVar, GetSType(ReturnVar), tok)
6499 BuildAssignmentWithoutBounds (tok, FALSE, TRUE)
6500 END AssignHighField ;
6507 PROCEDURE AssignHighFields (tok: CARDINAL;
6508 Sym, ArraySym, UnboundedSym, ParamType: CARDINAL; dim: CARDINAL) ;
6512 actualn, formaln: CARDINAL ;
6514 type := GetDType (Sym) ;
6516 IF (type # NulSym) AND (IsUnbounded (type) OR IsArray (type))
6518 actualn := GetDimension (type)
6520 actuali := dim + 1 ;
6522 formaln := GetDimension (GetDType (UnboundedSym)) ;
6523 WHILE (actuali < actualn) AND (formali < formaln) DO
6524 AssignHighField (tok, Sym, ArraySym, UnboundedSym, NulSym, actuali, formali) ;
6528 AssignHighField (tok, Sym, ArraySym, UnboundedSym, ParamType, actuali, formali)
6529 END AssignHighFields ;
6533 UnboundedNonVarLinkToArray - links an array, ArraySym, to an unbounded
6534 array, UnboundedSym. The parameter is a
6538 PROCEDURE UnboundedNonVarLinkToArray (tok: CARDINAL;
6539 Sym, ArraySym, UnboundedSym, ParamType: CARDINAL; dim: CARDINAL) ;
6542 AddressField: CARDINAL ;
6544 (* Unbounded.ArrayAddress := to be assigned at runtime. *)
6545 PushTFtok (UnboundedSym, GetSType (UnboundedSym), tok) ;
6547 Field := GetUnboundedAddressOffset(GetSType(UnboundedSym)) ;
6548 PushTFtok (Field, GetSType(Field), tok) ;
6550 BuildDesignatorRecord (tok) ;
6551 PopT (AddressField) ;
6553 (* caller saves non var unbounded array contents. *)
6554 GenQuadO (tok, UnboundedOp, AddressField, NulSym, Sym, FALSE) ;
6556 AssignHighFields (tok, Sym, ArraySym, UnboundedSym, ParamType, dim)
6557 END UnboundedNonVarLinkToArray ;
6561 UnboundedVarLinkToArray - links an array, ArraySym, to an unbounded array,
6562 UnboundedSym. The parameter is a VAR variety.
6565 PROCEDURE UnboundedVarLinkToArray (tok: CARDINAL;
6566 Sym, ArraySym, UnboundedSym, ParamType: CARDINAL; dim: CARDINAL) ;
6571 SymType := GetSType (Sym) ;
6572 (* Unbounded.ArrayAddress := ADR(Sym) *)
6573 PushTFtok (UnboundedSym, GetSType (UnboundedSym), tok) ;
6574 Field := GetUnboundedAddressOffset (GetSType (UnboundedSym)) ;
6575 PushTFtok (Field, GetSType (Field), tok) ;
6577 BuildDesignatorRecord (tok) ;
6578 PushTFtok (Adr, Address, tok) ; (* ADR(Sym) *)
6579 IF IsUnbounded (SymType) AND (dim = 0)
6581 PushTFADtok (Sym, SymType, UnboundedSym, dim, tok)
6583 PushTFADtok (Sym, SymType, ArraySym, dim, tok)
6585 PushT (1) ; (* 1 parameter for ADR() *)
6587 BuildAssignmentWithoutBounds (tok, FALSE, TRUE) ;
6589 AssignHighFields (tok, Sym, ArraySym, UnboundedSym, ParamType, dim)
6590 END UnboundedVarLinkToArray ;
6594 BuildPseudoProcedureCall - builds a pseudo procedure call.
6595 This procedure does not directly alter the
6596 stack, but by calling routines the stack
6597 will change in the following way when this
6619 | ProcSym | Type | Empty
6623 PROCEDURE BuildPseudoProcedureCall (tokno: CARDINAL) ;
6626 ProcSym : CARDINAL ;
6629 ProcSym := OperandT (NoOfParam + 1) ;
6631 (* Compile time stack restored to entry state *)
6634 BuildNewProcedure (tokno)
6635 ELSIF ProcSym = Dispose
6637 BuildDisposeProcedure (tokno)
6644 ELSIF ProcSym = Incl
6647 ELSIF ProcSym = Excl
6650 ELSIF ProcSym = Throw
6654 InternalError ('pseudo procedure not implemented yet')
6656 END BuildPseudoProcedureCall ;
6660 GetItemPointedTo - returns the symbol type that is being pointed to
6664 PROCEDURE GetItemPointedTo (Sym: CARDINAL) : CARDINAL ;
6668 RETURN GetSType (Sym)
6669 ELSIF IsVar (Sym) OR IsType (Sym)
6671 RETURN GetItemPointedTo (GetSType (Sym))
6673 END GetItemPointedTo ;
6677 BuildThrowProcedure - builds the pseudo procedure call M2RTS.Throw.
6697 | ProcSym | Type | Empty
6701 PROCEDURE BuildThrowProcedure ;
6703 functok : CARDINAL ;
6705 NoOfParam: CARDINAL ;
6708 functok := OperandTtok (NoOfParam + 1) ;
6711 op := OperandT (NoOfParam) ;
6712 GenQuadO (functok, ThrowOp, NulSym, NulSym, op, FALSE)
6714 MetaErrorT1 (functok, 'the pseudo procedure %{1Ea} takes one INTEGER parameter', Throw)
6717 END BuildThrowProcedure ;
6721 BuildReThrow - creates a ThrowOp _ _ NulSym, indicating that
6722 the exception needs to be rethrown. The stack
6726 PROCEDURE BuildReThrow (tokenno: CARDINAL) ;
6728 GenQuadO (tokenno, ThrowOp, NulSym, NulSym, NulSym, FALSE)
6733 BuildNewProcedure - builds the pseudo procedure call NEW.
6734 This procedure is traditionally a "macro" for
6735 NEW(x, ...) --> ALLOCATE(x, TSIZE(x^, ...))
6736 One method of implementation is to emulate a "macro"
6737 processor by pushing the relevant input tokens
6738 back onto the input stack.
6739 However this causes two problems:
6741 (i) Unnecessary code is produced for x^
6742 (ii) SIZE must be imported from SYSTEM
6743 Therefore we chose an alternative method of
6745 generate quadruples for ALLOCATE(x, TSIZE(x^, ...))
6746 this, although slightly more efficient,
6747 is more complex and circumvents problems (i) and (ii).
6768 | ProcSym | Type | Empty
6772 PROCEDURE BuildNewProcedure (functok: CARDINAL) ;
6777 ProcSym : CARDINAL ;
6779 combinedtok: CARDINAL ;
6784 ProcSym := RequestSym (functok, MakeKey('ALLOCATE')) ;
6785 IF (ProcSym#NulSym) AND IsProcedure(ProcSym)
6787 PtrSym := OperandT (NoOfParam) ;
6788 paramtok := OperandTtok (1) ;
6789 IF IsReallyPointer(PtrSym)
6791 combinedtok := MakeVirtualTok (functok, functok, paramtok) ;
6793 Build macro: ALLOCATE( PtrSym, SIZE(PtrSym^) )
6795 PushTFtok (TSize, Cardinal, paramtok) ;(* Procedure *)
6797 PushTtok (GetItemPointedTo (PtrSym), paramtok) ;
6798 PushT (1) ; (* One parameter *)
6802 PushTtok (ProcSym, combinedtok) ; (* ALLOCATE *)
6803 PushTtok (PtrSym, paramtok) ; (* x *)
6804 PushTtok (SizeSym, paramtok) ; (* TSIZE(x^) *)
6805 PushT (2) ; (* Two parameters *)
6806 BuildProcedureCall (combinedtok)
6808 MetaErrorT0 (paramtok, 'parameter to {%EkNEW} must be a pointer')
6811 MetaErrorT0 (functok, '{%E}ALLOCATE procedure not found for NEW substitution')
6814 MetaErrorT0 (functok, 'the pseudo procedure {%EkNEW} has one or more parameters')
6817 END BuildNewProcedure ;
6821 BuildDisposeProcedure - builds the pseudo procedure call DISPOSE.
6822 This procedure is traditionally a "macro" for
6823 DISPOSE(x) --> DEALLOCATE(x, TSIZE(x^))
6824 One method of implementation is to emulate a "macro"
6825 processor by pushing the relevant input tokens
6826 back onto the input stack.
6827 However this causes two problems:
6829 (i) Unnecessary code is produced for x^
6830 (ii) TSIZE must be imported from SYSTEM
6831 Therefore we chose an alternative method of
6833 generate quadruples for DEALLOCATE(x, TSIZE(x^))
6834 this, although slightly more efficient,
6835 is more complex and circumvents problems (i)
6857 | ProcSym | Type | Empty
6861 PROCEDURE BuildDisposeProcedure (functok: CARDINAL) ;
6866 ProcSym : CARDINAL ;
6868 paramtok : CARDINAL ;
6873 ProcSym := RequestSym (functok, MakeKey ('DEALLOCATE')) ;
6874 IF (ProcSym # NulSym) AND IsProcedure (ProcSym)
6876 PtrSym := OperandT (NoOfParam) ;
6877 paramtok := OperandTtok (1) ;
6878 IF IsReallyPointer (PtrSym)
6880 combinedtok := MakeVirtualTok (functok, functok, paramtok) ;
6882 Build macro: DEALLOCATE( PtrSym, TSIZE(PtrSym^) )
6884 PushTFtok (TSize, Cardinal, paramtok) ;(* Procedure *)
6886 PushTtok (GetItemPointedTo(PtrSym), paramtok) ;
6887 PushT (1) ; (* One parameter *)
6891 PushTtok (ProcSym, combinedtok) ; (* DEALLOCATE *)
6892 PushTtok (PtrSym, paramtok) ; (* x *)
6893 PushTtok (SizeSym, paramtok) ; (* TSIZE(x^) *)
6894 PushT (2) ; (* Two parameters *)
6895 BuildProcedureCall (combinedtok)
6897 MetaErrorT0 (paramtok, 'argument to {%EkDISPOSE} must be a pointer')
6900 MetaErrorT0 (functok, '{%E}DEALLOCATE procedure not found for DISPOSE substitution')
6903 MetaErrorT0 (functok, 'the pseudo procedure {%EkDISPOSE} has one or more parameters')
6906 END BuildDisposeProcedure ;
6910 CheckRangeIncDec - performs des := des <tok> expr
6911 with range checking (if enabled).
6917 empty | des + expr |
6921 PROCEDURE CheckRangeIncDec (tokenpos: CARDINAL; des, expr: CARDINAL; tok: Name) ;
6923 dtype, etype: CARDINAL ;
6925 dtype := GetDType(des) ;
6926 etype := GetDType(expr) ;
6927 IF WholeValueChecking AND (NOT MustNotCheckBounds)
6931 BuildRange (InitIncRangeCheck (des, expr))
6933 BuildRange (InitDecRangeCheck (des, expr))
6937 IF IsExpressionCompatible (dtype, etype)
6939 (* the easy case simulate a straightforward macro *)
6940 PushTF(des, dtype) ;
6942 PushTF(expr, etype) ;
6943 doBuildBinaryOp(FALSE, TRUE)
6945 IF (IsOrdinalType(dtype) OR (dtype=Address) OR IsPointer(dtype)) AND
6946 (IsOrdinalType(etype) OR (etype=Address) OR IsPointer(etype))
6948 PushTF (des, dtype) ;
6950 PushTF (Convert, NulSym) ;
6953 PushT (2) ; (* Two parameters *)
6954 BuildConvertFunction ;
6955 doBuildBinaryOp (FALSE, TRUE)
6959 MetaError0 ('cannot perform {%EkINC} using non ordinal types')
6961 MetaError0 ('cannot perform {%EkDEC} using non ordinal types')
6963 PushTFtok (MakeConstLit (tokenpos, MakeKey ('0'), NulSym), NulSym, tokenpos)
6966 END CheckRangeIncDec ;
6970 BuildIncProcedure - builds the pseudo procedure call INC.
6971 INC is a procedure which increments a variable.
6972 It takes one or two parameters:
6974 a := a+b or a := a+1
6995 | ProcSym | Type | Empty
6999 PROCEDURE BuildIncProcedure ;
7001 proctok : CARDINAL ;
7006 TempSym : CARDINAL ;
7009 proctok := OperandTtok (NoOfParam + 1) ;
7010 IF (NoOfParam = 1) OR (NoOfParam = 2)
7012 VarSym := OperandT (NoOfParam) ; (* bottom/first parameter *)
7015 dtype := GetDType (VarSym) ;
7018 OperandSym := DereferenceLValue (OperandTok (1), OperandT (1))
7020 PushOne (proctok, dtype, 'the {%EkINC} will cause an overflow {%1ad}') ;
7025 TempSym := DereferenceLValue (OperandTok (NoOfParam), VarSym) ;
7026 CheckRangeIncDec (proctok, TempSym, OperandSym, PlusTok) ; (* TempSym + OperandSym *)
7027 BuildAssignmentWithoutBounds (proctok, FALSE, TRUE) (* VarSym := TempSym + OperandSym *)
7029 MetaErrorT1 (proctok,
7030 'base procedure {%EkINC} expects a variable as a parameter but was given {%1Ed}',
7034 MetaErrorT0 (proctok,
7035 'the base procedure {%EkINC} expects 1 or 2 parameters')
7037 PopN (NoOfParam + 1)
7038 END BuildIncProcedure ;
7042 BuildDecProcedure - builds the pseudo procedure call DEC.
7043 DEC is a procedure which decrements a variable.
7044 It takes one or two parameters:
7046 a := a-b or a := a-1
7067 | ProcSym | Type | Empty
7071 PROCEDURE BuildDecProcedure ;
7078 TempSym : CARDINAL ;
7081 proctok := OperandTtok (NoOfParam + 1) ;
7082 IF (NoOfParam = 1) OR (NoOfParam = 2)
7084 VarSym := OperandT (NoOfParam) ; (* bottom/first parameter *)
7087 dtype := GetDType (VarSym) ;
7090 OperandSym := DereferenceLValue (OperandTok (1), OperandT (1))
7092 PushOne (proctok, dtype, 'the {%EkDEC} will cause an overflow {%1ad}') ;
7097 TempSym := DereferenceLValue (OperandTok (NoOfParam), VarSym) ;
7098 CheckRangeIncDec (proctok, TempSym, OperandSym, MinusTok) ; (* TempSym - OperandSym *)
7099 BuildAssignmentWithoutBounds (proctok, FALSE, TRUE) (* VarSym := TempSym - OperandSym *)
7101 MetaErrorT1 (proctok,
7102 'base procedure {%EkDEC} expects a variable as a parameter but was given {%1Ed}',
7106 MetaErrorT0 (proctok,
7107 'the base procedure {%EkDEC} expects 1 or 2 parameters')
7109 PopN (NoOfParam + 1)
7110 END BuildDecProcedure ;
7114 DereferenceLValue - checks to see whether, operand, is declare as an LValue
7115 and if so it dereferences it.
7118 PROCEDURE DereferenceLValue (tok: CARDINAL; operand: CARDINAL) : CARDINAL ;
7122 IF GetMode (operand) = LeftValue
7124 (* dereference the pointer *)
7125 sym := MakeTemporary (tok, AreConstant(IsConst(operand))) ;
7126 PutVar(sym, GetSType (operand)) ;
7128 PushTtok (sym, tok) ;
7129 PushTtok (operand, tok) ;
7130 BuildAssignmentWithoutBounds (tok, FALSE, TRUE) ;
7135 END DereferenceLValue ;
7139 BuildInclProcedure - builds the pseudo procedure call INCL.
7140 INCL is a procedure which adds bit b into a BITSET a.
7141 It takes two parameters:
7159 | ProcSym | Type | Empty
7163 PROCEDURE BuildInclProcedure ;
7173 proctok := OperandTtok (NoOfParam + 1) ;
7176 VarSym := OperandT (2) ;
7177 MarkArrayWritten (OperandA (2)) ;
7178 OperandSym := OperandT (1) ;
7179 optok := OperandTok (1) ;
7182 IF IsSet (GetDType (VarSym))
7184 DerefSym := DereferenceLValue (optok, OperandSym) ;
7185 BuildRange (InitInclCheck (VarSym, DerefSym)) ;
7186 GenQuadO (proctok, InclOp, VarSym, NulSym, DerefSym, FALSE)
7188 MetaErrorT1 (proctok,
7189 'the first parameter to {%EkINCL} must be a set variable but is {%E1d}',
7193 MetaErrorT1 (proctok,
7194 'base procedure {%EkINCL} expects a variable as a parameter but is {%E1d}',
7198 MetaErrorT0 (proctok, 'the base procedure {%EkINCL} expects 1 or 2 parameters')
7200 PopN (NoOfParam + 1)
7201 END BuildInclProcedure ;
7205 BuildExclProcedure - builds the pseudo procedure call EXCL.
7206 INCL is a procedure which removes bit b from SET a.
7207 It takes two parameters:
7225 | ProcSym | Type | Empty
7229 PROCEDURE BuildExclProcedure ;
7239 proctok := OperandTtok (NoOfParam + 1) ;
7242 VarSym := OperandT (2) ;
7243 MarkArrayWritten (OperandA(2)) ;
7244 OperandSym := OperandT (1) ;
7245 optok := OperandTok (1) ;
7248 IF IsSet (GetDType (VarSym))
7250 DerefSym := DereferenceLValue (optok, OperandSym) ;
7251 BuildRange (InitExclCheck (VarSym, DerefSym)) ;
7252 GenQuadO (proctok, ExclOp, VarSym, NulSym, DerefSym, FALSE)
7254 MetaErrorT1 (proctok,
7255 'the first parameter to {%EkEXCL} must be a set variable but is {%E1d}',
7259 MetaErrorT1 (proctok,
7260 'base procedure {%EkEXCL} expects a variable as a parameter but is {%E1d}',
7264 MetaErrorT0 (proctok,
7265 'the base procedure {%EkEXCL} expects 1 or 2 parameters')
7267 PopN (NoOfParam + 1)
7268 END BuildExclProcedure ;
7272 CheckBuildFunction - checks to see whether ProcSym is a function
7273 and if so it adds a TempSym value which will
7274 hold the return value once the function finishes.
7275 This procedure also generates an error message
7276 if the user is calling a function and ignoring
7277 the return result. The additional TempSym
7278 is not created if ProcSym is a procedure
7279 and the stack is unaltered.
7290 +----------------+ |----------------|
7291 | ProcSym | Type | | TempSym | Type |
7292 |----------------| |----------------|
7295 PROCEDURE CheckBuildFunction () : BOOLEAN ;
7300 ProcSym, Type: CARDINAL ;
7302 PopTFtok(ProcSym, Type, tokpos) ;
7303 IF IsVar(ProcSym) AND IsProcType(Type)
7305 IF GetSType(Type)#NulSym
7307 TempSym := MakeTemporary (tokpos, RightValue) ;
7308 PutVar(TempSym, GetSType(Type)) ;
7309 PushTFtok(TempSym, GetSType(Type), tokpos) ;
7310 PushTFtok(ProcSym, Type, tokpos) ;
7311 IF NOT IsReturnOptional(Type)
7313 IF IsTemporary(ProcSym)
7315 ErrorFormat0 (NewError (tokpos),
7316 'function is being called but its return value is ignored')
7318 n := GetSymName (ProcSym) ;
7319 ErrorFormat1 (NewError (tokpos),
7320 'function (%a) is being called but its return value is ignored', n)
7325 ELSIF IsProcedure(ProcSym) AND (Type#NulSym)
7327 TempSym := MakeTemporary (tokpos, RightValue) ;
7328 PutVar(TempSym, Type) ;
7329 PushTFtok(TempSym, Type, tokpos) ;
7330 PushTFtok(ProcSym, Type, tokpos) ;
7331 IF NOT IsReturnOptional(ProcSym)
7333 n := GetSymName(ProcSym) ;
7334 ErrorFormat1(NewError(tokpos),
7335 'function (%a) is being called but its return value is ignored', n)
7339 PushTFtok (ProcSym, Type, tokpos) ;
7341 END CheckBuildFunction ;
7345 BuildFunctionCall - builds a function call.
7364 |----------------| +------------+
7365 | ProcSym | Type | | ReturnVar |
7366 |----------------| |------------|
7369 PROCEDURE BuildFunctionCall ;
7375 ProcSym : CARDINAL ;
7378 functok := OperandTtok (NoOfParam + 1) ;
7379 ProcSym := OperandT (NoOfParam + 1) ;
7380 ProcSym := SkipConst (ProcSym) ;
7382 (* Compile time stack restored to entry state *)
7383 IF IsUnknown (ProcSym)
7385 paramtok := OperandTtok (1) ;
7386 combinedtok := MakeVirtualTok (functok, functok, paramtok) ;
7387 MetaErrorT1 (functok, 'procedure function {%1Ea} is undefined', ProcSym) ;
7388 PopN (NoOfParam + 2) ;
7389 PushT (MakeConstLit (combinedtok, MakeKey ('0'), NulSym)) (* fake return value to continue compiling *)
7390 ELSIF IsAModula2Type (ProcSym)
7392 ManipulatePseudoCallParameters ;
7394 ELSIF IsPseudoSystemFunction (ProcSym) OR
7395 IsPseudoBaseFunction (ProcSym)
7397 ManipulatePseudoCallParameters ;
7398 BuildPseudoFunctionCall
7400 BuildRealFunctionCall (functok)
7402 END BuildFunctionCall ;
7406 BuildConstFunctionCall - builds a function call and checks that this function can be
7407 called inside a ConstExpression.
7427 |----------------| +------------+
7428 | ProcSym | Type | | ReturnVar |
7429 |----------------| |------------|
7433 PROCEDURE BuildConstFunctionCall ;
7440 ProcSym : CARDINAL ;
7444 ProcSym := OperandT (NoOfParam + 1) ;
7445 functok := OperandTtok (NoOfParam + 1) ;
7446 IF CompilerDebugging
7448 printf2 ('procsym = %d token = %d\n', ProcSym, functok) ;
7449 ErrorStringAt (InitString ('constant function'), functok)
7452 IF (ProcSym # Convert) AND
7453 (IsPseudoBaseFunction (ProcSym) OR
7454 IsPseudoSystemFunctionConstExpression (ProcSym) OR
7455 (IsProcedure (ProcSym) AND IsProcedureBuiltin (ProcSym)))
7459 IF IsAModula2Type (ProcSym)
7461 (* type conversion *)
7464 ConstExpression := OperandT (NoOfParam + 1) ;
7465 paramtok := OperandTtok (NoOfParam + 1) ;
7466 PopN (NoOfParam + 2) ;
7468 Build macro: CONVERT( ProcSym, ConstExpression )
7470 PushTFtok (Convert, NulSym, functok) ;
7471 PushTtok (ProcSym, functok) ;
7472 PushTtok (ConstExpression, paramtok) ;
7473 PushT (2) ; (* Two parameters *)
7474 BuildConvertFunction
7476 MetaErrorT0 (functok, '{%E}a constant type conversion can only have one argument')
7479 (* error issue message and fake return stack *)
7482 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')
7484 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')
7488 paramtok := OperandTtok (NoOfParam + 1) ;
7489 combinedtok := MakeVirtualTok (functok, functok, paramtok)
7491 combinedtok := functok
7493 PopN (NoOfParam+2) ;
7494 PushT (MakeConstLit (combinedtok, MakeKey('0'), NulSym)) (* fake return value to continue compiling *)
7497 END BuildConstFunctionCall ;
7501 BuildTypeCoercion - builds the type coersion.
7502 MODULA-2 allows types to be coersed with no runtime
7504 It insists that the TSIZE(t1)=TSIZE(t2) where
7505 t2 variable := t2(variable of type t1).
7506 The ReturnVar on the stack is of type t2.
7526 |----------------| +------------+
7527 | ProcSym | Type | | ReturnVar |
7528 |----------------| |------------|
7532 CoerceOp ReturnVar Type Param1
7534 A type coercion will only be legal if the different
7535 types have exactly the same size.
7536 Since we can only decide this after M2Eval has processed
7537 the symbol table then we create a quadruple explaining
7538 the coercion taking place, the code generator can test
7539 this assertion and report an error if the type sizes
7543 PROCEDURE BuildTypeCoercion ;
7552 ProcSym : CARDINAL ;
7555 ProcSym := OperandT (NoOfParam+1) ;
7556 proctok := OperandTok (NoOfParam+1) ;
7557 IF NOT IsAModula2Type (ProcSym)
7559 MetaError1 ('coersion expecting a type, seen {%1Ea} which is {%1Ed}', ProcSym)
7563 PopTrwtok (exp, r, exptok) ;
7565 resulttok := MakeVirtualTok (proctok, proctok, exptok) ;
7566 ReturnVar := MakeTemporary (resulttok, RightValue) ;
7567 PutVar (ReturnVar, ProcSym) ; (* Set ReturnVar's TYPE *)
7568 PopN (1) ; (* pop procedure. *)
7569 IF IsConst (exp) OR IsVar (exp)
7571 GenQuad (CoerceOp, ReturnVar, ProcSym, exp)
7573 MetaError2 ('trying to coerse {%1EMRad} which is not a variable or constant into {%2ad}',
7575 MetaError2 ('trying to coerse {%1ECad} which is not a variable or constant into {%2ad}',
7578 PushTFtok (ReturnVar, ProcSym, resulttok)
7580 MetaError0 ('{%E}only one parameter expected in a TYPE coersion')
7582 END BuildTypeCoercion ;
7586 BuildRealFunctionCall - builds a function call.
7605 |----------------| +------------+
7606 | ProcSym | Type | | ReturnVar |
7607 |----------------| |------------|
7610 PROCEDURE BuildRealFunctionCall (tokno: CARDINAL) ;
7613 ProcSym : CARDINAL ;
7617 ProcSym := OperandT (NoOfParam+2) ;
7618 ProcSym := SkipConst (ProcSym) ;
7621 (* Procedure Variable ? *)
7622 ProcSym := SkipType(OperandF(NoOfParam+2))
7624 IF IsDefImp (GetScope (ProcSym)) AND IsDefinitionForC (GetScope(ProcSym))
7626 BuildRealFuncProcCall (tokno, TRUE, TRUE)
7628 BuildRealFuncProcCall (tokno, TRUE, FALSE)
7630 END BuildRealFunctionCall ;
7634 BuildPseudoFunctionCall - builds the pseudo function
7653 |----------------| +------------+
7654 | ProcSym | Type | | ReturnVar |
7655 |----------------| |------------|
7659 PROCEDURE BuildPseudoFunctionCall ;
7662 ProcSym : CARDINAL ;
7665 ProcSym := OperandT (NoOfParam+1) ;
7666 ProcSym := SkipConst (ProcSym) ;
7668 (* Compile time stack restored to entry state *)
7672 ELSIF ProcSym = LengthS
7678 ELSIF ProcSym = Size
7681 ELSIF ProcSym = TSize
7684 ELSIF ProcSym = TBitSize
7686 BuildTBitSizeFunction
7687 ELSIF ProcSym = Convert
7689 BuildConvertFunction
7705 ELSIF IsOrd (ProcSym)
7707 BuildOrdFunction (ProcSym)
7708 ELSIF IsInt (ProcSym)
7710 BuildIntFunction (ProcSym)
7711 ELSIF IsTrunc (ProcSym)
7713 BuildTruncFunction (ProcSym)
7714 ELSIF IsFloat (ProcSym)
7716 BuildFloatFunction (ProcSym)
7723 ELSIF ProcSym = AddAdr
7726 ELSIF ProcSym = SubAdr
7729 ELSIF ProcSym = DifAdr
7732 ELSIF ProcSym = Cast
7735 ELSIF ProcSym = Shift
7738 ELSIF ProcSym = Rotate
7741 ELSIF ProcSym = MakeAdr
7743 BuildMakeAdrFunction
7750 ELSIF ProcSym = Cmplx
7754 InternalError ('pseudo function not implemented yet')
7756 END BuildPseudoFunctionCall ;
7760 BuildAddAdrFunction - builds the pseudo procedure call ADDADR.
7762 PROCEDURE ADDADR (addr: ADDRESS; offset: CARDINAL): ADDRESS ;
7764 Which returns address given by (addr + offset),
7765 [ the standard says that it _may_
7766 "raise an exception if this address is not valid."
7767 currently we do not generate any exception code ]
7780 |----------------| +------------+
7781 | ProcSym | Type | | ReturnVar |
7782 |----------------| |------------|
7785 PROCEDURE BuildAddAdrFunction ;
7796 functok := OperandTtok (NoOfParam + 1) ;
7799 VarSym := OperandT (2) ;
7800 OperandSym := OperandT (1) ;
7801 optok := OperandTok (1) ;
7802 combinedtok := MakeVirtualTok (functok, functok, optok) ;
7803 PopN (NoOfParam + 1) ;
7806 IF IsReallyPointer (VarSym) OR (GetSType (VarSym) = Address)
7808 ReturnVar := MakeTemporary (combinedtok, RightValue) ;
7809 PutVar (ReturnVar, Address) ;
7810 GenQuad (AddOp, ReturnVar, VarSym, DereferenceLValue (optok, OperandSym)) ;
7811 PushTFtok (ReturnVar, Address, combinedtok)
7813 MetaErrorT1 (functok,
7814 'the first parameter to ADDADR {%1Ea} must be a variable of type ADDRESS or a {%EkPOINTER}, rather than a {%1Etsd}',
7816 PushTFtok (MakeConstLit (combinedtok, MakeKey('0'), Address), Address, combinedtok)
7819 MetaErrorT0 (functok, '{%E}SYSTEM procedure ADDADR expects a variable of type ADDRESS or POINTER as its first parameter') ;
7820 PushTFtok (MakeConstLit (combinedtok, MakeKey('0'), Address), Address, combinedtok)
7823 MetaErrorT0 (functok, '{%E}SYSTEM procedure ADDADR expects 2 parameters') ;
7824 PopN (NoOfParam + 1) ;
7825 PushTFtok (MakeConstLit (functok, MakeKey ('0'), Address), Address, functok)
7827 END BuildAddAdrFunction ;
7831 BuildSubAdrFunction - builds the pseudo procedure call ADDADR.
7833 PROCEDURE SUBADR (addr: ADDRESS; offset: CARDINAL): ADDRESS ;
7835 Which returns address given by (addr - offset),
7836 [ the standard says that it _may_
7837 "raise an exception if this address is not valid."
7838 currently we do not generate any exception code ]
7851 |----------------| +------------+
7852 | ProcSym | Type | | ReturnVar |
7853 |----------------| |------------|
7856 PROCEDURE BuildSubAdrFunction ;
7868 functok := OperandTtok (NoOfParam + 1) ;
7869 OperandSym := OperandT (1) ;
7870 optok := OperandTok (1) ;
7873 VarSym := OperandT (2) ;
7874 vartok := OperandTok (2) ;
7875 combinedtok := MakeVirtualTok (functok, functok, optok) ;
7876 PopN (NoOfParam + 1) ;
7879 IF IsReallyPointer (VarSym) OR (GetSType (VarSym) = Address)
7881 ReturnVar := MakeTemporary (combinedtok, RightValue) ;
7882 PutVar (ReturnVar, Address) ;
7883 GenQuad (SubOp, ReturnVar, VarSym, DereferenceLValue (optok, OperandSym)) ;
7884 PushTFtok (ReturnVar, Address, combinedtok)
7886 MetaErrorT1 (functok,
7887 'the first parameter to {%EkSUBADR} {%1Ea} must be a variable of type ADDRESS or a {%EkPOINTER}, rather than a {%1Etsd}',
7889 PushTFtok (MakeConstLit (vartok, MakeKey('0'), Address), Address, vartok)
7892 combinedtok := MakeVirtualTok (functok, functok, optok) ;
7893 MetaErrorT0 (combinedtok,
7894 '{%E}SYSTEM procedure {%EkSUBADR} expects a variable of type ADDRESS or POINTER as its first parameter') ;
7895 PushTFtok (MakeConstLit (combinedtok, MakeKey ('0'), Address), Address, combinedtok)
7898 combinedtok := MakeVirtualTok (functok, functok, optok) ;
7899 MetaErrorT0 (functok,
7900 '{%E}SYSTEM procedure {%EkSUBADR} expects 2 parameters') ;
7901 PopN (NoOfParam+1) ;
7902 PushTFtok (MakeConstLit (combinedtok, MakeKey('0'), Address), Address, combinedtok)
7904 END BuildSubAdrFunction ;
7908 BuildDifAdrFunction - builds the pseudo procedure call DIFADR.
7910 PROCEDURE DIFADR (addr1, addr2: ADDRESS): INTEGER ;
7912 Which returns address given by (addr1 - addr2),
7913 [ the standard says that it _may_
7914 "raise an exception if this address is invalid or
7915 address space is non-contiguous."
7916 currently we do not generate any exception code ]
7929 |----------------| +------------+
7930 | ProcSym | Type | | ReturnVar |
7931 |----------------| |------------|
7934 PROCEDURE BuildDifAdrFunction ;
7939 combinedtok: CARDINAL ;
7946 functok := OperandTtok (NoOfParam + 1) ;
7947 OperandSym := OperandT (1) ;
7948 optok := OperandTok (1) ;
7951 VarSym := OperandT (2) ;
7952 vartok := OperandTok (2) ;
7953 combinedtok := MakeVirtualTok (functok, functok, optok) ;
7954 PopN (NoOfParam + 1) ;
7957 IF IsReallyPointer (VarSym) OR (GetSType (VarSym) = Address)
7959 IF IsReallyPointer (OperandSym) OR (GetSType (OperandSym) = Address)
7961 TempVar := MakeTemporary (vartok, RightValue) ;
7962 PutVar (TempVar, Address) ;
7963 GenQuad (SubOp, TempVar, VarSym, DereferenceLValue (optok, OperandSym)) ;
7965 Build macro: CONVERT( INTEGER, TempVar )
7967 PushTFtok (Convert, NulSym, functok) ;
7968 PushTtok (Integer, functok) ;
7969 PushTtok (TempVar, vartok) ;
7970 PushT (2) ; (* Two parameters *)
7971 BuildConvertFunction
7973 MetaError1 ('the second parameter to {%EkDIFADR } {%1Ea} must be a variable of type ADDRESS or a {%EkPOINTER}, rather than a {%1Etsd}',
7975 PushTFtok (MakeConstLit (combinedtok, MakeKey ('0'), Integer), Integer, combinedtok)
7978 MetaError1 ('the first parameter to {%EkDIFADR } {%1Ea} must be a variable of type ADDRESS or a {%EkPOINTER}, rather than a {%1Etsd}',
7980 PushTFtok (MakeConstLit (combinedtok, MakeKey ('0'), Integer), Integer, combinedtok)
7983 MetaError0 ('{%E}SYSTEM procedure {%EkDIFADR } expects a variable of type ADDRESS or POINTER as its first parameter') ;
7984 PushTFtok (MakeConstLit (combinedtok, MakeKey('0'), Integer), Integer, combinedtok)
7987 combinedtok := MakeVirtualTok (functok, functok, optok) ;
7988 MetaErrorT0 (functok, '{%E}SYSTEM procedure {%EkDIFADR } expects 2 parameters') ;
7989 PopN (NoOfParam+1) ;
7990 PushTFtok (MakeConstLit (combinedtok, MakeKey('0'), Integer), Integer, combinedtok)
7992 END BuildDifAdrFunction ;
7996 BuildHighFunction - checks the stack in preparation for generating
7997 quadruples which perform HIGH.
7998 This procedure does not alter the stack but
7999 determines whether, a, in HIGH(a) is an ArraySym
8001 Both cases are different and appropriate quadruple
8002 generating routines are called.
8022 |----------------| +------------+
8023 | ProcSym | Type | | ReturnVar |
8024 |----------------| |------------|
8028 PROCEDURE BuildHighFunction ;
8032 paramtok : CARDINAL ;
8039 ProcSym := OperandT (NoOfParam+1) ;
8040 functok := OperandTok (NoOfParam + 1) ;
8041 BuildSizeCheckEnd (ProcSym) ; (* quadruple generation now on *)
8044 Param := OperandT (1) ;
8045 paramtok := OperandTok (1) ;
8046 combinedtok := MakeVirtualTok (paramtok, functok, paramtok) ;
8047 Type := GetDType (Param) ;
8048 (* Restore stack to original form *)
8050 IF (NOT IsVar(Param)) AND (NOT IsConstString(Param)) AND (NOT IsConst(Param))
8052 (* we cannot test for IsConst(Param) AND (GetSType(Param)=Char) as the type might not be assigned yet *)
8053 MetaError1 ('base procedure {%EkHIGH} expects a variable or string constant as its parameter {%1d:rather than {%1d}} {%1asa}', Param)
8054 ELSIF IsUnbounded(Type)
8056 BuildHighFromUnbounded (combinedtok)
8058 BuildConstHighFromSym (combinedtok)
8061 MetaError0 ('base procedure {%EkHIGH} requires one parameter') ;
8063 PushTFtok (MakeConstLit (functok, MakeKey ('0'), Cardinal), Cardinal, functok)
8065 END BuildHighFunction ;
8069 BuildConstHighFromSym - builds the pseudo function HIGH from an Sym.
8070 Sym is a constant or an array which has constant bounds
8071 and therefore it can be calculated at compile time.
8091 |----------------| +------------+
8092 | ProcSym | Type | | ReturnVar |
8093 |----------------| |------------|
8096 PROCEDURE BuildConstHighFromSym (tok: CARDINAL) ;
8100 ReturnVar: CARDINAL ;
8103 ReturnVar := MakeTemporary (tok, ImmediateValue) ;
8104 Dim := OperandD (1) ;
8106 GenHigh (tok, ReturnVar, 1, OperandT (1)) ;
8107 PopN (NoOfParam+1) ;
8108 PushTtok (ReturnVar, tok)
8109 END BuildConstHighFromSym ;
8113 BuildHighFromUnbounded - builds the pseudo function HIGH from an
8126 |----------------| +------------+
8127 | ProcSym | Type | | ReturnVar |
8128 |----------------| |------------|
8132 PROCEDURE BuildHighFromUnbounded (tok: CARDINAL) ;
8136 ReturnVar: CARDINAL ;
8139 Assert (NoOfParam=1) ;
8140 ReturnVar := MakeTemporary (tok, RightValue) ;
8141 PutVar (ReturnVar, Cardinal) ;
8142 Dim := OperandD (1) ;
8146 GenHigh (tok, ReturnVar, Dim, OperandA(1))
8148 GenHigh (tok, ReturnVar, Dim, OperandT(1))
8151 PushTFtok (ReturnVar, GetSType(ReturnVar), tok)
8152 END BuildHighFromUnbounded ;
8156 GetQualidentImport - returns the symbol as if it were qualified from, module.n.
8157 This is used to reference runtime support procedures and an
8158 error is generated if the symbol cannot be obtained.
8161 PROCEDURE GetQualidentImport (tokno: CARDINAL;
8162 n: Name; module: Name) : CARDINAL ;
8166 ModSym := MakeDefinitionSource (tokno, module) ;
8169 MetaErrorNT2 (tokno,
8170 'module %a cannot be found and is needed to import %a', module, n) ;
8174 Assert(IsDefImp(ModSym)) ;
8175 IF (GetExported (tokno, ModSym, n)=NulSym) OR IsUnknown (GetExported (tokno, ModSym, n))
8177 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',
8182 RETURN GetExported (tokno, MakeDefinitionSource (tokno, module), n)
8183 END GetQualidentImport ;
8187 MakeLengthConst - creates a constant which contains the length of string, sym.
8190 PROCEDURE MakeLengthConst (tok: CARDINAL; sym: CARDINAL) : CARDINAL ;
8192 RETURN MakeConstant (tok, GetStringLength (sym))
8193 END MakeLengthConst ;
8197 BuildLengthFunction - builds the inline standard function LENGTH.
8209 |----------------| +------------+
8210 | ProcSym | Type | | ReturnVar |
8211 |----------------| |------------|
8215 PROCEDURE BuildLengthFunction ;
8219 functok : CARDINAL ;
8224 ReturnVar : CARDINAL ;
8227 Param := OperandT (1) ;
8228 paramtok := OperandTok (1) ;
8229 functok := OperandTok (NoOfParam + 1) ;
8230 (* Restore stack to origional form *)
8232 Type := GetSType (Param) ; (* get the type from the symbol, not the stack *)
8235 MetaErrorT1 (functok, 'base procedure {%E1kLENGTH} expects 1 parameter, seen {%1En} parameters', NoOfParam)
8239 combinedtok := MakeVirtualTok (paramtok, functok, paramtok) ;
8240 IF IsConst (Param) AND (GetSType (Param) = Char)
8243 PopN (NoOfParam + 1) ;
8244 ReturnVar := MakeConstLit (combinedtok, MakeKey ('1'), Cardinal) ;
8245 PushTtok (ReturnVar, combinedtok)
8246 ELSIF IsConstString (Param)
8249 ReturnVar := MakeLengthConst (combinedtok, OperandT (1)) ;
8250 PopN (NoOfParam + 1) ;
8251 PushTtok (ReturnVar, combinedtok)
8253 ProcSym := GetQualidentImport (functok, MakeKey ('Length'), MakeKey ('M2RTS')) ;
8254 IF (ProcSym # NulSym) AND IsProcedure (ProcSym)
8257 IF IsConst (OperandT (1))
8259 (* we can fold this in M2GenGCC. *)
8260 ReturnVar := MakeTemporary (combinedtok, ImmediateValue) ;
8261 PutVar (ReturnVar, Cardinal) ;
8262 GenQuad (StandardFunctionOp, ReturnVar, ProcSym, OperandT (1)) ;
8263 PopN (NoOfParam + 1) ;
8264 PushTtok (ReturnVar, combinedtok)
8266 (* no we must resolve this at runtime or in the GCC optimizer. *)
8267 PopTF (Param, Type);
8269 PushTtok (ProcSym, functok) ;
8270 PushTFtok (Param, Type, paramtok) ;
8272 BuildRealFunctionCall (functok)
8276 PopN (NoOfParam + 1) ;
8277 PushTtok (MakeConstLit (combinedtok, MakeKey ('0'), Cardinal), combinedtok) ;
8278 MetaErrorT0 (functok, 'no procedure Length found for substitution to the standard function {%E1kLENGTH} which is required to calculate non constant string lengths')
8282 (* NoOfParam is _very_ wrong, we flush all outstanding errors *)
8285 END BuildLengthFunction ;
8289 BuildOddFunction - builds the pseudo procedure call ODD.
8290 This procedure is actually a "macro" for
8291 ORD(x) --> VAL(BOOLEAN, x MOD 2)
8292 However we cannot push tokens back onto the input stack
8293 because the compiler is currently building a function
8294 call and expecting a ReturnVar on the stack.
8295 Hence we manipulate the stack and call
8296 BuildConvertFunction.
8317 | ProcSym | Type | Empty
8321 PROCEDURE BuildOddFunction ;
8325 functok : CARDINAL ;
8327 Res, Var : CARDINAL ;
8330 functok := OperandTok (NoOfParam + 1) ;
8333 Var := OperandT (1) ;
8334 optok := OperandTok (1) ;
8335 combinedtok := MakeVirtualTok (functok, functok, optok) ;
8336 IF IsVar(Var) OR IsConst(Var)
8338 PopN (NoOfParam + 1) ;
8340 Build macro: VAL(BOOLEAN, (x MOD 2))
8343 (* compute (x MOD 2) *)
8344 PushTFtok (Var, GetSType (Var), optok) ;
8346 PushTFtok (MakeConstLit (optok, MakeKey ('2'), ZType), ZType, optok) ;
8350 (* compute IF ...=0 *)
8351 PushTtok (Res, optok) ;
8353 PushTFtok (MakeConstLit (optok, MakeKey ('0'), ZType), ZType, optok) ;
8354 BuildRelOp (combinedtok) ;
8357 Res := MakeTemporary (combinedtok, RightValue) ;
8358 PutVar (Res, Boolean) ;
8360 PushTtok (Res, combinedtok) ;
8361 PushTtok (False, combinedtok) ;
8362 BuildAssignment (combinedtok) ;
8364 PushTtok (Res, combinedtok) ;
8365 PushTtok (True, combinedtok) ;
8366 BuildAssignment (combinedtok) ;
8369 PushTtok (Res, combinedtok)
8371 MetaErrorT1 (combinedtok,
8372 'the parameter to {%E1kODD} must be a variable or constant, seen {%E1ad}',
8374 PushTtok (False, combinedtok)
8377 MetaErrorT1 (functok,
8378 'the pseudo procedure {%E1kODD} only has one parameter, seen {%E1n} parameters',
8380 PushTtok (False, functok)
8382 END BuildOddFunction ;
8386 BuildAbsFunction - builds a call to the standard function ABS.
8388 We cannot implement it as a macro or inline an
8389 IF THEN statement as the IF THEN ELSE requires
8390 we write the value to the same variable (or constant)
8391 twice. The macro implementation will fail as
8392 the compiler maybe building a function
8393 call and expecting a ReturnVar on the stack.
8394 The only method to implement this is to pass it to the
8416 | ProcSym | Type | Empty
8420 PROCEDURE BuildAbsFunction ;
8423 combinedtok: CARDINAL ;
8426 Res, Var : CARDINAL ;
8429 functok := OperandTok (NoOfParam + 1) ;
8432 Var := OperandT (1) ;
8433 combinedtok := MakeVirtualTok (functok, functok, vartok) ;
8434 IF IsVar(Var) OR IsConst(Var)
8436 ProcSym := OperandT (NoOfParam + 1) ;
8437 PopN (NoOfParam + 1) ;
8439 Res := MakeTemporary (combinedtok, AreConstant (IsConst (Var))) ;
8440 PutVar (Res, GetSType (Var)) ;
8442 GenQuadO (combinedtok, StandardFunctionOp, Res, ProcSym, Var, FALSE) ;
8443 PushTFtok (Res, GetSType (Var), combinedtok)
8445 MetaErrorT1 (combinedtok,
8446 'the parameter to {%A1kABS} must be a variable or constant, seen {%E1ad}',
8450 MetaErrorT1 (functok,
8451 'the pseudo procedure {%A1kABS} only has one parameter, seen {%E1n} parameters',
8454 END BuildAbsFunction ;
8458 BuildCapFunction - builds the pseudo procedure call CAP.
8459 We generate a the following quad:
8462 StandardFunctionOp ReturnVal Cap Param1
8474 |----------------| +-------------+
8475 | ProcSym | Type | | ReturnVal |
8476 |----------------| |-------------|
8479 PROCEDURE BuildCapFunction ;
8483 combinedtok: CARDINAL ;
8486 Res, Var : CARDINAL ;
8489 functok := OperandTok (NoOfParam + 1) ;
8492 Var := OperandT (1) ;
8493 optok := OperandTok (1) ;
8494 IF IsVar (Var) OR IsConst (Var)
8496 ProcSym := OperandT (NoOfParam + 1) ;
8497 PopN (NoOfParam + 1) ;
8499 combinedtok := MakeVirtualTok (functok, functok, optok) ;
8500 Res := MakeTemporary (combinedtok, AreConstant (IsConst (Var))) ;
8501 PutVar (Res, Char) ;
8502 GenQuadO (combinedtok, StandardFunctionOp, Res, ProcSym, Var, FALSE) ;
8503 PushTFtok (Res, Char, combinedtok)
8505 MetaErrorT1 (functok,
8506 'the parameter to {%A1kCAP} must be a variable or constant, seen {%E1ad}',
8510 MetaErrorT1 (functok,
8511 'the pseudo procedure {%A1kCAP} only has one parameter, seen {%E1n} parameters',
8514 END BuildCapFunction ;
8518 BuildChrFunction - builds the pseudo procedure call CHR.
8519 This procedure is actually a "macro" for
8520 CHR(x) --> CONVERT(CHAR, x)
8521 However we cannot push tokens back onto the input stack
8522 because the compiler is currently building a function
8523 call and expecting a ReturnVar on the stack.
8524 Hence we manipulate the stack and call
8525 BuildConvertFunction.
8546 | ProcSym | Type | Empty
8550 PROCEDURE BuildChrFunction ;
8558 functok := OperandTok (NoOfParam + 1) ;
8561 Var := OperandT (1) ;
8562 optok := OperandTok (1) ;
8563 IF IsVar (Var) OR IsConst (Var)
8565 PopN (NoOfParam + 1) ;
8567 Build macro: CONVERT( CHAR, Var )
8569 PushTFtok (Convert, NulSym, functok) ;
8570 PushTtok (Char, functok) ;
8571 PushTtok (Var, optok) ;
8572 PushT (2) ; (* Two parameters *)
8573 BuildConvertFunction
8575 MetaErrorT1 (functok,
8576 'the parameter to {%A1kCHR} must be a variable or constant, seen {%E1ad}',
8580 MetaErrorT1 (functok,
8581 'the pseudo procedure {%A1kCHR} only has one parameter, seen {%E1n} parameters',
8584 END BuildChrFunction ;
8588 BuildOrdFunction - builds the pseudo procedure call ORD.
8589 This procedure is actually a "macro" for
8590 ORD(x) --> CONVERT(GetSType(sym), x)
8591 However we cannot push tokens back onto the input stack
8592 because the compiler is currently building a function
8593 call and expecting a ReturnVar on the stack.
8594 Hence we manipulate the stack and call
8595 BuildConvertFunction.
8616 | ProcSym | Type | Empty
8620 PROCEDURE BuildOrdFunction (Sym: CARDINAL) ;
8625 Type, Var: CARDINAL ;
8628 functok := OperandTok (NoOfParam + 1) ;
8631 Var := OperandT (1) ;
8632 optok := OperandTok (1) ;
8633 IF IsVar (Var) OR IsConst (Var)
8635 Type := GetSType (Sym) ;
8636 PopN (NoOfParam + 1) ;
8638 Build macro: CONVERT( CARDINAL, Var )
8640 PushTFtok (Convert, NulSym, functok) ;
8641 PushTtok (Type, optok) ;
8642 PushTtok (Var, optok) ;
8643 PushT (2) ; (* Two parameters *)
8644 BuildConvertFunction
8646 MetaErrorT2 (functok,
8647 'the parameter to {%A1k%a} must be a variable or constant, seen {%2ad}',
8651 MetaErrorT2 (functok,
8652 'the pseudo procedure {%A1k%a} only has one parameter, seen {%2n} parameters',
8655 END BuildOrdFunction ;
8659 BuildIntFunction - builds the pseudo procedure call INT.
8660 This procedure is actually a "macro" for
8661 INT(x) --> CONVERT(INTEGER, x)
8662 However we cannot push tokens back onto the input stack
8663 because the compiler is currently building a function
8664 call and expecting a ReturnVar on the stack.
8665 Hence we manipulate the stack and call
8666 BuildConvertFunction.
8687 | ProcSym | Type | Empty
8691 PROCEDURE BuildIntFunction (Sym: CARDINAL) ;
8697 Type, Var : CARDINAL ;
8700 functok := OperandTok (NoOfParam + 1) ;
8703 Var := OperandT (1) ;
8704 optok := OperandTok (1) ;
8705 IF IsVar (Var) OR IsConst (Var)
8707 Type := GetSType (Sym) ; (* return type of function *)
8708 PopN (NoOfParam + 1) ;
8709 (* Build macro: CONVERT( CARDINAL, Var ). *)
8710 PushTFtok (Convert, NulSym, functok) ;
8711 PushTtok (Type, functok) ;
8712 PushTtok (Var, optok) ;
8713 PushT (2) ; (* Two parameters *)
8714 BuildConvertFunction
8716 combinedtok := MakeVirtualTok (functok, optok, optok) ;
8717 MetaErrorT2 (combinedtok,
8718 'the parameter to {%E1k%a} must be a variable or constant, seen {%2ad}',
8720 PushTtok (combinedtok, MakeConstLit (combinedtok, MakeKey ('0'), ZType))
8723 MetaErrorT2 (functok,
8724 'the pseudo procedure {%E1k%a} only has one parameter, seen {%2n} parameters',
8726 PushTtok (functok, MakeConstLit (functok, MakeKey ('0'), ZType))
8728 END BuildIntFunction ;
8732 BuildMakeAdrFunction - builds the pseudo procedure call MAKEADR.
8753 | ProcSym | Type | Empty
8757 PROCEDURE BuildMakeAdrFunction ;
8762 resulttok : CARDINAL ;
8763 AreConst : BOOLEAN ;
8765 NoOfParameters: CARDINAL ;
8766 ReturnVar : CARDINAL ;
8768 PopT (NoOfParameters) ;
8769 functok := OperandTok (NoOfParameters + 1) ;
8772 starttok := OperandTok (NoOfParameters + 1) ; (* ADR token. *)
8773 endtok := OperandTok (1) ; (* last parameter. *)
8774 GenQuad (ParamOp, 0, MakeAdr, MakeAdr) ;
8775 i := NoOfParameters ;
8776 (* stack index referencing stacked parameter, i *)
8779 GenQuadO (OperandTok (pi), ParamOp, i, MakeAdr, OperandT (pi), TRUE) ;
8785 WHILE i <= NoOfParameters DO
8786 IF IsVar (OperandT (i))
8789 ELSIF NOT IsConst (OperandT (i))
8791 MetaError1 ('problem in the {%E1N} argument for {%EkMAKEADR}, all arguments to {%EkMAKEADR} must be either variables or constants', i)
8795 (* ReturnVar - will have the type of the procedure *)
8796 resulttok := MakeVirtualTok (starttok, starttok, endtok) ;
8797 ReturnVar := MakeTemporary (resulttok, AreConstant(AreConst)) ;
8798 PutVar (ReturnVar, GetSType(MakeAdr)) ;
8799 GenQuadO (resulttok, FunctValueOp, ReturnVar, NulSym, MakeAdr, TRUE) ;
8800 PopN (NoOfParameters+1) ;
8801 PushTFtok (ReturnVar, GetSType (MakeAdr), resulttok)
8803 MetaError1 ('the pseudo procedure {%EkMAKEADR} requires at least one parameter, seen {%E1n}', NoOfParameters) ;
8805 PushTFtok (Nil, GetSType (MakeAdr), functok)
8807 END BuildMakeAdrFunction ;
8811 BuildShiftFunction - builds the pseudo procedure call SHIFT.
8813 PROCEDURE SHIFT (val: <any type>;
8814 num: INTEGER): <any type> ;
8816 "Returns a bit sequence obtained from val by
8817 shifting up or down (left or right) by the
8818 absolute value of num, introducing
8819 zeros as necessary. The direction is down if
8820 the sign of num is negative, otherwise the
8834 |----------------| +------------+
8835 | ProcSym | Type | | ReturnVar |
8836 |----------------| |------------|
8839 PROCEDURE BuildShiftFunction ;
8855 paramtok := OperandTok (1) ;
8856 functok := OperandTok (NoOfParam + 1) ;
8859 PopTrwtok (Exp, r, exptok) ;
8861 PopTtok (varSet, vartok) ;
8863 combinedtok := MakeVirtualTok (functok, exptok, vartok) ;
8864 IF (GetSType (varSet) # NulSym) AND IsSet (GetDType (varSet))
8866 derefExp := DereferenceLValue (exptok, Exp) ;
8867 BuildRange (InitShiftCheck (varSet, derefExp)) ;
8868 returnVar := MakeTemporary (combinedtok, RightValue) ;
8869 PutVar (returnVar, GetSType (varSet)) ;
8870 GenQuad (LogicalShiftOp, returnVar, varSet, derefExp) ;
8871 PushTFtok (returnVar, GetSType (varSet), combinedtok)
8873 MetaError1 ('SYSTEM procedure {%E1kSHIFT} expects a constant or variable which has a type of SET as its first parameter, seen {%E1ad}',
8875 PushTFtok (MakeConstLit (combinedtok, MakeKey ('0'), Cardinal), Cardinal, combinedtok)
8878 combinedtok := MakeVirtualTok (functok, functok, paramtok) ;
8879 MetaErrorT1 (functok,
8880 'the pseudo procedure {%EkSHIFT} requires at least two parameters, seen {%E1n}',
8882 PopN (NoOfParam + 1) ;
8883 PushTFtok (MakeConstLit (combinedtok, MakeKey ('0'), Cardinal), Cardinal, combinedtok)
8885 END BuildShiftFunction ;
8889 BuildRotateFunction - builds the pseudo procedure call ROTATE.
8891 PROCEDURE ROTATE (val: <any type>;
8892 num: INTEGER): <any type> ;
8894 "Returns a bit sequence obtained from val
8895 by rotating up or down (left or right) by
8896 the absolute value of num. The direction is
8897 down if the sign of num is negative, otherwise
8898 the direction is up."
8911 |----------------| +------------+
8912 | ProcSym | Type | | ReturnVar |
8913 |----------------| |------------|
8916 PROCEDURE BuildRotateFunction ;
8931 functok := OperandTok (NoOfParam + 1) ;
8934 PopTrwtok (Exp, r, exptok) ;
8936 PopTtok (varSet, vartok) ;
8938 IF (GetSType (varSet) # NulSym) AND IsSet (GetDType (varSet))
8940 combinedtok := MakeVirtualTok (functok, functok, exptok) ;
8941 derefExp := DereferenceLValue (exptok, Exp) ;
8942 BuildRange (InitRotateCheck (varSet, derefExp)) ;
8943 returnVar := MakeTemporary (combinedtok, RightValue) ;
8944 PutVar (returnVar, GetSType (varSet)) ;
8945 GenQuadO (combinedtok, LogicalRotateOp, returnVar, varSet, derefExp, TRUE) ;
8946 PushTFtok (returnVar, GetSType (varSet), combinedtok)
8948 MetaErrorT0 (functok,
8949 'SYSTEM procedure {%EkROTATE} expects a constant or variable which has a type of SET as its first parameter') ;
8950 PushTFtok (MakeConstLit (functok, MakeKey('0'), Cardinal), Cardinal, functok)
8953 MetaErrorT1 (functok,
8954 'SYSTEM procedure {%EkROTATE} expects 2 parameters and was given {%1n} parameters',
8956 PopN (NoOfParam + 1) ;
8957 PushTFtok (MakeConstLit (functok, MakeKey ('0'), Cardinal), Cardinal, functok)
8959 END BuildRotateFunction ;
8963 BuildValFunction - builds the pseudo procedure call VAL.
8964 This procedure is actually a "macro" for
8965 VAL(Type, x) --> CONVERT(Type, x)
8966 However we cannot push tokens back onto the input stack
8967 because the compiler is currently building a function
8968 call and expecting a ReturnVar on the stack.
8969 Hence we manipulate the stack and call
8970 BuildConvertFunction.
8991 | ProcSym | Type | Empty
8995 PROCEDURE BuildValFunction ;
8997 functok : CARDINAL ;
9000 Exp, Type: CARDINAL ;
9006 functok := OperandTok (NoOfParam + 1) ;
9009 PopTrwtok (Exp, r, exptok) ;
9011 PopTtok (Type, typetok) ;
9012 PopTtok (ProcSym, tok) ;
9015 (* not sensible to try and recover when we dont know the return type. *)
9016 MetaErrorT1 (typetok,
9017 'undeclared type found in builtin procedure function {%AkVAL} {%A1ad}',
9019 (* non recoverable error. *)
9020 ELSIF (IsSet (Type) OR IsEnumeration (Type) OR IsSubrange (Type) OR
9021 IsType (Type) OR IsPointer (Type) OR IsProcType (Type)) AND
9022 (IsVar (Exp) OR IsConst (Exp) OR IsProcedure (Exp))
9025 Build macro: CONVERT( Type, Var )
9027 PushTFtok (Convert, NulSym, tok) ;
9028 PushTtok (Type, typetok) ;
9029 PushTtok (Exp, exptok) ;
9030 PushT (2) ; (* Two parameters *)
9031 BuildConvertFunction
9033 (* not sensible to try and recover when we dont know the return type. *)
9034 MetaErrorT0 (functok,
9035 'the builtin procedure {%AkVAL} has thw following formal parameter declaration {%kVAL} (type, expression)')
9036 (* non recoverable error. *)
9039 (* not sensible to try and recover when we dont know the return type. *)
9040 MetaErrorT1 (functok,
9041 'the builtin procedure {%AkVAL} expects 2 parameters, a type and an expression, but was given {%1n} parameters', NoOfParam)
9042 (* non recoverable error. *)
9044 END BuildValFunction ;
9048 BuildCastFunction - builds the pseudo procedure call CAST.
9049 This procedure is actually a "macro" for
9050 CAST(Type, x) --> Type(x)
9051 However we cannot push tokens back onto the input stack
9052 because the compiler is currently building a function
9053 call and expecting a ReturnVar on the stack.
9054 Hence we manipulate the stack and call
9055 BuildConvertFunction.
9076 | ProcSym | Type | Empty
9080 PROCEDURE BuildCastFunction ;
9089 Var, Type : CARDINAL ;
9092 functok := OperandTok (NoOfParam + 1) ;
9095 Type := OperandT (2) ;
9096 typetok := OperandTok (2) ;
9097 Var := OperandT (1) ;
9098 vartok := OperandTok (1) ;
9101 n := GetSymName (Type) ;
9102 WriteFormat1 ('undeclared type found in CAST (%a)', n)
9103 ELSIF IsSet (Type) OR IsEnumeration (Type) OR IsSubrange (Type) OR IsType (Type) OR
9104 IsPointer (Type) OR IsArray (Type) OR IsProcType (Type)
9108 PopN (NoOfParam+1) ;
9110 Build macro: Type( Var )
9112 PushTFtok (Type, NulSym, typetok) ;
9113 PushTtok (Var, vartok) ;
9114 PushT (1) ; (* one parameter *)
9116 ELSIF IsVar (Var) OR IsProcedure (Var)
9118 PopN (NoOfParam + 1) ;
9119 combinedtok := MakeVirtualTok (functok, functok, vartok) ;
9120 ReturnVar := MakeTemporary (combinedtok, RightValue) ;
9121 PutVar (ReturnVar, Type) ;
9122 GenQuadO (combinedtok, CastOp, ReturnVar, Type, Var, FALSE) ;
9123 PushTFtok (ReturnVar, Type, combinedtok)
9125 (* not sensible to try and recover when we dont know the return type. *)
9126 MetaErrorT0 (functok,
9127 'the second parameter to the builtin procedure {%AkCAST} must either be a variable, constant or a procedure. The formal parameters to cast are CAST(type, variable or constant or procedure)')
9128 (* non recoverable error. *)
9131 (* not sensible to try and recover when we dont know the return type. *)
9132 MetaErrorT0 (functok,
9133 'the builtin procedure {%AkCAST} has the following formal parameter declaration {%kCAST} (type, expression)')
9134 (* non recoverable error. *)
9137 (* not sensible to try and recover when we dont know the return type. *)
9138 MetaErrorT1 (functok,
9139 'the builtin procedure {%AkCAST} `expects 2 parameters, a type and an expression, but was given {%1n} parameters', NoOfParam)
9140 (* non recoverable error. *)
9142 END BuildCastFunction ;
9146 BuildConvertFunction - builds the pseudo function CONVERT.
9147 CONVERT( Type, Variable ) ;
9167 |----------------| +---------------------+
9168 | ProcSym | Type | | ReturnVar | Param1 |
9169 |----------------| |---------------------|
9173 ConvertOp ReturnVar Param1 Param2
9175 Converts variable Param2 into a variable Param1
9179 PROCEDURE BuildConvertFunction ;
9189 ReturnVar : CARDINAL ;
9192 functok := OperandTok (NoOfParam + 1) ;
9195 PopTrwtok (Exp, r, exptok) ;
9197 PopTtok (Type, typetok) ;
9201 (* we cannot recover if we dont have a type. *)
9202 MetaErrorT1 (typetok, 'undeclared type {%A1ad} found in {%kCONVERT}', Type)
9203 (* non recoverable error. *)
9204 ELSIF IsUnknown (Exp)
9206 (* we cannot recover if we dont have a type. *)
9207 MetaErrorT1 (typetok, 'unknown {%A1d} {%1ad} found in {%kCONVERT}', Exp)
9208 (* non recoverable error. *)
9209 ELSIF (IsSet (Type) OR IsEnumeration (Type) OR IsSubrange (Type) OR
9210 IsType (Type) OR IsPointer (Type) OR IsProcType (Type) OR IsRecord (Type)) AND
9211 (IsVar (Exp) OR IsConst (Exp) OR IsProcedure (Exp))
9213 (* firstly dereference Var *)
9214 IF GetMode (Exp) = LeftValue
9216 t := MakeTemporary (exptok, RightValue) ;
9217 PutVar (t, GetSType (Exp)) ;
9218 CheckPointerThroughNil (exptok, Exp) ;
9219 doIndrX (exptok, t, Exp) ;
9223 combinedtok := MakeVirtualTok (functok, functok, exptok) ;
9224 ReturnVar := MakeTemporary (combinedtok, AreConstant (IsConst (Exp))) ;
9225 PutVar (ReturnVar, Type) ;
9226 GenQuadO (combinedtok, ConvertOp, ReturnVar, Type, Exp, TRUE) ;
9227 PushTFtok (ReturnVar, Type, combinedtok)
9229 (* not sensible to try and recover when we dont know the return type. *)
9230 MetaErrorT0 (functok,
9231 'the builtin procedure {%AkCONVERT} has the following formal parameter declaration {%kCONVERT} (type, expression)')
9232 (* non recoverable error. *)
9235 (* not sensible to try and recover when we dont know the return type. *)
9236 MetaErrorT1 (functok,
9237 'the builtin procedure {%AkCONVERT} expects 2 parameters, a type and an expression, but was given {%1n} parameters', NoOfParam)
9238 (* non recoverable error. *)
9240 END BuildConvertFunction ;
9244 CheckBaseTypeValue - checks to see whether the value, min, really exists.
9247 PROCEDURE CheckBaseTypeValue (tok: CARDINAL;
9250 func: CARDINAL) : CARDINAL ;
9252 IF (type = Real) OR (type = LongReal) OR (type = ShortReal)
9255 IF NOT IsValueAndTreeKnown ()
9258 '{%1Ead} ({%2ad}) cannot be calculated at compile time for the target architecture', func, type) ;
9259 RETURN MakeConstLit (tok, MakeKey ('1.0'), RType)
9263 END CheckBaseTypeValue ;
9267 GetTypeMin - returns the minimium value of type.
9270 PROCEDURE GetTypeMin (tok: CARDINAL; func, type: CARDINAL) : CARDINAL ;
9272 min, max: CARDINAL ;
9274 IF IsSubrange (type)
9276 min := MakeTemporary (tok, ImmediateValue) ;
9277 PutVar (min, type) ;
9278 GenQuad (SubrangeLowOp, min, NulSym, type) ;
9280 ELSIF IsSet (SkipType (type))
9282 RETURN GetTypeMin (tok, func, GetSType (SkipType (type)))
9283 ELSIF IsBaseType (type) OR IsEnumeration (type)
9285 GetBaseTypeMinMax (type, min, max) ;
9286 min := CheckBaseTypeValue (tok, type, min, func) ;
9288 ELSIF IsSystemType (type)
9290 GetSystemTypeMinMax (type, min, max) ;
9292 ELSIF GetSType (type) = NulSym
9295 'unable to obtain the {%AkMIN} value for type {%1Aad}', type)
9296 (* non recoverable error. *)
9298 RETURN GetTypeMin (tok, func, GetSType (type))
9304 GetTypeMax - returns the maximum value of type.
9307 PROCEDURE GetTypeMax (tok: CARDINAL; func, type: CARDINAL) : CARDINAL ;
9309 min, max: CARDINAL ;
9311 IF IsSubrange (type)
9313 max := MakeTemporary (tok, ImmediateValue) ;
9314 PutVar (max, type) ;
9315 GenQuad (SubrangeHighOp, max, NulSym, type) ;
9317 ELSIF IsSet (SkipType (type))
9319 RETURN GetTypeMax (tok, func, GetSType (SkipType (type)))
9320 ELSIF IsBaseType (type) OR IsEnumeration (type)
9322 GetBaseTypeMinMax (type, min, max) ;
9323 min := CheckBaseTypeValue (tok, type, min, func) ;
9325 ELSIF IsSystemType (type)
9327 GetSystemTypeMinMax (type, min, max) ;
9329 ELSIF GetSType (type) = NulSym
9332 'unable to obtain the {%AkMAX} value for type {%1Aad}', type)
9333 (* non recoverable error. *)
9335 RETURN GetTypeMax (tok, func, GetSType (type))
9341 BuildMinFunction - builds the pseudo function call Min.
9353 | ProcSym | Type | Empty
9357 PROCEDURE BuildMinFunction ;
9368 func := OperandT (NoOfParam + 1) ;
9369 functok := OperandTtok (NoOfParam + 1) ;
9372 Var := OperandT (1) ;
9373 vartok := OperandTok (1) ;
9374 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9375 combinedtok := MakeVirtualTok (functok, functok, vartok) ;
9376 IF IsAModula2Type (Var)
9378 min := GetTypeMin (vartok, func, Var) ;
9379 PushTFtok (min, GetSType (min), combinedtok)
9382 min := GetTypeMin (vartok, func, GetSType (Var)) ;
9383 PushTFtok (min, GetSType (Var), combinedtok)
9385 (* we dont know the type therefore cannot fake a return. *)
9386 MetaErrorT1 (vartok,
9387 'parameter to {%AkMIN} must be a type or a variable, seen {%1Aad}',
9389 (* non recoverable error. *)
9392 (* we dont know the type therefore cannot fake a return. *)
9393 MetaErrorT1 (functok,
9394 'the pseudo builtin procedure function {%AkMIN} only has one parameter, seen {%1An}',
9396 (* non recoverable error. *)
9398 END BuildMinFunction ;
9402 BuildMaxFunction - builds the pseudo function call Max.
9414 | ProcSym | Type | Empty
9418 PROCEDURE BuildMaxFunction ;
9429 func := OperandT (NoOfParam + 1) ;
9430 functok := OperandTtok (NoOfParam + 1) ;
9433 Var := OperandT (1) ;
9434 vartok := OperandTok (1) ;
9435 PopN (NoOfParam + 1) ; (* destroy arguments to this function *)
9436 combinedtok := MakeVirtualTok (functok, functok, vartok) ;
9437 IF IsAModula2Type (Var)
9439 max := GetTypeMax (vartok, func, Var) ;
9440 PushTFtok (max, GetSType (max), combinedtok)
9443 max := GetTypeMax (vartok, func, GetSType (Var)) ;
9444 PushTFtok (max, GetSType (Var), combinedtok)
9446 (* we dont know the type therefore cannot fake a return. *)
9447 MetaErrorT1 (vartok,
9448 'parameter to {%AkMAX} must be a type or a variable, seen {%1Aad}',
9450 (* non recoverable error. *)
9453 (* we dont know the type therefore cannot fake a return. *)
9454 MetaErrorT1 (functok,
9455 'the pseudo builtin procedure function {%AkMAX} only has one parameter, seen {%1An}',
9457 (* non recoverable error. *)
9459 END BuildMaxFunction ;
9463 BuildTruncFunction - builds the pseudo procedure call TRUNC.
9464 This procedure is actually a "macro" for
9465 TRUNC(x) --> CONVERT(INTEGER, x)
9466 However we cannot push tokens back onto the input stack
9467 because the compiler is currently building a function
9468 call and expecting a ReturnVar on the stack.
9469 Hence we manipulate the stack and call
9470 BuildConvertFunction.
9491 | ProcSym | Type | Empty
9495 PROCEDURE BuildTruncFunction (Sym: CARDINAL) ;
9498 functok : CARDINAL ;
9499 NoOfParam: CARDINAL ;
9505 Assert (IsTrunc (OperandT (NoOfParam+1))) ;
9506 functok := OperandTtok (NoOfParam + 1) ;
9509 ProcSym := RequestSym (functok, MakeKey ('CONVERT')) ;
9510 IF (ProcSym # NulSym) AND IsProcedure (ProcSym)
9512 Var := OperandT (1) ;
9513 vartok := OperandTtok (1) ;
9514 Type := GetSType (Sym) ;
9515 PopN (NoOfParam + 1) ; (* destroy arguments to this function *)
9516 IF IsVar (Var) OR IsConst (Var)
9518 IF IsRealType (GetSType (Var))
9520 (* build macro: CONVERT( INTEGER, Var ). *)
9521 PushTFtok (ProcSym, NulSym, functok) ;
9522 PushTtok (Type, functok) ;
9523 PushTtok (Var, vartok) ;
9524 PushT (2) ; (* two parameters *)
9525 BuildConvertFunction
9527 MetaErrorT1 (functok,
9528 'argument to {%1E%ad} must be a float point type', Sym) ;
9529 PushTFtok (MakeConstLit (functok, MakeKey('0'), Type), Type, functok)
9532 MetaErrorT2 (functok,
9533 'argument to {%1E%ad} must be a variable or constant, seen {%2ad}',
9535 PushTFtok (MakeConstLit (functok, MakeKey('0'), Type), Type, functok)
9538 InternalError ('CONVERT procedure not found for TRUNC substitution')
9541 (* we dont know the type therefore cannot fake a return. *)
9542 MetaErrorT1 (functok,
9543 'the pseudo builtin procedure function {%AkTRUNC} only has one parameter, seen {%1An}', NoOfParam)
9544 (* non recoverable error. *)
9546 END BuildTruncFunction ;
9550 BuildFloatFunction - builds the pseudo procedure call FLOAT.
9551 This procedure is actually a "macro" for
9552 FLOAT(x) --> CONVERT(REAL, x)
9553 However we cannot push tokens back onto the input stack
9554 because the compiler is currently building a function
9555 call and expecting a ReturnVar on the stack.
9556 Hence we manipulate the stack and call
9557 BuildConvertFunction.
9578 | ProcSym | Type | Empty
9582 PROCEDURE BuildFloatFunction (Sym: CARDINAL) ;
9585 functok : CARDINAL ;
9586 NoOfParam: CARDINAL ;
9589 ProcSym : CARDINAL ;
9592 functok := OperandTtok (NoOfParam + 1) ;
9593 Type := GetSType (Sym) ;
9596 ProcSym := RequestSym (functok, MakeKey ('CONVERT')) ;
9597 IF (ProcSym # NulSym) AND IsProcedure (ProcSym)
9599 Var := OperandT (1) ;
9600 vartok := OperandTtok (1) ;
9601 IF IsVar (Var) OR IsConst (Var)
9603 PopN (NoOfParam + 1) ; (* destroy arguments to this function. *)
9604 (* build macro: CONVERT (REAL, Var). *)
9605 PushTFtok (ProcSym, NulSym, functok) ;
9606 PushTtok (Type, functok) ;
9607 PushTtok (Var, vartok) ;
9608 PushT(2) ; (* two parameters. *)
9609 BuildConvertFunction
9611 MetaErrorT1 (functok,
9612 'argument to {%1E%ad} must be a variable or constant', ProcSym) ;
9613 PushTFtok (MakeConstLit (functok, MakeKey('0.0'), Type), Type, functok)
9616 InternalError ('CONVERT procedure not found for FLOAT substitution')
9619 MetaErrorT1 (functok,
9620 'the builtin procedure function {%1Ead} only has one parameter',
9622 PushTFtok (MakeConstLit (functok, MakeKey('0.0'), Type), Type, functok)
9624 END BuildFloatFunction ;
9628 BuildReFunction - builds the pseudo procedure call RE.
9649 | ProcSym | Type | Empty
9653 PROCEDURE BuildReFunction ;
9658 functok : CARDINAL ;
9659 NoOfParam : CARDINAL ;
9664 functok := OperandTtok (NoOfParam + 1) ;
9665 func := OperandT (NoOfParam + 1) ;
9668 Var := OperandT (1) ;
9669 vartok := OperandTok (1) ;
9670 combinedtok := MakeVirtualTok (functok, functok, vartok) ;
9671 IF IsVar(Var) OR IsConst(Var)
9673 ReturnVar := MakeTemporary (combinedtok, AreConstant (IsConst (Var))) ;
9674 PutVar (ReturnVar, ComplexToScalar (GetSType (Var))) ;
9675 GenQuadO (combinedtok, StandardFunctionOp, ReturnVar, Re, Var, FALSE) ;
9676 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9677 PushTFtok (ReturnVar, GetSType (ReturnVar), combinedtok)
9679 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9680 PushTFtok (MakeConstLit (combinedtok, MakeKey ('1.0'), RType), RType, combinedtok) ;
9681 MetaErrorT2 (functok,
9682 'the parameter to the builtin procedure function {%1Ead} must be a constant or a variable, seen {%2ad}',
9686 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9687 PushTFtok (MakeConstLit (functok, MakeKey ('1.0'), RType), RType, functok) ;
9688 MetaErrorT2 (functok,
9689 'the builtin procedure function {%1Ead} only has one parameter, seen {%2n}',
9692 END BuildReFunction ;
9696 BuildImFunction - builds the pseudo procedure call IM.
9717 | ProcSym | Type | Empty
9721 PROCEDURE BuildImFunction ;
9726 functok : CARDINAL ;
9727 NoOfParam : CARDINAL ;
9732 functok := OperandTtok (NoOfParam + 1) ;
9733 func := OperandT (NoOfParam + 1) ;
9736 Var := OperandT (1) ;
9737 vartok := OperandTok (1) ;
9738 combinedtok := MakeVirtualTok (functok, functok, vartok) ;
9739 IF IsVar(Var) OR IsConst(Var)
9741 ReturnVar := MakeTemporary (combinedtok, AreConstant (IsConst (Var))) ;
9742 PutVar (ReturnVar, ComplexToScalar (GetSType (Var))) ;
9743 GenQuadO (combinedtok, StandardFunctionOp, ReturnVar, Im, Var, FALSE) ;
9744 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9745 PushTFtok (ReturnVar, GetSType (ReturnVar), combinedtok)
9747 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9748 PushTFtok (MakeConstLit (combinedtok, MakeKey ('1.0'), RType), RType, combinedtok) ;
9749 MetaErrorT2 (functok,
9750 'the parameter to the builtin procedure function {%1Ead} must be a constant or a variable, seen {%2ad}',
9754 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9755 PushTFtok (MakeConstLit (functok, MakeKey ('1.0'), RType), RType, functok) ;
9756 MetaErrorT2 (functok,
9757 'the builtin procedure function {%1Ead} only has one parameter, seen {%2n}',
9760 END BuildImFunction ;
9764 BuildCmplxFunction - builds the pseudo procedure call CMPLX.
9785 | ProcSym | Type | Empty
9789 PROCEDURE BuildCmplxFunction ;
9793 combinedtok: CARDINAL ;
9794 NoOfParam : CARDINAL ;
9800 functok := OperandTtok (NoOfParam + 1) ;
9801 func := OperandT (NoOfParam + 1) ;
9806 endtok := OperandTok (1) ;
9807 combinedtok := MakeVirtualTok (functok, functok, endtok) ;
9808 IF (IsVar(l) OR IsConst(l)) AND
9809 (IsVar(r) OR IsConst(r))
9811 CheckExpressionCompatible (combinedtok, GetSType(l), GetSType(r)) ;
9812 ReturnVar := MakeTemporary (combinedtok, AreConstant (IsConst (l) AND IsConst (r))) ;
9813 PutVar (ReturnVar, GetCmplxReturnType (GetDType (l), GetDType (r))) ;
9814 GenQuadO (combinedtok, StandardFunctionOp, ReturnVar, Cmplx, Make2Tuple (l, r), TRUE) ;
9815 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9816 PushTFtok (ReturnVar, GetSType (ReturnVar), combinedtok)
9818 IF IsVar (l) OR IsConst (l)
9820 MetaErrorT2 (functok,
9821 'the builtin procedure {%1Ead} requires two parameters, both must be variables or constants but the second parameter is {%2d}',
9824 MetaErrorT2 (functok,
9825 'the builtin procedure {%1Ead} requires two parameters, both must be variables or constants but the first parameter is {%2d}',
9828 PopN (NoOfParam+1) ; (* destroy arguments to this function *)
9829 PushTFtok (MakeConstLit (combinedtok, MakeKey ('1.0'), CType), CType, combinedtok)
9832 MetaErrorT2 (functok,
9833 'the builtin procedure {%1Ead} requires two parameters, seen {%2n}',
9835 PopN (NoOfParam + 1) ; (* destroy arguments to this function *)
9836 PushTFtok (MakeConstLit (functok, MakeKey ('1.0'), CType), CType, functok)
9838 END BuildCmplxFunction ;
9842 BuildAdrFunction - builds the pseudo function ADR
9861 |----------------| +------------+
9862 | ProcSym | Type | | ReturnVar |
9863 |----------------| |------------|
9867 PROCEDURE BuildAdrFunction ;
9879 Type, rw : CARDINAL ;
9882 PopT (noOfParameters) ;
9883 procSym := OperandT (noOfParameters + 1) ;
9884 procTok := OperandTok (noOfParameters + 1) ; (* token of procedure ADR. *)
9885 endtok := OperandTok (1) ; (* last parameter. *)
9886 combinedTok := MakeVirtualTok (procTok, procTok, endtok) ;
9887 IF noOfParameters # 1
9889 MetaErrorNT0 (combinedTok,
9890 'SYSTEM procedure ADR expects 1 parameter') ;
9891 PopN (noOfParameters + 1) ; (* destroy the arguments and function *)
9892 PushTF (Nil, Address)
9893 ELSIF IsConstString (OperandT (1))
9895 returnVar := MakeLeftValue (combinedTok, OperandT (1), RightValue,
9896 GetSType (procSym)) ;
9897 PopN (noOfParameters + 1) ; (* destroy the arguments and function *)
9898 PushTFtok (returnVar, GetSType (returnVar), combinedTok)
9899 ELSIF (NOT IsVar(OperandT(1))) AND (NOT IsProcedure(OperandT(1)))
9901 MetaErrorNT0 (combinedTok,
9902 'SYSTEM procedure ADR expects a variable, procedure or a constant string as its parameter') ;
9903 PopN (noOfParameters + 1) ; (* destroy the arguments and function *)
9904 PushTFtok (Nil, Address, combinedTok)
9905 ELSIF IsProcedure (OperandT (1))
9907 returnVar := MakeLeftValue (combinedTok, OperandT (1), RightValue,
9908 GetSType (procSym)) ;
9909 PopN (noOfParameters + 1) ; (* destroy the arguments and function *)
9910 PushTFtok (returnVar, GetSType (returnVar), combinedTok)
9912 Type := GetSType (OperandT (1)) ;
9913 Dim := OperandD (1) ;
9914 MarkArrayWritten (OperandT (1)) ;
9915 MarkArrayWritten (OperandA (1)) ;
9916 (* if the operand is an unbounded which has not been indexed
9917 then we will lookup its address from the unbounded record.
9918 Otherwise we obtain the address of the operand.
9920 IF IsUnbounded (Type) AND (Dim = 0)
9922 (* we will reference the address field of the unbounded structure *)
9923 UnboundedSym := OperandT (1) ;
9924 rw := OperandRW (1) ;
9925 PushTFrw (UnboundedSym, GetSType (UnboundedSym), rw) ;
9926 Field := GetUnboundedAddressOffset (GetSType (UnboundedSym)) ;
9927 PushTF (Field, GetSType (Field)) ;
9929 BuildDesignatorRecord (combinedTok) ;
9930 PopTrw (returnVar, rw) ;
9931 IF GetMode (returnVar) = LeftValue
9933 t := MakeTemporary (combinedTok, RightValue) ;
9934 PutVar (t, GetSType (procSym)) ;
9935 doIndrX (combinedTok, t, returnVar) ;
9938 (* we need to cast returnVar into ADDRESS *)
9939 t := MakeTemporary (combinedTok, RightValue) ;
9940 PutVar (t, GetSType (procSym)) ;
9941 GenQuadO (combinedTok, ConvertOp, t, GetSType (procSym), returnVar, FALSE) ;
9945 returnVar := MakeTemporary (combinedTok, RightValue) ;
9946 PutVar (returnVar, GetSType (procSym)) ;
9947 IF GetMode (OperandT (1)) = LeftValue
9949 PutVar (returnVar, GetSType (procSym)) ;
9950 GenQuadO (combinedTok, ConvertOp, returnVar, GetSType (procSym), OperandT (1), FALSE)
9952 GenQuadO (combinedTok, AddrOp, returnVar, NulSym, OperandT (1), FALSE)
9954 rw := OperandMergeRW (1) ;
9955 Assert (IsLegal (rw))
9957 PopN (noOfParameters + 1) ; (* destroy the arguments and function *)
9958 PushTFrwtok (returnVar, GetSType (returnVar), rw, combinedTok)
9960 END BuildAdrFunction ;
9964 BuildSizeFunction - builds the pseudo function SIZE
9983 |----------------| +------------+
9984 | ProcSym | Type | | ReturnVar |
9985 |----------------| |------------|
9988 PROCEDURE BuildSizeFunction ;
9992 functok : CARDINAL ;
9997 ReturnVar : CARDINAL ;
10000 ProcSym := OperandT (NoOfParam + 1) ;
10001 functok := OperandTtok (NoOfParam + 1) ;
10004 MetaErrorT1 (functok,
10005 '{%E} SYSTEM procedure function {%kSIZE} requires one parameter, seen {%1n}',
10007 resulttok := functok ;
10008 ReturnVar := MakeConstLit (resulttok, MakeKey('0'), Cardinal)
10009 ELSIF IsAModula2Type (OperandT (1))
10011 paramtok := OperandTok (1) ;
10012 resulttok := MakeVirtualTok (functok, functok, paramtok) ;
10013 BuildSizeCheckEnd (ProcSym) ; (* quadruple generation now on *)
10014 ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
10015 GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, OperandT(1), TRUE)
10016 ELSIF IsVar (OperandT (1))
10018 BuildSizeCheckEnd (ProcSym) ; (* quadruple generation now on *)
10019 Type := GetSType (OperandT (1)) ;
10020 paramtok := OperandTok (1) ;
10021 resulttok := MakeVirtualTok (functok, functok, paramtok) ;
10022 IF IsUnbounded (Type)
10024 (* eg. SIZE(a) ; where a is unbounded dereference HIGH and multiply by the TYPE *)
10025 dim := OperandD (1) ;
10028 ReturnVar := calculateMultipicand (resulttok, OperandT (1), Type, dim)
10030 ReturnVar := calculateMultipicand (resulttok, OperandA (1), Type, dim)
10033 ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
10036 MetaErrorT1 (resulttok,
10037 'cannot get the type and size of {%E1ad}', OperandT (1))
10039 GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, Type, TRUE)
10042 resulttok := functok ;
10043 MetaErrorT1 (resulttok,
10044 '{%E}SYSTEM procedure {%kSIZE} expects a variable as its parameter, seen {%E1d}',
10046 ReturnVar := MakeConstLit (resulttok, MakeKey('0'), Cardinal)
10048 PopN (NoOfParam+1) ; (* destroy the arguments and function *)
10049 PushTFtok (ReturnVar, GetSType(ProcSym), resulttok)
10050 END BuildSizeFunction ;
10054 BuildTSizeFunction - builds the pseudo function TSIZE
10073 |----------------| +------------+
10074 | ProcSym | Type | | ReturnVar |
10075 |----------------| |------------|
10079 PROCEDURE BuildTSizeFunction ;
10083 functok : CARDINAL ;
10084 NoOfParam: CARDINAL ;
10087 ReturnVar: CARDINAL ;
10090 ProcSym := OperandT (NoOfParam + 1) ;
10091 functok := OperandTtok (NoOfParam) ;
10092 BuildSizeCheckEnd (ProcSym) ; (* quadruple generation now on *)
10095 paramtok := OperandTtok (1) ;
10096 resulttok := MakeVirtualTok (functok, functok, paramtok) ;
10097 IF IsAModula2Type (OperandT (1))
10099 ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
10100 GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, OperandT (1), FALSE)
10101 ELSIF IsVar (OperandT (1))
10103 ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
10104 GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, GetSType (OperandT (1)), FALSE)
10106 MetaErrorT1 (resulttok,
10107 '{%E}SYSTEM procedure function {%kTSIZE} expects a variable as its first parameter, seen {%E1d}',
10109 ReturnVar := MakeConstLit (resulttok, MakeKey ('0'), Cardinal)
10111 ELSIF NoOfParam = 0
10113 resulttok := functok ;
10114 MetaErrorT0 (resulttok,
10115 '{%E}SYSTEM procedure function {%kTSIZE} expects either one or two parameters, seen none') ;
10116 ReturnVar := MakeConstLit (resulttok, MakeKey ('0'), Cardinal)
10118 Record := OperandT (NoOfParam) ;
10119 paramtok := OperandTtok (1) ;
10120 resulttok := OperandTtok (NoOfParam) ;
10121 IF IsRecord (Record)
10123 paramtok := OperandTtok (1) ;
10124 resulttok := MakeVirtualTok (functok, functok, paramtok) ;
10125 ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
10126 GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, Record, FALSE)
10128 resulttok := MakeVirtualTok (functok, functok, paramtok) ;
10129 MetaErrorT1 (resulttok,
10130 '{%E}SYSTEM procedure function {%kTSIZE} expects the first parameter to be a record type, seen {%E1d}',
10132 ReturnVar := MakeConstLit (resulttok, MakeKey ('0'), Cardinal)
10135 PopN (NoOfParam+1) ; (* destroy the arguments and function *)
10136 PushTFtok (ReturnVar, GetSType (ProcSym), resulttok)
10137 END BuildTSizeFunction ;
10141 BuildTBitSizeFunction - builds the pseudo function TBITSIZE
10160 |----------------| +------------+
10161 | ProcSym | Type | | ReturnVar |
10162 |----------------| |------------|
10166 PROCEDURE BuildTBitSizeFunction ;
10170 functok : CARDINAL ;
10171 NoOfParam: CARDINAL ;
10174 ReturnVar: CARDINAL ;
10177 ProcSym := OperandT (NoOfParam + 1) ;
10178 functok := OperandTtok (NoOfParam) ;
10179 BuildSizeCheckEnd (ProcSym) ; (* quadruple generation now on *)
10182 paramtok := OperandTtok (1) ;
10183 resulttok := MakeVirtualTok (functok, functok, paramtok) ;
10184 IF IsAModula2Type (OperandT (1))
10186 ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
10187 GenQuadO (resulttok, StandardFunctionOp, ReturnVar, ProcSym, OperandT (1), FALSE)
10188 ELSIF IsVar (OperandT (1))
10190 ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
10191 GenQuadO (resulttok, StandardFunctionOp, ReturnVar, ProcSym, OperandT(1), FALSE)
10193 MetaErrorT1 (resulttok,
10194 '{%E}SYSTEM procedure function {%kTBITSIZE} expects a variable as its first parameter, seen {%E1d}',
10196 ReturnVar := MakeConstLit (resulttok, MakeKey ('0'), Cardinal)
10198 ELSIF NoOfParam = 0
10200 resulttok := functok ;
10201 MetaErrorT0 (functok,
10202 '{%E}SYSTEM procedure function {%kTBITSIZE} expects either one or two parameters, seen none') ;
10203 ReturnVar := MakeConstLit (functok, MakeKey ('0'), Cardinal)
10205 Record := OperandT (NoOfParam) ;
10206 paramtok := OperandTtok (1) ;
10207 resulttok := OperandTtok (NoOfParam) ;
10208 IF IsRecord (Record)
10210 paramtok := OperandTtok (1) ;
10211 resulttok := MakeVirtualTok (functok, functok, paramtok) ;
10212 ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
10213 GenQuad(StandardFunctionOp, ReturnVar, ProcSym, OperandT(1)) ;
10215 resulttok := MakeVirtualTok (functok, functok, paramtok) ;
10216 MetaErrorT1 (resulttok,
10217 '{%E}SYSTEM procedure function {%kTBITSIZE} expects the first parameter to be a record type, seen {%E1d}',
10219 ReturnVar := MakeConstLit (resulttok, MakeKey ('0'), Cardinal)
10222 PopN (NoOfParam + 1) ; (* destroy the arguments and function *)
10223 PushTFtok (ReturnVar, GetSType (ProcSym), resulttok)
10224 END BuildTBitSizeFunction ;
10228 ExpectingParameterType -
10231 PROCEDURE ExpectingParameterType (BlockSym, Type: CARDINAL) ;
10233 IF NOT IsAModula2Type (Type)
10235 IF (Type = NulSym) OR IsPartialUnbounded (Type) OR IsUnknown (Type)
10237 MetaError1 ('the type used in the formal parameter declaration in {%1Md} {%1a} is unknown',
10240 MetaError2 ('the type {%1Ead} used in the formal parameter declaration in {%2Md} {%2a} was not declared as a type',
10244 END ExpectingParameterType ;
10248 ExpectingVariableType -
10251 PROCEDURE ExpectingVariableType (BlockSym, Type: CARDINAL) ;
10253 IF NOT IsAModula2Type(Type)
10257 MetaError1 ('the type used during the variable declaration section in procedure {%1EMad} is unknown',
10259 MetaError1 ('the type used during the variable declaration section in procedure {%1Ead} is unknown',
10261 ELSIF IsPartialUnbounded(Type) OR IsUnknown(Type)
10263 MetaError2 ('the type {%1EMad} used during variable declaration section in procedure {%2ad} is unknown',
10265 MetaError2 ('the type {%1Ead} used during variable declaration section in procedure {%2Mad} is unknown',
10268 MetaError2 ('the {%1d} {%1Ea} is not a type and therefore cannot be used to declare a variable in {%2d} {%2a}',
10272 END ExpectingVariableType ;
10276 CheckVariablesAndParameterTypesInBlock - checks to make sure that block, BlockSym, has
10277 parameters types and variable types which are legal.
10280 PROCEDURE CheckVariablesAndParameterTypesInBlock (BlockSym: CARDINAL) ;
10283 ParamNo: CARDINAL ;
10285 IF IsProcedure(BlockSym)
10287 ParamNo := NoOfParam(BlockSym)
10293 n := GetNth(BlockSym, i) ;
10294 IF (n#NulSym) AND (NOT IsTemporary(n)) AND
10295 (IsProcedure(BlockSym) OR ((IsDefImp(BlockSym) AND (GetMainModule()=BlockSym)) OR IsModule(BlockSym)))
10299 (* n is a parameter *)
10300 ExpectingParameterType(BlockSym, GetSType(n))
10302 (* n is a local variable *)
10303 ExpectingVariableType(BlockSym, GetSType(n))
10308 END CheckVariablesAndParameterTypesInBlock ;
10312 BuildProcedureStart - Builds start of the procedure. Generates a
10313 quadruple which indicated the start of
10314 this procedure declarations scope.
10315 The Stack is expected to contain:
10322 +------------+ +-----------+
10323 | ProcSym | | ProcSym |
10324 |------------| |-----------|
10326 |------------| |-----------|
10331 q ProcedureScopeOp Line# Scope ProcSym
10334 PROCEDURE BuildProcedureStart ;
10336 ProcSym: CARDINAL ;
10339 Assert(IsProcedure(ProcSym)) ;
10340 PutProcedureScopeQuad(ProcSym, NextQuad) ;
10341 GenQuad(ProcedureScopeOp, GetPreviousTokenLineNo(), GetScope(ProcSym), ProcSym) ;
10343 END BuildProcedureStart ;
10347 BuildProcedureBegin - determines the start of the BEGIN END block of
10349 The Stack is expected to contain:
10356 +------------+ +-----------+
10357 | ProcSym | | ProcSym |
10358 |------------| |-----------|
10360 |------------| |-----------|
10365 q NewLocalVarOp TokenNo(BEGIN) _ ProcSym
10368 PROCEDURE BuildProcedureBegin ;
10370 ProcSym: CARDINAL ;
10373 Assert(IsProcedure(ProcSym)) ;
10374 PutProcedureStartQuad(ProcSym, NextQuad) ;
10375 PutProcedureBegin(ProcSym, GetTokenNo()) ;
10376 GenQuad(NewLocalVarOp, GetTokenNo(), GetScope(ProcSym), ProcSym) ;
10377 CurrentProc := ProcSym ;
10378 PushWord(ReturnStack, 0) ;
10380 CheckVariablesAt(ProcSym) ;
10381 CheckNeedPriorityBegin(GetTokenNo(), ProcSym, GetCurrentModule()) ;
10382 PushWord(TryStack, NextQuad) ;
10383 PushWord(CatchStack, 0) ;
10384 IF HasExceptionBlock(ProcSym)
10386 GenQuad(TryOp, NulSym, NulSym, 0)
10388 END BuildProcedureBegin ;
10392 BuildProcedureEnd - Builds end of the procedure. Destroys space for
10393 the local variables.
10394 The Stack is expected to contain:
10401 +------------+ +-----------+
10402 | ProcSym | | ProcSym |
10403 |------------| |-----------|
10405 |------------| |-----------|
10410 q KillLocalVarOp TokenNo(END) _ ProcSym
10413 PROCEDURE BuildProcedureEnd ;
10416 ProcSym: CARDINAL ;
10418 PopTtok(ProcSym, tok) ;
10419 IF HasExceptionBlock(ProcSym)
10421 BuildRTExceptLeave(tok, TRUE) ;
10422 GenQuad(CatchEndOp, NulSym, NulSym, NulSym)
10424 IF GetSType(ProcSym)#NulSym
10426 BuildError(InitNoReturnRangeCheck())
10428 BackPatch(PopWord(ReturnStack), NextQuad) ;
10429 CheckNeedPriorityEnd(tok, ProcSym, GetCurrentModule()) ;
10430 CurrentProc := NulSym ;
10431 PutProcedureEnd(ProcSym, GetTokenNo()-1) ; (* --fixme-- *)
10432 GenQuad(KillLocalVarOp, GetTokenNo()-1, NulSym, ProcSym) ;
10433 PutProcedureEndQuad(ProcSym, NextQuad) ;
10434 GenQuad(ReturnOp, NulSym, NulSym, ProcSym) ;
10435 CheckFunctionReturn(ProcSym) ;
10436 CheckVariablesInBlock(ProcSym) ;
10437 RemoveTop (CatchStack) ;
10438 RemoveTop (TryStack) ;
10440 END BuildProcedureEnd ;
10444 CheckReadBeforeInitialized -
10447 PROCEDURE CheckReadBeforeInitialized (ProcSym: CARDINAL; End: CARDINAL) ;
10451 ReadStart, ReadEnd,
10452 WriteStart, WriteEnd: CARDINAL ;
10454 ParamNo := NoOfParam(ProcSym) ;
10457 n := GetNth(ProcSym, i) ;
10458 IF (n#NulSym) AND (NOT IsTemporary(n))
10460 GetReadQuads(n, RightValue, ReadStart, ReadEnd) ;
10461 GetWriteQuads(n, RightValue, WriteStart, WriteEnd) ;
10464 (* n is a not a parameter thus we can check *)
10465 IF (ReadStart>0) AND (ReadStart<End)
10467 (* it is read in the first basic block *)
10468 IF ReadStart<WriteStart
10470 (* read before written, this is a problem which must be fixed *)
10471 s1 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(n)))) ;
10472 s2 := Mark(InitStringCharStar(KeyToCharStar(GetSymName(ProcSym)))) ;
10473 ErrorStringAt2(Sprintf2(Mark(InitString('reading from a variable (%s) before it is initialized in procedure (%s)')),
10475 GetDeclaredMod(n), GetDeclaredMod(n))
10482 END CheckReadBeforeInitialized ;
10486 VariableAnalysis - checks to see whether a variable is:
10488 read before it has been initialized
10491 PROCEDURE VariableAnalysis (Start, End: CARDINAL) ;
10493 Op : QuadOperator ;
10494 Op1, Op2, Op3: CARDINAL ;
10498 GetQuad(Start, Op, Op1, Op2, Op3) ;
10501 NewLocalVarOp: CheckReadBeforeInitialized(Op3, End)
10506 END VariableAnalysis ;
10510 IsNeverAltered - returns TRUE if variable, sym, is never altered
10511 between quadruples: Start..End
10514 PROCEDURE IsNeverAltered (sym: CARDINAL; Start, End: CARDINAL) : BOOLEAN ;
10516 WriteStart, WriteEnd: CARDINAL ;
10518 GetWriteLimitQuads(sym, GetMode(sym), Start, End, WriteStart, WriteEnd) ;
10519 RETURN( (WriteStart=0) AND (WriteEnd=0) )
10520 END IsNeverAltered ;
10524 IsConditionVariable - returns TRUE if the condition at quadruple, q, is variable.
10527 PROCEDURE IsConditionVariable (q: CARDINAL; Start, End: CARDINAL) : BOOLEAN ;
10529 op : QuadOperator ;
10530 op1, op2, op3: CARDINAL ;
10532 RightFixed : BOOLEAN ;
10534 GetQuad(q, op, op1, op2, op3) ;
10539 LeftFixed := IsConst(op1) ;
10540 RightFixed := IsConst(op2) ;
10543 LeftFixed := IsNeverAltered(op1, Start, End)
10547 RightFixed := IsNeverAltered(op2, Start, End)
10549 RETURN( NOT (LeftFixed AND RightFixed) )
10551 END IsConditionVariable ;
10555 IsInfiniteLoop - returns TRUE if an infinite loop is found.
10556 Given a backwards jump at, End, it returns a BOOLEAN which depends on
10557 whether a jump is found to jump beyond, End. If a conditonal jump is found
10558 to pass over, End, the condition is tested for global variables, procedure variables and
10562 variables - tested to see whether they are altered inside the loop
10563 global variable - the procedure tests to see whether it is altered as above
10564 but will also test to see whether this loop calls a procedure
10565 in which case it believes the loop NOT to be infinite
10566 (as this procedure call might alter the global variable)
10568 Note that this procedure can easily be fooled by the user altering variables
10572 PROCEDURE IsInfiniteLoop (End: CARDINAL) : BOOLEAN ;
10575 IsGlobal : BOOLEAN ;
10578 op : QuadOperator ;
10579 op1, op2, op3: CARDINAL ;
10581 SeenCall := FALSE ;
10582 IsGlobal := FALSE ;
10583 GetQuad(End, op, op1, op2, Start) ;
10585 WHILE Current#End DO
10586 GetQuad(Current, op, op1, op2, op3) ;
10587 (* remember that this function is only called once we have optimized the redundant gotos and conditionals *)
10588 IF IsConditional(Current) AND (NOT IsGlobal)
10590 IsGlobal := (IsVar(op1) AND (NOT IsProcedure(GetVarScope(op1)))) OR
10591 (IsVar(op2) AND (NOT IsProcedure(GetVarScope(op2))))
10597 IF (op=GotoOp) OR (IsConditional(Current) AND IsConditionVariable(Current, Start, End))
10599 IF (op3>End) OR (op3<Start)
10601 RETURN( FALSE ) (* may jump out of this loop, good *)
10604 Current := GetNextQuad(Current)
10606 GetQuad(End, op, op1, op2, op3) ;
10607 IF IsConditional(End)
10609 IF IsConditionVariable(End, Start, End)
10615 IsGlobal := (IsVar(op1) AND (NOT IsProcedure(GetVarScope(op1)))) OR
10616 (IsVar(op2) AND (NOT IsProcedure(GetVarScope(op2))))
10620 (* we have found a likely infinite loop if no conditional uses a global and no procedure call was seen *)
10621 RETURN( NOT (IsGlobal AND SeenCall) )
10622 END IsInfiniteLoop ;
10626 LoopAnalysis - checks whether an infinite loop exists.
10629 PROCEDURE LoopAnalysis (Current, End: CARDINAL) ;
10631 op : QuadOperator ;
10632 op1, op2, op3: CARDINAL ;
10636 WHILE (Current<=End) AND (Current#0) DO
10637 GetQuad(Current, op, op1, op2, op3) ;
10638 IF (op=GotoOp) OR IsConditional(Current)
10642 (* found a loop - ie a branch which goes back in quadruple numbers *)
10643 IF IsInfiniteLoop(Current)
10645 WarnStringAt(InitString('it is very likely (although not absolutely certain) that the top of an infinite loop is here'),
10646 QuadToTokenNo(op3)) ;
10647 WarnStringAt(InitString('and the bottom of the infinite loop is ends here or alternatively a component of this loop is never executed'),
10648 QuadToTokenNo(Current))
10652 Current := GetNextQuad(Current)
10659 CheckUninitializedVariablesAreUsed - checks to see whether uninitialized variables are used.
10662 PROCEDURE CheckUninitializedVariablesAreUsed (BlockSym: CARDINAL) ;
10665 ParamNo : CARDINAL ;
10669 WriteEnd : CARDINAL ;
10671 IF IsProcedure(BlockSym)
10673 ParamNo := NoOfParam(BlockSym)
10679 n := GetNth(BlockSym, i) ;
10680 IF (n#NulSym) AND (NOT IsTemporary(n)) AND
10681 (IsProcedure(BlockSym) OR (((IsDefImp(BlockSym) AND (GetMainModule()=BlockSym)) OR IsModule(BlockSym)) AND
10682 (NOT IsExported(BlockSym, n))))
10684 GetReadQuads(n, RightValue, ReadStart, ReadEnd) ;
10685 GetWriteQuads(n, RightValue, WriteStart, WriteEnd) ;
10688 (* n is a parameter *)
10689 IF UnusedParameterChecking
10695 MetaError2 ('unused parameter {%1WMad} in procedure {%2ad}', n, BlockSym)
10697 IF NOT IsVarParam (BlockSym, i)
10699 (* --fixme-- reconsider this. *)
10700 (* MetaError2 ('writing to a non var parameter {%1WMad} and never reading from it in procedure {%2ad}',
10707 (* n is a local variable *)
10708 IF UnusedVariableChecking
10714 MetaError2 ('unused variable {%1WMad} in {%2d} {%2ad}', n, BlockSym)
10716 (* --fixme-- reconsider this. *)
10717 (* MetaError2 ('writing to a variable {%1WMad} and never reading from it in {%2d} {%2ad}', n, BlockSym) *)
10722 MetaError2 ('variable {%1WMad} is being used but it is never initialized in {%2d} {%2ad}', n, BlockSym)
10730 END CheckUninitializedVariablesAreUsed ;
10734 IsInlineWithinBlock - returns TRUE if an InlineOp is found
10738 PROCEDURE IsInlineWithinBlock (start, end: CARDINAL) : BOOLEAN ;
10740 op : QuadOperator ;
10741 op1, op2, op3: CARDINAL ;
10743 WHILE (start#end) AND (start#0) DO
10744 GetQuad(start, op, op1, op2, op3) ;
10749 start := GetNextQuad(start)
10752 END IsInlineWithinBlock ;
10756 AsmStatementsInBlock - returns TRUE if an ASM statement is found within a block, BlockSym.
10759 PROCEDURE AsmStatementsInBlock (BlockSym: CARDINAL) : BOOLEAN ;
10765 EndFinish : CARDINAL ;
10767 IF IsProcedure(BlockSym)
10769 GetProcedureQuads(BlockSym, Scope, StartInit, EndInit) ;
10770 RETURN( IsInlineWithinBlock(StartInit, EndInit) )
10772 GetModuleQuads(BlockSym, StartInit, EndInit, StartFinish, EndFinish) ;
10773 RETURN( IsInlineWithinBlock(StartInit, EndInit) OR
10774 IsInlineWithinBlock(StartFinish, EndFinish) )
10776 END AsmStatementsInBlock ;
10780 CheckVariablesInBlock - given a block, BlockSym, check whether all variables are used.
10783 PROCEDURE CheckVariablesInBlock (BlockSym: CARDINAL) ;
10785 CheckVariablesAndParameterTypesInBlock (BlockSym) ;
10786 IF UnusedVariableChecking OR UnusedParameterChecking
10788 IF (NOT AsmStatementsInBlock (BlockSym))
10790 CheckUninitializedVariablesAreUsed (BlockSym)
10793 END CheckVariablesInBlock ;
10797 CheckFunctionReturn - checks to see that a RETURN statement was present in a function.
10800 PROCEDURE CheckFunctionReturn (ProcSym: CARDINAL) ;
10802 Op : QuadOperator ;
10805 Start, End : CARDINAL ;
10807 IF GetSType(ProcSym)#NulSym
10809 (* yes it is a function *)
10810 GetProcedureQuads(ProcSym, Scope, Start, End) ;
10811 GetQuad(Start, Op, Op1, Op2, Op3) ;
10814 InternalError ('incorrect start quad')
10816 WHILE (Start#End) AND (Op#ReturnValueOp) AND (Op#InlineOp) DO
10817 Start := GetNextQuad(Start) ;
10818 GetQuad(Start, Op, Op1, Op2, Op3)
10820 IF (Op#ReturnValueOp) AND (Op#InlineOp)
10822 (* an InlineOp can always be used to emulate a RETURN *)
10823 MetaError1 ('procedure function {%1Ea} does not RETURN a value', ProcSym)
10826 END CheckFunctionReturn ;
10830 CheckReturnType - checks to see that the return type from currentProc is
10831 assignment compatible with actualType.
10834 PROCEDURE CheckReturnType (tokno: CARDINAL; currentProc, actualVal, actualType: CARDINAL) ;
10836 procType: CARDINAL ;
10840 procType := GetSType (currentProc) ;
10841 IF procType = NulSym
10843 MetaError1 ('attempting to RETURN a value from procedure {%1Ea} which was not a declared as a procedure function', currentProc)
10844 ELSIF AssignmentRequiresWarning (actualType, GetSType (currentProc))
10846 MetaError2 ('attempting to RETURN a value {%1Wa} with an incompatible type {%1Wtsa} from a procedure function {%1a} which returns {%1tsa}', actualVal, currentProc)
10847 ELSIF NOT IsAssignmentCompatible (actualType, procType)
10849 n1 := GetSymName(actualType) ;
10850 n2 := GetSymName(procType) ;
10851 WriteFormat2('attempting to RETURN a value with an incompatible type (%a) from a function which returns (%a)',
10853 ELSIF IsProcedure(actualVal) AND (NOT IsAssignmentCompatible(actualVal, procType))
10856 MetaWarnings2('attempting to RETURN a value with an incompatible type {%1ad} from function {%2a} which returns {%2ta}',
10857 actualVal, currentProc)
10859 --fixme-- introduce MetaWarning, MetaWarning2, MetaWarning3 into M2MetaError
10861 s1 := InitStringCharStar(KeyToCharStar(GetSymName(actualVal))) ;
10862 s2 := InitStringCharStar(KeyToCharStar(GetSymName(procType))) ;
10863 ErrorString(NewWarning(GetTokenNo()),
10864 Sprintf2(Mark(InitString('attempting to RETURN a value with a (possibly on other targets) incompatible type (%s) from a function which returns (%s)')),
10866 ELSIF IsProcedure(actualVal) AND (NOT IsAssignmentCompatible(actualVal, GetSType(CurrentProc)))
10868 n1 := GetSymName(actualVal) ;
10869 n2 := GetSymName(GetSType(currentProc)) ;
10870 WriteFormat2('attempting to RETURN a value with an incompatible type (%a) from a function which returns (%a)',
10873 (* this checks the types are compatible, not the data contents. *)
10874 BuildRange (InitTypesAssignmentCheck (tokno, currentProc, actualVal))
10876 END CheckReturnType ;
10880 BuildReturn - Builds the Return part of the procedure.
10881 tokno is the location of the RETURN keyword.
10882 The Stack is expected to contain:
10894 PROCEDURE BuildReturn (tokno: CARDINAL) ;
10904 (* Des will be a boolean type *)
10905 Des := MakeTemporary (tokno, RightValue) ;
10906 PutVar (Des, Boolean) ;
10907 PushTF (Des, Boolean) ;
10909 BuildAssignmentWithoutBounds (tokno, FALSE, TRUE) ;
10910 PushTF (Des, Boolean)
10915 (* this will check that the type returned is compatible with
10916 the formal return type of the procedure. *)
10917 CheckReturnType (tokno, CurrentProc, e1, t1) ;
10918 (* dereference LeftValue if necessary *)
10919 IF GetMode (e1) = LeftValue
10921 t2 := GetSType (CurrentProc) ;
10922 e2 := MakeTemporary (tokno, RightValue) ;
10924 CheckPointerThroughNil (tokno, e1) ;
10925 doIndrX (tokno, e2, e1) ;
10926 (* here we check the data contents to ensure no overflow. *)
10927 BuildRange (InitReturnRangeCheck (tokno, CurrentProc, e2)) ;
10928 GenQuadO (tokno, ReturnValueOp, e2, NulSym, CurrentProc, FALSE)
10930 (* here we check the data contents to ensure no overflow. *)
10931 BuildRange (InitReturnRangeCheck (tokno, CurrentProc, e1)) ;
10932 GenQuadO (tokno, ReturnValueOp, e1, NulSym, CurrentProc, FALSE)
10935 GenQuadO (tokno, GotoOp, NulSym, NulSym, PopWord(ReturnStack), FALSE) ;
10936 PushWord (ReturnStack, NextQuad-1)
10941 IsReadOnly - a helper procedure function to detect constants.
10944 PROCEDURE IsReadOnly (sym: CARDINAL) : BOOLEAN ;
10946 RETURN IsConst (sym) OR (IsVar (sym) AND IsVarConst (sym))
10951 BuildDesignatorRecord - Builds the record referencing.
10952 The Stack is expected to contain:
10968 | fldn | typen | <- Ptr
10969 |--------------| +-------------+
10970 | Sym | Type | | S | type1|
10971 |--------------| |-------------|
10974 PROCEDURE BuildDesignatorRecord (dottok: CARDINAL) ;
10978 combinedtok: CARDINAL ;
10986 RecordSym := OperandT (n+1) ;
10987 (* RecordType could be found by: SkipType (OperandF (n+1)). *)
10988 RecordTok := OperandTok (n+1) ;
10989 rw := OperandMergeRW (n+1) ;
10990 Assert (IsLegal (rw)) ;
10991 Field := OperandT (n) ;
10992 FieldType := SkipType (OperandF (n)) ;
10993 FieldTok := OperandTok (n) ;
10994 combinedtok := MakeVirtualTok (dottok, RecordTok, FieldTok) ;
10997 InternalError ('not expecting to see n>1')
10999 IF IsUnused (Field)
11001 MetaErrors1 ('record field {%1Dad} was declared as unused by a pragma',
11002 'record field {%1ad} is being used after being declared as unused by a pragma', Field)
11004 Res := MakeComponentRef (MakeComponentRecord (combinedtok,
11005 RightValue, RecordSym), Field) ;
11006 PutVarConst (Res, IsReadOnly (RecordSym)) ;
11007 GenQuadO (combinedtok, RecordFieldOp, Res, RecordSym, Field, FALSE) ;
11009 PushTFrwtok (Res, FieldType, rw, combinedtok)
11010 END BuildDesignatorRecord ;
11014 BuildDesignatorError - removes the designator from the stack and replaces
11015 it with an error symbol.
11018 PROCEDURE BuildDesignatorError (message: ARRAY OF CHAR) ;
11022 exprTok : CARDINAL ;
11027 PopTtok (e, exprTok) ;
11028 PopTFDtok (Sym, Type, d, arrayTok) ;
11029 combinedTok := MakeVirtualTok (arrayTok, arrayTok, exprTok) ;
11030 error := MakeError (combinedTok, MakeKey (message)) ;
11031 PushTFDtok (error, Type, d, arrayTok)
11032 END BuildDesignatorError ;
11037 BuildDesignatorArray - Builds the array referencing.
11038 The purpose of this procedure is to work out
11039 whether the DesignatorArray is a static or
11040 dynamic array and to call the appropriate
11043 The Stack is expected to contain:
11052 |--------------| +------------+
11053 | Sym | Type | | S | T |
11054 |--------------| |------------|
11057 PROCEDURE BuildDesignatorArray ;
11061 exprTok : CARDINAL ;
11066 IF IsConst (OperandT (2)) AND IsConstructor (OperandT (2))
11068 t := GetDType (OperandT (2)) ;
11071 InternalError ('constructor type should have been resolved')
11074 PopTtok (e, exprTok) ;
11075 PopTFDtok (Sym, Type, d, arrayTok) ;
11076 t := MakeTemporary (exprTok, RightValue) ;
11078 PushTFtok (t, GetSType(t), exprTok) ;
11079 PushTtok (Sym, arrayTok) ;
11080 combinedTok := MakeVirtualTok (arrayTok, arrayTok, exprTok) ;
11081 PutVarConst (t, TRUE) ;
11082 BuildAssignConstant (combinedTok) ;
11083 PushTFDtok (t, GetDType(t), d, arrayTok) ;
11084 PushTtok (e, exprTok)
11087 IF (NOT IsVar (OperandT (2))) AND (NOT IsTemporary (OperandT (2)))
11089 MetaErrorT1 (OperandTtok (2),
11090 'can only access arrays using variables or formal parameters not {%1Ead}',
11092 BuildDesignatorError ('bad array access')
11094 Sym := OperandT (2) ;
11095 Type := GetDType (Sym) ;
11096 arrayTok := OperandTtok (2) ;
11099 IF (arrayTok = UnknownTokenNo) OR (arrayTok = BuiltinTokenNo)
11101 arrayTok := GetTokenNo ()
11103 MetaErrorT0 (arrayTok, "type of array is undefined") ;
11104 BuildDesignatorError ('bad array access')
11105 ELSIF IsUnbounded (Type)
11108 ELSIF IsArray (Type)
11112 MetaErrorT1 (arrayTok,
11113 'can only index static or dynamic arrays, {%1Ead} is not an array but a {%tad}',
11115 BuildDesignatorError ('bad array access')
11117 END BuildDesignatorArray ;
11121 BuildStaticArray - Builds the array referencing for static arrays.
11122 The Stack is expected to contain:
11131 |--------------| +------------+
11132 | Sym | Type | | S | T |
11133 |--------------| |------------|
11136 PROCEDURE BuildStaticArray ;
11140 arrayTok : CARDINAL ;
11146 Type, Adr : CARDINAL ;
11148 Index := OperandT (1) ;
11149 indexTok := OperandTtok (1) ;
11150 Array := OperandT (2) ;
11151 arrayTok := OperandTtok (2) ;
11152 Type := SkipType (OperandF (2)) ;
11153 rw := OperandMergeRW (2) ;
11154 Assert (IsLegal (rw)) ;
11155 Dim := OperandD (2) ;
11157 IF GetMode (Index)=LeftValue
11159 Index := MakeRightValue (indexTok, Index, GetSType (Index))
11161 BuildRange (InitStaticArraySubscriptRangeCheck (GetArraySubscript (Type), Index, Dim)) ;
11163 (* now make Adr point to the address of the indexed element *)
11164 combinedTok := MakeVirtualTok (arrayTok, arrayTok, indexTok) ;
11165 Adr := MakeTemporary (combinedTok, LeftValue) ;
11168 (* BuildDesignatorArray may have detected des is a constant. *)
11169 PutVarConst (Adr, IsVarConst (Array))
11172 From now on it must reference the array element by its lvalue
11173 - so we create the type of the referenced entity
11176 BackEndType := MakePointer (combinedTok, NulName) ;
11177 PutPointer (BackEndType, GetDType (Type)) ;
11178 (* PutVar(Adr, BackEndType) ; *)
11179 PutLeftValueFrontBackType (Adr, GetDType (Type), BackEndType) ;
11181 GenQuadO (combinedTok, ArrayOp, Adr, Index, Array, TRUE) ;
11182 PopN (2) ; (* remove all parameters to this procedure *)
11183 PushTFDrwtok (Adr, GetSType (Adr), Dim, rw, combinedTok)
11184 END BuildStaticArray ;
11188 calculateMultipicand - generates quadruples which calculate the
11189 multiplicand for the array at dimension, dim.
11192 PROCEDURE calculateMultipicand (tok: CARDINAL;
11193 arraySym, arrayType: CARDINAL; dim: CARDINAL) : CARDINAL ;
11195 ti, tj, tk, tl: CARDINAL ;
11197 IF dim = GetDimension (arrayType)
11199 (* ti has no type since constant *)
11200 ti := MakeTemporary (tok, ImmediateValue) ;
11201 PutVar(ti, Cardinal) ;
11202 GenQuadO (tok, ElementSizeOp, ti, arrayType, 1, TRUE)
11205 tk := MakeTemporary (tok, RightValue) ;
11206 PutVar(tk, Cardinal) ;
11207 GenHigh (tok, tk, dim, arraySym) ;
11208 tl := MakeTemporary (tok, RightValue) ;
11209 PutVar(tl, Cardinal) ;
11210 GenQuadO (tok, AddOp, tl, tk, MakeConstLit (tok, MakeKey ('1'), Cardinal), TRUE) ;
11211 tj := calculateMultipicand (tok, arraySym, arrayType, dim) ;
11212 ti := MakeTemporary (tok, RightValue) ;
11213 PutVar (ti, Cardinal) ;
11214 GenQuadO (tok, MultOp, ti, tj, tl, TRUE)
11217 END calculateMultipicand ;
11221 BuildDynamicArray - Builds the array referencing for dynamic arrays.
11222 The Stack is expected to contain:
11229 +-----------------------+
11231 |-----------------------| +---------------------------+
11232 | ArraySym | Type | Dim | | S | T | ArraySym | Dim+1 |
11233 |-----------------------| |---------------------------|
11238 S := base of ArraySym + TSIZE(Type)*Index
11240 S := S + TSIZE(Type)*Index
11244 PROCEDURE BuildDynamicArray ;
11248 indexTok : CARDINAL ;
11257 ti, tj, tk : CARDINAL ;
11260 Sym := OperandT (2) ;
11261 Type := SkipType (OperandF (2)) ;
11262 arrayTok := OperandTok (2) ;
11263 indexTok := OperandTok (1) ;
11264 combinedTok := MakeVirtualTok (arrayTok, arrayTok, indexTok) ;
11265 Dim := OperandD (2) ;
11266 rw := OperandMergeRW (2) ;
11267 Assert (IsLegal (rw)) ;
11272 Base has type address since
11273 BuildDesignatorRecord references by address.
11275 Build a record for retrieving the address of dynamic array.
11276 BuildDesignatorRecord will generate the required quadruples,
11277 therefore build sets up the stack for BuildDesignatorRecord
11278 which will generate the quads to access the record.
11281 UnboundedType := GetUnboundedRecordType (GetSType (Sym)) ;
11282 PushTFrwtok (Sym, UnboundedType, rw, arrayTok) ;
11283 PushTF (GetUnboundedAddressOffset (GetSType (Sym)),
11284 GetSType (GetUnboundedAddressOffset (GetSType (Sym)))) ;
11285 PushT (1) ; (* One record field to dereference *)
11286 BuildDesignatorRecord (combinedTok) ;
11289 (* Now actually copy Unbounded.ArrayAddress into base *)
11290 IF GetMode(PtrToBase) = LeftValue
11292 Base := MakeTemporary (arrayTok, RightValue) ;
11293 PutVar (Base, Address) ; (* has type ADDRESS *)
11294 CheckPointerThroughNil (arrayTok, PtrToBase) ;
11295 GenQuad (IndrXOp, Base, Address, PtrToBase) (* Base = *PtrToBase *)
11297 Assert (GetMode (PtrToBase) # ImmediateValue) ;
11301 (* Base already calculated previously and pushed to stack *)
11302 UnboundedType := SkipType (OperandF (2)) ;
11304 ArraySym := OperandA (2)
11306 Assert (GetSType (Sym) = Type) ;
11307 ti := calculateMultipicand (indexTok, Sym, Type, Dim) ;
11308 idx := OperandT (1) ;
11311 (* tj has no type since constant *)
11312 tj := MakeTemporary (indexTok, ImmediateValue) ;
11313 tk := MakeTemporary (indexTok, ImmediateValue) ;
11314 PutVar (tj, Cardinal) ;
11315 PutVar (tk, Cardinal)
11317 (* tj has Cardinal type since we have multiplied array indices *)
11318 tj := MakeTemporary (indexTok, RightValue) ;
11319 IF GetSType (idx) # Cardinal
11321 PushTF (RequestSym (indexTok, MakeKey ('CONVERT')), NulSym) ;
11323 PushTtok (idx, indexTok) ;
11324 PushT(2) ; (* Two parameters *)
11325 BuildConvertFunction ;
11328 PutVar (tj, Cardinal) ;
11329 tk := MakeTemporary (indexTok, RightValue) ;
11330 PutVar (tk, Cardinal)
11332 BuildRange (InitDynamicArraySubscriptRangeCheck (ArraySym, idx, Dim)) ;
11334 PushTtok (tj, indexTok) ;
11335 PushTtok (idx, indexTok) ;
11336 BuildAssignmentWithoutBounds (indexTok, FALSE, TRUE) ;
11338 GenQuad (MultOp, tk, ti, tj) ;
11339 Adr := MakeTemporary (combinedTok, LeftValue) ;
11341 Ok must reference by address
11342 - but we contain the type of the referenced entity
11344 BackEndType := MakePointer (combinedTok, NulName) ;
11345 PutPointer (BackEndType, GetSType (Type)) ;
11347 IF Dim = GetDimension (Type)
11349 PutLeftValueFrontBackType (Adr, GetSType(Type), BackEndType) ;
11351 GenQuad (AddOp, Adr, Base, tk) ;
11353 PushTFADrwtok (Adr, GetSType(Adr), ArraySym, Dim, rw, combinedTok)
11355 (* more to index *)
11356 PutLeftValueFrontBackType (Adr, Type, BackEndType) ;
11358 GenQuad (AddOp, Adr, Base, tk) ;
11360 PushTFADrwtok (Adr, GetSType(Adr), ArraySym, Dim, rw, combinedTok)
11362 END BuildDynamicArray ;
11366 BuildDesignatorPointer - Builds a pointer reference.
11367 The Stack is expected to contain:
11374 +--------------+ +--------------+
11375 | Sym1 | Type1| | Sym2 | Type2|
11376 |--------------| |--------------|
11379 PROCEDURE BuildDesignatorPointer (ptrtok: CARDINAL) ;
11382 exprtok : CARDINAL ;
11385 Sym2, Type2: CARDINAL ;
11387 PopTFrwtok (Sym1, Type1, rw, exprtok) ;
11388 Type1 := SkipType (Type1) ;
11389 IF IsUnknown (Sym1)
11391 MetaError1 ('{%1EMad} is undefined and therefore {%1ad}^ cannot be resolved', Sym1)
11392 ELSIF IsPointer (Type1)
11394 Type2 := GetSType (Type1) ;
11395 Sym2 := MakeTemporary (ptrtok, LeftValue) ;
11397 Ok must reference by address
11398 - but we contain the type of the referenced entity
11401 PutVarPointerCheck (Sym1, TRUE) ;
11402 CheckPointerThroughNil (ptrtok, Sym1) ;
11403 IF GetMode (Sym1) = LeftValue
11406 PutLeftValueFrontBackType (Sym2, Type2, Type1) ;
11407 GenQuad (IndrXOp, Sym2, Type1, Sym1) (* Sym2 := *Sym1 *)
11409 PutLeftValueFrontBackType (Sym2, Type2, NulSym) ;
11410 GenQuad (BecomesOp, Sym2, NulSym, Sym1) (* Sym2 := Sym1 *)
11412 PutVarPointerCheck (Sym2, TRUE) ; (* we should check this for *)
11413 (* Sym2 later on (pointer via NIL) *)
11414 combinedtok := MakeVirtualTok (exprtok, exprtok, ptrtok) ;
11415 PushTFrwtok (Sym2, Type2, rw, combinedtok)
11417 MetaError2 ('{%1ad} is not a pointer type but a {%2d}', Sym1, Type1)
11419 END BuildDesignatorPointer ;
11423 StartBuildWith - performs the with statement.
11429 | Sym | Type | Empty
11433 PROCEDURE StartBuildWith (withTok: CARDINAL) ;
11440 PopTFtok (Sym, Type, tok) ;
11441 Type := SkipType (Type) ;
11443 Ref := MakeTemporary (tok, LeftValue) ;
11444 PutVar (Ref, Type) ;
11445 IF GetMode (Sym) = LeftValue
11447 (* copy LeftValue *)
11448 GenQuadO (tok, BecomesOp, Ref, NulSym, Sym, TRUE)
11450 (* calculate the address of Sym *)
11451 GenQuadO (tok, AddrOp, Ref, NulSym, Sym, TRUE)
11454 PushWith (Sym, Type, Ref, tok) ;
11457 MetaError1 ('{%1Ea} {%1d} has a no type, the {%kWITH} statement requires a variable or parameter of a {%kRECORD} type',
11459 ELSIF NOT IsRecord(Type)
11461 MetaError1 ('the {%kWITH} statement requires that {%1Ea} {%1d} be of a {%kRECORD} {%1tsa:type rather than {%1tsa}}',
11466 END StartBuildWith ;
11470 EndBuildWith - terminates the innermost with scope.
11473 PROCEDURE EndBuildWith ;
11483 PushWith - pushes sym and type onto the with stack. It checks for
11484 previous declaration of this record type.
11487 PROCEDURE PushWith (Sym, Type, Ref, Tok: CARDINAL) ;
11494 n := NoOfItemsInStackAddress(WithStack) ;
11495 i := 1 ; (* top of the stack *)
11497 (* Search for other declarations of the with using Type *)
11498 f := PeepAddress(WithStack, i) ;
11499 IF f^.RecordSym=Type
11502 'cannot have nested {%kWITH} statements referencing the same {%kRECORD} {%1Ead}',
11504 MetaErrorT1 (f^.RecordTokPos,
11505 'cannot have nested {%kWITH} statements referencing the same {%kRECORD} {%1Ead}',
11514 RecordType := Type ;
11517 RecordTokPos := Tok
11519 PushAddress (WithStack, f)
11523 PROCEDURE PopWith ;
11527 f := PopAddress (WithStack) ;
11533 CheckWithReference - performs the with statement.
11538 +------------+ +------------+
11539 | Sym | Type | | Sym | Type |
11540 |------------| |------------|
11543 PROCEDURE CheckWithReference ;
11548 Sym, Type: CARDINAL ;
11550 n := NoOfItemsInStackAddress(WithStack) ;
11551 IF (n>0) AND (NOT SuppressWith)
11553 PopTFrwtok (Sym, Type, rw, tokpos) ;
11554 Assert (tokpos # UnknownTokenNo) ;
11555 (* inner WITH always has precidence *)
11556 i := 1 ; (* top of stack *)
11558 (* WriteString('Checking for a with') ; *)
11559 f := PeepAddress (WithStack, i) ;
11561 IF IsRecordField (Sym) AND (GetRecord (GetParent (Sym)) = RecordType)
11565 MetaError1('record field {%1Dad} was declared as unused by a pragma', Sym)
11567 (* Fake a RecordSym.op *)
11568 PushTFrwtok (RecordRef, RecordType, rw, RecordTokPos) ;
11569 PushTFtok (Sym, Type, tokpos) ;
11570 BuildAccessWithField ;
11571 PopTFrw (Sym, Type, rw) ;
11572 i := n+1 (* Finish loop. *)
11578 PushTFrwtok (Sym, Type, rw, tokpos)
11580 END CheckWithReference ;
11584 BuildAccessWithField - similar to BuildDesignatorRecord except it
11585 does not perform the address operation.
11586 The address will have been computed at the
11587 beginning of the WITH statement.
11588 It also stops the GenQuad procedure from examining the
11597 | Field | Type1| <- Ptr
11598 |-------|------| +-------------+
11599 | Adr | Type2| | Sym | Type1|
11600 |--------------| |-------------|
11603 PROCEDURE BuildAccessWithField ;
11605 rectok, fieldtok : CARDINAL ;
11606 OldSuppressWith : BOOLEAN ;
11609 Record, RecordType,
11612 OldSuppressWith := SuppressWith ;
11613 SuppressWith := TRUE ;
11615 now the WITH cannot look at the stack of outstanding WITH records.
11617 PopTFtok (Field, FieldType, fieldtok) ;
11618 PopTFrwtok (Record, RecordType, rw, rectok) ;
11620 Ref := MakeComponentRef (MakeComponentRecord (fieldtok,
11621 RightValue, Record), Field) ;
11622 PutVarConst (Ref, IsReadOnly (Record)) ;
11623 GenQuadO (fieldtok,
11624 RecordFieldOp, Ref, Record, Field, TRUE) ;
11626 PushTFrwtok (Ref, FieldType, rw, fieldtok) ;
11627 SuppressWith := OldSuppressWith
11628 END BuildAccessWithField ;
11632 BuildNulExpression - Builds a nul expression on the stack.
11638 Empty +------------+
11643 PROCEDURE BuildNulExpression ;
11646 END BuildNulExpression ;
11650 BuildTypeForConstructor - pushes the type implied by the current constructor.
11651 If no constructor is currently being built then
11652 it Pushes a Bitset type.
11655 PROCEDURE BuildTypeForConstructor ;
11657 c: ConstructorFrame ;
11659 IF NoOfItemsInStackAddress(ConstructorStack)=0
11663 c := PeepAddress(ConstructorStack, 1) ;
11665 IF IsArray(type) OR IsSet(type)
11667 PushT(GetSType(type))
11668 ELSIF IsRecord(type)
11670 PushT(GetSType(GetNth(type, index)))
11672 MetaError1('{%1ad} is not a set, record or array type which is expected when constructing an aggregate entity',
11677 END BuildTypeForConstructor ;
11681 BuildSetStart - Pushes a Bitset type on the stack.
11689 Empty +--------------+
11694 PROCEDURE BuildSetStart ;
11697 END BuildSetStart ;
11701 BuildSetEnd - pops the set value and type from the stack
11702 and pushes the value,type pair.
11708 | Set Value | <- Ptr
11709 |--------------| +--------------+
11710 | Set Type | | Value | Type |
11711 |--------------| |--------------|
11714 PROCEDURE BuildSetEnd ;
11726 BuildEmptySet - Builds an empty set on the stack.
11734 +-----------+ |-------------|
11735 | SetType | | SetType |
11736 |-----------| |-------------|
11740 PROCEDURE BuildEmptySet ;
11747 PopT(Type) ; (* type of set we are building *)
11748 tok := GetTokenNo () ;
11749 IF (Type=NulSym) AND Pim
11751 (* allowed generic {} in PIM Modula-2 *)
11752 ELSIF IsUnknown(Type)
11754 n := GetSymName(Type) ;
11755 WriteFormat1('set type %a is undefined', n) ;
11757 ELSIF NOT IsSet(SkipType(Type))
11759 n := GetSymName(Type) ;
11760 WriteFormat1('expecting a set type %a', n) ;
11763 Type := SkipType(Type) ;
11764 Assert((Type#NulSym))
11766 NulSet := MakeTemporary(tok, ImmediateValue) ;
11767 PutVar(NulSet, Type) ;
11768 PutConstSet(NulSet) ;
11769 IF CompilerDebugging
11771 n := GetSymName(Type) ;
11772 printf1('set type = %a\n', n)
11774 PushNulSet(Type) ; (* onto the ALU stack *)
11775 PopValue(NulSet) ; (* ALU -> symbol table *)
11777 (* and now construct the M2Quads stack as defined by the comments above *)
11780 IF CompilerDebugging
11782 n := GetSymName(Type) ;
11783 printf2('Type = %a (%d) built empty set\n', n, Type) ;
11784 DisplayStack (* Debugging info *)
11786 END BuildEmptySet ;
11790 BuildInclRange - includes a set range with a set.
11802 |------------| +-------------------+
11803 | Set Value | | Value + {El1..El2}|
11804 |------------| |-------------------|
11806 No quadruples produced as the range info is contained within
11810 PROCEDURE BuildInclRange ;
11819 IF NOT IsConstSet(value)
11821 n := GetSymName(el1) ;
11822 WriteFormat1('can only add bit ranges to a constant set, %a is not a constant set', n)
11824 IF IsConst(el1) AND IsConst(el2)
11826 PushValue(value) ; (* onto ALU stack *)
11827 AddBitRange(GetTokenNo(), el1, el2) ;
11828 PopValue(value) (* ALU -> symboltable *)
11830 IF NOT IsConst(el1)
11832 n := GetSymName(el1) ;
11833 WriteFormat1('must use constants as ranges when defining a set constant, problem with the low value %a', n)
11835 IF NOT IsConst(el2)
11837 n := GetSymName(el2) ;
11838 WriteFormat1('must use constants as ranges when defining a set constant, problem with the high value %a', n)
11842 END BuildInclRange ;
11846 BuildInclBit - includes a bit into the set.
11855 |------------| +------------+
11856 | Value | | Value |
11857 |------------| |------------|
11861 PROCEDURE BuildInclBit ;
11864 el, value, t: CARDINAL ;
11868 tok := GetTokenNo () ;
11871 PushValue(value) ; (* onto ALU stack *)
11873 PopValue(value) (* ALU -> symboltable *)
11875 IF GetMode(el)=LeftValue
11877 t := MakeTemporary(tok, RightValue) ;
11878 PutVar(t, GetSType(el)) ;
11879 CheckPointerThroughNil (tok, el) ;
11880 doIndrX(tok, t, el) ;
11885 (* move constant into a variable to achieve the include *)
11886 t := MakeTemporary(tok, RightValue) ;
11887 PutVar(t, GetSType(value)) ;
11888 GenQuad(BecomesOp, t, NulSym, value) ;
11891 GenQuad(InclOp, value, NulSym, el)
11901 PROCEDURE PushConstructor (sym: CARDINAL) ;
11903 c: ConstructorFrame ;
11907 type := SkipType(sym) ;
11910 PushAddress(ConstructorStack, c)
11911 END PushConstructor ;
11915 PopConstructor - removes the top constructor from the top of stack.
11918 PROCEDURE PopConstructor ;
11920 c: ConstructorFrame ;
11922 c := PopAddress (ConstructorStack) ;
11924 END PopConstructor ;
11928 NextConstructorField - increments the top of constructor stacks index by one.
11931 PROCEDURE NextConstructorField ;
11933 c: ConstructorFrame ;
11935 c := PeepAddress(ConstructorStack, 1) ;
11937 END NextConstructorField ;
11941 SilentBuildConstructor - places NulSym into the constructor fifo queue.
11944 PROCEDURE SilentBuildConstructor ;
11946 PutConstructorIntoFifoQueue (NulSym)
11947 END SilentBuildConstructor ;
11951 BuildConstructor - builds a constructor.
11962 PROCEDURE BuildConstructor (tokcbrpos: CARDINAL) ;
11968 PopTtok (type, tok) ;
11969 constValue := MakeTemporary (tok, ImmediateValue) ;
11970 PutVar (constValue, type) ;
11971 PutConstructor (constValue) ;
11972 PushValue (constValue) ;
11975 MetaErrorT0 (tokcbrpos,
11976 '{%E}constructor requires a type before the opening {')
11978 ChangeToConstructor (tok, type) ;
11979 PutConstructorFrom (constValue, type) ;
11980 PopValue (constValue) ;
11981 PutConstructorIntoFifoQueue (constValue)
11983 PushConstructor (type)
11984 END BuildConstructor ;
11988 SilentBuildConstructorStart - removes an entry from the constructor fifo queue.
11991 PROCEDURE SilentBuildConstructorStart ;
11993 constValue: CARDINAL ;
11995 GetConstructorFromFifoQueue (constValue)
11996 END SilentBuildConstructorStart ;
12000 BuildConstructorStart - builds a constructor.
12006 +------------+ +----------------+
12007 | Type | | ConstructorSym |
12008 |------------+ |----------------|
12011 PROCEDURE BuildConstructorStart (cbratokpos: CARDINAL) ;
12016 PopT (type) ; (* we ignore the type as we already have the constructor symbol from pass C *)
12017 GetConstructorFromFifoQueue (constValue) ;
12018 Assert (type = GetSType (constValue)) ;
12019 PushTtok (constValue, cbratokpos) ;
12020 PushConstructor (type)
12021 END BuildConstructorStart ;
12025 BuildConstructorEnd - removes the current constructor frame from the
12026 constructor stack (it does not effect the quad
12032 +------------+ +------------+
12033 | const | | const |
12034 |------------| |------------|
12037 PROCEDURE BuildConstructorEnd (cbratokpos: CARDINAL) ;
12040 value, valtok: CARDINAL ;
12042 PopTtok (value, valtok) ;
12047 typetok := OperandTtok (1)
12049 valtok := MakeVirtualTok (typetok, typetok, cbratokpos) ;
12050 PutDeclared (valtok, value) ;
12051 PushTtok (value, valtok) ; (* Use valtok as we now know it was a constructor. *)
12053 (* ; ErrorStringAt (Mark (InitString ('aggregate constant')), valtok) *)
12054 END BuildConstructorEnd ;
12058 AddFieldTo - adds field, e, to, value.
12061 PROCEDURE AddFieldTo (value, e: CARDINAL) : CARDINAL ;
12063 IF IsSet(GetDType(value))
12065 PutConstSet(value) ;
12072 AddField(GetTokenNo(), e) ;
12080 BuildComponentValue - builds a component value.
12087 +------------+ +------------+
12088 | const | | const |
12089 |------------| |------------|
12092 PROCEDURE BuildComponentValue ;
12095 e1, e2 : CARDINAL ;
12103 IF nuldotdot=NulTok
12107 PushT(AddFieldTo(const, e1))
12113 AddBitRange(GetTokenNo(), e1, e2) ;
12120 IF nuldotdot=NulTok
12125 AddElements(GetTokenNo(), e2, e1) ;
12132 WriteFormat0('the constant must be an array constructor or a set constructor but not both') ;
12136 END BuildComponentValue ;
12140 RecordOp - Records the operator passed on the stack.
12141 Checks for AND operator or OR operator
12142 if either of these operators are found then BackPatching
12144 The Expected Stack:
12149 +-------------+ +-------------+
12150 | OperatorTok | | OperatorTok |
12151 |-------------| |-------------|
12152 | t | f | | t | f |
12153 |-------------| |-------------|
12156 If OperatorTok=AndTok
12158 BackPatch(f, NextQuad)
12159 Elsif OperatorTok=OrTok
12161 BackPatch(t, NextQuad)
12165 PROCEDURE RecordOp ;
12171 PopTtok(Op, tokno) ;
12172 IF (Op=AndTok) OR (Op=AmbersandTok)
12176 BackPatch(t, NextQuad) ;
12182 BackPatch(f, NextQuad) ;
12185 PushTtok(Op, tokno)
12190 CheckLogicalOperator - returns a logical operator if the operands imply
12191 a logical operation should be performed.
12194 PROCEDURE CheckLogicalOperator (Tok: Name; left, lefttype: CARDINAL) : Name ;
12196 IF (Tok=PlusTok) OR (Tok=TimesTok) OR (Tok=DivideTok) OR (Tok=MinusTok)
12198 (* --fixme-- when we add complex arithmetic, we must check constructor is not a complex constant. *)
12199 IF ((lefttype#NulSym) AND IsSet(SkipType(lefttype))) OR
12200 IsConstSet(left) OR IsConstructor(left)
12204 RETURN( LogicalOrTok )
12205 ELSIF Tok=DivideTok
12207 RETURN( LogicalXorTok )
12210 RETURN( LogicalAndTok )
12213 RETURN( LogicalDifferenceTok )
12218 END CheckLogicalOperator ;
12222 doCheckGenericNulSet - checks to see whether e1 is a generic nul set and if so it alters it
12223 to the nul set of t2.
12227 PROCEDURE doCheckGenericNulSet (e1: CARDINAL; VAR t1: CARDINAL; t2: CARDINAL) ;
12233 MetaError2 ('incompatibility between a set constant {%1Ea} of type {%1tsa} and an object of type {%2sa}',
12237 IF IsGenericNulSet ()
12245 END doCheckGenericNulSet ;
12250 CheckGenericNulSet - if e1 or e2 is the generic nul set then
12251 alter it to the nul set of the other operands type.
12255 PROCEDURE CheckGenericNulSet (e1, e2: CARDINAL; VAR t1, t2: CARDINAL) ;
12259 doCheckGenericNulSet(e1, t1, t2) ;
12260 doCheckGenericNulSet(e2, t2, t1)
12262 END CheckGenericNulSet ;
12267 CheckDivModRem - initiates calls to check the divisor for DIV, MOD, REM
12271 PROCEDURE CheckDivModRem (TokPos: CARDINAL; tok: Name; d, e: CARDINAL) ;
12275 BuildRange (InitWholeZeroDivisionCheck (TokPos, d, e))
12278 BuildRange (InitWholeZeroDivisionCheck (TokPos, d, e))
12281 BuildRange (InitWholeZeroRemainderCheck (TokPos, d, e))
12283 END CheckDivModRem ;
12287 doConvert - convert, sym, to a new symbol with, type.
12288 Return the new symbol.
12291 PROCEDURE doConvert (type: CARDINAL; sym: CARDINAL) : CARDINAL ;
12293 IF GetSType(sym)#type
12295 PushTF(Convert, NulSym) ;
12298 PushT(2) ; (* Two parameters *)
12299 BuildConvertFunction ;
12307 BuildBinaryOp - Builds a binary operation from the quad stack.
12308 Be aware that this procedure will check for
12309 the overloading of the bitset operators + - \ *.
12310 So do NOT call this procedure if you are building
12311 a reference to an array which has a bitset type or
12312 the address arithmetic will be wrongly coersed into
12315 The Stack is expected to contain:
12325 | Operator | <- Ptr
12326 |------------| +------------+
12327 | Sym2 | | Temporary |
12328 |------------| |------------|
12331 Quadruples Produced
12333 q Operator Temporary Sym1 Sym2
12347 |------------| +------------+
12348 | T2 | F2 | | T1+T2| F1 |
12349 |------------| |------------|
12352 Quadruples Produced
12356 PROCEDURE BuildBinaryOp ;
12358 doBuildBinaryOp (TRUE, TRUE)
12359 END BuildBinaryOp ;
12363 doBuildBinaryOp - build the binary op, with or without type
12367 PROCEDURE doBuildBinaryOp (checkTypes, checkOverflow: BOOLEAN) ;
12377 lefttype, righttype,
12379 leftpos, rightpos : CARDINAL ;
12382 Operator := OperandT(2) ;
12383 IF Operator = OrTok
12387 PopTtok (Operator, OperatorPos) ;
12390 PushBool (Merge (t1, t2), f1)
12391 ELSIF (Operator = AndTok) OR (Operator = AmbersandTok)
12395 PopTtok (Operator, OperatorPos) ;
12398 PushBool (t1, Merge (f1, f2))
12400 PopTFrwtok (right, righttype, rightrw, rightpos) ;
12401 PopTtok (Operator, OperatorPos) ;
12402 PopTFrwtok (left, lefttype, leftrw, leftpos) ;
12403 MarkAsRead (rightrw) ;
12404 MarkAsRead (leftrw) ;
12405 NewOp := CheckLogicalOperator (Operator, (* right, righttype, *) left, lefttype) ;
12406 IF NewOp = Operator
12409 BinaryOps and UnaryOps only work with immediate and
12410 offset addressing. This is fine for calculating
12411 array and record offsets but we need to get the real
12412 values to perform normal arithmetic. Not address
12415 However the set operators will dereference LValues
12416 (to optimize large set arithemetic)
12418 IF GetMode (right) = LeftValue
12420 value := MakeTemporary (rightpos, RightValue) ;
12421 PutVar (value, righttype) ;
12422 CheckPointerThroughNil (rightpos, right) ;
12423 doIndrX (rightpos, value, right) ;
12426 IF GetMode (left) = LeftValue
12428 value := MakeTemporary (leftpos, RightValue) ;
12429 PutVar (value, lefttype) ;
12430 CheckPointerThroughNil (leftpos, left) ;
12431 doIndrX (leftpos, value, left) ;
12435 (* CheckForGenericNulSet(e1, e2, t1, t2) *)
12437 IF (Operator = PlusTok) AND IsConstString(left) AND IsConstString(right)
12439 (* handle special addition for constant strings *)
12440 s := InitStringCharStar (KeyToCharStar (GetString (left))) ;
12441 s := ConCat (s, Mark (InitStringCharStar (KeyToCharStar (GetString (right))))) ;
12442 value := MakeConstLitString (OperatorPos, makekey (string (s))) ;
12443 s := KillString (s)
12445 OldPos := OperatorPos ;
12446 OperatorPos := MakeVirtualTok (OperatorPos, leftpos, rightpos) ;
12449 BuildRange (InitTypesExpressionCheck (OperatorPos, left, right, FALSE, FALSE))
12451 value := MakeTemporaryFromExpressions (OperatorPos,
12453 AreConstant (IsConst (left) AND IsConst (right))) ;
12455 CheckDivModRem (OperatorPos, NewOp, value, right) ;
12459 s := InitStringCharStar (KeyToCharStar (GetTokenName (Operator))) ;
12460 WarnStringAt (s, OldPos) ;
12461 s := InitString ('left') ;
12462 WarnStringAt (s, leftpos) ;
12463 s := InitString ('right') ;
12464 WarnStringAt (s, rightpos) ;
12465 s := InitString ('caret') ;
12466 WarnStringAt (s, OldPos) ;
12467 s := InitString ('combined') ;
12468 WarnStringAt (s, OperatorPos) ;
12469 (* MetaErrorT1 (GetDeclaredMod (t), 'in binary with a {%1a}', t) *)
12471 GenQuadOtok (OperatorPos, MakeOp (NewOp), value, left, right, checkOverflow,
12472 OperatorPos, leftpos, rightpos)
12474 PushTFtok (value, GetSType (value), OperatorPos)
12476 END doBuildBinaryOp ;
12480 BuildUnaryOp - Builds a unary operation from the quad stack.
12481 The Stack is expected to contain:
12490 |------------| +------------+
12491 | Operator | | Temporary | <- Ptr
12492 |------------| |------------|
12495 Quadruples Produced
12497 q Operator Temporary _ Sym
12501 PROCEDURE BuildUnaryOp ;
12504 tokpos : CARDINAL ;
12508 SymT, r, t: CARDINAL ;
12510 PopTrwtok (Sym, r, sympos) ;
12511 PopTtok (Tok, tokpos) ;
12515 type := NegateType (GetSType (Sym) (* , sympos *) ) ;
12516 tokpos := MakeVirtualTok (tokpos, tokpos, sympos) ;
12518 t := MakeTemporary (tokpos, AreConstant(IsConst(Sym))) ;
12522 variables must have a type and REAL/LONGREAL constants must
12526 IF NOT IsConst(Sym)
12528 IF (type#NulSym) AND IsSet(SkipType(type))
12530 (* do not dereference set variables *)
12531 ELSIF GetMode(Sym)=LeftValue
12533 (* dereference symbols which are not sets and which are variables *)
12535 SymT := MakeTemporary (sympos, RightValue) ;
12536 PutVar (SymT, GetSType (Sym)) ;
12537 CheckPointerThroughNil (sympos, Sym) ;
12538 doIndrX (sympos, SymT, Sym) ;
12542 GenQuadO (tokpos, NegateOp, t, NulSym, Sym, TRUE) ;
12543 PushTtok (t, tokpos)
12546 tokpos := MakeVirtualTok (tokpos, tokpos, sympos) ;
12547 PushTrwtok (Sym, r, tokpos)
12549 MetaErrorNT1 (tokpos,
12550 'expecting an unary operator, seen {%Ek%a}', Tok)
12556 AreConstant - returns immediate addressing mode if b is true else
12557 offset mode is returned. b determines whether the
12558 operands are all constant - in which case we can use
12559 a constant temporary variable.
12562 PROCEDURE AreConstant (b: BOOLEAN) : ModeOfAddr ;
12566 RETURN ImmediateValue
12574 ConvertBooleanToVariable - converts a BoolStack(i) from a Boolean True|False
12575 exit pair into a variable containing the value TRUE or
12576 FALSE. The parameter, i, is relative to the top
12580 PROCEDURE ConvertBooleanToVariable (tok: CARDINAL; i: CARDINAL) ;
12585 Assert (IsBoolean (i)) ;
12587 need to convert it to a variable containing the result.
12588 Des will be a boolean type
12590 Des := MakeTemporary (tok, RightValue) ;
12591 PutVar (Des, Boolean) ;
12592 PushTtok (Des, tok) ; (* we have just increased the stack so we must use i+1 *)
12593 f := PeepAddress (BoolStack, i+1) ;
12594 PushBool (f^.TrueExit, f^.FalseExit) ;
12595 BuildAssignmentWithoutBounds (tok, FALSE, TRUE) ; (* restored stack *)
12596 f := PeepAddress (BoolStack, i) ;
12598 TrueExit := Des ; (* alter Stack(i) to contain the variable *)
12599 FalseExit := Boolean ;
12600 BooleanOp := FALSE ; (* no longer a Boolean True|False pair *)
12601 Unbounded := NulSym ;
12603 ReadWrite := NulSym ;
12605 Annotation := KillString (Annotation) ;
12606 Annotation := InitString ('%1s(%1d)|%2s(%2d)||boolean var|type')
12608 END ConvertBooleanToVariable ;
12612 BuildBooleanVariable - tests to see whether top of stack is a boolean
12613 conditional and if so it converts it into a boolean
12617 PROCEDURE BuildBooleanVariable ;
12621 ConvertBooleanToVariable (OperandTtok (1), 1)
12623 END BuildBooleanVariable ;
12627 BuildRelOpFromBoolean - builds a relational operator sequence of quadruples
12628 instead of using a temporary boolean variable.
12629 This function can only be used when we perform
12630 the following translation:
12632 (a=b) # (c=d) alternatively (a=b) = (c=d)
12635 it only allows # = to be used as >= <= > < all
12636 assume a particular value for TRUE and FALSE.
12637 (In which case the user should specify ORD)
12644 q+2 if r2 op3 op4 t1
12647 after (in case of =)
12649 q if r1 op1 op2 q+2
12651 q+2 if r2 op3 op4 t
12653 q+4 if r2 op3 op4 f
12656 after (in case of #)
12658 q if r1 op1 op2 q+2
12660 q+2 if r2 op3 op4 f
12662 q+4 if r2 op3 op4 t
12665 The Stack is expected to contain:
12675 | Operator | <- Ptr
12676 |------------| +------------+
12677 | t2 | f2 | | t | f |
12678 |------------| |------------|
12683 PROCEDURE BuildRelOpFromBoolean (tokpos: CARDINAL) ;
12690 Assert (IsBoolean (1) AND IsBoolean (3)) ;
12691 IF OperandT (2) = EqualTok
12693 (* are the two boolean expressions the same? *)
12697 (* give the false exit a second chance *)
12698 BackPatch (t2, t1) ; (* q if _ _ q+2 *)
12699 BackPatch (f2, NextQuad) ; (* q+1 if _ _ q+4 *)
12700 Assert (NextQuad = f1+1) ;
12703 GenQuadO (tokpos, Operator, Operand1, Operand2, 0, FALSE)
12705 GenQuadO (tokpos, GotoOp, NulSym, NulSym, 0, FALSE) ;
12706 PushBool (Merge (NextQuad-1, t1), Merge (NextQuad-2, f1))
12707 ELSIF (OperandT (2) = HashTok) OR (OperandT (2) = LessGreaterTok)
12709 (* are the two boolean expressions the different? *)
12713 (* give the false exit a second chance *)
12714 BackPatch (t2, t1) ; (* q if _ _ q+2 *)
12715 BackPatch (f2, NextQuad) ; (* q+1 if _ _ q+4 *)
12716 Assert (NextQuad = f1+1) ;
12719 GenQuadO (tokpos, Operator, Operand1, Operand2, 0, FALSE)
12721 GenQuadO (tokpos, GotoOp, NulSym, NulSym, 0, FALSE) ;
12722 PushBool (Merge (NextQuad-2, f1), Merge (NextQuad-1, t1))
12724 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}')
12726 END BuildRelOpFromBoolean ;
12730 CheckVariableOrConstantOrProcedure - checks to make sure sym is a variable, constant or procedure.
12733 PROCEDURE CheckVariableOrConstantOrProcedure (tokpos: CARDINAL; sym: CARDINAL) ;
12737 type := GetSType (sym) ;
12740 MetaErrorT1 (tokpos, '{%1EUad} has not been declared', sym) ;
12741 UnknownReported (sym)
12742 ELSIF IsPseudoSystemFunction (sym) OR IsPseudoBaseFunction (sym)
12744 MetaErrorT1 (tokpos,
12745 '{%1Ead} expected a variable, procedure, constant or expression, not an intrinsic procedure function',
12747 ELSIF (NOT IsConst(sym)) AND (NOT IsVar(sym)) AND
12748 (NOT IsProcedure(sym)) AND
12749 (NOT IsTemporary(sym)) AND (NOT MustNotCheckBounds)
12751 MetaErrorsT1 (tokpos,
12752 '{%1Ead} expected a variable, procedure, constant or expression',
12753 'and it was declared as a {%1Dd}', sym) ;
12754 ELSIF (type#NulSym) AND IsArray(type)
12756 MetaErrorsT1 (tokpos,
12757 '{%1EU} not expecting an array variable as an operand for either comparison or binary operation',
12758 'it was declared as a {%1Dd}', sym)
12759 ELSIF IsConstString(sym) AND (GetStringLength(sym)>1)
12761 MetaErrorT1 (tokpos,
12762 '{%1EU} not expecting a string constant as an operand for either comparison or binary operation',
12765 END CheckVariableOrConstantOrProcedure ;
12769 BuildRelOp - Builds a relative operation from the quad stack.
12770 The Stack is expected to contain:
12779 |------------| <- Ptr
12781 |------------| +------------+
12783 |------------| |------------|
12786 Quadruples Produced
12788 q IFOperator e2 e1 TrueExit ; e2 e1 since
12789 q+1 GotoOp FalseExit ; relation > etc
12793 PROCEDURE BuildRelOp (optokpos: CARDINAL) ;
12797 leftpos : CARDINAL ;
12800 rightType, leftType,
12801 right, left : CARDINAL ;
12803 IF CompilerDebugging
12805 DisplayStack (* Debugging info *)
12807 IF IsBoolean (1) AND IsBoolean (3)
12810 we allow # and = to be used with Boolean expressions.
12811 we do not allow > < >= <= though
12813 BuildRelOpFromBoolean (optokpos)
12817 ConvertBooleanToVariable (OperandTtok (1), 1)
12821 ConvertBooleanToVariable (OperandTtok (3), 3)
12823 PopTFtok (right, rightType, rightpos) ;
12825 PopTFtok (left, leftType, leftpos) ;
12827 CheckVariableOrConstantOrProcedure (rightpos, right) ;
12828 CheckVariableOrConstantOrProcedure (leftpos, left) ;
12830 IF (left#NulSym) AND (right#NulSym)
12832 (* BuildRange will check the expression later on once gcc knows about all data types. *)
12833 BuildRange (InitTypesExpressionCheck (optokpos, left, right, TRUE, Op = InTok))
12836 (* Must dereference LeftValue operands. *)
12837 IF GetMode(right) = LeftValue
12839 t := MakeTemporary (rightpos, RightValue) ;
12840 PutVar(t, GetSType(right)) ;
12841 CheckPointerThroughNil (rightpos, right) ;
12842 doIndrX (rightpos, t, right) ;
12845 IF GetMode(left) = LeftValue
12847 t := MakeTemporary (leftpos, RightValue) ;
12848 PutVar (t, GetSType (left)) ;
12849 CheckPointerThroughNil (leftpos, left) ;
12850 doIndrX (leftpos, t, left) ;
12853 combinedTok := MakeVirtualTok (optokpos, leftpos, rightpos) ;
12854 GenQuadO (combinedTok, MakeOp(Op), left, right, 0, FALSE) ; (* True Exit *)
12855 GenQuadO (combinedTok, GotoOp, NulSym, NulSym, 0, FALSE) ; (* False Exit *)
12856 PushBool (NextQuad-2, NextQuad-1)
12862 BuildNot - Builds a NOT operation from the quad stack.
12863 The Stack is expected to contain:
12870 +------------+ +------------+
12871 | t | f | | f | t |
12872 |------------| |------------|
12875 PROCEDURE BuildNot (notTokPos: CARDINAL) ;
12878 exprTokPos : CARDINAL ;
12882 PopBooltok (t, f, exprTokPos) ;
12883 combinedTok := MakeVirtualTok (notTokPos, notTokPos, exprTokPos) ;
12884 PushBooltok (f, t, combinedTok)
12889 MakeOp - returns the equalent quadruple operator to a token, t.
12892 PROCEDURE MakeOp (t: Name) : QuadOperator ;
12905 RETURN( DivTruncOp )
12908 RETURN( ModTruncOp )
12917 RETURN( IfNotEquOp )
12918 ELSIF t=LessGreaterTok
12920 RETURN( IfNotEquOp )
12921 ELSIF t=GreaterEqualTok
12923 RETURN( IfGreEquOp )
12924 ELSIF t=LessEqualTok
12926 RETURN( IfLessEquOp )
12939 ELSIF t=LogicalOrTok
12941 RETURN( LogicalOrOp )
12942 ELSIF t=LogicalAndTok
12944 RETURN( LogicalAndOp )
12945 ELSIF t=LogicalXorTok
12947 RETURN( LogicalXorOp )
12948 ELSIF t=LogicalDifferenceTok
12950 RETURN( LogicalDiffOp )
12952 InternalError('binary operation not implemented yet')
12958 GenQuadO - generate a quadruple with Operation, Op1, Op2, Op3, overflow.
12961 PROCEDURE GenQuadO (TokPos: CARDINAL;
12962 Operation: QuadOperator;
12963 Op1, Op2, Op3: CARDINAL; overflow: BOOLEAN) ;
12967 (* WriteString('Potential Quad: ') ; *)
12968 IF QuadrupleGeneration
12972 f := GetQF (NextQuad-1) ;
12973 f^.Next := NextQuad
12975 PutQuadO (NextQuad, Operation, Op1, Op2, Op3, overflow) ;
12976 f := GetQF (NextQuad) ;
12979 LineNo := GetLineNo () ;
12980 IF TokPos = UnknownTokenNo
12982 TokenNo := GetTokenNo ()
12987 IF NextQuad=BreakAtQuad
12991 (* DisplayQuad(NextQuad) ; *)
12998 GenQuad - Generate a quadruple with Operation, Op1, Op2, Op3.
13001 PROCEDURE GenQuad (Operation: QuadOperator;
13002 Op1, Op2, Op3: CARDINAL) ;
13004 GenQuadO (UnknownTokenNo, Operation, Op1, Op2, Op3, TRUE)
13009 GenQuadOtok - generate a quadruple with Operation, Op1, Op2, Op3, overflow.
13012 PROCEDURE GenQuadOtok (TokPos: CARDINAL;
13013 Operation: QuadOperator;
13014 Op1, Op2, Op3: CARDINAL; overflow: BOOLEAN;
13015 Op1Pos, Op2Pos, Op3Pos: CARDINAL) ;
13019 (* WriteString('Potential Quad: ') ; *)
13020 IF QuadrupleGeneration
13024 f := GetQF (NextQuad-1) ;
13025 f^.Next := NextQuad
13027 PutQuadO (NextQuad, Operation, Op1, Op2, Op3, overflow) ;
13028 f := GetQF (NextQuad) ;
13031 LineNo := GetLineNo () ;
13032 IF TokPos = UnknownTokenNo
13034 TokenNo := GetTokenNo ()
13042 IF NextQuad=BreakAtQuad
13046 (* DisplayQuad(NextQuad) ; *)
13053 DisplayQuadList - displays all quads.
13056 PROCEDURE DisplayQuadList ;
13061 printf0('Quadruples:\n') ;
13068 END DisplayQuadList ;
13072 DisplayQuadRange - displays all quads in list range, start..end.
13075 PROCEDURE DisplayQuadRange (start, end: CARDINAL) ;
13079 printf0('Quadruples:\n') ;
13080 WHILE (start<=end) AND (start#0) DO
13081 DisplayQuad(start) ;
13082 f := GetQF(start) ;
13085 END DisplayQuadRange ;
13089 BackPatch - Makes each of the quadruples on the list pointed to by
13090 StartQuad, take quadruple Value as a target.
13093 PROCEDURE BackPatch (QuadNo, Value: CARDINAL) ;
13098 IF QuadrupleGeneration
13101 f := GetQF(QuadNo) ;
13103 i := Operand3 ; (* Next Link along the BackPatch *)
13104 ManipulateReference(QuadNo, Value) (* Filling in the BackPatch. *)
13113 Merge - joins two quad lists, QuadList2 to the end of QuadList1.
13114 A QuadList of value zero is a nul list.
13117 PROCEDURE Merge (QuadList1, QuadList2: CARDINAL) : CARDINAL ;
13124 RETURN( QuadList2 )
13127 RETURN( QuadList1 )
13135 ManipulateReference(j, QuadList2) ;
13136 RETURN( QuadList1 )
13142 Annotate - annotate the top of stack.
13145 PROCEDURE Annotate (a: ARRAY OF CHAR) ;
13149 IF DebugStackOn AND CompilerDebugging AND (NoOfItemsInStackAddress(BoolStack)>0)
13151 f := PeepAddress(BoolStack, 1) ; (* top of stack *)
13155 Annotation := KillString(Annotation)
13157 Annotation := InitString(a)
13164 OperandAnno - returns the annotation string associated with the
13165 position, n, on the stack.
13168 PROCEDURE OperandAnno (n: CARDINAL) : String ;
13172 f := PeepAddress (BoolStack, n) ;
13173 RETURN f^.Annotation
13178 DisplayStack - displays the compile time symbol stack.
13181 PROCEDURE DisplayStack ;
13183 IF DebugStackOn AND CompilerDebugging
13185 DebugStack (NoOfItemsInStackAddress (BoolStack),
13186 OperandTno, OperandFno, OperandA,
13187 OperandD, OperandRW, OperandTok, OperandAnno)
13193 ds - tiny procedure name, useful for calling from the gdb shell.
13205 DisplayQuad - displays a quadruple, QuadNo.
13208 PROCEDURE DisplayQuad (QuadNo: CARDINAL) ;
13211 printf1('%4d ', QuadNo) ; WriteQuad(QuadNo) ; printf0('\n') ;
13217 DisplayProcedureAttributes -
13220 PROCEDURE DisplayProcedureAttributes (proc: CARDINAL) ;
13224 printf0 (" (ctor)")
13228 printf0 (" (public)")
13232 printf0 (" (extern)")
13234 IF IsMonoName (proc)
13236 printf0 (" (mononame)")
13238 END DisplayProcedureAttributes ;
13242 WriteQuad - Writes out the Quad BufferQuad.
13245 PROCEDURE WriteQuad (BufferQuad: CARDINAL) ;
13252 f := GetQF(BufferQuad) ;
13254 WriteOperator(Operator) ;
13255 printf1(' [%d] ', NoOfTimesReferenced) ;
13258 HighOp : WriteOperand(Operand1) ;
13259 printf1(' %4d ', Operand2) ;
13260 WriteOperand(Operand3) |
13273 AddrOp : WriteOperand(Operand1) ;
13275 WriteOperand(Operand3) |
13284 IfGreEquOp : WriteOperand(Operand1) ;
13286 WriteOperand(Operand2) ;
13287 printf1(' %4d', Operand3) |
13292 GotoOp : printf1('%4d', Operand3) |
13294 StatementNoteOp : l := TokenToLineNo(Operand3, 0) ;
13295 n := GetTokenName (Operand3) ;
13296 printf4('%a:%d:%a (tokenno %d)', Operand1, l, n, Operand3) |
13297 LineNumberOp : printf2('%a:%d', Operand1, Operand3) |
13299 EndFileOp : n1 := GetSymName(Operand3) ;
13300 printf1('%a', n1) |
13305 KillLocalVarOp : WriteOperand(Operand3) |
13307 ProcedureScopeOp : n1 := GetSymName(Operand2) ;
13308 n2 := GetSymName(Operand3) ;
13309 printf3(' %4d %a %a', Operand1, n1, n2) ;
13310 DisplayProcedureAttributes (Operand3) |
13315 InitStartOp : n1 := GetSymName(Operand2) ;
13316 n2 := GetSymName(Operand3) ;
13317 printf3(' %4d %a %a', Operand1, n1, n2) |
13320 StartModFileOp : n1 := GetSymName(Operand3) ;
13321 printf4('%a:%d %a(%d)', Operand2, Operand1, n1, Operand3) |
13323 StartDefFileOp : n1 := GetSymName(Operand3) ;
13324 printf2(' %4d %a', Operand1, n1) |
13327 ParamOp : printf1('%4d ', Operand1) ;
13328 WriteOperand(Operand2) ;
13330 WriteOperand(Operand3) |
13355 DivTruncOp : WriteOperand(Operand1) ;
13357 WriteOperand(Operand2) ;
13359 WriteOperand(Operand3) |
13367 BuiltinConstOp : WriteOperand(Operand1) ;
13368 printf1(' %a', Operand3) |
13369 BuiltinTypeInfoOp : WriteOperand(Operand1) ;
13370 printf1(' %a', Operand2) ;
13371 printf1(' %a', Operand3) |
13372 StandardFunctionOp: WriteOperand(Operand1) ;
13374 WriteOperand(Operand2) ;
13376 WriteOperand(Operand3) |
13381 ErrorOp : WriteRangeCheck(Operand3) |
13383 RestoreExceptionOp: WriteOperand(Operand1) ;
13385 WriteOperand(Operand3)
13388 InternalError ('quadruple not recognised')
13395 WriteOperator - writes the name of the quadruple operator.
13398 PROCEDURE WriteOperator (Operator: QuadOperator) ;
13402 InitAddressOp : printf0('InitAddress ') |
13403 LogicalOrOp : printf0('Or ') |
13404 LogicalAndOp : printf0('And ') |
13405 LogicalXorOp : printf0('Xor ') |
13406 LogicalDiffOp : printf0('Ldiff ') |
13407 LogicalShiftOp : printf0('Shift ') |
13408 LogicalRotateOp : printf0('Rotate ') |
13409 BecomesOp : printf0('Becomes ') |
13410 IndrXOp : printf0('IndrX ') |
13411 XIndrOp : printf0('XIndr ') |
13412 ArrayOp : printf0('Array ') |
13413 ElementSizeOp : printf0('ElementSize ') |
13414 RecordFieldOp : printf0('RecordField ') |
13415 AddrOp : printf0('Addr ') |
13416 SizeOp : printf0('Size ') |
13417 IfInOp : printf0('If IN ') |
13418 IfNotInOp : printf0('If NOT IN ') |
13419 IfNotEquOp : printf0('If <> ') |
13420 IfEquOp : printf0('If = ') |
13421 IfLessEquOp : printf0('If <= ') |
13422 IfGreEquOp : printf0('If >= ') |
13423 IfGreOp : printf0('If > ') |
13424 IfLessOp : printf0('If < ') |
13425 GotoOp : printf0('Goto ') |
13426 DummyOp : printf0('Dummy ') |
13427 ModuleScopeOp : printf0('ModuleScopeOp ') |
13428 StartDefFileOp : printf0('StartDefFile ') |
13429 StartModFileOp : printf0('StartModFile ') |
13430 EndFileOp : printf0('EndFileOp ') |
13431 InitStartOp : printf0('InitStart ') |
13432 InitEndOp : printf0('InitEnd ') |
13433 FinallyStartOp : printf0('FinallyStart ') |
13434 FinallyEndOp : printf0('FinallyEnd ') |
13435 RetryOp : printf0('Retry ') |
13436 TryOp : printf0('Try ') |
13437 ThrowOp : printf0('Throw ') |
13438 CatchBeginOp : printf0('CatchBegin ') |
13439 CatchEndOp : printf0('CatchEnd ') |
13440 AddOp : printf0('+ ') |
13441 SubOp : printf0('- ') |
13442 DivM2Op : printf0('DIV M2 ') |
13443 ModM2Op : printf0('MOD M2 ') |
13444 DivCeilOp : printf0('DIV ceil ') |
13445 ModCeilOp : printf0('MOD ceil ') |
13446 DivFloorOp : printf0('DIV floor ') |
13447 ModFloorOp : printf0('MOD floor ') |
13448 DivTruncOp : printf0('DIV trunc ') |
13449 ModTruncOp : printf0('MOD trunc ') |
13450 MultOp : printf0('* ') |
13451 NegateOp : printf0('Negate ') |
13452 InclOp : printf0('Incl ') |
13453 ExclOp : printf0('Excl ') |
13454 ReturnOp : printf0('Return ') |
13455 ReturnValueOp : printf0('ReturnValue ') |
13456 FunctValueOp : printf0('FunctValue ') |
13457 CallOp : printf0('Call ') |
13458 ParamOp : printf0('Param ') |
13459 OptParamOp : printf0('OptParam ') |
13460 NewLocalVarOp : printf0('NewLocalVar ') |
13461 KillLocalVarOp : printf0('KillLocalVar ') |
13462 ProcedureScopeOp : printf0('ProcedureScope ') |
13463 UnboundedOp : printf0('Unbounded ') |
13464 CoerceOp : printf0('Coerce ') |
13465 ConvertOp : printf0('Convert ') |
13466 CastOp : printf0('Cast ') |
13467 HighOp : printf0('High ') |
13468 CodeOnOp : printf0('CodeOn ') |
13469 CodeOffOp : printf0('CodeOff ') |
13470 ProfileOnOp : printf0('ProfileOn ') |
13471 ProfileOffOp : printf0('ProfileOff ') |
13472 OptimizeOnOp : printf0('OptimizeOn ') |
13473 OptimizeOffOp : printf0('OptimizeOff ') |
13474 InlineOp : printf0('Inline ') |
13475 StatementNoteOp : printf0('StatementNote ') |
13476 LineNumberOp : printf0('LineNumber ') |
13477 BuiltinConstOp : printf0('BuiltinConst ') |
13478 BuiltinTypeInfoOp : printf0('BuiltinTypeInfo ') |
13479 StandardFunctionOp : printf0('StandardFunction ') |
13480 SavePriorityOp : printf0('SavePriority ') |
13481 RestorePriorityOp : printf0('RestorePriority ') |
13482 RangeCheckOp : printf0('RangeCheck ') |
13483 ErrorOp : printf0('Error ') |
13484 SaveExceptionOp : printf0('SaveException ') |
13485 RestoreExceptionOp : printf0('RestoreException ')
13488 InternalError ('operator not expected')
13490 END WriteOperator ;
13494 WriteOperand - displays the operands name, symbol id and mode of addressing.
13497 PROCEDURE WriteOperand (Sym: CARDINAL) ;
13503 printf0('<nulsym>')
13505 n := GetSymName(Sym) ;
13507 IF IsVar(Sym) OR IsConst(Sym)
13509 printf0('[') ; WriteMode(GetMode(Sym)) ; printf0(']')
13511 printf1('(%d)', Sym)
13516 PROCEDURE WriteMode (Mode: ModeOfAddr) ;
13520 ImmediateValue: printf0('i') |
13521 NoValue : printf0('n') |
13522 RightValue : printf0('r') |
13523 LeftValue : printf0('l')
13526 InternalError ('unrecognised mode')
13532 GetQuadOp - returns the operator for quad.
13535 PROCEDURE GetQuadOp (quad: CARDINAL) : QuadOperator ;
13539 f := GetQF (quad) ;
13545 GetM2OperatorDesc - returns the Modula-2 string associated with the quad operator
13546 (if possible). It returns NIL if no there is not an obvious match
13547 in Modula-2. It is assummed that the string will be used during
13548 construction of error messages and therefore keywords are
13549 wrapped with a format specifier.
13552 PROCEDURE GetM2OperatorDesc (op: QuadOperator) : String ;
13556 NegateOp : RETURN InitString ('-') |
13557 AddOp : RETURN InitString ('+') |
13558 SubOp : RETURN InitString ('-') |
13559 MultOp : RETURN InitString ('*') |
13563 DivTruncOp : RETURN InitString ('{%kDIV}') |
13566 ModFloorOp : RETURN InitString ('{%kMOD}') |
13567 ModTruncOp : RETURN InitString ('{%kREM}') |
13568 LogicalOrOp : RETURN InitString ('{%kOR}') |
13569 LogicalAndOp: RETURN InitString ('{%kAND}') |
13570 InclOp : RETURN InitString ('{%kINCL}') |
13571 ExclOp : RETURN InitString ('{%kEXCL}')
13576 END GetM2OperatorDesc ;
13581 PushExit - pushes the exit value onto the EXIT stack.
13584 PROCEDURE PushExit (Exit: CARDINAL) ;
13586 PushWord(ExitStack, Exit)
13591 PopExit - pops the exit value from the EXIT stack.
13594 PROCEDURE PopExit() : WORD ;
13596 RETURN( PopWord(ExitStack) )
13601 PushFor - pushes the exit value onto the FOR stack.
13604 PROCEDURE PushFor (Exit: CARDINAL) ;
13606 PushWord(ForStack, Exit)
13611 PopFor - pops the exit value from the FOR stack.
13614 PROCEDURE PopFor() : WORD ;
13616 RETURN( PopWord(ForStack) )
13621 OperandTno - returns the ident operand stored in the true position
13622 on the boolean stack. This is exactly the same as
13623 OperandT but it has no IsBoolean checking.
13626 PROCEDURE OperandTno (pos: CARDINAL) : WORD ;
13631 f := PeepAddress(BoolStack, pos) ;
13632 RETURN( f^.TrueExit )
13637 OperandFno - returns the ident operand stored in the false position
13638 on the boolean stack. This is exactly the same as
13639 OperandF but it has no IsBoolean checking.
13642 PROCEDURE OperandFno (pos: CARDINAL) : WORD ;
13647 f := PeepAddress (BoolStack, pos) ;
13648 RETURN f^.FalseExit
13653 OperandTtok - returns the token associated with the position, pos
13654 on the boolean stack.
13657 PROCEDURE OperandTtok (pos: CARDINAL) : CARDINAL ;
13662 f := PeepAddress (BoolStack, pos) ;
13668 PopBooltok - Pops a True and a False exit quad number from the True/False
13672 PROCEDURE PopBooltok (VAR True, False: CARDINAL; VAR tokno: CARDINAL) ;
13676 f := PopAddress (BoolStack) ;
13679 False := FalseExit ;
13688 PushBooltok - Push a True and a False exit quad numbers onto the
13692 PROCEDURE PushBooltok (True, False: CARDINAL; tokno: CARDINAL) ;
13696 Assert (True<=NextQuad) ;
13697 Assert (False<=NextQuad) ;
13698 f := newBoolFrame () ;
13701 FalseExit := False ;
13702 BooleanOp := TRUE ;
13706 PushAddress (BoolStack, f) ;
13707 Annotate ('<q%1d>|<q%2d>||true quad|false quad')
13712 PopBool - Pops a True and a False exit quad number from the True/False
13716 PROCEDURE PopBool (VAR True, False: CARDINAL) ;
13720 PopBooltok (True, False, tokno)
13725 PushBool - Push a True and a False exit quad numbers onto the
13729 PROCEDURE PushBool (True, False: CARDINAL) ;
13731 PushBooltok (True, False, UnknownTokenNo)
13736 IsBoolean - returns true is the Stack position pos contains a Boolean
13737 Exit. False is returned if an Ident is stored.
13740 PROCEDURE IsBoolean (pos: CARDINAL) : BOOLEAN ;
13745 f := PeepAddress(BoolStack, pos) ;
13746 RETURN( f^.BooleanOp )
13751 OperandD - returns possible array dimension associated with the ident
13752 operand stored on the boolean stack.
13755 PROCEDURE OperandD (pos: CARDINAL) : WORD ;
13760 Assert(NOT IsBoolean (pos)) ;
13761 f := PeepAddress(BoolStack, pos) ;
13762 RETURN( f^.Dimension )
13767 OperandA - returns possible array symbol associated with the ident
13768 operand stored on the boolean stack.
13771 PROCEDURE OperandA (pos: CARDINAL) : WORD ;
13776 Assert(NOT IsBoolean (pos)) ;
13777 f := PeepAddress(BoolStack, pos) ;
13778 RETURN( f^.Unbounded )
13783 OperandT - returns the ident operand stored in the true position on the boolean stack.
13786 PROCEDURE OperandT (pos: CARDINAL) : WORD ;
13788 Assert(NOT IsBoolean (pos)) ;
13789 RETURN( OperandTno(pos) )
13794 OperandF - returns the ident operand stored in the false position on the boolean stack.
13797 PROCEDURE OperandF (pos: CARDINAL) : WORD ;
13799 Assert(NOT IsBoolean (pos)) ;
13800 RETURN( OperandFno(pos) )
13805 OperandRW - returns the rw operand stored on the boolean stack.
13808 PROCEDURE OperandRW (pos: CARDINAL) : WORD ;
13813 Assert(NOT IsBoolean (pos)) ;
13814 f := PeepAddress(BoolStack, pos) ;
13815 RETURN( f^.ReadWrite )
13820 OperandMergeRW - returns the rw operand if not NulSym else it
13824 PROCEDURE OperandMergeRW (pos: CARDINAL) : WORD ;
13826 IF OperandRW (pos) = NulSym
13828 RETURN OperandT (pos)
13830 RETURN OperandRW (pos)
13832 END OperandMergeRW ;
13836 OperandTok - returns the token associated with pos, on the stack.
13839 PROCEDURE OperandTok (pos: CARDINAL) : WORD ;
13841 Assert (NOT IsBoolean (pos)) ;
13842 RETURN OperandTtok (pos)
13847 BuildCodeOn - generates a quadruple declaring that code should be
13848 emmitted from henceforth.
13850 The Stack is unnaffected.
13853 PROCEDURE BuildCodeOn ;
13855 GenQuad(CodeOnOp, NulSym, NulSym, NulSym)
13860 BuildCodeOff - generates a quadruple declaring that code should not be
13861 emmitted from henceforth.
13863 The Stack is unnaffected.
13866 PROCEDURE BuildCodeOff ;
13868 GenQuad(CodeOffOp, NulSym, NulSym, NulSym)
13873 BuildProfileOn - generates a quadruple declaring that profile timings
13874 should be emmitted from henceforth.
13876 The Stack is unnaffected.
13879 PROCEDURE BuildProfileOn ;
13881 GenQuad(ProfileOnOp, NulSym, NulSym, NulSym)
13882 END BuildProfileOn ;
13886 BuildProfileOn - generates a quadruple declaring that profile timings
13887 should be emmitted from henceforth.
13889 The Stack is unnaffected.
13892 PROCEDURE BuildProfileOff ;
13894 GenQuad(ProfileOffOp, NulSym, NulSym, NulSym)
13895 END BuildProfileOff ;
13899 BuildOptimizeOn - generates a quadruple declaring that optimization
13900 should occur from henceforth.
13902 The Stack is unnaffected.
13905 PROCEDURE BuildOptimizeOn ;
13907 GenQuad(OptimizeOnOp, NulSym, NulSym, NulSym)
13908 END BuildOptimizeOn ;
13912 BuildOptimizeOff - generates a quadruple declaring that optimization
13913 should not occur from henceforth.
13915 The Stack is unnaffected.
13918 PROCEDURE BuildOptimizeOff ;
13920 GenQuad(OptimizeOffOp, NulSym, NulSym, NulSym)
13921 END BuildOptimizeOff ;
13925 BuildInline - builds an Inline pseudo quadruple operator.
13926 The inline interface, Sym, is stored as the operand
13927 to the operator InlineOp.
13929 The stack is expected to contain:
13941 PROCEDURE BuildInline ;
13946 GenQuad(InlineOp, NulSym, NulSym, Sym)
13951 BuildLineNo - builds a LineNumberOp pseudo quadruple operator.
13952 This quadruple indicates which source line has been
13953 processed, these quadruples are only generated if we
13954 are producing runtime debugging information.
13956 The stack is not affected, read or altered in any way.
13965 PROCEDURE BuildLineNo ;
13970 IF (NextQuad#Head) AND (GenerateLineDebug OR GenerateDebugging) AND FALSE
13972 filename := makekey(string(GetFileName())) ;
13973 f := GetQF(NextQuad-1) ;
13974 IF NOT ((f^.Operator=LineNumberOp) AND (f^.Operand1=WORD(filename)))
13976 GenQuad(LineNumberOp, WORD(filename), NulSym, WORD(GetLineNo()))
13983 UseLineNote - uses the line note and returns it to the free list.
13986 PROCEDURE UseLineNote (l: LineNote) ;
13991 f := GetQF(NextQuad-1) ;
13992 IF (f^.Operator=LineNumberOp) AND (f^.Operand1=WORD(File))
13998 GenQuad(LineNumberOp, WORD(File), NulSym, WORD(Line))
14001 Next := FreeLineList
14008 PopLineNo - pops a line note from the line stack.
14011 PROCEDURE PopLineNo () : LineNote ;
14015 l := PopAddress(LineStack) ;
14018 InternalError ('no line note available')
14025 InitLineNote - creates a line note and initializes it to
14026 contain, file, line.
14029 PROCEDURE InitLineNote (file: Name; line: CARDINAL) : LineNote ;
14033 IF FreeLineList=NIL
14037 l := FreeLineList ;
14038 FreeLineList := FreeLineList^.Next
14052 PROCEDURE PushLineNote (l: LineNote) ;
14054 PushAddress(LineStack, l)
14059 PushLineNo - pushes the current file and line number to the stack.
14062 PROCEDURE PushLineNo ;
14064 PushLineNote(InitLineNote(makekey(string(GetFileName())), GetLineNo()))
14069 BuildStmtNote - builds a StatementNoteOp pseudo quadruple operator.
14070 This quadruple indicates which source line has been
14071 processed and it represents the start of a statement
14073 It differs from LineNumberOp in that multiple successive
14074 LineNumberOps will be removed and the final one is attached to
14075 the next real GCC tree. Whereas a StatementNoteOp is always left
14076 alone. Depending upon the debugging level it will issue a nop
14077 instruction to ensure that the gdb single step will step into
14078 this line. Practically it allows pedalogical debugging to
14079 occur when there is syntax sugar such as:
14085 a := 1 ; (* step *)
14090 The stack is not affected, read or altered in any way.
14099 PROCEDURE BuildStmtNote (offset: INTEGER) ;
14107 f := GetQF (NextQuad-1) ;
14109 INC (i, GetTokenNo ()) ;
14110 (* no need to have multiple notes at the same position. *)
14111 IF (f^.Operator # StatementNoteOp) OR (f^.Operand3 # VAL (CARDINAL, i))
14113 filename := makekey (string (GetFileName ())) ;
14114 GenQuad (StatementNoteOp, WORD (filename), NulSym, i)
14117 END BuildStmtNote ;
14121 AddRecordToList - adds the record held on the top of stack to the
14122 list of records and varient fields.
14125 PROCEDURE AddRecordToList ;
14131 Assert(IsRecord(r) OR IsFieldVarient(r)) ;
14133 r might be a field varient if the declaration consists of nested
14134 varients. However ISO TSIZE can only utilise record types, we store
14135 a varient field anyway as the next pass would not know whether to
14136 ignore a varient field.
14138 PutItemIntoList (VarientFields, r) ;
14141 n := NoOfItemsInList(VarientFields) ;
14144 printf2('in list: record %d is %d\n', n, r)
14146 printf2('in list: varient field %d is %d\n', n, r)
14149 END AddRecordToList ;
14153 AddVarientToList - adds varient held on the top of stack to the list.
14156 PROCEDURE AddVarientToList ;
14161 Assert(IsVarient(v)) ;
14162 PutItemIntoList(VarientFields, v) ;
14165 n := NoOfItemsInList(VarientFields) ;
14166 printf2('in list: varient %d is %d\n', n, v)
14168 END AddVarientToList ;
14172 AddVarientFieldToList - adds varient field, f, to the list of all varient
14176 PROCEDURE AddVarientFieldToList (f: CARDINAL) ;
14180 Assert(IsFieldVarient(f)) ;
14181 PutItemIntoList(VarientFields, f) ;
14184 n := NoOfItemsInList(VarientFields) ;
14185 printf2('in list: varient field %d is %d\n', n, f)
14187 END AddVarientFieldToList ;
14194 PROCEDURE GetRecordOrField () : CARDINAL ;
14198 INC(VarientFieldNo) ;
14199 f := GetItemFromList(VarientFields, VarientFieldNo) ;
14204 printf2('out list: record %d is %d\n', VarientFieldNo, f)
14206 printf2('out list: varient field %d is %d\n', VarientFieldNo, f)
14210 END GetRecordOrField ;
14214 BeginVarient - begin a varient record.
14217 PROCEDURE BeginVarient ;
14221 r := GetRecordOrField() ;
14222 Assert(IsRecord(r) OR IsFieldVarient(r)) ;
14223 v := GetRecordOrField() ;
14224 Assert(IsVarient(v)) ;
14225 BuildRange(InitCaseBounds(PushCase(r, v)))
14230 EndVarient - end a varient record.
14233 PROCEDURE EndVarient ;
14240 ElseVarient - associate an ELSE clause with a varient record.
14243 PROCEDURE ElseVarient ;
14247 f := GetRecordOrField() ;
14248 Assert(IsFieldVarient(f)) ;
14255 BeginVarientList - begin an ident list containing ranges belonging to a
14259 PROCEDURE BeginVarientList ;
14263 f := GetRecordOrField() ;
14264 Assert(IsFieldVarient(f)) ;
14266 END BeginVarientList ;
14270 EndVarientList - end a range list for a varient field.
14273 PROCEDURE EndVarientList ;
14276 END EndVarientList ;
14280 AddVarientRange - creates a range from the top two contant expressions
14281 on the stack which are recorded with the current
14282 varient field. The stack is unaltered.
14285 PROCEDURE AddVarientRange ;
14291 AddRange(r1, r2, GetTokenNo())
14292 END AddVarientRange ;
14296 AddVarientEquality - adds the contant expression on the top of the stack
14297 to the current varient field being recorded.
14298 The stack is unaltered.
14301 PROCEDURE AddVarientEquality ;
14306 AddRange(r1, NulSym, GetTokenNo())
14307 END AddVarientEquality ;
14311 IncOperandD - increment the dimension number associated with symbol
14312 at, pos, on the boolean stack.
14316 PROCEDURE IncOperandD (pos: CARDINAL) ;
14320 f := PeepAddress(BoolStack, pos) ;
14327 PushTFA - Push True, False, Array, numbers onto the
14328 True/False stack. True and False are assumed to
14329 contain Symbols or Ident etc.
14332 PROCEDURE PushTFA (True, False, Array: WORD) ;
14336 f := newBoolFrame () ;
14339 FalseExit := False ;
14342 PushAddress(BoolStack, f)
14347 PushTFAD - Push True, False, Array, Dim, numbers onto the
14348 True/False stack. True and False are assumed to
14349 contain Symbols or Ident etc.
14352 PROCEDURE PushTFAD (True, False, Array, Dim: WORD) ;
14356 f := newBoolFrame () ;
14359 FalseExit := False ;
14360 Unbounded := Array ;
14363 PushAddress(BoolStack, f)
14368 PushTFADtok - Push True, False, Array, Dim, numbers onto the
14369 True/False stack. True and False are assumed to
14370 contain Symbols or Ident etc.
14373 PROCEDURE PushTFADtok (True, False, Array, Dim: WORD; tokno: CARDINAL) ;
14377 f := newBoolFrame () ;
14380 FalseExit := False ;
14381 Unbounded := Array ;
14385 PushAddress (BoolStack, f)
14390 PushTFADrwtok - Push True, False, Array, Dim, rw, numbers onto the
14391 True/False stack. True and False are assumed to
14392 contain Symbols or Ident etc.
14395 PROCEDURE PushTFADrwtok (True, False, Array, Dim, rw: WORD; Tok: CARDINAL) ;
14399 f := newBoolFrame () ;
14402 FalseExit := False ;
14403 Unbounded := Array ;
14408 PushAddress (BoolStack, f)
14409 END PushTFADrwtok ;
14413 PopTFrwtok - Pop a True and False number from the True/False stack.
14414 True and False are assumed to contain Symbols or Ident etc.
14417 PROCEDURE PopTFrwtok (VAR True, False, rw: WORD; VAR tokno: CARDINAL) ;
14421 f := PopAddress(BoolStack) ;
14424 False := FalseExit ;
14425 Assert(NOT BooleanOp) ;
14434 PushTFrwtok - Push an item onto the stack in the T (true) position,
14435 it is assummed to be a token and its token location is recorded.
14438 PROCEDURE PushTFrwtok (True, False, rw: WORD; tokno: CARDINAL) ;
14442 f := newBoolFrame () ;
14445 FalseExit := False ;
14449 PushAddress(BoolStack, f)
14454 PushTFDtok - Push True, False, Dim, numbers onto the
14455 True/False stack. True and False are assumed to
14456 contain Symbols or Ident etc.
14459 PROCEDURE PushTFDtok (True, False, Dim: WORD; Tok: CARDINAL) ;
14463 f := newBoolFrame () ;
14466 FalseExit := False ;
14470 PushAddress (BoolStack, f)
14475 PopTFDtok - Pop a True, False, Dim number from the True/False stack.
14476 True and False are assumed to contain Symbols or Ident etc.
14479 PROCEDURE PopTFDtok (VAR True, False, Dim: WORD; VAR Tok: CARDINAL) ;
14483 f := PopAddress(BoolStack) ;
14486 False := FalseExit ;
14489 Assert(NOT BooleanOp)
14496 PushTFDrwtok - Push True, False, Dim, numbers onto the
14497 True/False stack. True and False are assumed to
14498 contain Symbols or Ident etc.
14501 PROCEDURE PushTFDrwtok (True, False, Dim, rw: WORD; Tok: CARDINAL) ;
14505 f := newBoolFrame () ;
14508 FalseExit := False ;
14513 PushAddress (BoolStack, f)
14518 PushTFrw - Push a True and False numbers onto the True/False stack.
14519 True and False are assumed to contain Symbols or Ident etc.
14520 It also pushes the higher level symbol which is associated
14521 with the True symbol. Eg record variable or array variable.
14524 PROCEDURE PushTFrw (True, False: WORD; rw: CARDINAL) ;
14528 f := newBoolFrame () ;
14531 FalseExit := False ;
14534 PushAddress(BoolStack, f)
14539 PopTFrw - Pop a True and False number from the True/False stack.
14540 True and False are assumed to contain Symbols or Ident etc.
14543 PROCEDURE PopTFrw (VAR True, False, rw: WORD) ;
14547 f := PopAddress(BoolStack) ;
14550 False := FalseExit ;
14551 Assert(NOT BooleanOp) ;
14559 PushTF - Push a True and False numbers onto the True/False stack.
14560 True and False are assumed to contain Symbols or Ident etc.
14563 PROCEDURE PushTF (True, False: WORD) ;
14567 f := newBoolFrame () ;
14572 PushAddress(BoolStack, f)
14577 PopTF - Pop a True and False number from the True/False stack.
14578 True and False are assumed to contain Symbols or Ident etc.
14581 PROCEDURE PopTF (VAR True, False: WORD) ;
14585 f := PopAddress(BoolStack) ;
14588 False := FalseExit ;
14589 Assert(NOT BooleanOp)
14596 newBoolFrame - creates a new BoolFrame with all fields initialised to their defaults.
14599 PROCEDURE newBoolFrame () : BoolFrame ;
14607 Unbounded := NulSym ;
14608 BooleanOp := FALSE ;
14610 ReadWrite := NulSym ;
14612 Annotation := NIL ;
14613 tokenno := UnknownTokenNo
14620 PushTtok - Push an item onto the stack in the T (true) position,
14621 it is assummed to be a token and its token location is recorded.
14624 PROCEDURE PushTtok (True: WORD; tokno: CARDINAL) ;
14628 (* PrintTokenNo (tokno) ; *)
14629 f := newBoolFrame () ;
14634 PushAddress (BoolStack, f)
14639 PushT - Push an item onto the stack in the T (true) position.
14642 PROCEDURE PushT (True: WORD) ;
14646 f := newBoolFrame () ;
14650 PushAddress (BoolStack, f)
14655 PopT - Pops the T value from the stack.
14658 PROCEDURE PopT (VAR True: WORD) ;
14662 f := PopAddress (BoolStack) ;
14665 Assert(NOT BooleanOp)
14672 PopTtok - Pops the T value from the stack and token position.
14675 PROCEDURE PopTtok (VAR True: WORD; VAR tok: CARDINAL) ;
14679 f := PopAddress(BoolStack) ;
14683 Assert(NOT BooleanOp)
14690 PushTrw - Push an item onto the True/False stack. The False value will be zero.
14694 PROCEDURE PushTrw (True: WORD; rw: WORD) ;
14698 f := newBoolFrame () ;
14703 PushAddress(BoolStack, f)
14709 PushTrwtok - Push an item onto the True/False stack. The False value will be zero.
14712 PROCEDURE PushTrwtok (True: WORD; rw: WORD; tok: CARDINAL) ;
14716 f := newBoolFrame () ;
14722 PushAddress(BoolStack, f)
14727 PopTrw - Pop a True field and rw symbol from the stack.
14730 PROCEDURE PopTrw (VAR True, rw: WORD) ;
14734 f := PopAddress(BoolStack) ;
14737 Assert(NOT BooleanOp) ;
14745 PopTrwtok - Pop a True field and rw symbol from the stack.
14748 PROCEDURE PopTrwtok (VAR True, rw: WORD; VAR tok: CARDINAL) ;
14752 f := PopAddress(BoolStack) ;
14755 Assert(NOT BooleanOp) ;
14764 PushTFn - Push a True and False numbers onto the True/False stack.
14765 True and False are assumed to contain Symbols or Ident etc.
14768 PROCEDURE PushTFn (True, False, n: WORD) ;
14772 f := newBoolFrame () ;
14775 FalseExit := False ;
14778 PushAddress(BoolStack, f)
14783 PushTFntok - Push a True and False numbers onto the True/False stack.
14784 True and False are assumed to contain Symbols or Ident etc.
14787 PROCEDURE PushTFntok (True, False, n: WORD; tokno: CARDINAL) ;
14791 f := newBoolFrame () ;
14794 FalseExit := False ;
14798 PushAddress (BoolStack, f)
14803 PopTFn - Pop a True and False number from the True/False stack.
14804 True and False are assumed to contain Symbols or Ident etc.
14807 PROCEDURE PopTFn (VAR True, False, n: WORD) ;
14811 f := PopAddress(BoolStack) ;
14814 False := FalseExit ;
14816 Assert(NOT BooleanOp)
14823 PopNothing - pops the top element on the boolean stack.
14826 PROCEDURE PopNothing ;
14830 f := PopAddress(BoolStack) ;
14836 PopN - pops multiple elements from the BoolStack.
14839 PROCEDURE PopN (n: CARDINAL) ;
14849 PushTFtok - Push an item onto the stack in the T (true) position,
14850 it is assummed to be a token and its token location is recorded.
14853 PROCEDURE PushTFtok (True, False: WORD; tokno: CARDINAL) ;
14857 f := newBoolFrame () ;
14860 FalseExit := False ;
14863 PushAddress(BoolStack, f)
14868 PopTFtok - Pop T/F/tok from the stack.
14871 PROCEDURE PopTFtok (VAR True, False: WORD; VAR tokno: CARDINAL) ;
14875 f := PopAddress(BoolStack) ;
14878 False := FalseExit ;
14885 PushTFAtok - Push T/F/A/tok to the stack.
14888 PROCEDURE PushTFAtok (True, False, Array: WORD; tokno: CARDINAL) ;
14892 f := newBoolFrame () ;
14895 FalseExit := False ;
14896 Unbounded := Array ;
14899 PushAddress(BoolStack, f)
14904 Top - returns the no of items held in the stack.
14907 PROCEDURE Top () : CARDINAL ;
14909 RETURN( NoOfItemsInStackAddress(BoolStack) )
14914 PushAutoOn - push the auto flag and then set it to TRUE.
14915 Any call to ident in the parser will result in the token being pushed.
14918 PROCEDURE PushAutoOn ;
14920 PushWord(AutoStack, IsAutoOn) ;
14926 PushAutoOff - push the auto flag and then set it to FALSE.
14929 PROCEDURE PushAutoOff ;
14931 PushWord(AutoStack, IsAutoOn) ;
14937 IsAutoPushOn - returns the value of the current Auto ident push flag.
14940 PROCEDURE IsAutoPushOn () : BOOLEAN ;
14947 PopAuto - restores the previous value of the Auto flag.
14950 PROCEDURE PopAuto ;
14952 IsAutoOn := PopWord(AutoStack)
14957 PushInConstExpression - push the InConstExpression flag and then set it to TRUE.
14960 PROCEDURE PushInConstExpression ;
14962 PushWord(ConstStack, InConstExpression) ;
14963 InConstExpression := TRUE
14964 END PushInConstExpression ;
14968 PopInConstExpression - restores the previous value of the InConstExpression.
14971 PROCEDURE PopInConstExpression ;
14973 InConstExpression := PopWord(ConstStack)
14974 END PopInConstExpression ;
14978 IsInConstExpression - returns the value of the InConstExpression.
14981 PROCEDURE IsInConstExpression () : BOOLEAN ;
14983 RETURN( InConstExpression )
14984 END IsInConstExpression ;
14988 MustCheckOverflow - returns TRUE if the quadruple should test for overflow.
14991 PROCEDURE MustCheckOverflow (q: CARDINAL) : BOOLEAN ;
14996 RETURN( f^.CheckOverflow )
14997 END MustCheckOverflow ;
15005 PROCEDURE StressStack ;
15009 n, i, j: CARDINAL ;
15014 FOR n := 1 TO Maxtries DO
15015 FOR i := n TO 1 BY -1 DO
15018 FOR i := n TO 1 BY -1 DO
15019 Assert(OperandT(i)=i)
15022 Assert(OperandT(i)=i)
15024 FOR i := 1 TO n BY 10 DO
15025 Assert(OperandT(i)=i)
15027 IF (n>1) AND (n MOD 2 = 0)
15029 FOR i := 1 TO n DIV 2 DO
15033 FOR i := n DIV 2 TO 1 BY -1 DO
15047 Init - initialize the M2Quads module, all the stacks, all the lists
15048 and the quads list.
15053 LogicalOrTok := MakeKey('_LOR') ;
15054 LogicalAndTok := MakeKey('_LAND') ;
15055 LogicalXorTok := MakeKey('_LXOR') ;
15056 LogicalDifferenceTok := MakeKey('_LDIFF') ;
15057 QuadArray := InitIndex (1) ;
15059 NewQuad(NextQuad) ;
15060 Assert(NextQuad=1) ;
15061 BoolStack := InitStackAddress() ;
15062 ExitStack := InitStackWord() ;
15063 RepeatStack := InitStackWord() ;
15064 WhileStack := InitStackWord() ;
15065 ForStack := InitStackWord() ;
15066 WithStack := InitStackAddress() ;
15067 ReturnStack := InitStackWord() ;
15068 LineStack := InitStackAddress() ;
15069 PriorityStack := InitStackWord() ;
15070 TryStack := InitStackWord() ;
15071 CatchStack := InitStackWord() ;
15072 ExceptStack := InitStackWord() ;
15073 ConstructorStack := InitStackAddress() ;
15074 ConstStack := InitStackWord() ;
15075 (* StressStack ; *)
15076 SuppressWith := FALSE ;
15079 MustNotCheckBounds := FALSE ;
15081 GrowInitialization := 0 ;
15082 ForInfo := InitIndex (1) ;
15083 QuadrupleGeneration := TRUE ;
15084 BuildingHigh := FALSE ;
15085 BuildingSize := FALSE ;
15086 AutoStack := InitStackWord() ;
15088 InConstExpression := FALSE ;
15089 FreeLineList := NIL ;
15090 InitList(VarientFields) ;
15091 VarientFieldNo := 0 ;