M2.lst 249 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852
  1. Coco/R - Compiler-Compiler V1.53
  2. Released by Pat Terry 17 September 2002
  3. Source file: M2.atg
  4. Grammar Tests:
  5. Deletable symbols:
  6. DeclSeq
  7. Undefined nonterminals: -- none --
  8. Unreachable nonterminals: -- none --
  9. Circular derivations: -- none --
  10. Underivable nonterminals: -- none --
  11. LL(1) conditions:
  12. LL(1) error in ProcTypeSection: ident is the start of several alternatives.
  13. LL(1) error in TypeBlock: "CLASS" is the start & successor of a deletable structure
  14. Listing:
  15. 1 COMPILER M2
  16. 2 (* Step 1 — minimal integer pipeline (m2compiler-V3).
  17. 3 Subset: program MODULE + CONST (literal) + VAR INTEGER +
  18. 4 assignment + integer expressions (+ - * DIV MOD, leading sign,
  19. 5 parens). Fresh QBE backend (QbeGen) to gen_ssa/<Module>.ssa;
  20. 6 assemble with qbe, link with cc.
  21. 7
  22. 8 Test convention: a global VAR ExitCode : INTEGER makes generated
  23. 9 $main return its value as the process exit code, else return 0.
  24. 10
  25. 11 Semantic errors reuse the V1/V2/Test2 family: 200 duplicate,
  26. 12 201 undeclared, 202 module name mismatch, 210 bad assignment,
  27. 13 211 bad arithmetic, 221 not a type, 230 not supported yet,
  28. 14 231 opaque type outside definition.
  29. 15 Scalar-phase TYPEs (named, integer subrange, enum) check fully;
  30. 16 composite forms wait for step 3. Procedure headings (formals,
  31. 17 result, FORWARD) enter scopes now; bodies parse + check with one
  32. 18 230 at END (lowering = step 4).
  33. 19 Statements: assignment, IF/ELSIF/ELSE, WHILE, REPEAT/UNTIL,
  34. 20 LOOP/EXIT (230 outside LOOP), FOR/TO/static-sign-BY, full CASE
  35. 21 (labels, ranges, ELSE; compare-chain), RETURN with 232 checks
  36. 22 (outside proc / value mismatch / missing value). WITH waits for
  37. 23 records (step 3). Boolean connectives are eager (or/and/xor);
  38. 24 relations yield 0/1 via cXXw.
  39. 25 Clarion-form classes (docs/OOP.txt): CLASS decl + single
  40. 26 inheritance + CLASS IMPLEMENTATION blocks, methods with ";"
  41. 27 (per the Table example, not the sketch's ","), VIRTUAL flagged.
  42. 28 Scopes and member checks now; lowering later (one 230 per
  43. 29 class/impl block). Classic identifiers: no underscores, so the
  44. 30 Table example's _names stay lexically out of reach.
  45. 31 Step 3.1 arrays: "ARRAY [lo..hi, ...] OF T" (folded literal
  46. 32 bounds, int/char) and open "ARRAY OF T" formals; index suffixes
  47. 33 with per-level checks (217/218, trap on breach via $abort);
  48. 34 whole-array ":=" with runtime count check + blit; string
  49. 35 literals lower as descriptors (1-char stays CHAR, empty works);
  50. 36 array/string "=" is 213 (no built-in whole comparison).
  51. 37 Step 3.3 sets: multi-word masks (no header, static words) over
  52. 38 bases ≤ 256 values; literals are SET OF [0..255] (222 on
  53. 39 out-of-span); + - * / as or/and/xor-not, IN with span trap,
  54. 40 =/# word-wise (lenient cross-base); CASE labels reject sets.
  55. 41 Step 3.4 records: flat blobs; array fields are pointers to static
  56. 42 descriptors (locked amendment — one layout per type); nested
  57. 43 records inline; static declaration-order offsets; field chains
  58. 44 mix with indexes; WITH pushes fields + bases (215/216);
  59. 45 whole-record deep copy; record/set/class "=" is 213.
  60. 46 Step 3.6 pointers: vars (l), NIL as a real type (FNil — assignment
  61. 47 and =/# work, everything else 210-214/222), ^ deref with sfx
  62. 48 discipline (address flows, load at use; chains compose),
  63. 49 pointer =/# via ceql/cnel (< > etc. are 213), NEW/DISPOSE as
  64. 50 builtin statements via extern malloc/free (recursive skeleton
  65. 51 init; DISPOSE shallow and nils, deviating from Wirth-undefined);
  66. 52 nil-deref is raw (no check). *)
  67. 53
  68. 54 IMPORT SymTab, QbeGen, AST, Lower;
  69. 55
  70. 56 VAR
  71. 57 (* Two-phase frontend (docs/plan-two-phase.md). When TRUE the
  72. 58 productions ALSO build AST nodes alongside the legacy emit path.
  73. 59 Slice 1: the nodes are inert scaffolding — nothing reads them, so
  74. 60 the emitted output is unchanged. *)
  75. 61 twoPhase: BOOLEAN;
  76. 62
  77. 63 (* Result slot for the expression-AST builder (slice 2). Every
  78. 64 Expr/SimExpr/Term/Fact leaves its node here; the combination
  79. 65 productions save it into locals before parsing the next operand.
  80. 66 `astIsLit` in Fact is per-invocation, so a nested Fact cannot make
  81. 67 an outer non-literal Fact look literal. *)
  82. 68 astCur: AST.Node;
  83. 69
  84. 70 (* Actual-argument nodes collected by ActParam for the call being
  85. 71 parsed by ArgList (slice 4). Fact resets the count before the
  86. 72 optional ArgList and then folds the nodes into an NkCall. *)
  87. 73 astNArgs: CARDINAL;
  88. 74 astArgs: ARRAY [0 .. 31] OF AST.Node;
  89. 75
  90. 76 (* Statement-AST result slot (slice 5): the most recently parsed
  91. 77 statement. StatSeq folds these into an NkBlock. *)
  92. 78 astStmt: AST.Node;
  93. 79
  94. 80 (* Declaration-AST result slot (slice 6): the most recently built
  95. 81 declaration; DeclSeq folds these into an NkDeclSeq. *)
  96. 82 astDecl: AST.Node;
  97. 83
  98. 84 (* The local declarations of the most recent Block (a procedure body);
  99. 85 ProcDecl stores them as the proc node's child 2. *)
  100. 86 astBlkDecls: AST.Node;
  101. 87
  102. 88 (* Unit-AST root (slice 7): NkUnit(name, decls, body). *)
  103. 89 astUnit: AST.Node;
  104. 90
  105. 91 (* Test-only: when TRUE the program unit is re-emitted from the AST via
  106. 92 Lower right after the legacy EndModule (before EndUnit closes the
  107. 93 module scope, so Lower can still resolve names). *)
  108. 94 lowerRequested: BOOLEAN;
  109. 95
  110. 96 (* Import accumulator (slice 11): `{ Import }` appends NkImport
  111. 97 nodes here; each unit stores them as NkUnit child[3]. *)
  112. 98 astImp, astImpTail: AST.Node;
  113. 99
  114. 100 (* Class-AST accumulators (slice 13): the class node currently being
  115. 101 parsed and its parent/field/method lists. Classes are not nested
  116. 102 inside one another, so module-level state is safe. *)
  117. 103 astCls, astClsP, astClsPTail, astClsF, astClsFTail,
  118. 104 astClsM, astClsMTail, astMethod: AST.Node;
  119. 105
  120. 106 (* Class of the method named by the last `obj.Method` designator
  121. 107 (InvalidType when the callee is an ordinary procedure). Set by
  122. 108 Design, consumed by the following ArgList. *)
  123. 109 methCls: SymTab.TypeIndex;
  124. 110 (* Class of the type of the innermost `TypeName{...}` brace
  125. 111 constructor (ClSet or ClArray); dispatches BraceElem. *)
  126. 112 braceCls: INTEGER;
  127. 113 (* Module-level VAR declarations whose type was still an unresolved
  128. 114 forward alias at declaration time; emitted once the TYPE block
  129. 115 completes (module scope only). *)
  130. 116 nPendVar: CARDINAL;
  131. 117 pendVarName: ARRAY [0 .. 255] OF SymTab.Name;
  132. 118 pendVarT: ARRAY [0 .. 255] OF SymTab.TypeIndex;
  133. 119 (* Forward module-level variables referenced from a procedure body. *)
  134. 120 nFvarRefs: CARDINAL;
  135. 121 fvarId: ARRAY [0 .. 255] OF INTEGER;
  136. 122 fvarSlot: ARRAY [0 .. 255] OF INTEGER;
  137. 123
  138. 124 PROCEDURE FlushPend;
  139. 125 (* Emit module-level globals whose forward type is now resolved. *)
  140. 126 VAR k: CARDINAL;
  141. 127 BEGIN
  142. 128 k := 0;
  143. 129 WHILE k < nPendVar DO
  144. 130 QbeGen.DeclVar(pendVarName[k], pendVarT[k]);
  145. 131 INC(k)
  146. 132 END;
  147. 133 nPendVar := 0
  148. 134 END FlushPend;
  149. 135
  150. 136 PROCEDURE FwdVarNote (id, slot: INTEGER);
  151. 137 BEGIN
  152. 138 IF nFvarRefs <= HIGH(fvarId) THEN
  153. 139 fvarId[nFvarRefs] := id;
  154. 140 fvarSlot[nFvarRefs] := slot;
  155. 141 INC(nFvarRefs)
  156. 142 END
  157. 143 END FwdVarNote;
  158. 144
  159. 145 PROCEDURE FwdVarFlush;
  160. 146 (* At module end: resolve every forward reference against the declared
  161. 147 names (an unresolved one is 201) and patch its placeholder symbol. *)
  162. 148 VAR k: CARDINAL; nm, g: SymTab.Name; cls: INTEGER; oper: CHAR;
  163. 149 t: SymTab.TypeIndex; ok: BOOLEAN;
  164. 150 BEGIN
  165. 151 k := 0;
  166. 152 WHILE k < nFvarRefs DO
  167. 153 SymTab.FwdVarName(fvarId[k], nm);
  168. 154 IF nm[0] # CHR(0) THEN
  169. 155 IF NOT SymTab.FwdVarResolve(fvarId[k]) THEN
  170. 156 SemError(201)
  171. 157 ELSE
  172. 158 t := SymTab.FwdVarType(fvarId[k]);
  173. 159 cls := SymTab.ClassOf(t);
  174. 160 IF cls = SymTab.ClReal THEN oper := "d"
  175. 161 ELSIF SymTab.IsLongFamily(t) THEN oper := "l"
  176. 162 ELSE oper := "w"
  177. 163 END;
  178. 164 ok := SymTab.GlobalRef(nm, g);
  179. 165 QbeGen.FwdPatch(fvarSlot[k], fvarSlot[k], nm, oper, ok)
  180. 166 END
  181. 167 END;
  182. 168 INC(k)
  183. 169 END;
  184. 170 nFvarRefs := 0
  185. 171 END FwdVarFlush;
  186. 172
  187. 173 PROCEDURE AstCallNode (callee: AST.Node) : AST.Node;
  188. 174 (* Builds NkCall(callee, actuals...) from astArgs/astNArgs. *)
  189. 175 VAR n: AST.Node; j: CARDINAL;
  190. 176 BEGIN
  191. 177 n := AST.MakeNode(AST.NkCall);
  192. 178 AST.SetChild(n, 0, callee);
  193. 179 j := 0;
  194. 180 WHILE (j < astNArgs) AND (AST.NChild(n) < AST.MaxChild) DO
  195. 181 AST.SetChild(n, AST.NChild(n), astArgs[j]); INC(j)
  196. 182 END;
  197. 183 RETURN n
  198. 184 END AstCallNode;
  199. 185
  200. 186 PROCEDURE AstAppend (kind: INTEGER; VAR head, tail: AST.Node;
  201. 187 item: AST.Node);
  202. 188 (* Appends `item` to a chunked sequence: each node holds up to
  203. 189 AST.MaxChild-1 items; child[MaxChild-1] continues into the next
  204. 190 chunk. Unbounded, so blocks/decl sequences are not capped at 8. *)
  205. 191 VAR n: AST.Node;
  206. 192 BEGIN
  207. 193 IF item = AST.NoNode THEN RETURN END;
  208. 194 IF head = AST.NoNode THEN
  209. 195 head := AST.MakeNode(kind); tail := head
  210. 196 END;
  211. 197 IF AST.NChild(tail) >= AST.MaxChild - 1 THEN
  212. 198 n := AST.MakeNode(kind);
  213. 199 AST.SetChild(tail, AST.MaxChild - 1, n);
  214. 200 tail := n
  215. 201 END;
  216. 202 AST.SetChild(tail, AST.NChild(tail), item)
  217. 203 END AstAppend;
  218. 204
  219. 205 PROCEDURE GetUnit (): AST.Node;
  220. 206 (* The most recently parsed unit's AST root (for the Lower comparison). *)
  221. 207 BEGIN
  222. 208 RETURN astUnit
  223. 209 END GetUnit;
  224. 210
  225. 211 PROCEDURE SetLower (b: BOOLEAN);
  226. 212 (* Enables the test-only Lower re-emit at program-unit end. *)
  227. 213 BEGIN
  228. 214 lowerRequested := b
  229. 215 END SetLower;
  230. 216
  231. 217 CHARACTERS
  232. 218 eol = CHR(13) .
  233. 219 lf = CHR(10) .
  234. 220 letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" .
  235. 221 digit = "0123456789" .
  236. 222 hexDigit = digit + "ABCDEFabcdef" .
  237. 223 noQuote1 = ANY - "'" - eol .
  238. 224 noQuote2 = ANY - '"' - eol .
  239. 225
  240. 226 IGNORE CHR(9) .. CHR(13)
  241. 227
  242. 228 COMMENTS FROM "(*" TO "*)" NESTED
  243. 229 COMMENTS FROM "//" TO lf
  244. 230
  245. 231 TOKENS
  246. 232 ident = letter { letter | digit | "_" } .
  247. 233 integer = digit { digit }
  248. 234 | digit { digit } CONTEXT("..")
  249. 235 | "0x" hexDigit { hexDigit }
  250. 236 | "0X" hexDigit { hexDigit } .
  251. 237 real = digit { digit } "." { digit }
  252. 238 [ ( "E" | "e" ) [ "+" | "-" ] digit { digit } ] .
  253. 239 string = "'" { noQuote1 } "'"
  254. 240 | '"' { noQuote2 } '"' .
  255. 241 charConst = digit { digit } ( "C" | "c" ) .
  256. 242 ustring = ( "U" | "u" ) ( "'" { noQuote1 } "'" | '"' { noQuote2 } '"' ) .
  257. 243
  258. 244 PRODUCTIONS
  259. 245 M2
  260. 246 = (. AST.Init; twoPhase := TRUE; astCur := AST.NoNode; astStmt := AST.NoNode; astDecl := AST.NoNode; astImp := AST.NoNode; astImpTail := AST.NoNode; Lower.Reset;
  261. 247 astImp := AST.NoNode;
  262. 248 astImpTail := AST.NoNode; .)
  263. 249 Unit "." (. FileIO.WriteString(FileIO.StdOut, "ASTDUMP:"); FileIO.WriteLn(FileIO.StdOut); AST.Dump(astUnit, 0); .) .
  264. 250 (* Units: program modules compile fully; DEFINITION and
  265. 251 IMPLEMENTATION modules parse + check now but lower in step 4
  266. 252 (each ends with one 230); same for nested local modules. *)
  267. 253 Unit
  268. 254 = DefUnit
  269. 255 | ImplUnit
  270. 256 | ProgModule .
  271. 257 (* Step 4.3: one session compiles DEFINITION, its IMPLEMENTATION
  272. 258 and one program (last) into one image. Units share the symbol
  273. 259 table; imports materialize exported names. *)
  274. 260 DefUnit (. VAR m1, m2, pn: SymTab.Name; .)
  275. 261 = "DEFINITION" "MODULE"
  276. 262 GetIdent<m1> (. IF NOT SymTab.BeginDef(m1) THEN
  277. 263 SemError(200) END;
  278. 264 QbeGen.SetModule(m1); .)
  279. 265 ";"
  280. 266 { Import (. AstAppend(AST.NkDeclSeq,
  281. 267 astImp, astImpTail, astDecl); .) }
  282. 268 [ "EXPORT" [ "QUALIFIED" ] (. (* definition-module export
  283. 269 list: parsed, and the
  284. 270 names are already exported
  285. 271 by the module scope *) .)
  286. 272 GetIdent<pn> { "," GetIdent<pn> } ";" ]
  287. 273 { ConstBlock | TypeBlock<TRUE> | VarBlock
  288. 274 | ProcHeading<pn, SymTab.InvalidType> ";"
  289. 275 (. SymTab.CloseProc;
  290. 276 QbeGen.AbortFunc; .) }
  291. 277 (. astUnit := AST.MakeNode(AST.NkUnit);
  292. 278 AST.SetChild(astUnit, 0,
  293. 279 AST.MakeLeaf(AST.NkIdent, m1));
  294. 280 AST.SetChild(astUnit, 1, astDecl);
  295. 281 AST.SetChild(astUnit, 3, astImp);
  296. 282 astDecl := AST.NoNode;
  297. 283 astStmt := AST.NoNode; .)
  298. 284 "END"
  299. 285 GetIdent<m2> (. IF NOT SymTab.Equal(m1, m2) THEN
  300. 286 SemError(202) END;
  301. 287 SymTab.EndUnit; .) .
  302. 288 ImplUnit (. VAR m1, m2: SymTab.Name;
  303. 289 k: CARDINAL;
  304. 290 fname: SymTab.Name;
  305. 291 unres: BOOLEAN;
  306. 292 astNode: AST.Node; .)
  307. 293 = "IMPLEMENTATION" "MODULE"
  308. 294 GetIdent<m1> (. IF NOT SymTab.BeginImpl(m1) THEN
  309. 295 SemError(201) END;
  310. 296 astStmt := AST.NoNode;
  311. 297 astDecl := AST.NoNode;
  312. 298 astImp := AST.NoNode;
  313. 299 astImpTail := AST.NoNode;
  314. 300 nPendVar := 0;
  315. 301 QbeGen.SetModule(m1); .)
  316. 302 ";"
  317. 303 { Import (. AstAppend(AST.NkDeclSeq,
  318. 304 astImp, astImpTail, astDecl); .) }
  319. 305 DeclSeq
  320. 306 [ "BEGIN" (. FlushPend;
  321. 307 k := 0;
  322. 308 WHILE k < SymTab.FwdPending() DO
  323. 309 SymTab.FwdInfo(k, fname, unres);
  324. 310 IF unres THEN SemError(201) END;
  325. 311 INC(k)
  326. 312 END;
  327. 313 SymTab.FwdClear;
  328. 314 FwdVarFlush;
  329. 315 QbeGen.BeginInit(m1); .)
  330. 316 [ StatSeq ] (. QbeGen.EndInit; .) ]
  331. 317 "END"
  332. 318 GetIdent<m2> (. FlushPend;
  333. 319 k := 0;
  334. 320 WHILE k < SymTab.FwdPending() DO
  335. 321 SymTab.FwdInfo(k, fname, unres);
  336. 322 IF unres THEN SemError(201) END;
  337. 323 INC(k)
  338. 324 END;
  339. 325 SymTab.FwdClear;
  340. 326 FwdVarFlush;
  341. 327 astNode := AST.MakeNode(AST.NkUnit);
  342. 328 AST.SetChild(astNode, 0,
  343. 329 AST.MakeLeaf(AST.NkIdent, m1));
  344. 330 AST.SetChild(astNode, 1, astDecl);
  345. 331 AST.SetChild(astNode, 2, astStmt);
  346. 332 AST.SetChild(astNode, 3, astImp);
  347. 333 astUnit := astNode;
  348. 334 IF NOT SymTab.Equal(m1, m2) THEN
  349. 335 SemError(202) END;
  350. 336 SymTab.EndUnit; .) .
  351. 337 ProgModule (. VAR m1, m2: SymTab.Name;
  352. 338 k: CARDINAL;
  353. 339 fname: SymTab.Name;
  354. 340 unres: BOOLEAN;
  355. 341 astNode: AST.Node; .)
  356. 342 = "MODULE"
  357. 343 GetIdent<m1> (. IF NOT SymTab.BeginProg(m1) THEN
  358. 344 SemError(200) END;
  359. 345 astStmt := AST.NoNode;
  360. 346 astDecl := AST.NoNode;
  361. 347 astImp := AST.NoNode;
  362. 348 astImpTail := AST.NoNode;
  363. 349 nPendVar := 0;
  364. 350 QbeGen.SetModule(m1); .)
  365. 351 [ Priority ]
  366. 352 ";"
  367. 353 { Import (. AstAppend(AST.NkDeclSeq,
  368. 354 astImp, astImpTail, astDecl); .) }
  369. 355 DeclSeq
  370. 356 [ "BEGIN" (. FlushPend;
  371. 357 k := 0;
  372. 358 WHILE k < SymTab.FwdPending() DO
  373. 359 SymTab.FwdInfo(k, fname, unres);
  374. 360 IF unres THEN SemError(201) END;
  375. 361 INC(k)
  376. 362 END;
  377. 363 SymTab.FwdClear;
  378. 364 FwdVarFlush;
  379. 365 QbeGen.BeginBody; .)
  380. 366 [ StatSeq ] ]
  381. 367 "END"
  382. 368 GetIdent<m2> (. FlushPend;
  383. 369 k := 0;
  384. 370 WHILE k < SymTab.FwdPending() DO
  385. 371 SymTab.FwdInfo(k, fname, unres);
  386. 372 IF unres THEN SemError(201) END;
  387. 373 INC(k)
  388. 374 END;
  389. 375 SymTab.FwdClear;
  390. 376 FwdVarFlush;
  391. 377 IF NOT SymTab.Equal(m1, m2) THEN
  392. 378 SemError(202) END;
  393. 379 astNode := AST.MakeNode(AST.NkUnit);
  394. 380 AST.SetChild(astNode, 0,
  395. 381 AST.MakeLeaf(AST.NkIdent, m1));
  396. 382 AST.SetChild(astNode, 1, astDecl);
  397. 383 AST.SetChild(astNode, 2, astStmt);
  398. 384 AST.SetChild(astNode, 3, astImp);
  399. 385 astUnit := astNode;
  400. 386 QbeGen.EndModule(m1);
  401. 387 IF lowerRequested
  402. 388 AND Lower.CanLower(astNode) THEN
  403. 389 Lower.LowerUnit(astNode)
  404. 390 END;
  405. 391 SymTab.EndUnit; .) .
  406. 392 DeclSeq (. VAR astSeq, astTail: AST.Node; .)
  407. 393 = (. astSeq := AST.NoNode;
  408. 394 astTail := AST.NoNode; .)
  409. 395 { (. astDecl := AST.NoNode; .)
  410. 396 ( ConstBlock | TypeBlock<FALSE> | VarBlock | ProcDecl ";"
  411. 397 | NestedModule ";" | ClassItem ";" )
  412. 398 (. AstAppend(AST.NkDeclSeq,
  413. 399 astSeq, astTail, astDecl); .) }
  414. 400 (. astDecl := astSeq; .) .
  415. 401 (* Local module, Wirth form. Declarations lower like top-level ones
  416. 402 (same QBE module prefix); a BEGIN body becomes an init function
  417. 403 that main calls; the EXPORT list is hoisted into the enclosing
  418. 404 scope at END. *)
  419. 405 NestedModule (. VAR m1, m2: SymTab.Name;
  420. 406 expNames: ARRAY [0 .. 63] OF SymTab.Name;
  421. 407 expCount, k: CARDINAL;
  422. 408 astNode, nImp, nImpTail:
  423. 409 AST.Node; .)
  424. 410 = "MODULE"
  425. 411 GetIdent<m1> (. IF NOT SymTab.Enter(m1,
  426. 412 SymTab.KindModule) THEN
  427. 413 SemError(200) END;
  428. 414 SymTab.PushScope;
  429. 415 expCount := 0;
  430. 416 astNode := AST.MakeNode(AST.NkUnit);
  431. 417 AST.SetChild(astNode, 0,
  432. 418 AST.MakeLeaf(AST.NkIdent, m1));
  433. 419 astStmt := AST.NoNode;
  434. 420 astDecl := AST.NoNode;
  435. 421 nImp := AST.NoNode;
  436. 422 nImpTail := AST.NoNode; .)
  437. 423 [ Priority ]
  438. 424 ";"
  439. 425 { Import (. AstAppend(AST.NkDeclSeq,
  440. 426 nImp, nImpTail, astDecl); .) }
  441. 427 [ "EXPORT" [ "QUALIFIED" ]
  442. 428 GetIdent<expNames[expCount]> (. INC(expCount); .)
  443. 429 { "," GetIdent<expNames[expCount]>
  444. 430 (. INC(expCount); .) }
  445. 431 ";" ]
  446. 432 DeclSeq
  447. 433 [ "BEGIN" (. astStmt := AST.NoNode;
  448. 434 QbeGen.BeginInit(m1); .)
  449. 435 [ StatSeq ] (. QbeGen.EndInit; .) ]
  450. 436 "END"
  451. 437 GetIdent<m2> (. AST.SetChild(astNode, 1, astDecl);
  452. 438 AST.SetChild(astNode, 2, astStmt);
  453. 439 AST.SetChild(astNode, 3, nImp);
  454. 440 astDecl := astNode;
  455. 441 IF NOT SymTab.Equal(m1, m2) THEN
  456. 442 SemError(202) END;
  457. 443 k := 0;
  458. 444 WHILE k < expCount DO
  459. 445 SymTab.ExportUp(expNames[k]);
  460. 446 INC(k)
  461. 447 END;
  462. 448 SymTab.PopScope; .) .
  463. 449 Priority
  464. 450 = "[" integer "]" (. SemError(230); .) .
  465. 451 (* Imports (4.3): FROM materializes the names (unqualified use);
  466. 452 plain IMPORT only demands the module exists — qualified `L.x`
  467. 453 materializes on first use (Design). *)
  468. 454 (* Unknown modules stay unchecked stubs (legacy, so hand-written
  469. 455 import lines don't fail); a known module's missing export is
  470. 456 201. *)
  471. 457 Import (. VAR n: SymTab.Name;
  472. 458 astImport: AST.Node; .)
  473. 459 = "FROM"
  474. 460 GetIdent<n> (. astImport := AST.MakeNode(AST.NkImport);
  475. 461 AST.SetChild(astImport, 0,
  476. 462 AST.MakeLeaf(AST.NkIdent, n)); .)
  477. 463 "IMPORT"
  478. 464 ImpList<n, astImport> ";" (. astDecl := astImport; .)
  479. 465 | "IMPORT" (. astImport := AST.MakeNode(AST.NkImport); .)
  480. 466 ImpModList<astImport> ";" (. astDecl := astImport; .) .
  481. 467 ImpList<mod: SymTab.Name; node: AST.Node>
  482. 468 (. VAR n: SymTab.Name; .)
  483. 469 = ImpName<mod, node>
  484. 470 { "," ImpName<mod, node> } .
  485. 471 (* Pervasive built-ins imported from SYSTEM (e.g. TSIZE) are
  486. 472 accepted and ignored: the built-in applies regardless. *)
  487. 473 ImpName<mod: SymTab.Name; node: AST.Node>
  488. 474 (. VAR n: SymTab.Name; .)
  489. 475 = GetIdent<n> (. AST.SetChild(node, AST.NChild(node),
  490. 476 AST.MakeLeaf(AST.NkIdent, n));
  491. 477 IF SymTab.Equal(mod, "libc") THEN
  492. 478 (* intrinsic C library:
  493. 479 permissive external *)
  494. 480 IF NOT SymTab.DeclareCProc(n) THEN
  495. 481 SemError(201) END
  496. 482 ELSIF SymTab.ModKnown(mod)
  497. 483 AND NOT SymTab.ImportFrom(mod, n) THEN
  498. 484 SemError(201) END; .)
  499. 485 | ( "TSIZE" | "SIZE" | "ADR" | "HIGH" | "LEN"
  500. 486 | "CHR" | "ORD" | "ORDL" | "VAL" | "ABS" | "CAP"
  501. 487 | "UCHR" | "CHR8" | "UORD"
  502. 488 | "INC" | "DEC" ) .
  503. 489 ImpModList<node: AST.Node> (. VAR n: SymTab.Name; .)
  504. 490 = GetIdent<n> (. AST.SetChild(node, AST.NChild(node),
  505. 491 AST.MakeLeaf(AST.NkIdent, n)); .)
  506. 492 { "," GetIdent<n> (. AST.SetChild(node, AST.NChild(node),
  507. 493 AST.MakeLeaf(AST.NkIdent, n)); .) } .
  508. 494 (* Opaque TYPE declarations (definition modules). The targetless
  509. 495 alias resolves to InvalidType until step 4 completes it. *)
  510. 496 (* Scalar-phase TYPEs: named types, integer subranges, enumerations.
  511. 497 Opaque "TYPE T;" needs isDef (definition units); elsewhere 231.
  512. 498 Composite forms (ARRAY/RECORD/SET/POINTER) arrive with step 3. *)
  513. 499 TypeBlock<isDef: BOOLEAN> (. VAR astSeq, astTail: AST.Node; .)
  514. 500 = "TYPE" (. SymTab.BeginTypeBlock;
  515. 501 astSeq := AST.NoNode;
  516. 502 astTail := AST.NoNode; .)
  517. 503 { (. astDecl := AST.NoNode; .)
  518. 504 ( TypeItem<isDef> ";" | ClassItem ";" )
  519. 505 (. AstAppend(AST.NkDeclSeq,
  520. 506 astSeq, astTail, astDecl); .) }
  521. 507 (. SymTab.EndTypeBlock;
  522. 508 astDecl := astSeq; .) .
  523. 509 TypeItem<isDef: BOOLEAN> (. VAR n: SymTab.Name;
  524. 510 t, op: SymTab.TypeIndex;
  525. 511 astNode: AST.Node; .)
  526. 512 = GetIdent<n> (. op := SymTab.OpaqueBase(n);
  527. 513 IF op = SymTab.InvalidType THEN
  528. 514 IF NOT SymTab.Enter(n,
  529. 515 SymTab.KindType) THEN
  530. 516 SemError(200) END
  531. 517 END; .)
  532. 518 ( "=" Type<t, FALSE> (. astNode := AST.MakeNode(AST.NkTypeDecl);
  533. 519 AST.SetChild(astNode, 0,
  534. 520 AST.MakeLeaf(AST.NkIdent, n));
  535. 521 AST.SetTy(astNode, t);
  536. 522 astDecl := astNode;
  537. 523 IF op # SymTab.InvalidType THEN
  538. 524 SymTab.SetTarget(op, t)
  539. 525 ELSE SymTab.SetSymType(n, t)
  540. 526 END; .)
  541. 527 | (. IF op # SymTab.InvalidType THEN
  542. 528 (* stays opaque *)
  543. 529 ELSIF NOT isDef THEN
  544. 530 SemError(231)
  545. 531 ELSE SymTab.SetSymType(n,
  546. 532 SymTab.NewAlias()) END; .) ) .
  547. 533 Type<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
  548. 534 = TypeIdent<t> [ Subrange<t> ] (* anchored subrange: T[lo..hi] *)
  549. 535 | Subrange<t>
  550. 536 | Enum<t>
  551. 537 | ArrayType<t, allowOpen>
  552. 538 | SetType<t>
  553. 539 | RecordType<t>
  554. 540 | PointerType<t>
  555. 541 | ProcType<t> .
  556. 542 PointerType<VAR t: SymTab.TypeIndex> (. VAR base: SymTab.TypeIndex; .)
  557. 543 = "POINTER" "TO" Type<base, FALSE>(. t := SymTab.NewPtr(base); .) .
  558. 544 (* Procedure types (step 8.5): PROCEDURE (params): result. Values
  559. 545 are code pointers; params are collected into the descriptor. *)
  560. 546 ProcType<VAR t: SymTab.TypeIndex> (. VAR res, pt: SymTab.TypeIndex;
  561. 547 isV: BOOLEAN; .)
  562. 548 = "PROCEDURE" (. res := SymTab.InvalidType;
  563. 549 t := SymTab.NewProcType(res); .)
  564. 550 [ "(" [ ProcTypeSection<t> { ";" ProcTypeSection<t> } ] ")" ]
  565. 551 [ ":" TypeIdent<res> (. SymTab.SetProcTypeRes(t, res); .) ] .
  566. 552 ProcTypeSection<t: SymTab.TypeIndex> (. VAR pt: SymTab.TypeIndex;
  567. 553 isV: BOOLEAN;
  568. 554 cnt, k: CARDINAL;
  569. 555 names: ARRAY [0 .. 15] OF SymTab.Name; .)
  570. 556 = (. isV := FALSE; cnt := 0; .)
  571. 557 [ "VAR" (. isV := TRUE; .) ]
  572. 558 ( GetIdent<names[cnt]> (. INC(cnt); .)
  573. 559 { "," GetIdent<names[cnt]> (. INC(cnt); .) }
  574. 560 ( ":" Type<pt, TRUE> (. k := 0;
  575. 561 WHILE k < cnt DO
  576. 562 SymTab.ProcTypeAdd(t, isV, pt);
  577. 563 INC(k)
  578. 564 END; .)
  579. 565 | (. (* type-only parameter list:
  580. 566 each name is a type (GNU
  581. 567 shorthand used by the
  582. 568 Coco/R scanner frame) *)
  583. 569 k := 0;
  584. 570 WHILE k < cnt DO
  585. 571 IF SymTab.Lookup(names[k])
  586. 572 AND ((SymTab.SymKind(names[k]) = SymTab.KindType)
  587. 573 OR (SymTab.SymKind(names[k]) = SymTab.KindPredef)) THEN
  588. 574 pt := SymTab.SymType(names[k])
  589. 575 ELSE SemError(201);
  590. 576 pt := SymTab.InvalidType
  591. 577 END;
  592. 578 SymTab.ProcTypeAdd(t, isV, pt);
  593. 579 INC(k)
  594. 580 END; .) )
  595. 581 | Type<pt, TRUE> (. (* unnamed parameter (PIM):
  596. 582 e.g. PROCEDURE (VAR ARRAY OF REAL) *)
  597. 583 SymTab.ProcTypeAdd(t, isV, pt); .) ) .
  598. 584 (* Arrays: "OF" without bounds is an open formal (allowed only
  599. 585 where allowOpen); "[lo..hi, ...]" nests bounded levels inside
  600. 586 out. Bounds are folded literals (int/char); anything else 230.
  601. 587 Bare-type indices ("ARRAY Color OF") wait for enum ordinals. *)
  602. 588 ArrayType<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
  603. 589 (. VAR elem: SymTab.TypeIndex;
  604. 590 ok: BOOLEAN;
  605. 591 bnds, bndh: ARRAY [0 .. 7] OF INTEGER;
  606. 592 nb, k: CARDINAL;
  607. 593 idx: SymTab.TypeIndex;
  608. 594 ilo, ihi: INTEGER; .)
  609. 595 = "ARRAY"
  610. 596 ( "OF" Type<elem, FALSE> (. IF NOT allowOpen THEN
  611. 597 SemError(230) END;
  612. 598 t := SymTab.NewOpenArray(elem); .)
  613. 599 | TypeIdent<idx> [ Subrange<idx> ]
  614. 600 "OF" Type<elem, FALSE> (. (* index-type array: the index
  615. 601 type's ordinal bounds give the
  616. 602 [lo..hi] pair *)
  617. 603 IF SymTab.TypeBounds(idx, ilo,
  618. 604 ihi)
  619. 605 THEN t := SymTab.NewArrayB(elem,
  620. 606 ilo, ihi)
  621. 607 ELSE SemError(230);
  622. 608 t := SymTab.InvalidType
  623. 609 END; .)
  624. 610 | "[" (. SymTab.BoundBegin; ok := TRUE; .)
  625. 611 BoundPair<ok>
  626. 612 { "," BoundPair<ok> }
  627. 613 "]" (. (* snapshot before the element
  628. 614 type, which reuses the bound
  629. 615 buffer for a nested ARRAY *)
  630. 616 nb := SymTab.BoundCount();
  631. 617 k := 0;
  632. 618 WHILE k < nb DO
  633. 619 bnds[k] := SymTab.BoundLo(k);
  634. 620 bndh[k] := SymTab.BoundHi(k);
  635. 621 INC(k)
  636. 622 END; .)
  637. 623 "OF" Type<elem, FALSE>
  638. 624 (. IF ok THEN
  639. 625 k := nb;
  640. 626 WHILE k > 0 DO
  641. 627 DEC(k);
  642. 628 elem := SymTab.NewArrayB(
  643. 629 elem, bnds[k], bndh[k])
  644. 630 END;
  645. 631 t := elem
  646. 632 ELSE t := SymTab.InvalidType
  647. 633 END; .) ) .
  648. 634 BoundPair<VAR ok: BOOLEAN> (. VAR tlo, thi: SymTab.TypeIndex;
  649. 635 qlo, qhi: QbeGen.QVal;
  650. 636 lo, hi: INTEGER;
  651. 637 cl, cl2: INTEGER; .)
  652. 638 = Expr<tlo, qlo> ".." Expr<thi, qhi>
  653. 639 (. IF (tlo = SymTab.InvalidType)
  654. 640 OR (thi = SymTab.InvalidType) THEN
  655. 641 ok := FALSE
  656. 642 ELSE cl := SymTab.ClassOf(tlo);
  657. 643 cl2 := SymTab.ClassOf(thi);
  658. 644 IF ((cl # SymTab.ClInt)
  659. 645 AND (cl # SymTab.ClChar))
  660. 646 OR ((cl2 # SymTab.ClInt)
  661. 647 AND (cl2 # SymTab.ClChar)) THEN
  662. 648 SemError(230); ok := FALSE
  663. 649 ELSIF NOT SymTab.ConstInt(qlo, lo)
  664. 650 OR NOT SymTab.ConstInt(qhi, hi)
  665. 651 OR (lo > hi) THEN
  666. 652 SemError(230); ok := FALSE
  667. 653 ELSIF NOT SymTab.BoundAdd(lo, hi) THEN
  668. 654 SemError(230); ok := FALSE
  669. 655 END;
  670. 656 END; .) .
  671. 657 (* Sets: multi-word masks over bases ≤ 256 values (bool, char,
  672. 658 bounded subranges; enums wait for ordinals, INTEGER is
  673. 659 unbounded). Literals are SET OF [0..255]; assignment and
  674. 660 comparison across suitable bases are lenient (masks over min
  675. 661 words + zero-check extras), out-of-span literals are 222. *)
  676. 662 SetType<VAR t: SymTab.TypeIndex> (. VAR base: SymTab.TypeIndex;
  677. 663 blo, bhi, bspan: INTEGER;
  678. 664 bcls: INTEGER; .)
  679. 665 = "SET" "OF" Type<base, FALSE>
  680. 666 (. IF base = SymTab.InvalidType THEN
  681. 667 t := SymTab.InvalidType
  682. 668 ELSE bcls :=
  683. 669 SymTab.ClassOf(base);
  684. 670 IF bcls = SymTab.ClBool THEN
  685. 671 blo := 0; bspan := 2
  686. 672 ELSIF bcls = SymTab.ClChar THEN
  687. 673 blo := 0; bspan := 256
  688. 674 ELSIF bcls = SymTab.ClEnum THEN
  689. 675 blo := 0;
  690. 676 bspan := VAL(INTEGER,
  691. 677 SymTab.EnumCount(base))
  692. 678 ELSIF SymTab.SubBounds(base,
  693. 679 blo, bhi) THEN
  694. 680 bspan := bhi - blo + 1
  695. 681 ELSE bspan := 0 END;
  696. 682 IF (bspan <= 0)
  697. 683 OR (bspan > 65536) THEN
  698. 684 SemError(230);
  699. 685 t := SymTab.InvalidType
  700. 686 ELSE t := SymTab.NewSet(base)
  701. 687 END
  702. 688 END; .) .
  703. 689 (* Records: flat blobs; array fields are pointers to static
  704. 690 descriptors (locked amendment), nested records inline. Field
  705. 691 offsets static and declaration-ordered. *)
  706. 692 (* Field list: plain fields and (optionally) one variant part. The
  707. 693 variant part is a `CASE ... END` item; because it starts with the
  708. 694 CASE keyword it is unambiguously distinguishable from a field
  709. 695 (which starts with an identifier). *)
  710. 696 RecordType<VAR t: SymTab.TypeIndex> (. VAR t2: SymTab.TypeIndex;
  711. 697 tagOk: BOOLEAN; .)
  712. 698 = "RECORD" (. t := SymTab.NewRecord(); .)
  713. 699 [ RecItem<t> { ";" [ RecItem<t> ] } ]
  714. 700 "END" .
  715. 701 RecItem<rec: SymTab.TypeIndex> (. VAR tt: SymTab.TypeIndex; .)
  716. 702 = RecField<rec>
  717. 703 | CaseField<rec> (. SymTab.MarkVariant(rec); .) .
  718. 704 (* A variant part: CASE tag : Type OF variants. The layout overlays
  719. 705 every branch from the tag slot (see SymTab.ComputeOffsets). *)
  720. 706 CaseField<rec: SymTab.TypeIndex> (. VAR tagT: SymTab.TypeIndex;
  721. 707 tagN: SymTab.Name; .)
  722. 708 = "CASE" (. SymTab.ResetFields(rec); .)
  723. 709 GetIdent<tagN> (. IF NOT SymTab.FieldPending(rec,
  724. 710 tagN) THEN
  725. 711 SemError(200) END; .)
  726. 712 ":" Type<tagT, FALSE> (. IF (tagT # SymTab.InvalidType)
  727. 713 AND NOT SymTab.IsOrdinal(tagT) THEN
  728. 714 SemError(224)
  729. 715 END;
  730. 716 SymTab.FixPendingF(rec, tagT);
  731. 717 SymTab.SetVariantTag(rec, tagN); .)
  732. 718 "OF"
  733. 719 RecFieldList<rec>
  734. 720 { "|" (. SymTab.ResetFields(rec); .)
  735. 721 RecFieldList<rec> }
  736. 722 "END" .
  737. 723 RecFieldList<rec: SymTab.TypeIndex> (. VAR lt, lq: SymTab.TypeIndex;
  738. 724 lv1, lv2: QbeGen.QVal; .)
  739. 725 = VarLabel<lt, lv1> [ ".." VarLabel<lq, lv2> ] ":"
  740. 726 RecField<rec> { ";" [ RecField<rec> ] } .
  741. 727 (* Variant case label: a constant (or a constant range). Values are
  742. 728 not interpreted (the layout overlays regardless). *)
  743. 729 VarLabel<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  744. 730 (. VAR lname: SymTab.Name; .)
  745. 731 = ( ident (. LexName(lname);
  746. 732 QbeGen.CopyOp("0", q);
  747. 733 t := SymTab.IntType(); .)
  748. 734 | integer (. LexString(lname);
  749. 735 QbeGen.CopyOp("0", q);
  750. 736 t := SymTab.IntType(); .)
  751. 737 | charConst (. LexString(lname);
  752. 738 QbeGen.CopyOp("0", q);
  753. 739 t := SymTab.CharType(); .) ) .
  754. 740 RecField<rec: SymTab.TypeIndex> (. VAR n: SymTab.Name;
  755. 741 t2: SymTab.TypeIndex; .)
  756. 742 = RecIdents<rec> ":" Type<t2, FALSE>(. SymTab.FixPendingF(rec, t2); .) .
  757. 743 RecIdents<rec: SymTab.TypeIndex> (. VAR n: SymTab.Name; .)
  758. 744 = GetIdent<n> (. IF NOT SymTab.FieldPending(rec,
  759. 745 n) THEN
  760. 746 SemError(200) END; .)
  761. 747 { "," GetIdent<n> (. IF NOT SymTab.FieldPending(rec,
  762. 748 n) THEN
  763. 749 SemError(200) END; .) } .
  764. 750 TypeIdent<VAR t: SymTab.TypeIndex> (. VAR n, qid: SymTab.Name;
  765. 751 k: INTEGER;
  766. 752 dotted: BOOLEAN; .)
  767. 753 = GetIdent<n> (. dotted := FALSE;
  768. 754 IF NOT SymTab.Lookup(n) THEN
  769. 755 k := -1;
  770. 756 t := SymTab.ForwardType(n);
  771. 757 IF t = SymTab.InvalidType THEN
  772. 758 SemError(201)
  773. 759 END
  774. 760 ELSE k := SymTab.SymKind(n);
  775. 761 IF (k = SymTab.KindType)
  776. 762 OR (k = SymTab.KindPredef) THEN
  777. 763 t := SymTab.SymType(n)
  778. 764 ELSE t := SymTab.InvalidType
  779. 765 END
  780. 766 END; .)
  781. 767 [ "." GetIdent<qid> (. dotted := TRUE;
  782. 768 IF k = SymTab.KindModule THEN
  783. 769 t := SymTab.QualType(n, qid);
  784. 770 IF t = SymTab.InvalidType THEN
  785. 771 SemError(201)
  786. 772 END
  787. 773 ELSE SemError(221);
  788. 774 t := SymTab.InvalidType
  789. 775 END; .) ]
  790. 776 (. IF NOT dotted THEN
  791. 777 IF (k = SymTab.KindModule)
  792. 778 OR ((k # SymTab.KindType)
  793. 779 AND (k # SymTab.KindPredef)
  794. 780 AND (k # SymTab.KindImport)
  795. 781 AND (k # -1)) THEN
  796. 782 SemError(221)
  797. 783 END
  798. 784 END; .) .
  799. 785 Subrange<VAR t: SymTab.TypeIndex> (. VAR tlo, thi: SymTab.TypeIndex;
  800. 786 qlo, qhi: QbeGen.QVal;
  801. 787 lo, hi: INTEGER; .)
  802. 788 = "[" Expr<tlo, qlo> ".." Expr<thi, qhi>
  803. 789 (. IF (tlo = SymTab.InvalidType)
  804. 790 OR (thi = SymTab.InvalidType) THEN
  805. 791 t := SymTab.InvalidType
  806. 792 ELSIF NOT SymTab.IsOrdinal(tlo)
  807. 793 OR NOT SymTab.IsOrdinal(thi) THEN
  808. 794 SemError(230);
  809. 795 t := SymTab.InvalidType
  810. 796 ELSIF NOT SymTab.ConstInt(qlo, lo)
  811. 797 OR NOT SymTab.ConstInt(qhi, hi)
  812. 798 OR (lo > hi) THEN
  813. 799 SemError(230);
  814. 800 t := SymTab.InvalidType
  815. 801 ELSE t := SymTab.NewSubR(lo, hi)
  816. 802 END; .)
  817. 803 "]" .
  818. 804 Enum<VAR t: SymTab.TypeIndex> (. VAR n: SymTab.Name;
  819. 805 ord: INTEGER;
  820. 806 qv: QbeGen.QVal; .)
  821. 807 = "(" (. t := SymTab.NewEnum();
  822. 808 ord := 0; .)
  823. 809 GetIdent<n> (. IF NOT SymTab.Enter(n,
  824. 810 SymTab.KindConst) THEN
  825. 811 SemError(200) END;
  826. 812 SymTab.SetSymType(n, t);
  827. 813 QbeGen.IntStr(ord, qv);
  828. 814 SymTab.SetSymVal(n, qv);
  829. 815 INC(ord); .)
  830. 816 { "," GetIdent<n> (. IF NOT SymTab.Enter(n,
  831. 817 SymTab.KindConst) THEN
  832. 818 SemError(200) END;
  833. 819 SymTab.SetSymType(n, t);
  834. 820 QbeGen.IntStr(ord, qv);
  835. 821 SymTab.SetSymVal(n, qv);
  836. 822 INC(ord); .) }
  837. 823 ")" (. SymTab.SetEnumCount(t,
  838. 824 VAL(CARDINAL, ord)); .) .
  839. 825 (* Clarion-form classes (docs/OOP.txt): declaration + single
  840. 826 inheritance + IMPLEMENTATION blocks. Scopes and member checks
  841. 827 now; lowering (vtable, dispatch, THIS) later — one 230 per
  842. 828 class/impl block. Methods end with ";" per the Table example
  843. 829 (not "," as in the sketch). No underscores in identifiers. *)
  844. 830 (* Single CLASS item in both loops: separating declaration from
  845. 831 IMPLEMENTATION at the loop level needs 2-token lookahead
  846. 832 (CLASS ident vs CLASS IMPLEMENTATION), which LL(1) cannot do.
  847. 833 The second token decides after CLASS is consumed. A misplaced
  848. 834 CLASS IMPLEMENTATION inside TYPE still parses (harmless: the
  849. 835 whole unit ends 230 until lowering). *)
  850. 836 ClassItem
  851. 837 = "CLASS" ( "IMPLEMENTATION" ClassImplRest | ClassRest ) .
  852. 838 ClassRest (. VAR cn, m2, pn: SymTab.Name;
  853. 839 ct: SymTab.TypeIndex; .)
  854. 840 = GetIdent<cn> (. IF NOT SymTab.Enter(cn,
  855. 841 SymTab.KindType) THEN
  856. 842 SemError(200) END;
  857. 843 ct := SymTab.NewClass();
  858. 844 SymTab.SetSymType(cn, ct);
  859. 845 SymTab.PushClassScope(ct);
  860. 846 astCls := AST.MakeNode(AST.NkClassDecl);
  861. 847 AST.SetChild(astCls, 0,
  862. 848 AST.MakeLeaf(AST.NkIdent, cn));
  863. 849 astClsP := AST.NoNode;
  864. 850 astClsPTail := AST.NoNode;
  865. 851 astClsF := AST.NoNode;
  866. 852 astClsFTail := AST.NoNode;
  867. 853 astClsM := AST.NoNode;
  868. 854 astClsMTail := AST.NoNode; .)
  869. 855 [ Parents<ct> ]
  870. 856 ";"
  871. 857 { ClassField<ct> ";" }
  872. 858 { MethodHeading<pn, SymTab.InvalidType> ";"
  873. 859 (. SymTab.CloseProc;
  874. 860 QbeGen.AbortFunc; .) }
  875. 861 "END"
  876. 862 GetIdent<m2> (. IF NOT SymTab.Equal(cn, m2) THEN
  877. 863 SemError(202) END;
  878. 864 SymTab.LayoutClass(ct);
  879. 865 SymTab.PopScope;
  880. 866 AST.SetChild(astCls, 1, astClsP);
  881. 867 AST.SetChild(astCls, 2, astClsF);
  882. 868 AST.SetChild(astCls, 3, astClsM);
  883. 869 astDecl := astCls; .) .
  884. 870 Parents<ct: SymTab.TypeIndex> (. VAR p: SymTab.Name; .)
  885. 871 = "(" Parent1<ct>
  886. 872 { "," GetIdent<p> (. SemError(230); .) }
  887. 873 ")" .
  888. 874 Parent1<ct: SymTab.TypeIndex> (. VAR p: SymTab.Name;
  889. 875 pt: SymTab.TypeIndex; .)
  890. 876 = GetIdent<p> (. IF NOT SymTab.Lookup(p) THEN
  891. 877 SemError(201)
  892. 878 ELSE pt := SymTab.SymType(p);
  893. 879 IF SymTab.ClassOf(pt) #
  894. 880 SymTab.ClClass THEN
  895. 881 SemError(230)
  896. 882 ELSE SymTab.SetParent(ct, pt)
  897. 883 END
  898. 884 END;
  899. 885 AstAppend(AST.NkFieldDecl,
  900. 886 astClsP, astClsPTail,
  901. 887 AST.MakeLeaf(AST.NkIdent, p)); .) .
  902. 888 ClassField<ct: SymTab.TypeIndex> (. VAR n, rhs: SymTab.Name;
  903. 889 t: SymTab.TypeIndex;
  904. 890 astNode: AST.Node; .)
  905. 891 = GetIdent<n>
  906. 892 ( "=" GetIdent<rhs> (. IF NOT SymTab.Enter(n,
  907. 893 SymTab.KindConst) THEN
  908. 894 SemError(200) END;
  909. 895 astNode := AST.MakeNode(AST.NkConstDecl);
  910. 896 AST.SetChild(astNode, 0,
  911. 897 AST.MakeLeaf(AST.NkIdent, n));
  912. 898 AST.SetChild(astNode, 1,
  913. 899 AST.MakeLeaf(AST.NkIdent, rhs));
  914. 900 AstAppend(AST.NkFieldDecl,
  915. 901 astClsF, astClsFTail, astNode);
  916. 902 IF SymTab.Lookup(rhs) THEN
  917. 903 SymTab.SetSymType(n,
  918. 904 SymTab.SymType(rhs))
  919. 905 END; .)
  920. 906 | (. IF NOT SymTab.FieldPending(ct,
  921. 907 n) THEN
  922. 908 SemError(200) END;
  923. 909 astNode := AST.MakeNode(AST.NkVarDecl);
  924. 910 AST.SetChild(astNode, 0,
  925. 911 AST.MakeLeaf(AST.NkIdent, n)); .)
  926. 912 { "," GetIdent<n> (. IF NOT SymTab.FieldPending(ct,
  927. 913 n) THEN
  928. 914 SemError(200) END;
  929. 915 AST.SetChild(astNode,
  930. 916 AST.NChild(astNode),
  931. 917 AST.MakeLeaf(AST.NkIdent, n)); .) }
  932. 918 ":" Type<t, FALSE> (. SymTab.FixPendingF(ct, t);
  933. 919 AST.SetTy(astNode, t);
  934. 920 AstAppend(AST.NkFieldDecl,
  935. 921 astClsF, astClsFTail, astNode); .) ) .
  936. 922 MethodHeading<VAR pn: SymTab.Name; ct: SymTab.TypeIndex>
  937. 923 (. VAR wantVirt: BOOLEAN; .)
  938. 924 = (. wantVirt := FALSE; .)
  939. 925 [ "VIRTUAL" (. wantVirt := TRUE; .) ]
  940. 926 ProcHeading<pn, ct> (. IF wantVirt THEN
  941. 927 SymTab.MarkVirtual END;
  942. 928 astMethod := AST.MakeNode(AST.NkProcDecl);
  943. 929 AST.SetChild(astMethod, 0,
  944. 930 AST.MakeLeaf(AST.NkIdent, pn));
  945. 931 IF wantVirt THEN
  946. 932 AST.SetOp(astMethod, 3)
  947. 933 ELSE AST.SetOp(astMethod, 0)
  948. 934 END;
  949. 935 AstAppend(AST.NkFieldDecl,
  950. 936 astClsM, astClsMTail, astMethod); .) .
  951. 937 ClassImplRest (. VAR cn, m2: SymTab.Name;
  952. 938 ct: SymTab.TypeIndex; .)
  953. 939 = GetIdent<cn> (. IF NOT SymTab.Lookup(cn) THEN
  954. 940 SemError(201);
  955. 941 ct := SymTab.InvalidType
  956. 942 ELSE ct := SymTab.SymType(cn);
  957. 943 IF SymTab.ClassOf(ct) #
  958. 944 SymTab.ClClass THEN
  959. 945 SemError(230);
  960. 946 ct := SymTab.InvalidType
  961. 947 END
  962. 948 END;
  963. 949 astCls := AST.MakeNode(AST.NkClassDecl);
  964. 950 AST.SetOp(astCls, 1);
  965. 951 AST.SetChild(astCls, 0,
  966. 952 AST.MakeLeaf(AST.NkIdent, cn));
  967. 953 astClsM := AST.NoNode;
  968. 954 astClsMTail := AST.NoNode;
  969. 955 astStmt := AST.NoNode;
  970. 956 IF ct #
  971. 957 SymTab.InvalidType THEN
  972. 958 IF NOT SymTab.PushClassMembers(
  973. 959 ct) THEN
  974. 960 SemError(230) END;
  975. 961 SymTab.PushImplClass(ct)
  976. 962 END; .)
  977. 963 ";" { MethodImpl<ct> ";" }
  978. 964 (. astStmt := AST.NoNode; .)
  979. 965 [ "BEGIN" (. astStmt := AST.MakeNode(AST.NkBlock);
  980. 966 QbeGen.BeginInit(cn); .)
  981. 967 [ StatSeq ] (. QbeGen.EndInit; .) ]
  982. 968 "END"
  983. 969 GetIdent<m2> (. IF NOT SymTab.Equal(cn, m2) THEN
  984. 970 SemError(202) END;
  985. 971 SymTab.PopImplClass;
  986. 972 SymTab.PopScope;
  987. 973 AST.SetChild(astCls, 1, AST.NoNode);
  988. 974 AST.SetChild(astCls, 2, astStmt);
  989. 975 AST.SetChild(astCls, 3, astClsM);
  990. 976 astDecl := astCls; .) .
  991. 977 MethodImpl<ct: SymTab.TypeIndex> (. VAR pn: SymTab.Name;
  992. 978 thisQ: QbeGen.QVal;
  993. 979 methRes: SymTab.TypeIndex; .)
  994. 980 = MethodHeading<pn, ct> ";"
  995. 981 (. IF (ct #
  996. 982 SymTab.InvalidType)
  997. 983 AND NOT SymTab.MethodExists(ct,
  998. 984 pn) THEN
  999. 985 SemError(201) END; .)
  1000. 986 ( "FORWARD" (. AST.SetOp(astMethod, 1);
  1001. 987 SymTab.MarkFwd;
  1002. 988 QbeGen.AbortFunc;
  1003. 989 SymTab.CloseProc; .)
  1004. 990 | (. QbeGen.EndFuncHeader;
  1005. 991 (* bind the receiver: bare
  1006. 992 field names resolve
  1007. 993 against THIS *)
  1008. 994 QbeGen.ThisBase(thisQ);
  1009. 995 QbeGen.PushWith(thisQ); .)
  1010. 996 Block<pn> (. AST.SetChild(astMethod, 1, astStmt);
  1011. 997 QbeGen.PopWith;
  1012. 998 methRes := SymTab.CurRes();
  1013. 999 SymTab.CloseProc;
  1014. 1000 QbeGen.EndFunc(methRes); .) ) .
  1015. 1001 ConstBlock (. VAR astSeq, astTail: AST.Node; .)
  1016. 1002 = "CONST" (. astSeq := AST.NoNode;
  1017. 1003 astTail := AST.NoNode; .)
  1018. 1004 { ConstDecl ";" (. AstAppend(AST.NkDeclSeq,
  1019. 1005 astSeq, astTail, astDecl); .) }
  1020. 1006 (. astDecl := astSeq; .) .
  1021. 1007 ConstDecl (. VAR n: SymTab.Name;
  1022. 1008 t: SymTab.TypeIndex;
  1023. 1009 qv: QbeGen.QVal;
  1024. 1010 cls: INTEGER;
  1025. 1011 astNode: AST.Node; .)
  1026. 1012 = GetIdent<n> (. IF NOT SymTab.Enter(n,
  1027. 1013 SymTab.KindConst) THEN
  1028. 1014 SemError(200) END; .)
  1029. 1015 "="
  1030. 1016 Expr<t, qv> (. astNode := AST.MakeNode(AST.NkConstDecl);
  1031. 1017 AST.SetChild(astNode, 0,
  1032. 1018 AST.MakeLeaf(AST.NkIdent, n));
  1033. 1019 AST.SetChild(astNode, 1, astCur);
  1034. 1020 AST.SetTy(astNode, t);
  1035. 1021 astDecl := astNode;
  1036. 1022 Lower.NoteVar(n, SymTab.KindConst, t);
  1037. 1023 SymTab.SetSymType(n, t);
  1038. 1024 cls := SymTab.ClassOf(t);
  1039. 1025 IF (cls = SymTab.ClArray)
  1040. 1026 OR (cls = SymTab.ClRecord)
  1041. 1027 OR (cls = SymTab.ClClass)
  1042. 1028 OR (cls = SymTab.ClStr)
  1043. 1029 OR (cls = SymTab.ClUStr) THEN
  1044. 1030 (* an aggregate/string
  1045. 1031 constant: qv is its
  1046. 1032 descriptor address; no
  1047. 1033 scalar data *)
  1048. 1034 SymTab.SetSymVal(n, qv)
  1049. 1035 ELSIF NOT QbeGen.IsImm(qv) THEN
  1050. 1036 SemError(230)
  1051. 1037 ELSE
  1052. 1038 SymTab.SetSymVal(n, qv);
  1053. 1039 QbeGen.DeclConst(n, qv, t)
  1054. 1040 END; .) .
  1055. 1041 VarBlock (. VAR astSeq, astTail: AST.Node; .)
  1056. 1042 = "VAR" (. astSeq := AST.NoNode;
  1057. 1043 astTail := AST.NoNode; .)
  1058. 1044 { VarDecl ";" (. AstAppend(AST.NkDeclSeq,
  1059. 1045 astSeq, astTail, astDecl); .) }
  1060. 1046 (. astDecl := astSeq; .) .
  1061. 1047 VarDecl (. VAR nm: SymTab.Name;
  1062. 1048 t: SymTab.TypeIndex;
  1063. 1049 i: CARDINAL;
  1064. 1050 cls: INTEGER;
  1065. 1051 astNode: AST.Node; .)
  1066. 1052 = VarIdents ":"
  1067. 1053 Type<t, FALSE> (. astNode := AST.MakeNode(AST.NkVarDecl);
  1068. 1054 i := 0;
  1069. 1055 WHILE i < SymTab.PendCount() DO
  1070. 1056 SymTab.PendName(i, nm);
  1071. 1057 Lower.NoteVar(nm, SymTab.KindVar, t);
  1072. 1058 AST.SetChild(astNode,
  1073. 1059 AST.NChild(astNode),
  1074. 1060 AST.MakeLeaf(AST.NkIdent, nm));
  1075. 1061 INC(i)
  1076. 1062 END;
  1077. 1063 AST.SetTy(astNode, t);
  1078. 1064 astDecl := astNode;
  1079. 1065 cls := SymTab.ClassOf(t);
  1080. 1066 IF (t # SymTab.InvalidType)
  1081. 1067 AND NOT SymTab.IsUnresolved(t)
  1082. 1068 AND (cls # SymTab.ClInt)
  1083. 1069 AND (cls # SymTab.ClBool)
  1084. 1070 AND (cls # SymTab.ClChar)
  1085. 1071 AND (cls # SymTab.ClReal)
  1086. 1072 AND (cls # SymTab.ClArray)
  1087. 1073 AND (cls # SymTab.ClSet)
  1088. 1074 AND (cls # SymTab.ClRecord)
  1089. 1075 AND (cls # SymTab.ClPtr)
  1090. 1076 AND (cls # SymTab.ClLong)
  1091. 1077 AND (cls # SymTab.ClProc)
  1092. 1078 AND (cls # SymTab.ClUChar)
  1093. 1079 AND (cls # SymTab.ClUStr)
  1094. 1080 AND (cls # SymTab.ClEnum)
  1095. 1081 AND (cls # SymTab.ClClass) THEN
  1096. 1082 SemError(230) END;
  1097. 1083 IF QbeGen.LocFull() THEN
  1098. 1084 SemError(233) END;
  1099. 1085 i := 0;
  1100. 1086 IF SymTab.IsUnresolved(t)
  1101. 1087 AND NOT SymTab.InProc() THEN
  1102. 1088 (* a forward-typed global:
  1103. 1089 defer emission until the
  1104. 1090 TYPE block completes *)
  1105. 1091 WHILE i < SymTab.PendCount() DO
  1106. 1092 SymTab.PendName(i, nm);
  1107. 1093 IF nPendVar <=
  1108. 1094 HIGH(pendVarName) THEN
  1109. 1095 pendVarName[nPendVar] := nm;
  1110. 1096 pendVarT[nPendVar] := t;
  1111. 1097 INC(nPendVar)
  1112. 1098 END;
  1113. 1099 INC(i)
  1114. 1100 END
  1115. 1101 ELSE
  1116. 1102 WHILE i < SymTab.PendCount() DO
  1117. 1103 SymTab.PendName(i, nm);
  1118. 1104 QbeGen.DeclVar(nm, t);
  1119. 1105 INC(i)
  1120. 1106 END
  1121. 1107 END;
  1122. 1108 (* a plain VAR list, not a
  1123. 1109 heading: the signature
  1124. 1110 result is discarded *)
  1125. 1111 IF NOT SymTab.FixPending(t) THEN
  1126. 1112 END; .) .
  1127. 1113 VarIdents (. VAR n: SymTab.Name; .)
  1128. 1114 = GetIdent<n> (. IF NOT SymTab.EnterPending(n,
  1129. 1115 SymTab.KindVar) THEN
  1130. 1116 SemError(200) END; .)
  1131. 1117 { ","
  1132. 1118 GetIdent<n> (. IF NOT SymTab.EnterPending(n,
  1133. 1119 SymTab.KindVar) THEN
  1134. 1120 SemError(200) END; .) } .
  1135. 1121 ParIdents<isV: BOOLEAN> (. VAR n: SymTab.Name; .)
  1136. 1122 = GetIdent<n> (. IF NOT SymTab.EnterParam(n, isV) THEN
  1137. 1123 SemError(200) END; .)
  1138. 1124 { "," GetIdent<n> (. IF NOT SymTab.EnterParam(n, isV) THEN
  1139. 1125 SemError(200) END; .) } .
  1140. 1126 (* Procedure headings enter scopes/params/result and buffer the
  1141. 1127 QBE header; bodies lower to functions (4.1, module level only).
  1142. 1128 FORWARD marks; the body heading re-enters (signature compare
  1143. 1129 deferred). Nested procedures parse + check, lowering = 4.2. *)
  1144. 1130 ProcHeading<VAR pn: SymTab.Name; methCls: SymTab.TypeIndex>
  1145. 1131 (. VAR t: SymTab.TypeIndex;
  1146. 1132 mg: QbeGen.QVal; .)
  1147. 1133 = "PROCEDURE"
  1148. 1134 GetIdent<pn> (. IF methCls #
  1149. 1135 SymTab.InvalidType THEN
  1150. 1136 (* a method: resume the
  1151. 1137 declared symbol (reuse
  1152. 1138 its uid) *)
  1153. 1139 IF NOT SymTab.ResumeMethod(
  1154. 1140 methCls, pn) THEN
  1155. 1141 SemError(200) END
  1156. 1142 ELSIF NOT SymTab.EnterProc(pn) THEN
  1157. 1143 IF NOT SymTab.ReenterProc(pn) THEN
  1158. 1144 IF NOT SymTab.ResumeProc(pn) THEN
  1159. 1145 SemError(200) END
  1160. 1146 END
  1161. 1147 END;
  1162. 1148 Lower.ScopeEnter;
  1163. 1149 Lower.NoteProc(pn,
  1164. 1150 SymTab.ProcUid(pn),
  1165. 1151 SymTab.InvalidType,
  1166. 1152 SymTab.ProcDepthOf(pn),
  1167. 1153 FALSE);
  1168. 1154 IF methCls #
  1169. 1155 SymTab.InvalidType THEN
  1170. 1156 QbeGen.Mangled(pn,
  1171. 1157 SymTab.MethUid(), mg)
  1172. 1158 ELSE
  1173. 1159 QbeGen.Mangled(pn,
  1174. 1160 SymTab.ProcUid(pn), mg)
  1175. 1161 END;
  1176. 1162 QbeGen.BeginFunc(mg);
  1177. 1163 IF methCls #
  1178. 1164 SymTab.InvalidType THEN
  1179. 1165 (* hidden THIS receiver:
  1180. 1166 a VAR param of the
  1181. 1167 class type, pushed as
  1182. 1168 the WITH base *)
  1183. 1169 IF NOT SymTab.EnterThisParam(
  1184. 1170 methCls) THEN
  1185. 1171 SemError(200) END;
  1186. 1172 IF NOT QbeGen.FuncParam(
  1187. 1173 "THIS", TRUE,
  1188. 1174 methCls) THEN
  1189. 1175 SemError(233) END
  1190. 1176 END; .)
  1191. 1177 [ FormalParams ]
  1192. 1178 [ ":" TypeIdent<t> (. IF NOT SymTab.SetProcRes(t) THEN
  1193. 1179 SemError(235) END;
  1194. 1180 Lower.SetProcRes(t);
  1195. 1181 QbeGen.SetFuncRes(t);
  1196. 1182 IF (t #
  1197. 1183 SymTab.InvalidType)
  1198. 1184 AND ((SymTab.ClassOf(t)
  1199. 1185 = SymTab.ClArray)
  1200. 1186 OR (SymTab.ClassOf(t)
  1201. 1187 = SymTab.ClRecord)
  1202. 1188 OR (SymTab.ClassOf(t)
  1203. 1189 = SymTab.ClSet)
  1204. 1190 OR (SymTab.ClassOf(t)
  1205. 1191 = SymTab.ClClass)) THEN
  1206. 1192 SemError(230) END; .) ] .
  1207. 1193 FormalParams
  1208. 1194 = "(" [ ParamSection { ";" ParamSection } ] ")" .
  1209. 1195 ParamSection (. VAR t: SymTab.TypeIndex;
  1210. 1196 nm: SymTab.Name;
  1211. 1197 i: CARDINAL;
  1212. 1198 isV: BOOLEAN; .)
  1213. 1199 = (. isV := FALSE; .)
  1214. 1200 [ "VAR" (. isV := TRUE; .) ]
  1215. 1201 ParIdents<isV> ":" Type<t, TRUE> (. i := 0;
  1216. 1202 WHILE i < SymTab.PendCount() DO
  1217. 1203 SymTab.PendName(i, nm);
  1218. 1204 Lower.NoteParam(nm, t, isV);
  1219. 1205 Lower.NoteVar(nm, SymTab.KindParam, t);
  1220. 1206 (* value open arrays are
  1221. 1207 passed as descriptor
  1222. 1208 addresses (no copy):
  1223. 1209 same representation as
  1224. 1210 VAR formals *)
  1225. 1211 IF NOT QbeGen.FuncParam(nm,
  1226. 1212 isV
  1227. 1213 OR SymTab.IsOpenArray(t),
  1228. 1214 t) THEN
  1229. 1215 SemError(233) END;
  1230. 1216 INC(i)
  1231. 1217 END;
  1232. 1218 IF NOT SymTab.FixPending(t) THEN
  1233. 1219 SemError(235) END; .) .
  1234. 1220 (* Nested procedures lower like top-level ones (4.2): the
  1235. 1221 static link gives them their parent's frame. Methods keep
  1236. 1222 parse-now/230-later. *)
  1237. 1223 ProcDecl (. VAR pn: SymTab.Name;
  1238. 1224 astNode: AST.Node; .)
  1239. 1225 = ProcHeading<pn, SymTab.InvalidType> ";"
  1240. 1226 (. astNode := AST.MakeNode(AST.NkProcDecl);
  1241. 1227 AST.SetOp(astNode, 0);
  1242. 1228 AST.SetChild(astNode, 0,
  1243. 1229 AST.MakeLeaf(AST.NkIdent, pn)); .)
  1244. 1230 ( "FORWARD" (. AST.SetOp(astNode, 1);
  1245. 1231 astDecl := astNode;
  1246. 1232 Lower.ScopeLeave;
  1247. 1233 SymTab.MarkFwd;
  1248. 1234 SymTab.CloseProc;
  1249. 1235 QbeGen.AbortFunc; .)
  1250. 1236 | "EXTERNAL" (. AST.SetOp(astNode, 2);
  1251. 1237 astDecl := astNode;
  1252. 1238 Lower.ScopeLeave;
  1253. 1239 SymTab.MarkExternal("");
  1254. 1240 SymTab.CloseProc;
  1255. 1241 QbeGen.AbortFunc; .)
  1256. 1242 | (. QbeGen.EndFuncHeader; .)
  1257. 1243 Block<pn> (. AST.SetChild(astNode, 1, astStmt);
  1258. 1244 AST.SetChild(astNode, 2, astBlkDecls);
  1259. 1245 astDecl := astNode;
  1260. 1246 Lower.ScopeLeave;
  1261. 1247 SymTab.CloseProc;
  1262. 1248 QbeGen.EndFunc(
  1263. 1249 SymTab.ProcRes(pn)); .) ) .
  1264. 1250 Block<pn: SymTab.Name> (. VAR m2: SymTab.Name; .)
  1265. 1251 = DeclSeq (. astBlkDecls := astDecl;
  1266. 1252 astStmt := AST.NoNode; .)
  1267. 1253 [ "BEGIN"
  1268. 1254 [ StatSeq ] ]
  1269. 1255 "END"
  1270. 1256 GetIdent<m2> (. IF NOT SymTab.Equal(pn, m2) THEN
  1271. 1257 SemError(202) END; .) .
  1272. 1258 StatSeq (. VAR astSeq, astTail: AST.Node; .)
  1273. 1259 = (. astSeq := AST.NoNode;
  1274. 1260 astTail := AST.NoNode; .)
  1275. 1261 Statement (. AstAppend(AST.NkBlock,
  1276. 1262 astSeq, astTail, astStmt); .)
  1277. 1263 { ";" [ Statement (. AstAppend(AST.NkBlock,
  1278. 1264 astSeq, astTail, astStmt); .) ] }
  1279. 1265 (. astStmt := astSeq; .) .
  1280. 1266 (* Trailing/empty statements (`a; ; b`, Coco/R's generated `;;`)
  1281. 1267 are accepted: the statement after ';' is optional. *)
  1282. 1268 Statement (. VAR lx: QbeGen.QVal; .)
  1283. 1269 = (. astStmt := AST.NoNode; .)
  1284. 1270 ( AssOrCall
  1285. 1271 | IfStat
  1286. 1272 | WhileStat
  1287. 1273 | RepeatStat
  1288. 1274 | LoopStat
  1289. 1275 | ForStat
  1290. 1276 | CaseStat
  1291. 1277 | WithStat
  1292. 1278 | ReturnStat
  1293. 1279 | HaltStat
  1294. 1280 | NewStat
  1295. 1281 | DisposeStat
  1296. 1282 | IncDecStat
  1297. 1283 | InclExclStat
  1298. 1284 | "EXIT" (. IF QbeGen.TopLoop(lx) THEN
  1299. 1285 QbeGen.Jmp(lx)
  1300. 1286 ELSE SemError(230) END;
  1301. 1287 astStmt := AST.MakeNode(AST.NkExit); .) ) .
  1302. 1288 (* INCL(set, elem) / EXCL(set, elem): PIM set-element builtins. *)
  1303. 1289 InclExclStat (. VAR at, et2: SymTab.TypeIndex;
  1304. 1290 dk: INTEGER;
  1305. 1291 qd, qe: QbeGen.QVal;
  1306. 1292 qn: SymTab.Name;
  1307. 1293 sfx, isInc: BOOLEAN;
  1308. 1294 astNode, astD: AST.Node; .)
  1309. 1295 = ( "INCL" (. isInc := TRUE; .)
  1310. 1296 | "EXCL" (. isInc := FALSE; .) )
  1311. 1297 "(" Design<at, dk, qd, qn, sfx> (. astD := astCur; .) ","
  1312. 1298 Expr<et2, qe> ")"
  1313. 1299 (. astNode := AST.MakeNode(AST.NkCall);
  1314. 1300 IF isInc THEN
  1315. 1301 AST.SetChild(astNode, 0,
  1316. 1302 AST.MakeLeaf(AST.NkIdent, "INCL"))
  1317. 1303 ELSE AST.SetChild(astNode, 0,
  1318. 1304 AST.MakeLeaf(AST.NkIdent, "EXCL"))
  1319. 1305 END;
  1320. 1306 IF astD # AST.NoNode THEN
  1321. 1307 AST.SetChild(astNode, 1, astD) END;
  1322. 1308 IF astCur # AST.NoNode THEN
  1323. 1309 AST.SetChild(astNode, 2, astCur) END;
  1324. 1310 astStmt := astNode; .)
  1325. 1311 (. IF at = SymTab.InvalidType THEN
  1326. 1312 ELSIF SymTab.ClassOf(at) #
  1327. 1313 SymTab.ClSet THEN
  1328. 1314 SemError(222)
  1329. 1315 ELSE
  1330. 1316 IF isInc THEN
  1331. 1317 QbeGen.SetBit(qd, qe,
  1332. 1318 SymTab.SetBaseLo(at),
  1333. 1319 SymTab.SetCount(at))
  1334. 1320 ELSE
  1335. 1321 QbeGen.SetClearBit(qd, qe,
  1336. 1322 SymTab.SetBaseLo(at),
  1337. 1323 SymTab.SetCount(at))
  1338. 1324 END
  1339. 1325 END; .) .
  1340. 1326 (* INC(v [,step]) / DEC(v [,step]) as builtin statements over an
  1341. 1327 integer designator. *)
  1342. 1328 IncDecStat (. VAR dt, et2: SymTab.TypeIndex;
  1343. 1329 dk: INTEGER;
  1344. 1330 qd, qv, qn2, qstep:
  1345. 1331 QbeGen.QVal;
  1346. 1332 qn: SymTab.Name;
  1347. 1333 sfx, isInc: BOOLEAN;
  1348. 1334 astNode, astD, astStep:
  1349. 1335 AST.Node; .)
  1350. 1336 = (. isInc := TRUE; .)
  1351. 1337 ( "INC" (. isInc := TRUE; .)
  1352. 1338 | "DEC" (. isInc := FALSE; .) )
  1353. 1339 "(" (. QbeGen.CopyOp("1", qstep); astStep := AST.NoNode; .)
  1354. 1340 Design<dt, dk, qd, qn, sfx> (. astD := astCur; .)
  1355. 1341 [ "," Expr<et2, qstep> (. astStep := astCur; .) ]
  1356. 1342 ")" (. astNode := AST.MakeNode(AST.NkCall);
  1357. 1343 IF isInc THEN
  1358. 1344 AST.SetChild(astNode, 0,
  1359. 1345 AST.MakeLeaf(AST.NkIdent, "INC"))
  1360. 1346 ELSE AST.SetChild(astNode, 0,
  1361. 1347 AST.MakeLeaf(AST.NkIdent, "DEC"))
  1362. 1348 END;
  1363. 1349 IF astD # AST.NoNode THEN
  1364. 1350 AST.SetChild(astNode, 1, astD) END;
  1365. 1351 IF astStep # AST.NoNode THEN
  1366. 1352 AST.SetChild(astNode, 2, astStep) END;
  1367. 1353 astStmt := astNode; .) (. IF dt = SymTab.InvalidType THEN
  1368. 1354 ELSIF (dk # SymTab.KindVar)
  1369. 1355 AND (dk # SymTab.KindParam)
  1370. 1356 AND (dk # SymTab.KindField) THEN
  1371. 1357 SemError(210)
  1372. 1358 ELSIF NOT SymTab.IsIntFamily(dt) THEN
  1373. 1359 SemError(211)
  1374. 1360 ELSE
  1375. 1361 IF sfx
  1376. 1362 OR (dk = SymTab.KindField) THEN
  1377. 1363 QbeGen.ElemLoad(qd, dt, qv)
  1378. 1364 ELSE QbeGen.LoadVar(qn,
  1379. 1365 FALSE, qv)
  1380. 1366 END;
  1381. 1367 QbeGen.NewTemp(qn2);
  1382. 1368 IF isInc THEN
  1383. 1369 QbeGen.Op3("add", qn2, qv,
  1384. 1370 qstep, FALSE)
  1385. 1371 ELSE QbeGen.Op3("sub", qn2, qv,
  1386. 1372 qstep, FALSE)
  1387. 1373 END;
  1388. 1374 IF sfx
  1389. 1375 OR (dk = SymTab.KindField) THEN
  1390. 1376 QbeGen.ElemStore(qd, qn2,
  1391. 1377 dt)
  1392. 1378 ELSE QbeGen.StoreVar(qn,
  1393. 1379 qn2, FALSE)
  1394. 1380 END
  1395. 1381 END; .) .
  1396. 1382 (* NEW/DISPOSE as builtin statements (no call syntax until step 4).
  1397. 1383 Targets are pointer designators; DISPOSE nils afterwards (safer
  1398. 1384 than Wirth-undefined; documented). DISPOSE is shallow. *)
  1399. 1385 NewStat (. VAR dt: SymTab.TypeIndex;
  1400. 1386 dk: INTEGER;
  1401. 1387 qd, qm: QbeGen.QVal;
  1402. 1388 qn: SymTab.Name;
  1403. 1389 sfx: BOOLEAN;
  1404. 1390 bt: SymTab.TypeIndex;
  1405. 1391 astNode, astD: AST.Node; .)
  1406. 1392 = "NEW" "(" Design<dt, dk, qd, qn, sfx> (. astD := astCur; .) ")"
  1407. 1393 (. astNode := AST.MakeNode(AST.NkCall);
  1408. 1394 AST.SetChild(astNode, 0,
  1409. 1395 AST.MakeLeaf(AST.NkIdent, "NEW"));
  1410. 1396 IF astD # AST.NoNode THEN
  1411. 1397 AST.SetChild(astNode, 1, astD) END;
  1412. 1398 astStmt := astNode; .)
  1413. 1399 (. IF dt = SymTab.InvalidType THEN
  1414. 1400 ELSIF (dk # SymTab.KindVar)
  1415. 1401 AND (dk # SymTab.KindParam)
  1416. 1402 AND (dk # SymTab.KindField) THEN
  1417. 1403 SemError(210)
  1418. 1404 ELSIF SymTab.ClassOf(dt) #
  1419. 1405 SymTab.ClPtr THEN
  1420. 1406 SemError(219)
  1421. 1407 ELSE bt := SymTab.PtrBase(dt);
  1422. 1408 IF bt #
  1423. 1409 SymTab.InvalidType THEN
  1424. 1410 QbeGen.NewHeap(bt, qm);
  1425. 1411 QbeGen.InitHeap(qm, bt);
  1426. 1412 IF sfx
  1427. 1413 OR (dk =
  1428. 1414 SymTab.KindField) THEN
  1429. 1415 QbeGen.ElemStore(qd, qm,
  1430. 1416 dt)
  1431. 1417 ELSE QbeGen.StorePtr(qn,
  1432. 1418 qm)
  1433. 1419 END
  1434. 1420 END
  1435. 1421 END; .) .
  1436. 1422 DisposeStat (. VAR dt: SymTab.TypeIndex;
  1437. 1423 dk: INTEGER;
  1438. 1424 qd, qv: QbeGen.QVal;
  1439. 1425 qn: SymTab.Name;
  1440. 1426 sfx: BOOLEAN;
  1441. 1427 astNode, astD: AST.Node; .)
  1442. 1428 = "DISPOSE" "(" Design<dt, dk, qd, qn, sfx> (. astD := astCur; .) ")"
  1443. 1429 (. astNode := AST.MakeNode(AST.NkCall);
  1444. 1430 AST.SetChild(astNode, 0,
  1445. 1431 AST.MakeLeaf(AST.NkIdent, "DISPOSE"));
  1446. 1432 IF astD # AST.NoNode THEN
  1447. 1433 AST.SetChild(astNode, 1, astD) END;
  1448. 1434 astStmt := astNode; .)
  1449. 1435 (. IF dt = SymTab.InvalidType THEN
  1450. 1436 ELSIF (dk # SymTab.KindVar)
  1451. 1437 AND (dk # SymTab.KindParam)
  1452. 1438 AND (dk # SymTab.KindField) THEN
  1453. 1439 SemError(210)
  1454. 1440 ELSIF SymTab.ClassOf(dt) #
  1455. 1441 SymTab.ClPtr THEN
  1456. 1442 SemError(219)
  1457. 1443 ELSE
  1458. 1444 IF sfx
  1459. 1445 OR (dk =
  1460. 1446 SymTab.KindField) THEN
  1461. 1447 QbeGen.ElemLoad(qd, dt,
  1462. 1448 qv)
  1463. 1449 ELSE QbeGen.LoadPtr(qn, qv)
  1464. 1450 END;
  1465. 1451 QbeGen.FreeHeap(qv);
  1466. 1452 IF sfx
  1467. 1453 OR (dk =
  1468. 1454 SymTab.KindField) THEN
  1469. 1455 QbeGen.ElemStore(qd, "0",
  1470. 1456 dt)
  1471. 1457 ELSE QbeGen.StorePtr(qn,
  1472. 1458 "0")
  1473. 1459 END
  1474. 1460 END; .) .
  1475. 1461 (* WITH pushes each record's fields (inner wins) plus its base
  1476. 1462 address; field designators resolve through both stacks. *)
  1477. 1463 WithStat (. VAR nW: CARDINAL;
  1478. 1464 astNode: AST.Node; .)
  1479. 1465 = "WITH" (. nW := 0;
  1480. 1466 astNode := AST.MakeNode(AST.NkWith); .)
  1481. 1467 WithItem<nW, astNode> { "," WithItem<nW, astNode> }
  1482. 1468 "DO" (. astStmt := AST.NoNode; .)
  1483. 1469 [ StatSeq ] "END" (. AST.SetChild(astNode,
  1484. 1470 AST.NChild(astNode), astStmt);
  1485. 1471 astStmt := astNode;
  1486. 1472 WHILE nW > 0 DO
  1487. 1473 SymTab.PopScope;
  1488. 1474 QbeGen.PopWith;
  1489. 1475 DEC(nW)
  1490. 1476 END; .) .
  1491. 1477 WithItem<VAR nW: CARDINAL; wnode: AST.Node>
  1492. 1478 (. VAR dt: SymTab.TypeIndex;
  1493. 1479 dk: INTEGER;
  1494. 1480 qd, qe: QbeGen.QVal;
  1495. 1481 qn: SymTab.Name;
  1496. 1482 sfx: BOOLEAN; .)
  1497. 1483 = Design<dt, dk, qd, qn, sfx>
  1498. 1484 (. IF astCur # AST.NoNode THEN
  1499. 1485 AST.SetChild(wnode,
  1500. 1486 AST.NChild(wnode), astCur) END;
  1501. 1487 IF dt = SymTab.InvalidType THEN
  1502. 1488 ELSIF (SymTab.ClassOf(dt) #
  1503. 1489 SymTab.ClRecord)
  1504. 1490 AND (SymTab.ClassOf(dt) #
  1505. 1491 SymTab.ClClass) THEN
  1506. 1492 SemError(215)
  1507. 1493 ELSIF SymTab.PushRecord(dt) THEN
  1508. 1494 QbeGen.PushWith(qd);
  1509. 1495 INC(nW)
  1510. 1496 END; .) .
  1511. 1497 (* Assignment or procedure-statement call (4.1, module level).
  1512. 1498 Bare `P;` is a syntax error; function-as-statement is 233. *)
  1513. 1499 AssOrCall (. VAR dt, et: SymTab.TypeIndex;
  1514. 1500 dk: INTEGER;
  1515. 1501 qd, qe, qt, ql: QbeGen.QVal;
  1516. 1502 qn: SymTab.Name;
  1517. 1503 ct2, res0: SymTab.TypeIndex;
  1518. 1504 q2, mg0: QbeGen.QVal;
  1519. 1505 isR, conv, wconv: BOOLEAN;
  1520. 1506 called, sfx: BOOLEAN;
  1521. 1507 astLhs: AST.Node; .)
  1522. 1508 = Design<dt, dk, qd, qn, sfx>
  1523. 1509 (. astLhs := astCur; astNArgs := 0; .)
  1524. 1510 ( ":="
  1525. 1511 Expr<et, qe> (. astStmt := AST.MakeBin(
  1526. 1512 AST.NkAssign, 0, astLhs, astCur);
  1527. 1513 IF (dt # SymTab.InvalidType)
  1528. 1514 AND (dk # SymTab.KindVar)
  1529. 1515 AND (dk # SymTab.KindParam)
  1530. 1516 AND (dk # SymTab.KindField) THEN
  1531. 1517 SemError(210)
  1532. 1518 ELSIF NOT SymTab.Assignable(et,
  1533. 1519 dt) THEN
  1534. 1520 SemError(210)
  1535. 1521 ELSIF (dt # SymTab.InvalidType)
  1536. 1522 AND (SymTab.ClassOf(dt) =
  1537. 1523 SymTab.ClClass) THEN
  1538. 1524 SemError(230) END;
  1539. 1525 isR := (dt #
  1540. 1526 SymTab.InvalidType)
  1541. 1527 AND (SymTab.ClassOf(dt)
  1542. 1528 = SymTab.ClReal);
  1543. 1529 conv := isR
  1544. 1530 AND SymTab.IsIntFamily(et);
  1545. 1531 wconv := (dt #
  1546. 1532 SymTab.InvalidType)
  1547. 1533 AND SymTab.IsLongFamily(dt)
  1548. 1534 AND SymTab.IsIntFamily(et);
  1549. 1535 IF ((dk = SymTab.KindVar)
  1550. 1536 OR (dk = SymTab.KindParam)
  1551. 1537 OR (dk = SymTab.KindField))
  1552. 1538 AND (dt # SymTab.InvalidType)
  1553. 1539 AND (et # SymTab.InvalidType)
  1554. 1540 AND (SymTab.ClassOf(dt) #
  1555. 1541 SymTab.ClClass) THEN
  1556. 1542 IF sfx
  1557. 1543 OR (dk = SymTab.KindField) THEN
  1558. 1544 IF SymTab.ClassOf(dt) =
  1559. 1545 SymTab.ClArray THEN
  1560. 1546 IF (et # SymTab.InvalidType)
  1561. 1547 AND (SymTab.ClassOf(et) = SymTab.ClUStr)
  1562. 1548 AND SymTab.IsUCharArray(dt) THEN
  1563. 1549 QbeGen.UAssign(qd, qe)
  1564. 1550 ELSIF SymTab.StrCompat(dt,
  1565. 1551 et) THEN
  1566. 1552 QbeGen.StrAssign(qd,
  1567. 1553 qe)
  1568. 1554 ELSE
  1569. 1555 QbeGen.CopyArray(qd,
  1570. 1556 qe, dt)
  1571. 1557 END
  1572. 1558 ELSIF SymTab.ClassOf(dt) =
  1573. 1559 SymTab.ClSet THEN
  1574. 1560 QbeGen.CopySet(qd, qe,
  1575. 1561 SymTab.SetWords(dt),
  1576. 1562 SymTab.SetWords(et))
  1577. 1563 ELSIF SymTab.ClassOf(dt) =
  1578. 1564 SymTab.ClRecord THEN
  1579. 1565 QbeGen.CopyRecord(qd, qe,
  1580. 1566 dt)
  1581. 1567 ELSIF SymTab.IsLongFamily(dt) THEN
  1582. 1568 IF wconv THEN
  1583. 1569 QbeGen.WidenLong(qe, ql);
  1584. 1570 QbeGen.ElemStore(qd, ql,
  1585. 1571 dt)
  1586. 1572 ELSE QbeGen.ElemStore(qd, qe,
  1587. 1573 dt)
  1588. 1574 END
  1589. 1575 ELSIF conv THEN
  1590. 1576 QbeGen.ConvIR(qe, qt);
  1591. 1577 QbeGen.ElemStore(qd, qt,
  1592. 1578 dt)
  1593. 1579 ELSE QbeGen.ElemStore(qd, qe,
  1594. 1580 dt)
  1595. 1581 END
  1596. 1582 ELSIF SymTab.ClassOf(dt) =
  1597. 1583 SymTab.ClArray THEN
  1598. 1584 IF (et # SymTab.InvalidType)
  1599. 1585 AND (SymTab.ClassOf(et) = SymTab.ClUStr)
  1600. 1586 AND SymTab.IsUCharArray(dt) THEN
  1601. 1587 QbeGen.UAssign(qd, qe)
  1602. 1588 ELSIF SymTab.StrCompat(dt,
  1603. 1589 et) THEN
  1604. 1590 QbeGen.StrAssign(qd, qe)
  1605. 1591 ELSE
  1606. 1592 QbeGen.CopyArray(qd, qe,
  1607. 1593 dt)
  1608. 1594 END
  1609. 1595 ELSIF SymTab.ClassOf(dt) =
  1610. 1596 SymTab.ClSet THEN
  1611. 1597 QbeGen.CopySet(qd, qe,
  1612. 1598 SymTab.SetWords(dt),
  1613. 1599 SymTab.SetWords(et))
  1614. 1600 ELSIF SymTab.ClassOf(dt) =
  1615. 1601 SymTab.ClRecord THEN
  1616. 1602 QbeGen.CopyRecord(qd, qe, dt)
  1617. 1603 ELSIF (SymTab.ClassOf(dt) =
  1618. 1604 SymTab.ClPtr)
  1619. 1605 OR (SymTab.ClassOf(dt) =
  1620. 1606 SymTab.ClProc) THEN
  1621. 1607 QbeGen.StorePtr(qn, qe)
  1622. 1608 ELSIF SymTab.IsLongFamily(dt) THEN
  1623. 1609 IF wconv THEN
  1624. 1610 QbeGen.WidenLong(qe, ql);
  1625. 1611 QbeGen.StoreLong(qn, ql)
  1626. 1612 ELSE QbeGen.StoreLong(qn, qe)
  1627. 1613 END
  1628. 1614 ELSIF conv THEN
  1629. 1615 QbeGen.ConvIR(qe, qt);
  1630. 1616 QbeGen.StoreVar(qn, qt, TRUE)
  1631. 1617 ELSE
  1632. 1618 QbeGen.StoreVar(qn, qe, isR)
  1633. 1619 END
  1634. 1620 END; .)
  1635. 1621 | ArgList<qn, dt, qd, FALSE, FALSE, methCls, ct2, q2, called>
  1636. 1622 (. astStmt := AstCallNode(astLhs); .)
  1637. 1623 | (* bare `P;`: proper parameterless
  1638. 1624 procedure call; anything else
  1639. 1625 here is 233 (was a bare syntax
  1640. 1626 error before 4.2) *)
  1641. 1627 (. astStmt := AstCallNode(astLhs);
  1642. 1628 IF (dk = SymTab.KindProc)
  1643. 1629 AND NOT sfx THEN
  1644. 1630 res0 := SymTab.ProcRes(qn);
  1645. 1631 IF res0 #
  1646. 1632 SymTab.InvalidType THEN
  1647. 1633 SemError(233)
  1648. 1634 ELSIF SymTab.ProcNPar(qn) #
  1649. 1635 0 THEN
  1650. 1636 SemError(233)
  1651. 1637 ELSE QbeGen.Mangled(qn,
  1652. 1638 SymTab.ProcUid(qn), mg0);
  1653. 1639 QbeGen.CallBegin(mg0,
  1654. 1640 res0,
  1655. 1641 SymTab.ProcDepthOf(qn),
  1656. 1642 SymTab.IsExternal(qn));
  1657. 1643 QbeGen.CallEnd(FALSE, q2)
  1658. 1644 END
  1659. 1645 ELSE SemError(233)
  1660. 1646 END; .) ) .
  1661. 1647 (* Actual-parameter list shared by statement and expression calls.
  1662. 1648 want selects CallEnd's result handling; t/q carry the call
  1663. 1649 value (statement calls discard). Arity/type failures are 233;
  1664. 1650 evaluation code still emits so the .ssa stays assembleable. *)
  1665. 1651 ArgList<pn: SymTab.Name; pt: SymTab.TypeIndex; callee: QbeGen.QVal;
  1666. 1652 want: BOOLEAN; soft: BOOLEAN; methCls: SymTab.TypeIndex;
  1667. 1653 VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
  1668. 1654 VAR called: BOOLEAN> (. VAR i, np: CARDINAL;
  1669. 1655 vs: INTEGER;
  1670. 1656 res: SymTab.TypeIndex;
  1671. 1657 mg: QbeGen.QVal;
  1672. 1658 ok, ind, isMeth, va: BOOLEAN; .)
  1673. 1659 = "(" (. called := TRUE;
  1674. 1660 ok := TRUE;
  1675. 1661 ind := FALSE;
  1676. 1662 isMeth := methCls #
  1677. 1663 SymTab.InvalidType;
  1678. 1664 IF isMeth THEN
  1679. 1665 (* class method: the
  1680. 1666 receiver is armed.
  1681. 1667 Virtual -> dispatch
  1682. 1668 through the vtable;
  1683. 1669 otherwise a static
  1684. 1670 call. *)
  1685. 1671 res := SymTab.ClassMethodRes(
  1686. 1672 methCls, pn);
  1687. 1673 vs := SymTab.VirtSlot(
  1688. 1674 methCls, pn);
  1689. 1675 IF vs >= 0 THEN
  1690. 1676 QbeGen.VirtCallBegin(
  1691. 1677 callee, vs, res)
  1692. 1678 ELSE
  1693. 1679 QbeGen.Mangled(pn,
  1694. 1680 SymTab.ClassMethodUid(
  1695. 1681 methCls, pn), mg);
  1696. 1682 QbeGen.CallBegin(mg, res, 0,
  1697. 1683 FALSE)
  1698. 1684 END
  1699. 1685 ELSIF SymTab.SymKind(pn) =
  1700. 1686 SymTab.KindProc THEN
  1701. 1687 res := SymTab.ProcRes(pn);
  1702. 1688 QbeGen.Mangled(pn,
  1703. 1689 SymTab.ProcUid(pn), mg);
  1704. 1690 QbeGen.CallBegin(mg, res,
  1705. 1691 SymTab.ProcDepthOf(pn),
  1706. 1692 SymTab.IsExternal(pn))
  1707. 1693 ELSIF (pt # SymTab.InvalidType)
  1708. 1694 AND (SymTab.ClassOf(pt) = SymTab.ClProc) THEN
  1709. 1695 ind := TRUE;
  1710. 1696 res :=
  1711. 1697 SymTab.ProcTypeRes(pt);
  1712. 1698 QbeGen.CallBeginInd(callee,
  1713. 1699 res, FALSE)
  1714. 1700 ELSE SemError(233);
  1715. 1701 ok := FALSE;
  1716. 1702 res := SymTab.InvalidType
  1717. 1703 END;
  1718. 1704 i := 0; .)
  1719. 1705 [ ActParam<pn, pt, ind, methCls, i> (. INC(i); .)
  1720. 1706 { "," ActParam<pn, pt, ind, methCls, i> (. INC(i); .) } ]
  1721. 1707 ")" (. IF ok THEN
  1722. 1708 IF isMeth THEN
  1723. 1709 np := SymTab.ClassMethodNPar(
  1724. 1710 methCls, pn)
  1725. 1711 ELSIF ind THEN
  1726. 1712 np := SymTab.ProcTypeNPar(pt)
  1727. 1713 ELSE np := SymTab.ProcNPar(pn)
  1728. 1714 END;
  1729. 1715 va := (NOT isMeth) AND (NOT ind)
  1730. 1716 AND (SymTab.SymKind(pn) =
  1731. 1717 SymTab.KindProc)
  1732. 1718 AND SymTab.Varargs(pn);
  1733. 1719 IF (i # np) AND NOT va THEN
  1734. 1720 SemError(233); ok := FALSE
  1735. 1721 END
  1736. 1722 END;
  1737. 1723 IF NOT ok THEN
  1738. 1724 t := SymTab.InvalidType;
  1739. 1725 QbeGen.CopyOp("0", q)
  1740. 1726 ELSIF want THEN
  1741. 1727 IF res =
  1742. 1728 SymTab.InvalidType THEN
  1743. 1729 SemError(233);
  1744. 1730 t := SymTab.InvalidType;
  1745. 1731 QbeGen.CopyOp("0", q)
  1746. 1732 ELSE t := res;
  1747. 1733 QbeGen.CallEnd(TRUE, q)
  1748. 1734 END
  1749. 1735 ELSE
  1750. 1736 IF res #
  1751. 1737 SymTab.InvalidType THEN
  1752. 1738 SemError(233)
  1753. 1739 END;
  1754. 1740 t := SymTab.InvalidType;
  1755. 1741 QbeGen.CopyOp("0", q);
  1756. 1742 QbeGen.CallEnd(FALSE, q)
  1757. 1743 END; .) .
  1758. 1744 (* One actual: VAR formals take recorded designator addresses
  1759. 1745 (233 otherwise); value formals take converted expressions. *)
  1760. 1746 ActParam<pn: SymTab.Name; pt: SymTab.TypeIndex; ind: BOOLEAN;
  1761. 1747 methCls: SymTab.TypeIndex; i: CARDINAL>
  1762. 1748 (. VAR at, ft: SymTab.TypeIndex;
  1763. 1749 qe, qa, qt: QbeGen.QVal;
  1764. 1750 isV, conv, va: BOOLEAN;
  1765. 1751 cl: CHAR; .)
  1766. 1752 = Expr<at, qe> (. IF astNArgs <= HIGH(astArgs) THEN
  1767. 1753 astArgs[astNArgs] := astCur;
  1768. 1754 INC(astNArgs)
  1769. 1755 END;
  1770. 1756 va := (NOT ind)
  1771. 1757 AND (methCls =
  1772. 1758 SymTab.InvalidType)
  1773. 1759 AND (SymTab.SymKind(pn) =
  1774. 1760 SymTab.KindProc)
  1775. 1761 AND SymTab.Varargs(pn);
  1776. 1762 IF ind THEN
  1777. 1763 ft :=
  1778. 1764 SymTab.ProcTypeParamType(pt,
  1779. 1765 i);
  1780. 1766 isV :=
  1781. 1767 SymTab.ProcTypeParamIsVar(pt,
  1782. 1768 i)
  1783. 1769 ELSIF methCls #
  1784. 1770 SymTab.InvalidType THEN
  1785. 1771 ft :=
  1786. 1772 SymTab.ClassMethodParamType(
  1787. 1773 methCls, pn, i);
  1788. 1774 isV :=
  1789. 1775 SymTab.ClassMethodParamIsVar(
  1790. 1776 methCls, pn, i)
  1791. 1777 ELSE
  1792. 1778 ft := SymTab.ParamType(pn, i);
  1793. 1779 isV := SymTab.ParamIsVar(pn, i)
  1794. 1780 END;
  1795. 1781 IF (at = SymTab.InvalidType) THEN
  1796. 1782 ELSIF ft = SymTab.InvalidType THEN
  1797. 1783 IF va THEN
  1798. 1784 QbeGen.CArgAdd(qe, at, qa, cl)
  1799. 1785 END
  1800. 1786 ELSIF isV THEN
  1801. 1787 IF (SymTab.ClassOf(at)
  1802. 1788 = SymTab.ClChar)
  1803. 1789 AND (SymTab.ClassOf(ft) = SymTab.ClArray)
  1804. 1790 AND (SymTab.ClassOf(SymTab.ArrayElem(ft))
  1805. 1791 = SymTab.ClChar)
  1806. 1792 AND QbeGen.IsImm(qe) THEN
  1807. 1793 (* 1-char string
  1808. 1794 literal passed to
  1809. 1795 a VAR ARRAY OF CHAR *)
  1810. 1796 QbeGen.DeclCharStr(qe,
  1811. 1797 qa);
  1812. 1798 IF NOT QbeGen.CallArg(qa,
  1813. 1799 "l") THEN
  1814. 1800 SemError(233)
  1815. 1801 END
  1816. 1802 ELSIF NOT QbeGen.AddrOfVal(qe,
  1817. 1803 qa) THEN
  1818. 1804 SemError(233)
  1819. 1805 ELSIF NOT SymTab.VarParamOk(at,
  1820. 1806 ft) THEN
  1821. 1807 SemError(233)
  1822. 1808 ELSIF NOT QbeGen.CallArg(qa,
  1823. 1809 "l") THEN
  1824. 1810 SemError(233)
  1825. 1811 END
  1826. 1812 ELSE
  1827. 1813 IF (SymTab.ClassOf(at)
  1828. 1814 = SymTab.ClChar)
  1829. 1815 AND (SymTab.ClassOf(ft) = SymTab.ClArray)
  1830. 1816 AND (SymTab.ClassOf(SymTab.ArrayElem(ft))
  1831. 1817 = SymTab.ClChar)
  1832. 1818 AND QbeGen.IsImm(qe) THEN
  1833. 1819 (* 1-char string
  1834. 1820 literal passed to
  1835. 1821 ARRAY OF CHAR *)
  1836. 1822 QbeGen.DeclCharStr(qe,
  1837. 1823 qa);
  1838. 1824 IF NOT QbeGen.CallArg(qa,
  1839. 1825 "l") THEN
  1840. 1826 SemError(233)
  1841. 1827 END
  1842. 1828 ELSIF NOT SymTab.Assignable(at,
  1843. 1829 ft) THEN
  1844. 1830 SemError(233)
  1845. 1831 ELSE
  1846. 1832 conv := (SymTab.ClassOf(
  1847. 1833 ft) = SymTab.ClReal)
  1848. 1834 AND SymTab.IsIntFamily(at);
  1849. 1835 IF conv THEN
  1850. 1836 QbeGen.ConvIR(qe, qt);
  1851. 1837 IF NOT QbeGen.CallArg(qt,
  1852. 1838 "d") THEN
  1853. 1839 SemError(233)
  1854. 1840 END
  1855. 1841 ELSIF NOT QbeGen.CallArg(qe,
  1856. 1842 QbeGen.ArgClass(ft)) THEN
  1857. 1843 SemError(233)
  1858. 1844 END
  1859. 1845 END
  1860. 1846 END; .) .
  1861. 1847 IfStat (. VAR t: SymTab.TypeIndex;
  1862. 1848 q, lThen, lElse, lEnd:
  1863. 1849 QbeGen.QVal;
  1864. 1850 hasElse: BOOLEAN;
  1865. 1851 astCond, astIf, astLast,
  1866. 1852 astNode: AST.Node; .)
  1867. 1853 = "IF" (. hasElse := FALSE; .)
  1868. 1854 Expr<t, q> (. astCond := astCur; astStmt := AST.NoNode;
  1869. 1855 IF NOT SymTab.BoolCheck(t) THEN
  1870. 1856 SemError(214) END;
  1871. 1857 QbeGen.NewLabel(lThen);
  1872. 1858 QbeGen.NewLabel(lElse);
  1873. 1859 QbeGen.NewLabel(lEnd);
  1874. 1860 QbeGen.Jnz(q, lThen, lElse);
  1875. 1861 QbeGen.EmitLabel(lThen); .)
  1876. 1862 "THEN" [ StatSeq ] (. astNode := AST.MakeNode(AST.NkIf);
  1877. 1863 AST.SetChild(astNode, 0, astCond);
  1878. 1864 AST.SetChild(astNode, 1, astStmt);
  1879. 1865 astIf := astNode;
  1880. 1866 astLast := astNode;
  1881. 1867 QbeGen.Jmp(lEnd); .)
  1882. 1868 { "ELSIF" (. QbeGen.EmitLabel(lElse);
  1883. 1869 QbeGen.NewLabel(lElse); .)
  1884. 1870 Expr<t, q> (. astCond := astCur; astStmt := AST.NoNode;
  1885. 1871 IF NOT SymTab.BoolCheck(t) THEN
  1886. 1872 SemError(214) END;
  1887. 1873 QbeGen.NewLabel(lThen);
  1888. 1874 QbeGen.Jnz(q, lThen, lElse);
  1889. 1875 QbeGen.EmitLabel(lThen); .)
  1890. 1876 "THEN" [ StatSeq ] (. astNode := AST.MakeNode(AST.NkIf);
  1891. 1877 AST.SetChild(astNode, 0, astCond);
  1892. 1878 AST.SetChild(astNode, 1, astStmt);
  1893. 1879 AST.SetChild(astLast, 2, astNode);
  1894. 1880 astLast := astNode;
  1895. 1881 QbeGen.Jmp(lEnd); .) }
  1896. 1882 [ "ELSE" (. QbeGen.EmitLabel(lElse);
  1897. 1883 hasElse := TRUE;
  1898. 1884 astStmt := AST.NoNode; .)
  1899. 1885 [ StatSeq ] (. AST.SetChild(astLast, 2, astStmt); .) ]
  1900. 1886 "END" (. astStmt := astIf;
  1901. 1887 IF hasElse THEN
  1902. 1888 QbeGen.EmitLabel(lEnd)
  1903. 1889 ELSE QbeGen.EmitLabel(lElse);
  1904. 1890 QbeGen.EmitLabel(lEnd)
  1905. 1891 END; .) .
  1906. 1892 WhileStat (. VAR t: SymTab.TypeIndex;
  1907. 1893 q, lTop, lBody, lEnd:
  1908. 1894 QbeGen.QVal;
  1909. 1895 astCond, astNode: AST.Node; .)
  1910. 1896 = "WHILE" (. astStmt := AST.NoNode;
  1911. 1897 QbeGen.NewLabel(lTop);
  1912. 1898 QbeGen.NewLabel(lBody);
  1913. 1899 QbeGen.NewLabel(lEnd);
  1914. 1900 QbeGen.EmitLabel(lTop); .)
  1915. 1901 Expr<t, q> (. astCond := astCur;
  1916. 1902 IF NOT SymTab.BoolCheck(t) THEN
  1917. 1903 SemError(214) END;
  1918. 1904 QbeGen.Jnz(q, lBody, lEnd);
  1919. 1905 QbeGen.EmitLabel(lBody); .)
  1920. 1906 "DO" [ StatSeq ] (. astNode := AST.MakeNode(AST.NkWhile);
  1921. 1907 AST.SetChild(astNode, 0, astCond);
  1922. 1908 AST.SetChild(astNode, 1, astStmt);
  1923. 1909 astStmt := astNode;
  1924. 1910 QbeGen.Jmp(lTop); .)
  1925. 1911 "END" (. QbeGen.EmitLabel(lEnd); .) .
  1926. 1912 RepeatStat (. VAR t: SymTab.TypeIndex;
  1927. 1913 q, lTop, lEnd: QbeGen.QVal;
  1928. 1914 astCond, astBody, astNode:
  1929. 1915 AST.Node; .)
  1930. 1916 = "REPEAT" (. astStmt := AST.NoNode;
  1931. 1917 QbeGen.NewLabel(lTop);
  1932. 1918 QbeGen.NewLabel(lEnd);
  1933. 1919 QbeGen.EmitLabel(lTop); .)
  1934. 1920 [ StatSeq ] (. astBody := astStmt; .)
  1935. 1921 "UNTIL" Expr<t, q> (. astCond := astCur;
  1936. 1922 astNode := AST.MakeNode(AST.NkRepeat);
  1937. 1923 AST.SetChild(astNode, 0, astBody);
  1938. 1924 AST.SetChild(astNode, 1, astCond);
  1939. 1925 astStmt := astNode;
  1940. 1926 IF NOT SymTab.BoolCheck(t) THEN
  1941. 1927 SemError(214) END;
  1942. 1928 QbeGen.Jnz(q, lEnd, lTop);
  1943. 1929 QbeGen.EmitLabel(lEnd); .) .
  1944. 1930 LoopStat (. VAR lTop, lEnd: QbeGen.QVal; astNode: AST.Node; .)
  1945. 1931 = "LOOP" (. QbeGen.NewLabel(lTop);
  1946. 1932 astStmt := AST.NoNode;
  1947. 1933 QbeGen.NewLabel(lEnd);
  1948. 1934 QbeGen.PushLoop(lEnd);
  1949. 1935 QbeGen.EmitLabel(lTop); .)
  1950. 1936 [ StatSeq ]
  1951. 1937 "END" (. astNode := AST.MakeNode(AST.NkLoop);
  1952. 1938 AST.SetChild(astNode, 0, astStmt);
  1953. 1939 astStmt := astNode;
  1954. 1940 QbeGen.Jmp(lTop);
  1955. 1941 QbeGen.PopLoop;
  1956. 1942 QbeGen.EmitLabel(lEnd); .) .
  1957. 1943 (* FOR with static-sign BY (literal, non-zero; 220 otherwise).
  1958. 1944 Runtime direction would need a compare-select; the literal
  1959. 1945 sign picks cslew/csegew at "DO" time. *)
  1960. 1946 ForStat (. VAR lv: SymTab.Name;
  1961. 1947 tlo, thi, tby:
  1962. 1948 SymTab.TypeIndex;
  1963. 1949 qlo, qhi, qby, qt, qk, qb:
  1964. 1950 QbeGen.QVal;
  1965. 1951 lTop, lBody, lEnd:
  1966. 1952 QbeGen.QVal;
  1967. 1953 by: INTEGER;
  1968. 1954 ok: BOOLEAN;
  1969. 1955 astVar, astLo, astHi, astBy,
  1970. 1956 astNode: AST.Node; .)
  1971. 1957 = "FOR" (. by := 1; .)
  1972. 1958 GetIdent<lv> (. astVar := AST.MakeLeaf(AST.NkIdent, lv);
  1973. 1959 astStmt := AST.NoNode;
  1974. 1960 astBy := AST.NoNode;
  1975. 1961 ok := SymTab.Lookup(lv);
  1976. 1962 IF NOT ok THEN
  1977. 1963 SemError(201)
  1978. 1964 ELSIF (SymTab.SymKind(lv) #
  1979. 1965 SymTab.KindVar)
  1980. 1966 AND (SymTab.SymKind(lv) #
  1981. 1967 SymTab.KindParam) THEN
  1982. 1968 SemError(220); ok := FALSE
  1983. 1969 ELSIF NOT SymTab.IsIntFamily(
  1984. 1970 SymTab.SymType(lv)) THEN
  1985. 1971 SemError(220); ok := FALSE
  1986. 1972 END; .)
  1987. 1973 ":=" Expr<tlo, qlo> (. astLo := astCur;
  1988. 1974 IF NOT SymTab.IsIntFamily(tlo) THEN
  1989. 1975 SemError(220); ok := FALSE
  1990. 1976 END; .)
  1991. 1977 "TO" Expr<thi, qhi> (. astHi := astCur;
  1992. 1978 IF NOT SymTab.IsIntFamily(thi) THEN
  1993. 1979 SemError(220); ok := FALSE
  1994. 1980 END; .)
  1995. 1981 [ "BY" Expr<tby, qby> (. astBy := astCur;
  1996. 1982 IF (tby #
  1997. 1983 SymTab.InvalidType)
  1998. 1984 AND NOT SymTab.IsIntFamily(tby) THEN
  1999. 1985 SemError(220); ok := FALSE
  2000. 1986 END;
  2001. 1987 IF NOT SymTab.ConstInt(qby, by) THEN
  2002. 1988 SemError(230); by := 1
  2003. 1989 ELSIF by = 0 THEN
  2004. 1990 SemError(220); by := 1
  2005. 1991 END; .) ]
  2006. 1992 "DO" (. IF ok THEN
  2007. 1993 QbeGen.StoreVar(lv, qlo,
  2008. 1994 FALSE) END;
  2009. 1995 QbeGen.NewLabel(lTop);
  2010. 1996 QbeGen.NewLabel(lBody);
  2011. 1997 QbeGen.NewLabel(lEnd);
  2012. 1998 QbeGen.EmitLabel(lTop);
  2013. 1999 QbeGen.LoadVar(lv, FALSE, qt);
  2014. 2000 QbeGen.NewTemp(qk);
  2015. 2001 IF by > 0 THEN
  2016. 2002 QbeGen.Op3("cslew", qk,
  2017. 2003 qt, qhi, FALSE)
  2018. 2004 ELSE QbeGen.Op3("csgew", qk,
  2019. 2005 qt, qhi, FALSE)
  2020. 2006 END;
  2021. 2007 QbeGen.Jnz(qk, lBody, lEnd);
  2022. 2008 QbeGen.EmitLabel(lBody); .)
  2023. 2009 [ StatSeq ]
  2024. 2010 "END" (. astNode := AST.MakeNode(AST.NkFor);
  2025. 2011 AST.SetChild(astNode, 0, astVar);
  2026. 2012 AST.SetChild(astNode, 1, astLo);
  2027. 2013 AST.SetChild(astNode, 2, astHi);
  2028. 2014 AST.SetChild(astNode, 3, astBy);
  2029. 2015 AST.SetChild(astNode, 4, astStmt);
  2030. 2016 astStmt := astNode;
  2031. 2017 IF ok THEN
  2032. 2018 QbeGen.LoadVar(lv, FALSE,
  2033. 2019 qt);
  2034. 2020 QbeGen.IntStr(by, qb);
  2035. 2021 QbeGen.NewTemp(qk);
  2036. 2022 QbeGen.Op3("add", qk,
  2037. 2023 qt, qb, FALSE);
  2038. 2024 QbeGen.StoreVar(lv, qk,
  2039. 2025 FALSE) END;
  2040. 2026 QbeGen.Jmp(lTop);
  2041. 2027 QbeGen.EmitLabel(lEnd); .) .
  2042. 2028 CaseStat (. VAR tsel: SymTab.TypeIndex;
  2043. 2029 qsel, lEnd: QbeGen.QVal;
  2044. 2030 arm, astNode: AST.Node; .)
  2045. 2031 = "CASE" Expr<tsel, qsel> (. astNode := AST.MakeNode(AST.NkCase);
  2046. 2032 AST.SetChild(astNode, 0, astCur);
  2047. 2033 QbeGen.NewLabel(lEnd); .)
  2048. 2034 "OF" CaseAlt<tsel, qsel, lEnd, astNode>
  2049. 2035 { "|" CaseAlt<tsel, qsel, lEnd, astNode> }
  2050. 2036 [ "ELSE" (. astStmt := AST.NoNode; .)
  2051. 2037 [ StatSeq ] (. arm := AST.MakeNode(AST.NkCaseArm);
  2052. 2038 AST.SetOp(arm, 1);
  2053. 2039 AST.SetChild(arm, 0, astStmt);
  2054. 2040 AST.SetChild(astNode,
  2055. 2041 AST.NChild(astNode), arm); .) ]
  2056. 2042 "END" (. astStmt := astNode;
  2057. 2043 QbeGen.EmitLabel(lEnd); .) .
  2058. 2044 (* Compare-chain lowering: each alternative ends its match-tests
  2059. 2045 with "jmp lAfter", so the no-match fallthrough skips the body:
  2060. 2046 "cmp; jnz(lBody,lF); lF: ... ; jmp lAfter; lBody: S; jmp lEnd;
  2061. 2047 lAfter:". Falls into the next alternative, ELSE, or END. *)
  2062. 2048 CaseAlt<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
  2063. 2049 lEnd: QbeGen.QVal; cnode: AST.Node>
  2064. 2050 (. VAR lBody, lAfter: QbeGen.QVal;
  2065. 2051 arm: AST.Node; .)
  2066. 2052 = (. arm := AST.MakeNode(AST.NkCaseArm);
  2067. 2053 QbeGen.NewLabel(lBody);
  2068. 2054 QbeGen.NewLabel(lAfter); .)
  2069. 2055 CaseLabel<tsel, qsel, lBody, arm>
  2070. 2056 { "," CaseLabel<tsel, qsel, lBody, arm> }
  2071. 2057 ":" (. astStmt := AST.NoNode;
  2072. 2058 QbeGen.Jmp(lAfter);
  2073. 2059 QbeGen.EmitLabel(lBody); .)
  2074. 2060 [ StatSeq ] (. AST.SetChild(arm, AST.NChild(arm),
  2075. 2061 astStmt);
  2076. 2062 AST.SetChild(cnode,
  2077. 2063 AST.NChild(cnode), arm);
  2078. 2064 QbeGen.Jmp(lEnd);
  2079. 2065 QbeGen.EmitLabel(lAfter); .) .
  2080. 2066 CaseLabel<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
  2081. 2067 lBody: QbeGen.QVal; arm: AST.Node>
  2082. 2068 (. VAR t2, t3: SymTab.TypeIndex;
  2083. 2069 q2, q3, qc, qd, qe:
  2084. 2070 QbeGen.QVal;
  2085. 2071 astLab: AST.Node;
  2086. 2072 lNext: QbeGen.QVal; .)
  2087. 2073 = Expr<t2, q2> (. astLab := astCur;
  2088. 2074 IF (t2 #
  2089. 2075 SymTab.InvalidType)
  2090. 2076 AND (tsel #
  2091. 2077 SymTab.InvalidType)
  2092. 2078 AND ((SymTab.ClassOf(t2) =
  2093. 2079 SymTab.ClSet)
  2094. 2080 OR (SymTab.ClassOf(tsel) =
  2095. 2081 SymTab.ClSet)) THEN
  2096. 2082 SemError(230)
  2097. 2083 ELSIF (t2 #
  2098. 2084 SymTab.InvalidType)
  2099. 2085 AND (tsel #
  2100. 2086 SymTab.InvalidType)
  2101. 2087 AND NOT SymTab.EqCheck(t2,
  2102. 2088 tsel) THEN
  2103. 2089 SemError(213) END;
  2104. 2090 IF NOT QbeGen.IsImm(q2) THEN
  2105. 2091 SemError(230);
  2106. 2092 QbeGen.CopyOp("0", q2)
  2107. 2093 END;
  2108. 2094 QbeGen.NewLabel(lNext);
  2109. 2095 QbeGen.Cmp(SymTab.OpEq,
  2110. 2096 qsel, q2, qc, FALSE);
  2111. 2097 QbeGen.Jnz(qc, lBody, lNext);
  2112. 2098 QbeGen.EmitLabel(lNext); .)
  2113. 2099 [ ".." Expr<t3, q3> (. astLab := AST.MakeBin(
  2114. 2100 AST.NkSubrange, 0, astLab, astCur);
  2115. 2101 IF (t3 #
  2116. 2102 SymTab.InvalidType)
  2117. 2103 AND (tsel #
  2118. 2104 SymTab.InvalidType)
  2119. 2105 AND NOT SymTab.EqCheck(t3,
  2120. 2106 tsel) THEN
  2121. 2107 SemError(213) END;
  2122. 2108 IF NOT QbeGen.IsImm(q3) THEN
  2123. 2109 SemError(230);
  2124. 2110 QbeGen.CopyOp("0", q3)
  2125. 2111 END;
  2126. 2112 QbeGen.Cmp(SymTab.OpGe,
  2127. 2113 qsel, q2, qc, FALSE);
  2128. 2114 QbeGen.Cmp(SymTab.OpLe,
  2129. 2115 qsel, q3, qd, FALSE);
  2130. 2116 QbeGen.NewTemp(qe);
  2131. 2117 QbeGen.Op3("and", qe, qc, qd,
  2132. 2118 FALSE);
  2133. 2119 QbeGen.NewLabel(lNext);
  2134. 2120 QbeGen.Jnz(qe, lBody, lNext);
  2135. 2121 QbeGen.EmitLabel(lNext); .) ]
  2136. 2122 (. AST.SetChild(arm,
  2137. 2123 AST.NChild(arm), astLab); .) .
  2138. 2124 ReturnStat (. VAR t: SymTab.TypeIndex;
  2139. 2125 q, qt: QbeGen.QVal;
  2140. 2126 res: SymTab.TypeIndex;
  2141. 2127 hadE, conv: BOOLEAN;
  2142. 2128 astVal, astNode: AST.Node; .)
  2143. 2129 = "RETURN" (. hadE := FALSE; astStmt := AST.NoNode; .)
  2144. 2130 [ Expr<t, q> (. hadE := TRUE; astVal := astCur; .) ]
  2145. 2131 (. astNode := AST.MakeNode(AST.NkReturn);
  2146. 2132 IF hadE THEN
  2147. 2133 AST.SetChild(astNode, 0, astVal)
  2148. 2134 END;
  2149. 2135 astStmt := astNode;
  2150. 2136 conv := FALSE;
  2151. 2137 IF NOT SymTab.InProc() THEN
  2152. 2138 SemError(232)
  2153. 2139 ELSE res := SymTab.CurRes();
  2154. 2140 IF NOT hadE THEN
  2155. 2141 IF res #
  2156. 2142 SymTab.InvalidType THEN
  2157. 2143 SemError(232)
  2158. 2144 ELSE QbeGen.EmitRet(q,
  2159. 2145 FALSE)
  2160. 2146 END
  2161. 2147 ELSIF (res =
  2162. 2148 SymTab.InvalidType)
  2163. 2149 OR (t #
  2164. 2150 SymTab.InvalidType)
  2165. 2151 AND NOT SymTab.Assignable(t,
  2166. 2152 res) THEN
  2167. 2153 SemError(232)
  2168. 2154 ELSE
  2169. 2155 conv := (SymTab.ClassOf(
  2170. 2156 res) = SymTab.ClReal)
  2171. 2157 AND SymTab.IsIntFamily(t);
  2172. 2158 IF conv THEN
  2173. 2159 QbeGen.ConvIR(q, qt);
  2174. 2160 QbeGen.EmitRet(qt, TRUE)
  2175. 2161 ELSE QbeGen.EmitRet(q, TRUE)
  2176. 2162 END
  2177. 2163 END
  2178. 2164 END; .) .
  2179. 2165 HaltStat (. VAR t: SymTab.TypeIndex;
  2180. 2166 q: QbeGen.QVal;
  2181. 2167 astVal, astNode: AST.Node; .)
  2182. 2168 = "HALT" (. astVal := AST.NoNode; .)
  2183. 2169 [ "(" Expr<t, q> (. astVal := astCur; .) ")" ]
  2184. 2170 (. astNode := AST.MakeNode(AST.NkHalt);
  2185. 2171 IF astVal # AST.NoNode THEN
  2186. 2172 AST.SetChild(astNode, 0, astVal)
  2187. 2173 END;
  2188. 2174 astStmt := astNode;
  2189. 2175 QbeGen.HaltQ; .) .
  2190. 2176 (* Designator: scalar loads, array addresses, and index suffixes.
  2191. 2177 Each index descends one level (bounds-checked, trap on breach);
  2192. 2178 nested levels reload the inner descriptor address. q ends as the
  2193. 2179 value (scalars), the descriptor address (plain arrays), or the
  2194. 2180 element address (indexed); sfx marks the indexed form. *)
  2195. 2181 Design<VAR t: SymTab.TypeIndex; VAR k: INTEGER;
  2196. 2182 VAR q: QbeGen.QVal; VAR qn: SymTab.Name; VAR sfx: BOOLEAN>
  2197. 2183 (. VAR n, fn, mal: SymTab.Name;
  2198. 2184 cls: INTEGER;
  2199. 2185 ic: SymTab.TypeIndex;
  2200. 2186 curT, it, eT, bt:
  2201. 2187 SymTab.TypeIndex;
  2202. 2188 iq, ql, qlo, qhi, qe:
  2203. 2189 QbeGen.QVal;
  2204. 2190 lo, hi: INTEGER;
  2205. 2191 fo: INTEGER;
  2206. 2192 isOpen: BOOLEAN;
  2207. 2193 qb, cv: QbeGen.QVal;
  2208. 2194 fid, fref, slot: INTEGER;
  2209. 2195 r: BOOLEAN;
  2210. 2196 astDes, astSel: AST.Node; .)
  2211. 2197 = GetIdent<n> (. methCls := SymTab.InvalidType;
  2212. 2198 QbeGen.CopyOp(n, qn);
  2213. 2199 sfx := FALSE;
  2214. 2200 fid := 0; fref := 0; slot := 0;
  2215. 2201 IF NOT SymTab.Lookup(n) THEN
  2216. 2202 (* a bare method name inside
  2217. 2203 a CLASS IMPLEMENTATION
  2218. 2204 is a sibling call on
  2219. 2205 THIS *)
  2220. 2206 ic := SymTab.CurImplClass();
  2221. 2207 IF (ic #
  2222. 2208 SymTab.InvalidType)
  2223. 2209 AND SymTab.MethodExists(ic, n) THEN
  2224. 2210 sfx := FALSE;
  2225. 2211 QbeGen.ThisBase(q);
  2226. 2212 QbeGen.ArmRecv(q);
  2227. 2213 methCls := ic;
  2228. 2214 k := SymTab.KindProc;
  2229. 2215 t := SymTab.InvalidType
  2230. 2216 ELSIF SymTab.InProc() THEN
  2231. 2217 (* not declared yet: a
  2232. 2218 forward reference to a
  2233. 2219 module-level variable
  2234. 2220 declared further down. *)
  2235. 2221 k := SymTab.KindVar;
  2236. 2222 r := SymTab.FwdVarRef(n, k,
  2237. 2223 fref, t);
  2238. 2224 slot := QbeGen.FwdDesignator();
  2239. 2225 FwdVarNote(fref, slot);
  2240. 2226 fid := slot;
  2241. 2227 QbeGen.FwdAddrOper(fid, q);
  2242. 2228 sfx := TRUE
  2243. 2229 ELSE
  2244. 2230 SemError(201);
  2245. 2231 t :=
  2246. 2232 SymTab.InvalidType;
  2247. 2233 k := -1;
  2248. 2234 QbeGen.CopyOp("0", q)
  2249. 2235 END
  2250. 2236 ELSE
  2251. 2237 t := SymTab.SymType(n);
  2252. 2238 k := SymTab.SymKind(n);
  2253. 2239 IF k = SymTab.KindConst THEN
  2254. 2240 IF SymTab.Equal(n,
  2255. 2241 "TRUE") THEN
  2256. 2242 t := SymTab.BoolType();
  2257. 2243 QbeGen.CopyOp("1", q)
  2258. 2244 ELSIF SymTab.Equal(n,
  2259. 2245 "FALSE") THEN
  2260. 2246 t := SymTab.BoolType();
  2261. 2247 QbeGen.CopyOp("0", q)
  2262. 2248 ELSIF SymTab.Equal(n,
  2263. 2249 "NIL") THEN
  2264. 2250 QbeGen.CopyOp("0", q)
  2265. 2251 ELSE
  2266. 2252 cls :=
  2267. 2253 SymTab.ClassOf(t);
  2268. 2254 IF (t #
  2269. 2255 SymTab.InvalidType)
  2270. 2256 AND ((cls = SymTab.ClInt)
  2271. 2257 OR (cls
  2272. 2258 = SymTab.ClChar)
  2273. 2259 OR (cls
  2274. 2260 = SymTab.ClEnum)
  2275. 2261 OR (cls
  2276. 2262 = SymTab.ClReal)
  2277. 2263 OR (cls
  2278. 2264 = SymTab.ClLong)
  2279. 2265 OR (cls
  2280. 2266 = SymTab.ClNil)) THEN
  2281. 2267 IF cls = SymTab.ClNil THEN
  2282. 2268 QbeGen.CopyOp("0", q)
  2283. 2269 ELSIF ((cls
  2284. 2270 = SymTab.ClInt)
  2285. 2271 OR (cls
  2286. 2272 = SymTab.ClChar)
  2287. 2273 OR (cls
  2288. 2274 = SymTab.ClEnum)
  2289. 2275 OR (cls
  2290. 2276 = SymTab.ClLong))
  2291. 2277 AND SymTab.GetSymVal(n, cv)
  2292. 2278 AND QbeGen.IsImm(cv) THEN
  2293. 2279 QbeGen.CopyOp(cv, q)
  2294. 2280 ELSE
  2295. 2281 QbeGen.LoadVar(n,
  2296. 2282 cls = SymTab.ClReal,
  2297. 2283 q)
  2298. 2284 END
  2299. 2285 ELSIF (cls = SymTab.ClArray)
  2300. 2286 OR (cls = SymTab.ClRecord)
  2301. 2287 OR (cls = SymTab.ClClass)
  2302. 2288 OR (cls = SymTab.ClStr)
  2303. 2289 OR (cls = SymTab.ClUStr) THEN
  2304. 2290 (* aggregate constant:
  2305. 2291 its value IS the
  2306. 2292 descriptor address *)
  2307. 2293 IF SymTab.GetSymVal(n, cv) THEN
  2308. 2294 QbeGen.CopyOp(cv, q)
  2309. 2295 ELSE
  2310. 2296 QbeGen.CopyOp("0", q)
  2311. 2297 END
  2312. 2298 ELSE
  2313. 2299 IF t #
  2314. 2300 SymTab.InvalidType THEN
  2315. 2301 SemError(230)
  2316. 2302 END;
  2317. 2303 QbeGen.CopyOp("0", q)
  2318. 2304 END
  2319. 2305 END
  2320. 2306 ELSIF (k = SymTab.KindVar)
  2321. 2307 OR (k = SymTab.KindParam) THEN
  2322. 2308 cls :=
  2323. 2309 SymTab.ClassOf(t);
  2324. 2310 IF (cls = SymTab.ClInt)
  2325. 2311 OR (cls = SymTab.ClBool)
  2326. 2312 OR (cls = SymTab.ClChar)
  2327. 2313 OR (cls = SymTab.ClUChar)
  2328. 2314 OR (cls = SymTab.ClEnum)
  2329. 2315 OR (cls
  2330. 2316 = SymTab.ClReal) THEN
  2331. 2317 QbeGen.LoadVar(n,
  2332. 2318 cls = SymTab.ClReal, q)
  2333. 2319 ELSIF (cls = SymTab.ClPtr)
  2334. 2320 OR (cls = SymTab.ClProc) THEN
  2335. 2321 QbeGen.LoadPtr(n, q)
  2336. 2322 ELSIF cls = SymTab.ClLong THEN
  2337. 2323 QbeGen.LoadLong(n, q)
  2338. 2324 ELSIF (cls
  2339. 2325 = SymTab.ClArray)
  2340. 2326 OR (cls
  2341. 2327 = SymTab.ClSet)
  2342. 2328 OR (cls
  2343. 2329 = SymTab.ClRecord)
  2344. 2330 OR (cls
  2345. 2331 = SymTab.ClUStr)
  2346. 2332 OR (cls
  2347. 2333 = SymTab.ClClass) THEN
  2348. 2334 QbeGen.AddrOf(n, q)
  2349. 2335 ELSE SemError(230);
  2350. 2336 QbeGen.CopyOp("0", q)
  2351. 2337 END
  2352. 2338 ELSE QbeGen.CopyOp("0", q);
  2353. 2339 IF k = SymTab.KindImport THEN
  2354. 2340 SemError(230)
  2355. 2341 ELSIF k =
  2356. 2342 SymTab.KindProc THEN
  2357. 2343 (* bare procedure name:
  2358. 2344 a following ArgList
  2359. 2345 makes it a call;
  2360. 2346 otherwise Fact
  2361. 2347 reports 230 *)
  2362. 2348 ELSE
  2363. 2349 IF k = SymTab.KindField THEN
  2364. 2350 IF QbeGen.TopWith(qb) THEN
  2365. 2351 fo :=
  2366. 2352 SymTab.FieldOffset(
  2367. 2353 SymTab.FieldOwner(n),
  2368. 2354 n);
  2369. 2355 QbeGen.FieldAddr(qb,
  2370. 2356 fo, q);
  2371. 2357 sfx := TRUE
  2372. 2358 ELSE SemError(230);
  2373. 2359 QbeGen.CopyOp("0", q)
  2374. 2360 END
  2375. 2361 END
  2376. 2362 END
  2377. 2363 END
  2378. 2364 END; .)
  2379. 2365 (. astDes := AST.MakeNode(AST.NkDesignator);
  2380. 2366 AST.SetChild(astDes, AST.NChild(astDes), AST.MakeLeaf(AST.NkIdent, n)); .)
  2381. 2367 { "[" Expr<it, iq>
  2382. 2368 (. AST.SetChild(astDes, AST.NChild(astDes),
  2383. 2369 AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
  2384. 2370 ELSIF SymTab.ClassOf(t) #
  2385. 2371 SymTab.ClArray THEN
  2386. 2372 SemError(217);
  2387. 2373 t := SymTab.InvalidType
  2388. 2374 ELSIF NOT SymTab.IsIntFamily(it)
  2389. 2375 AND (SymTab.ClassOf(it) #
  2390. 2376 SymTab.ClChar)
  2391. 2377 AND (SymTab.ClassOf(it) #
  2392. 2378 SymTab.ClEnum) THEN
  2393. 2379 SemError(218);
  2394. 2380 t := SymTab.InvalidType
  2395. 2381 ELSE
  2396. 2382 QbeGen.WidenIndex(iq, ql);
  2397. 2383 isOpen :=
  2398. 2384 SymTab.IsOpenArray(t);
  2399. 2385 IF isOpen THEN
  2400. 2386 QbeGen.CopyOp("0", qlo);
  2401. 2387 IF SymTab.IsCharArray(t)
  2402. 2388 OR SymTab.IsUCharArray(t) THEN
  2403. 2389 QbeGen.OpenHiChar(q, qhi)
  2404. 2390 ELSE QbeGen.OpenHi(q, qhi)
  2405. 2391 END
  2406. 2392 ELSE
  2407. 2393 lo := SymTab.ArrayLo(t);
  2408. 2394 hi := SymTab.ArrayHi(t);
  2409. 2395 IF SymTab.IsCharArray(t)
  2410. 2396 OR SymTab.IsUCharArray(t) THEN
  2411. 2397 hi := hi + 1
  2412. 2398 END;
  2413. 2399 QbeGen.IntStr(lo, qlo);
  2414. 2400 QbeGen.IntStr(hi, qhi)
  2415. 2401 END;
  2416. 2402 QbeGen.CheckRange(ql, qlo,
  2417. 2403 qhi);
  2418. 2404 eT := SymTab.ArrayElem(t);
  2419. 2405 QbeGen.ElemAddr(q, ql, qlo,
  2420. 2406 t, qe);
  2421. 2407 IF SymTab.ClassOf(eT) =
  2422. 2408 SymTab.ClArray THEN
  2423. 2409 QbeGen.ElemLoad(qe, eT, q)
  2424. 2410 ELSE QbeGen.CopyOp(qe, q)
  2425. 2411 END;
  2426. 2412 t := eT; sfx := TRUE
  2427. 2413 END; .)
  2428. 2414 { "," Expr<it, iq>
  2429. 2415 (. AST.SetChild(astDes, AST.NChild(astDes),
  2430. 2416 AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
  2431. 2417 ELSIF SymTab.ClassOf(t) #
  2432. 2418 SymTab.ClArray THEN
  2433. 2419 SemError(217);
  2434. 2420 t := SymTab.InvalidType
  2435. 2421 ELSIF NOT SymTab.IsIntFamily(it)
  2436. 2422 AND (SymTab.ClassOf(it) #
  2437. 2423 SymTab.ClChar)
  2438. 2424 AND (SymTab.ClassOf(it) #
  2439. 2425 SymTab.ClEnum) THEN
  2440. 2426 SemError(218);
  2441. 2427 t := SymTab.InvalidType
  2442. 2428 ELSE
  2443. 2429 QbeGen.WidenIndex(iq, ql);
  2444. 2430 isOpen :=
  2445. 2431 SymTab.IsOpenArray(t);
  2446. 2432 IF isOpen THEN
  2447. 2433 QbeGen.CopyOp("0", qlo);
  2448. 2434 IF SymTab.IsCharArray(t)
  2449. 2435 OR SymTab.IsUCharArray(t) THEN
  2450. 2436 QbeGen.OpenHiChar(q, qhi)
  2451. 2437 ELSE QbeGen.OpenHi(q, qhi)
  2452. 2438 END
  2453. 2439 ELSE
  2454. 2440 lo := SymTab.ArrayLo(t);
  2455. 2441 hi := SymTab.ArrayHi(t);
  2456. 2442 IF SymTab.IsCharArray(t)
  2457. 2443 OR SymTab.IsUCharArray(t) THEN
  2458. 2444 hi := hi + 1
  2459. 2445 END;
  2460. 2446 QbeGen.IntStr(lo, qlo);
  2461. 2447 QbeGen.IntStr(hi, qhi)
  2462. 2448 END;
  2463. 2449 QbeGen.CheckRange(ql, qlo,
  2464. 2450 qhi);
  2465. 2451 eT := SymTab.ArrayElem(t);
  2466. 2452 QbeGen.ElemAddr(q, ql, qlo,
  2467. 2453 t, qe);
  2468. 2454 IF SymTab.ClassOf(eT) =
  2469. 2455 SymTab.ClArray THEN
  2470. 2456 QbeGen.ElemLoad(qe, eT, q)
  2471. 2457 ELSE QbeGen.CopyOp(qe, q)
  2472. 2458 END;
  2473. 2459 t := eT; sfx := TRUE
  2474. 2460 END; .) }
  2475. 2461 "]"
  2476. 2462 | "." GetIdent<fn>
  2477. 2463 (. astSel := AST.MakeNode(AST.NkSelector);
  2478. 2464 AST.SetOp(astSel, AST.SelField);
  2479. 2465 AST.SetChild(astSel, 0, AST.MakeLeaf(AST.NkIdent, fn));
  2480. 2466 AST.SetChild(astDes, AST.NChild(astDes), astSel); IF k = SymTab.KindModule THEN
  2481. 2467 (* qualified L.x: materialize
  2482. 2468 the export, then load it *)
  2483. 2469 IF NOT SymTab.MaterializeAlias(n,
  2484. 2470 fn, mal) THEN
  2485. 2471 SemError(201);
  2486. 2472 t := SymTab.InvalidType;
  2487. 2473 QbeGen.CopyOp("0", q)
  2488. 2474 ELSE
  2489. 2475 QbeGen.CopyOp(mal, qn);
  2490. 2476 t := SymTab.SymType(mal);
  2491. 2477 k := SymTab.SymKind(mal);
  2492. 2478 sfx := FALSE;
  2493. 2479 IF k = SymTab.KindProc THEN
  2494. 2480 (* call: ArgList supplies
  2495. 2481 the value *)
  2496. 2482 QbeGen.CopyOp("0", q)
  2497. 2483 ELSIF NOT QbeGen.LoadDesignator(
  2498. 2484 mal, t, k, q) THEN
  2499. 2485 SemError(230);
  2500. 2486 QbeGen.CopyOp("0", q)
  2501. 2487 END
  2502. 2488 END
  2503. 2489 ELSIF t = SymTab.InvalidType THEN
  2504. 2490 ELSIF (SymTab.ClassOf(t) #
  2505. 2491 SymTab.ClRecord)
  2506. 2492 AND (SymTab.ClassOf(t) #
  2507. 2493 SymTab.ClClass) THEN
  2508. 2494 SemError(215);
  2509. 2495 t := SymTab.InvalidType
  2510. 2496 ELSIF (SymTab.ClassOf(t) =
  2511. 2497 SymTab.ClClass)
  2512. 2498 AND SymTab.MethodExists(t, fn) THEN
  2513. 2499 (* obj.Method: bind the
  2514. 2500 method and pass obj as
  2515. 2501 the hidden receiver; q
  2516. 2502 already holds the
  2517. 2503 object's address *)
  2518. 2504 QbeGen.ArmRecv(q);
  2519. 2505 QbeGen.CopyOp(fn, n);
  2520. 2506 QbeGen.CopyOp(fn, qn);
  2521. 2507 methCls := t;
  2522. 2508 k := SymTab.KindProc;
  2523. 2509 t := SymTab.InvalidType
  2524. 2510 ELSIF NOT SymTab.FieldExists(t,
  2525. 2511 fn) THEN
  2526. 2512 SemError(216);
  2527. 2513 t := SymTab.InvalidType
  2528. 2514 ELSE
  2529. 2515 fo := SymTab.FieldOffset(t,
  2530. 2516 fn);
  2531. 2517 t := SymTab.FieldType(t, fn);
  2532. 2518 QbeGen.FieldAddr(q, fo, qe);
  2533. 2519 (* array fields are inline:
  2534. 2520 the field address is the
  2535. 2521 descriptor, like records *)
  2536. 2522 QbeGen.CopyOp(qe, q);
  2537. 2523 sfx := TRUE
  2538. 2524 END; .)
  2539. 2525 | "^"
  2540. 2526 (. astSel := AST.MakeNode(AST.NkSelector);
  2541. 2527 AST.SetOp(astSel, AST.SelDeref);
  2542. 2528 AST.SetChild(astDes, AST.NChild(astDes), astSel); IF t = SymTab.InvalidType THEN
  2543. 2529 ELSIF SymTab.ClassOf(t) #
  2544. 2530 SymTab.ClPtr THEN
  2545. 2531 SemError(219);
  2546. 2532 t := SymTab.InvalidType
  2547. 2533 ELSE
  2548. 2534 bt := SymTab.PtrBase(t);
  2549. 2535 IF bt = SymTab.InvalidType THEN
  2550. 2536 ELSE
  2551. 2537 IF sfx THEN
  2552. 2538 QbeGen.ElemLoad(q, t,
  2553. 2539 qb);
  2554. 2540 QbeGen.CopyOp(qb, q)
  2555. 2541 END;
  2556. 2542 t := bt;
  2557. 2543 (* q holds the pointee
  2558. 2544 address: Fact loads
  2559. 2545 scalars/pointers and uses
  2560. 2546 the address for
  2561. 2547 aggregates; the VAR-actual
  2562. 2548 note is q itself. *)
  2563. 2549 sfx := TRUE
  2564. 2550 END
  2565. 2551 END; .) } (. astCur := astDes; .) .
  2566. 2552 (* Result suffix (ISO component after a function call): `F()^`,
  2567. 2553 `F()[i]`, `F().field`. The call result is in t/q with sfx FALSE
  2568. 2554 (a value, or a descriptor address for aggregates); each component
  2569. 2555 descends one level exactly like the Design components. *)
  2570. 2556 ResultComp<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
  2571. 2557 VAR sfx: BOOLEAN; VAR node: AST.Node> (. VAR it, eT, bt: SymTab.TypeIndex;
  2572. 2558 iq, ql, qlo, qhi, qe, qb:
  2573. 2559 QbeGen.QVal;
  2574. 2560 lo, hi, fo: INTEGER;
  2575. 2561 isOpen: BOOLEAN;
  2576. 2562 fname: SymTab.Name;
  2577. 2563 astWrap, astSel: AST.Node; .)
  2578. 2564 = "[" Expr<it, iq>
  2579. 2565 (. IF AST.Kind(node) # AST.NkDesignator THEN
  2580. 2566 astWrap := AST.MakeNode(
  2581. 2567 AST.NkDesignator);
  2582. 2568 AST.SetChild(astWrap, 0, node);
  2583. 2569 node := astWrap
  2584. 2570 END;
  2585. 2571 AST.SetChild(node, AST.NChild(node),
  2586. 2572 AST.MakeUn(AST.NkSelector,
  2587. 2573 AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
  2588. 2574 ELSIF SymTab.ClassOf(t) #
  2589. 2575 SymTab.ClArray THEN
  2590. 2576 SemError(217);
  2591. 2577 t := SymTab.InvalidType
  2592. 2578 ELSIF NOT SymTab.IsIntFamily(it)
  2593. 2579 AND (SymTab.ClassOf(it) # SymTab.ClChar)
  2594. 2580 AND (SymTab.ClassOf(it) # SymTab.ClEnum) THEN
  2595. 2581 SemError(218);
  2596. 2582 t := SymTab.InvalidType
  2597. 2583 ELSE
  2598. 2584 QbeGen.WidenIndex(iq, ql);
  2599. 2585 isOpen :=
  2600. 2586 SymTab.IsOpenArray(t);
  2601. 2587 IF isOpen THEN
  2602. 2588 QbeGen.CopyOp("0", qlo);
  2603. 2589 IF SymTab.IsCharArray(t)
  2604. 2590 OR SymTab.IsUCharArray(t) THEN
  2605. 2591 QbeGen.OpenHiChar(q, qhi)
  2606. 2592 ELSE QbeGen.OpenHi(q, qhi)
  2607. 2593 END
  2608. 2594 ELSE
  2609. 2595 lo := SymTab.ArrayLo(t);
  2610. 2596 hi := SymTab.ArrayHi(t);
  2611. 2597 IF SymTab.IsCharArray(t)
  2612. 2598 OR SymTab.IsUCharArray(t) THEN
  2613. 2599 hi := hi + 1
  2614. 2600 END;
  2615. 2601 QbeGen.IntStr(lo, qlo);
  2616. 2602 QbeGen.IntStr(hi, qhi)
  2617. 2603 END;
  2618. 2604 QbeGen.CheckRange(ql, qlo,
  2619. 2605 qhi);
  2620. 2606 eT := SymTab.ArrayElem(t);
  2621. 2607 QbeGen.ElemAddr(q, ql, qlo,
  2622. 2608 t, qe);
  2623. 2609 IF SymTab.ClassOf(eT) =
  2624. 2610 SymTab.ClArray THEN
  2625. 2611 QbeGen.ElemLoad(qe, eT, q)
  2626. 2612 ELSE QbeGen.CopyOp(qe, q)
  2627. 2613 END;
  2628. 2614 t := eT; sfx := TRUE
  2629. 2615 END; .)
  2630. 2616 "]"
  2631. 2617 | "." GetIdent<fname>
  2632. 2618 (. IF AST.Kind(node) # AST.NkDesignator THEN
  2633. 2619 astWrap := AST.MakeNode(
  2634. 2620 AST.NkDesignator);
  2635. 2621 AST.SetChild(astWrap, 0, node);
  2636. 2622 node := astWrap
  2637. 2623 END;
  2638. 2624 AST.SetChild(node, AST.NChild(node),
  2639. 2625 AST.MakeUn(AST.NkSelector,
  2640. 2626 AST.SelField,
  2641. 2627 AST.MakeLeaf(AST.NkIdent,
  2642. 2628 fname))); IF t = SymTab.InvalidType THEN
  2643. 2629 ELSIF (SymTab.ClassOf(t) #
  2644. 2630 SymTab.ClRecord)
  2645. 2631 AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN
  2646. 2632 SemError(215);
  2647. 2633 t := SymTab.InvalidType
  2648. 2634 ELSIF NOT SymTab.FieldExists(t,
  2649. 2635 fname) THEN
  2650. 2636 SemError(216);
  2651. 2637 t := SymTab.InvalidType
  2652. 2638 ELSE
  2653. 2639 fo := SymTab.FieldOffset(t,
  2654. 2640 fname);
  2655. 2641 t := SymTab.FieldType(t, fname);
  2656. 2642 QbeGen.FieldAddr(q, fo, qe);
  2657. 2643 QbeGen.CopyOp(qe, q);
  2658. 2644 sfx := TRUE
  2659. 2645 END; .)
  2660. 2646 | "^" (. IF AST.Kind(node) # AST.NkDesignator THEN
  2661. 2647 astWrap := AST.MakeNode(
  2662. 2648 AST.NkDesignator);
  2663. 2649 AST.SetChild(astWrap, 0, node);
  2664. 2650 node := astWrap
  2665. 2651 END;
  2666. 2652 astSel := AST.MakeNode(AST.NkSelector);
  2667. 2653 AST.SetOp(astSel, AST.SelDeref);
  2668. 2654 AST.SetChild(node,
  2669. 2655 AST.NChild(node), astSel); IF t = SymTab.InvalidType THEN
  2670. 2656 ELSIF SymTab.ClassOf(t) #
  2671. 2657 SymTab.ClPtr THEN
  2672. 2658 SemError(219);
  2673. 2659 t := SymTab.InvalidType
  2674. 2660 ELSE
  2675. 2661 bt := SymTab.PtrBase(t);
  2676. 2662 IF bt # SymTab.InvalidType THEN
  2677. 2663 IF sfx THEN
  2678. 2664 QbeGen.ElemLoad(q, t, qb);
  2679. 2665 QbeGen.CopyOp(qb, q)
  2680. 2666 END;
  2681. 2667 t := bt; sfx := TRUE
  2682. 2668 END
  2683. 2669 END; .) .
  2684. 2670 Expr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  2685. 2671 (. VAR t2: SymTab.TypeIndex;
  2686. 2672 op: INTEGER;
  2687. 2673 q2, qt, wl: QbeGen.QVal;
  2688. 2674 astA, astB: AST.Node;
  2689. 2675 astOp: INTEGER;
  2690. 2676 astMade: BOOLEAN;
  2691. 2677 isR: BOOLEAN; .)
  2692. 2678 = SimExpr<t, q> (. astA := astCur; astMade := FALSE; .)
  2693. 2679 [ Rel<op> SimExpr<t2, q2>
  2694. 2680 (. astB := astCur; astMade := TRUE;
  2695. 2681 astOp := AST.OpEq;
  2696. 2682 IF op = SymTab.OpNeq1 THEN astOp := AST.OpNe
  2697. 2683 ELSIF op = SymTab.OpNeq2 THEN astOp := AST.OpNe
  2698. 2684 ELSIF op = SymTab.OpLt THEN astOp := AST.OpLt
  2699. 2685 ELSIF op = SymTab.OpLe THEN astOp := AST.OpLe
  2700. 2686 ELSIF op = SymTab.OpGt THEN astOp := AST.OpGt
  2701. 2687 ELSIF op = SymTab.OpGe THEN astOp := AST.OpGe
  2702. 2688 ELSIF op = SymTab.OpIn THEN astOp := AST.OpIn
  2703. 2689 END;
  2704. 2690 IF op = SymTab.OpIn THEN
  2705. 2691 IF SymTab.InCheck(t, t2) THEN
  2706. 2692 IF (t = SymTab.InvalidType)
  2707. 2693 OR (t2 = SymTab.InvalidType) THEN
  2708. 2694 t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
  2709. 2695 ELSE
  2710. 2696 QbeGen.InSet(q, q2, SymTab.SetBaseLo(t2),
  2711. 2697 SymTab.SetCount(t2), qt);
  2712. 2698 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
  2713. 2699 END
  2714. 2700 ELSE SemError(222); t := SymTab.InvalidType;
  2715. 2701 QbeGen.CopyOp("0", q)
  2716. 2702 END
  2717. 2703 ELSIF SymTab.RelCheck(t, t2, op) THEN
  2718. 2704 IF (t = SymTab.InvalidType)
  2719. 2705 OR (t2 = SymTab.InvalidType) THEN
  2720. 2706 t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
  2721. 2707 ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
  2722. 2708 OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN
  2723. 2709 IF SymTab.IsFwdVar(t) OR SymTab.IsFwdVar(t2) THEN
  2724. 2710 QbeGen.Cmp(op, q, q2, qt, FALSE);
  2725. 2711 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
  2726. 2712 ELSIF (op # SymTab.OpEq) AND (op # SymTab.OpNeq1)
  2727. 2713 AND (op # SymTab.OpNeq2) THEN
  2728. 2714 SemError(213); t := SymTab.InvalidType;
  2729. 2715 QbeGen.CopyOp("0", q)
  2730. 2716 ELSE
  2731. 2717 QbeGen.CmpL(op, q, q2, qt);
  2732. 2718 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
  2733. 2719 END
  2734. 2720 ELSIF (SymTab.ClassOf(t) = SymTab.ClSet)
  2735. 2721 OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
  2736. 2722 QbeGen.CmpSet(op, q, q2,
  2737. 2723 SymTab.SetWords(t), SymTab.SetWords(t2), qt);
  2738. 2724 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
  2739. 2725 ELSIF SymTab.StrCompat(t, t2) THEN
  2740. 2726 QbeGen.StrEq(op, q, q2, qt);
  2741. 2727 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
  2742. 2728 ELSIF SymTab.IsLongFamily(t)
  2743. 2729 OR SymTab.IsLongFamily(t2) THEN
  2744. 2730 IF SymTab.IsIntFamily(t) THEN
  2745. 2731 QbeGen.WidenLong(q, wl); QbeGen.CopyOp(wl, q)
  2746. 2732 END;
  2747. 2733 IF SymTab.IsIntFamily(t2) THEN
  2748. 2734 QbeGen.WidenLong(q2, wl); QbeGen.CopyOp(wl, q2)
  2749. 2735 END;
  2750. 2736 QbeGen.CmpLong(op, q, q2, qt);
  2751. 2737 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
  2752. 2738 ELSE
  2753. 2739 isR := SymTab.ClassOf(t) = SymTab.ClReal;
  2754. 2740 t := SymTab.BoolType();
  2755. 2741 QbeGen.Cmp(op, q, q2, qt, isR);
  2756. 2742 QbeGen.CopyOp(qt, q)
  2757. 2743 END
  2758. 2744 ELSE SemError(213); t := SymTab.InvalidType;
  2759. 2745 QbeGen.CopyOp("0", q)
  2760. 2746 END;
  2761. 2747 astCur := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB); .) ]
  2762. 2748 (. IF NOT astMade THEN astCur := astA END; .) .
  2763. 2749 Rel<VAR op: INTEGER>
  2764. 2750 = "=" (. op := SymTab.OpEq; .)
  2765. 2751 | "#" (. op := SymTab.OpNeq1; .)
  2766. 2752 | "<" (. op := SymTab.OpLt; .)
  2767. 2753 | "<=" (. op := SymTab.OpLe; .)
  2768. 2754 | ">" (. op := SymTab.OpGt; .)
  2769. 2755 | ">=" (. op := SymTab.OpGe; .)
  2770. 2756 | "IN" (. op := SymTab.OpIn; .) .
  2771. 2757 SimExpr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  2772. 2758 (. VAR t2, res2, lt, rt:
  2773. 2759 SymTab.TypeIndex;
  2774. 2760 op: INTEGER;
  2775. 2761 q2, qt, wq, qf, q2a, q2b:
  2776. 2762 QbeGen.QVal;
  2777. 2763 neg, isR, isL, folded:
  2778. 2764 BOOLEAN;
  2779. 2765 fok: BOOLEAN;
  2780. 2766 lw, rw, mw: CARDINAL;
  2781. 2767 lTrue, lNext, lDone, qr, qs: QbeGen.QVal;
  2782. 2768 astA, astB: AST.Node;
  2783. 2769 astSign, astOp: INTEGER; .)
  2784. 2770 = (. neg := FALSE; astSign := 0; .)
  2785. 2771 [ "+" (. neg := TRUE; astSign := 1; .)
  2786. 2772 | "-" (. neg := TRUE; astSign := -1; .) ]
  2787. 2773 Term<t, q> (. astA := astCur; IF neg THEN
  2788. 2774 IF QbeGen.IsImm(q) THEN
  2789. 2775 QbeGen.NegFold(q, q)
  2790. 2776 ELSE QbeGen.NewTemp(qt);
  2791. 2777 QbeGen.NegQ(q, qt,
  2792. 2778 SymTab.ClassOf(t)
  2793. 2779 = SymTab.ClReal);
  2794. 2780 QbeGen.CopyOp(qt, q)
  2795. 2781 END
  2796. 2782 END;
  2797. 2783 IF astSign < 0 THEN
  2798. 2784 astCur := AST.MakeUn(
  2799. 2785 AST.NkUnary, AST.OpSub, astA);
  2800. 2786 astA := astCur
  2801. 2787 END; .)
  2802. 2788 { AddOp<op> (. IF op = SymTab.OpOr THEN
  2803. 2789 QbeGen.DelayBegin END; .)
  2804. 2790 Term<t2, q2> (. astB := astCur; IF op = SymTab.OpOr THEN
  2805. 2791 QbeGen.DelayEnd END; .)
  2806. 2792 (. astOp := AST.OpAdd;
  2807. 2793 IF op = SymTab.OpSub THEN astOp := AST.OpSub
  2808. 2794 ELSIF op = SymTab.OpOr THEN astOp := AST.OpOr END;
  2809. 2795 astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB);
  2810. 2796 astCur := astA;
  2811. 2797 IF op = SymTab.OpOr THEN
  2812. 2798 (* short-circuit: if q is true the RHS is skipped *)
  2813. 2799 IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
  2814. 2800 t := SymTab.BoolType()
  2815. 2801 ELSE SemError(212); t := SymTab.InvalidType END;
  2816. 2802 IF t # SymTab.InvalidType THEN
  2817. 2803 QbeGen.Slot4(qs);
  2818. 2804 QbeGen.NewLabel(lTrue);
  2819. 2805 QbeGen.NewLabel(lNext);
  2820. 2806 QbeGen.NewLabel(lDone);
  2821. 2807 QbeGen.Jnz(q, lTrue, lNext);
  2822. 2808 QbeGen.EmitLabel(lTrue);
  2823. 2809 QbeGen.StoreW(qs, "1");
  2824. 2810 QbeGen.Jmp(lDone);
  2825. 2811 QbeGen.EmitLabel(lNext);
  2826. 2812 QbeGen.DelayFlush;
  2827. 2813 QbeGen.StoreW(qs, q2);
  2828. 2814 QbeGen.Jmp(lDone);
  2829. 2815 QbeGen.EmitLabel(lDone);
  2830. 2816 QbeGen.LoadW(qs, qr);
  2831. 2817 QbeGen.CopyOp(qr, q)
  2832. 2818 ELSE QbeGen.DelayFlush; QbeGen.CopyOp("0", q)
  2833. 2819 END
  2834. 2820 ELSIF (op = SymTab.OpAdd)
  2835. 2821 AND (SymTab.UStrCompat(t, t2)
  2836. 2822 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
  2837. 2823 AND (SymTab.ClassOf(t2) = SymTab.ClUStr))
  2838. 2824 OR ((SymTab.ClassOf(t) = SymTab.ClUStr)
  2839. 2825 AND (SymTab.ClassOf(t2) = SymTab.ClUChar))
  2840. 2826 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
  2841. 2827 AND (SymTab.ClassOf(t2) = SymTab.ClUChar))) THEN
  2842. 2828 (* UString concatenation: a UCHAR operand becomes a
  2843. 2829 1-codepoint UString; the result is a descriptor in the
  2844. 2830 shim's concat buffer. Work on copies so neither
  2845. 2831 operand is clobbered. *)
  2846. 2832 IF SymTab.ClassOf(t) = SymTab.ClUStr THEN
  2847. 2833 QbeGen.CopyOp(q, q2a)
  2848. 2834 ELSE
  2849. 2835 QbeGen.UStrFrom(q, q2a)
  2850. 2836 END;
  2851. 2837 IF SymTab.ClassOf(t2) = SymTab.ClUStr THEN
  2852. 2838 QbeGen.UStrCat(q2a, q2, qt)
  2853. 2839 ELSE
  2854. 2840 QbeGen.UStrFrom(q2, q2b);
  2855. 2841 QbeGen.UStrCat(q2a, q2b, qt)
  2856. 2842 END;
  2857. 2843 t := SymTab.NewUStr();
  2858. 2844 QbeGen.CopyOp(qt, q)
  2859. 2845 ELSIF (op = SymTab.OpAdd)
  2860. 2846 AND (SymTab.StrCompat(t, t2)
  2861. 2847 OR (SymTab.IsStrType(t)
  2862. 2848 AND (SymTab.ClassOf(t2) = SymTab.ClChar))
  2863. 2849 OR ((SymTab.ClassOf(t) = SymTab.ClChar)
  2864. 2850 AND SymTab.IsStrType(t2))) THEN
  2865. 2851 (* string concatenation; a CHAR operand becomes a
  2866. 2852 1-character string literal. When both operands are
  2867. 2853 constants, fold to a single string literal so a
  2868. 2854 constructor element stays compile-time. *)
  2869. 2855 QbeGen.StrFold(q, q2, SymTab.ClassOf(t), SymTab.ClassOf(t2),
  2870. 2856 qt, fok);
  2871. 2857 IF NOT fok THEN
  2872. 2858 IF SymTab.StrCompat(t, t2) THEN
  2873. 2859 QbeGen.StrCat(q, q2, qt)
  2874. 2860 ELSIF SymTab.IsStrType(t) THEN
  2875. 2861 QbeGen.DeclCharStr(q2, qs);
  2876. 2862 QbeGen.StrCat(q, qs, qt)
  2877. 2863 ELSE
  2878. 2864 QbeGen.DeclCharStr(q, qs);
  2879. 2865 QbeGen.StrCat(qs, q2, qt)
  2880. 2866 END
  2881. 2867 END;
  2882. 2868 t := SymTab.NewStr();
  2883. 2869 QbeGen.CopyOp(qt, q)
  2884. 2870 ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
  2885. 2871 AND (SymTab.ClassOf(t) = SymTab.ClSet)
  2886. 2872 AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
  2887. 2873 lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
  2888. 2874 mw := lw;
  2889. 2875 IF rw > mw THEN mw := rw END;
  2890. 2876 IF op = SymTab.OpAdd THEN
  2891. 2877 QbeGen.SetBinOp(0, q, q2, lw, rw, qt)
  2892. 2878 ELSE
  2893. 2879 QbeGen.SetBinOp(2, q, q2, lw, rw, qt)
  2894. 2880 END;
  2895. 2881 t := SymTab.NewSet(
  2896. 2882 SymTab.NewSubR(0,
  2897. 2883 VAL(INTEGER, mw) * 32 - 1));
  2898. 2884 QbeGen.CopyOp(qt, q)
  2899. 2885 ELSE
  2900. 2886 IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
  2901. 2887 lt := t; rt := t2; t := res2
  2902. 2888 ELSE SemError(211); t := SymTab.InvalidType END;
  2903. 2889 IF t # SymTab.InvalidType THEN
  2904. 2890 isL := SymTab.IsLongFamily(t);
  2905. 2891 isR := SymTab.ClassOf(t) = SymTab.ClReal;
  2906. 2892 folded := FALSE;
  2907. 2893 IF (NOT isL) AND (NOT isR)
  2908. 2894 AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
  2909. 2895 IF op = SymTab.OpAdd THEN
  2910. 2896 folded := QbeGen.Fold2(0, q, q2, qf)
  2911. 2897 ELSE
  2912. 2898 folded := QbeGen.Fold2(1, q, q2, qf)
  2913. 2899 END
  2914. 2900 END;
  2915. 2901 IF folded THEN QbeGen.CopyOp(qf, q)
  2916. 2902 ELSE
  2917. 2903 IF isL THEN
  2918. 2904 IF SymTab.IsIntFamily(lt) THEN
  2919. 2905 QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
  2920. 2906 END;
  2921. 2907 IF SymTab.IsIntFamily(rt) THEN
  2922. 2908 QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
  2923. 2909 END;
  2924. 2910 QbeGen.NewTemp(qt);
  2925. 2911 IF op = SymTab.OpAdd THEN
  2926. 2912 QbeGen.Op3L("add", qt, q, q2)
  2927. 2913 ELSE
  2928. 2914 QbeGen.Op3L("sub", qt, q, q2)
  2929. 2915 END
  2930. 2916 ELSE
  2931. 2917 QbeGen.NewTemp(qt);
  2932. 2918 IF op = SymTab.OpAdd THEN
  2933. 2919 QbeGen.Op3("add", qt, q, q2, isR)
  2934. 2920 ELSE
  2935. 2921 QbeGen.Op3("sub", qt, q, q2, isR)
  2936. 2922 END
  2937. 2923 END;
  2938. 2924 QbeGen.CopyOp(qt, q)
  2939. 2925 END
  2940. 2926 ELSE QbeGen.CopyOp("0", q)
  2941. 2927 END
  2942. 2928 END; .) } .
  2943. 2929 AddOp<VAR op: INTEGER>
  2944. 2930 = "+" (. op := SymTab.OpAdd; .)
  2945. 2931 | "-" (. op := SymTab.OpSub; .)
  2946. 2932 | "OR" (. op := SymTab.OpOr; .) .
  2947. 2933 Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  2948. 2934 (. VAR t2, res2, lt, rt:
  2949. 2935 SymTab.TypeIndex;
  2950. 2936 op: INTEGER;
  2951. 2937 q2, qt, wq, qf:
  2952. 2938 QbeGen.QVal;
  2953. 2939 isR, isL, folded: BOOLEAN;
  2954. 2940 lw, rw, mw: CARDINAL;
  2955. 2941 lNext, lFalse, lDone, qr, qs: QbeGen.QVal;
  2956. 2942 astA, astB: AST.Node;
  2957. 2943 astOp: INTEGER; .)
  2958. 2944 = Fact<t, q> (. astA := astCur; .) { MulOp<op> (. IF op = SymTab.OpAnd THEN
  2959. 2945 QbeGen.DelayBegin END; .)
  2960. 2946 Fact<t2, q2> (. astB := astCur; IF op = SymTab.OpAnd THEN
  2961. 2947 QbeGen.DelayEnd END; .)
  2962. 2948 (. astOp := AST.OpMul;
  2963. 2949 IF op = SymTab.OpSlash THEN astOp := AST.OpDiv
  2964. 2950 ELSIF op = SymTab.OpDiv THEN astOp := AST.OpDiv
  2965. 2951 ELSIF op = SymTab.OpMod THEN astOp := AST.OpMod
  2966. 2952 ELSIF op = SymTab.OpAnd THEN astOp := AST.OpAnd END;
  2967. 2953 astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB);
  2968. 2954 astCur := astA;
  2969. 2955 IF op = SymTab.OpAnd THEN
  2970. 2956 (* short-circuit: if q is false the RHS is skipped *)
  2971. 2957 IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
  2972. 2958 t := SymTab.BoolType()
  2973. 2959 ELSE SemError(212); t := SymTab.InvalidType END;
  2974. 2960 IF t # SymTab.InvalidType THEN
  2975. 2961 QbeGen.Slot4(qs);
  2976. 2962 QbeGen.NewLabel(lNext);
  2977. 2963 QbeGen.NewLabel(lFalse);
  2978. 2964 QbeGen.NewLabel(lDone);
  2979. 2965 QbeGen.Jnz(q, lNext, lFalse);
  2980. 2966 QbeGen.EmitLabel(lNext);
  2981. 2967 QbeGen.DelayFlush;
  2982. 2968 QbeGen.StoreW(qs, q2);
  2983. 2969 QbeGen.Jmp(lDone);
  2984. 2970 QbeGen.EmitLabel(lFalse);
  2985. 2971 QbeGen.StoreW(qs, "0");
  2986. 2972 QbeGen.Jmp(lDone);
  2987. 2973 QbeGen.EmitLabel(lDone);
  2988. 2974 QbeGen.LoadW(qs, qr);
  2989. 2975 QbeGen.CopyOp(qr, q)
  2990. 2976 ELSE QbeGen.DelayFlush; QbeGen.CopyOp("0", q)
  2991. 2977 END
  2992. 2978 ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
  2993. 2979 AND (SymTab.ClassOf(t) = SymTab.ClSet)
  2994. 2980 AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
  2995. 2981 lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
  2996. 2982 mw := lw;
  2997. 2983 IF rw > mw THEN mw := rw END;
  2998. 2984 IF op = SymTab.OpTimes THEN
  2999. 2985 QbeGen.SetBinOp(1, q, q2, lw, rw, qt)
  3000. 2986 ELSE
  3001. 2987 QbeGen.SetBinOp(3, q, q2, lw, rw, qt)
  3002. 2988 END;
  3003. 2989 t := SymTab.NewSet(
  3004. 2990 SymTab.NewSubR(0,
  3005. 2991 VAL(INTEGER, mw) * 32 - 1));
  3006. 2992 QbeGen.CopyOp(qt, q)
  3007. 2993 ELSE
  3008. 2994 IF SymTab.ArithCheck(t, t2,
  3009. 2995 (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
  3010. 2996 res2) THEN
  3011. 2997 lt := t; rt := t2; t := res2
  3012. 2998 ELSE SemError(211); t := SymTab.InvalidType END;
  3013. 2999 IF t # SymTab.InvalidType THEN
  3014. 3000 isL := SymTab.IsLongFamily(t);
  3015. 3001 isR := SymTab.ClassOf(t) = SymTab.ClReal;
  3016. 3002 folded := FALSE;
  3017. 3003 IF (NOT isL) AND (NOT isR)
  3018. 3004 AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
  3019. 3005 IF op = SymTab.OpTimes THEN
  3020. 3006 folded := QbeGen.Fold2(2, q, q2, qf)
  3021. 3007 ELSIF op = SymTab.OpDiv THEN
  3022. 3008 folded := QbeGen.Fold2(3, q, q2, qf)
  3023. 3009 ELSIF op = SymTab.OpMod THEN
  3024. 3010 folded := QbeGen.Fold2(4, q, q2, qf)
  3025. 3011 END
  3026. 3012 END;
  3027. 3013 IF folded THEN QbeGen.CopyOp(qf, q)
  3028. 3014 ELSE
  3029. 3015 IF isL THEN
  3030. 3016 IF SymTab.IsIntFamily(lt) THEN
  3031. 3017 QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
  3032. 3018 END;
  3033. 3019 IF SymTab.IsIntFamily(rt) THEN
  3034. 3020 QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
  3035. 3021 END;
  3036. 3022 QbeGen.NewTemp(qt);
  3037. 3023 IF op = SymTab.OpTimes THEN
  3038. 3024 QbeGen.Op3L("mul", qt, q, q2)
  3039. 3025 ELSIF (op = SymTab.OpDiv)
  3040. 3026 OR (op = SymTab.OpSlash) THEN
  3041. 3027 QbeGen.Op3L("div", qt, q, q2)
  3042. 3028 ELSE
  3043. 3029 QbeGen.Op3L("rem", qt, q, q2)
  3044. 3030 END
  3045. 3031 ELSE
  3046. 3032 QbeGen.NewTemp(qt);
  3047. 3033 IF op = SymTab.OpTimes THEN
  3048. 3034 QbeGen.Op3("mul", qt, q, q2, isR)
  3049. 3035 ELSIF (op = SymTab.OpDiv)
  3050. 3036 OR (op = SymTab.OpSlash) THEN
  3051. 3037 QbeGen.Op3("div", qt, q, q2, isR)
  3052. 3038 ELSE
  3053. 3039 QbeGen.Op3("rem", qt, q, q2, isR)
  3054. 3040 END
  3055. 3041 END;
  3056. 3042 QbeGen.CopyOp(qt, q)
  3057. 3043 END
  3058. 3044 ELSE QbeGen.CopyOp("0", q)
  3059. 3045 END
  3060. 3046 END; .) } .
  3061. 3047 MulOp<VAR op: INTEGER>
  3062. 3048 = "*" (. op := SymTab.OpTimes; .)
  3063. 3049 | "/" (. op := SymTab.OpSlash; .)
  3064. 3050 | "DIV" (. op := SymTab.OpDiv; .)
  3065. 3051 | "MOD" (. op := SymTab.OpMod; .)
  3066. 3052 | ( "AND" | "&" ) (. op := SymTab.OpAnd; .) .
  3067. 3053 Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  3068. 3054 (. VAR s: ARRAY [0 .. 255] OF CHAR;
  3069. 3055 et, dt, t2, st, ct2, et2:
  3070. 3056 SymTab.TypeIndex;
  3071. 3057 dk: INTEGER;
  3072. 3058 qd, q2, sq, qa, qm0, qr, qt:
  3073. 3059 QbeGen.QVal;
  3074. 3060 qn, vn: SymTab.Name;
  3075. 3061 vt: SymTab.TypeIndex;
  3076. 3062 c1, c2: INTEGER;
  3077. 3063 lo, hi: INTEGER;
  3078. 3064 isMax: BOOLEAN;
  3079. 3065 called, isHigh, sfx, isCh,
  3080. 3066 isU, uok, isStr: BOOLEAN;
  3081. 3067 ucp: INTEGER; astIsLit: BOOLEAN;
  3082. 3068 astD: AST.Node;
  3083. 3069 astCall: BOOLEAN;
  3084. 3070 astNode, astNot: AST.Node;
  3085. 3071 j: CARDINAL;
  3086. 3072 astArg2: AST.Node;
  3087. 3073 astBrace: AST.Node;
  3088. 3074 astRes: AST.Node; .)
  3089. 3075 = (. astIsLit := FALSE; .)
  3090. 3076 ( integer (. LexString(s);
  3091. 3077 QbeGen.NormInt(s, q); IF twoPhase THEN astIsLit := TRUE; astCur := AST.MakeLeaf(AST.NkIntLit, s) END;
  3092. 3078 t := SymTab.IntType(); .)
  3093. 3079 | charConst (. LexString(s);
  3094. 3080 QbeGen.NormLit(s, q, isCh);
  3095. 3081 IF twoPhase THEN
  3096. 3082 astIsLit := TRUE;
  3097. 3083 astCur := AST.MakeLeaf(
  3098. 3084 AST.NkCharLit, s)
  3099. 3085 END;
  3100. 3086 t := SymTab.CharType(); .)
  3101. 3087 | real (. LexString(s);
  3102. 3088 QbeGen.NormReal(s, q);
  3103. 3089 IF twoPhase THEN
  3104. 3090 astIsLit := TRUE;
  3105. 3091 astCur := AST.MakeLeaf(
  3106. 3092 AST.NkRealLit, s)
  3107. 3093 END;
  3108. 3094 t := SymTab.RealType(); .)
  3109. 3095 | string (. LexString(s);
  3110. 3096 IF twoPhase THEN
  3111. 3097 astIsLit := TRUE;
  3112. 3098 astCur := AST.MakeLeaf(
  3113. 3099 AST.NkStrLit, s)
  3114. 3100 END;
  3115. 3101 IF SymTab.StrLen(s) = 3 THEN
  3116. 3102 t := SymTab.CharType();
  3117. 3103 QbeGen.IntStr(
  3118. 3104 QbeGen.CharVal(s), q)
  3119. 3105 ELSE t := SymTab.NewStr();
  3120. 3106 QbeGen.DeclStr(s, q);
  3121. 3107 (* a literal's value IS its
  3122. 3108 static descriptor address *)
  3123. 3109 QbeGen.NoteAddr(q, q)
  3124. 3110 END; .)
  3125. 3111 | ustring (. LexString(s);
  3126. 3112 IF twoPhase THEN
  3127. 3113 astIsLit := TRUE;
  3128. 3114 astCur := AST.MakeLeaf(
  3129. 3115 AST.NkStrLit, s)
  3130. 3116 END;
  3131. 3117 QbeGen.DeclUStr(s, q, isU, ucp,
  3132. 3118 uok);
  3133. 3119 IF NOT uok THEN
  3134. 3120 SemError(234);
  3135. 3121 t := SymTab.InvalidType
  3136. 3122 ELSIF isU THEN
  3137. 3123 t := SymTab.UCharType();
  3138. 3124 QbeGen.IntStr(ucp, q)
  3139. 3125 ELSE
  3140. 3126 t := SymTab.NewUStr();
  3141. 3127 QbeGen.NoteAddr(q, q)
  3142. 3128 END; .)
  3143. 3129 | Design<dt, dk, qd, qn, sfx> (. astD := astCur; astCall := FALSE; astBrace := AST.NoNode;
  3144. 3130 astNArgs := 0; called := FALSE;
  3145. 3131 t := dt;
  3146. 3132 IF sfx THEN
  3147. 3133 IF dt =
  3148. 3134 SymTab.InvalidType THEN
  3149. 3135 QbeGen.CopyOp("0", q)
  3150. 3136 ELSIF (SymTab.ClassOf(dt) =
  3151. 3137 SymTab.ClRecord)
  3152. 3138 OR (SymTab.ClassOf(dt) =
  3153. 3139 SymTab.ClSet)
  3154. 3140 OR (SymTab.ClassOf(dt) =
  3155. 3141 SymTab.ClArray)
  3156. 3142 OR (SymTab.ClassOf(dt) =
  3157. 3143 SymTab.ClClass) THEN
  3158. 3144 QbeGen.CopyOp(qd, q)
  3159. 3145 ELSE QbeGen.ElemLoad(qd, dt,
  3160. 3146 q)
  3161. 3147 END
  3162. 3148 ELSE QbeGen.CopyOp(qd, q)
  3163. 3149 END;
  3164. 3150 IF (dk = SymTab.KindVar)
  3165. 3151 OR (dk = SymTab.KindParam)
  3166. 3152 OR (dk =
  3167. 3153 SymTab.KindField) THEN
  3168. 3154 IF sfx THEN
  3169. 3155 QbeGen.NoteAddr(q, qd)
  3170. 3156 ELSE
  3171. 3157 QbeGen.AddrOf(qn, qa);
  3172. 3158 QbeGen.NoteAddr(q, qa)
  3173. 3159 END
  3174. 3160 ELSIF sfx
  3175. 3161 AND (dt #
  3176. 3162 SymTab.InvalidType)
  3177. 3163 AND ((SymTab.ClassOf(dt) =
  3178. 3164 SymTab.ClArray)
  3179. 3165 OR (SymTab.ClassOf(dt) =
  3180. 3166 SymTab.ClSet)
  3181. 3167 OR (SymTab.ClassOf(dt) =
  3182. 3168 SymTab.ClRecord)) THEN
  3183. 3169 QbeGen.NoteAddr(qd, qd)
  3184. 3170 END; .)
  3185. 3171 [ TypedBraceLit<dt, q> (. t := dt; astCall := TRUE;
  3186. 3172 astBrace := astCur; .) ]
  3187. 3173 [ ArgList<qn, dt, qd, TRUE, FALSE, methCls, ct2, q2, called>
  3188. 3174 (. astCall := TRUE;
  3189. 3175 astNode := AstCallNode(astD);
  3190. 3176 astRes := astNode;
  3191. 3177 t := ct2;
  3192. 3178 QbeGen.CopyOp(q2, q);
  3193. 3179 sfx := FALSE; .)
  3194. 3180 { ResultComp<t, q, sfx, astRes> }
  3195. 3181 (. IF sfx THEN
  3196. 3182 IF t = SymTab.InvalidType THEN
  3197. 3183 QbeGen.CopyOp("0", q)
  3198. 3184 ELSIF (SymTab.ClassOf(t) #
  3199. 3185 SymTab.ClRecord)
  3200. 3186 AND (SymTab.ClassOf(t) # SymTab.ClSet)
  3201. 3187 AND (SymTab.ClassOf(t) # SymTab.ClArray)
  3202. 3188 AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN
  3203. 3189 QbeGen.ElemLoad(q, t, q2);
  3204. 3190 QbeGen.CopyOp(q2, q)
  3205. 3191 END
  3206. 3192 END; .) ]
  3207. 3193 (. IF called THEN
  3208. 3194 astCur := astRes
  3209. 3195 ELSIF astCall THEN
  3210. 3196 astCur := astBrace
  3211. 3197 ELSE astCur := astD
  3212. 3198 END;
  3213. 3199 astIsLit := TRUE;
  3214. 3200 IF NOT called
  3215. 3201 AND (dk = SymTab.KindProc) THEN
  3216. 3202 (* bare zero-arg function
  3217. 3203 call (parentheses may be
  3218. 3204 omitted); a proper or
  3219. 3205 parameterised proc here
  3220. 3206 is 230 *)
  3221. 3207 IF (SymTab.ProcNPar(qn) = 0)
  3222. 3208 AND (SymTab.ProcRes(qn) #
  3223. 3209 SymTab.InvalidType) THEN
  3224. 3210 QbeGen.Mangled(qn,
  3225. 3211 SymTab.ProcUid(qn), qm0);
  3226. 3212 QbeGen.CallBegin(qm0,
  3227. 3213 SymTab.ProcRes(qn),
  3228. 3214 SymTab.ProcDepthOf(qn),
  3229. 3215 SymTab.IsExternal(qn));
  3230. 3216 QbeGen.CallEnd(TRUE, q);
  3231. 3217 t := SymTab.ProcRes(qn)
  3232. 3218 ELSE
  3233. 3219 (* procedure used as a
  3234. 3220 value (assign to a
  3235. 3221 procedure variable):
  3236. 3222 its code address *)
  3237. 3223 t := SymTab.ProcTypeOf(qn);
  3238. 3224 QbeGen.Mangled(qn,
  3239. 3225 SymTab.ProcUid(qn), qm0);
  3240. 3226 QbeGen.ProcAddr(qm0, q)
  3241. 3227 END
  3242. 3228 END; .)
  3243. 3229 | ( "HIGH" (. isHigh := TRUE; .)
  3244. 3230 | ( "LEN" | "LENGTH" ) (. isHigh := FALSE; .) )
  3245. 3231 "(" ( Design<dt, dk, qd, qn, sfx> (. isStr := FALSE;
  3246. 3232 isU := FALSE; .)
  3247. 3233 | string (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s);
  3248. 3234 isStr := TRUE;
  3249. 3235 isU := FALSE;
  3250. 3236 IF SymTab.StrLen(s) = 3 THEN
  3251. 3237 dt := SymTab.CharType();
  3252. 3238 QbeGen.IntStr(QbeGen.CharVal(s),
  3253. 3239 qd)
  3254. 3240 ELSE
  3255. 3241 dt := SymTab.NewStr();
  3256. 3242 QbeGen.DeclStr(s, qd);
  3257. 3243 QbeGen.NoteAddr(qd, qd)
  3258. 3244 END;
  3259. 3245 dk := -1;
  3260. 3246 qn[0] := CHR(0); .)
  3261. 3247 | ustring (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s);
  3262. 3248 QbeGen.DeclUStr(s, qd, isU, ucp,
  3263. 3249 uok);
  3264. 3250 isStr := FALSE;
  3265. 3251 IF NOT uok THEN
  3266. 3252 SemError(234);
  3267. 3253 dt := SymTab.InvalidType
  3268. 3254 ELSIF isU THEN
  3269. 3255 (* one codepoint: a UCHAR;
  3270. 3256 LEN is 1, HIGH is 0 *)
  3271. 3257 dt := SymTab.UCharType();
  3272. 3258 QbeGen.IntStr(ucp, qd)
  3273. 3259 ELSE
  3274. 3260 dt := SymTab.NewUStr();
  3275. 3261 QbeGen.NoteAddr(qd, qd)
  3276. 3262 END;
  3277. 3263 dk := -1;
  3278. 3264 qn[0] := CHR(0); .) )
  3279. 3265 ")"
  3280. 3266 (. astNode := AST.MakeNode(AST.NkCall);
  3281. 3267 IF isHigh THEN AST.SetChild(astNode, 0,
  3282. 3268 AST.MakeLeaf(AST.NkIdent, "HIGH"))
  3283. 3269 ELSE AST.SetChild(astNode, 0,
  3284. 3270 AST.MakeLeaf(AST.NkIdent, "LEN")) END;
  3285. 3271 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
  3286. 3272 astCur := astNode; astIsLit := TRUE;
  3287. 3273 IF (dt # SymTab.InvalidType)
  3288. 3274 AND (SymTab.ClassOf(dt) = SymTab.ClUStr) THEN
  3289. 3275 (* UString: the count is
  3290. 3276 the descriptor header *)
  3291. 3277 IF isHigh THEN
  3292. 3278 QbeGen.UStrLen(qd, qr);
  3293. 3279 QbeGen.DecQ(qr)
  3294. 3280 ELSE
  3295. 3281 QbeGen.UStrLen(qd, qr)
  3296. 3282 END;
  3297. 3283 t := SymTab.IntType();
  3298. 3284 QbeGen.CopyOp(qr, q)
  3299. 3285 ELSIF (dt # SymTab.InvalidType)
  3300. 3286 AND (SymTab.ClassOf(dt) = SymTab.ClUChar) THEN
  3301. 3287 (* single UCHAR codepoint *)
  3302. 3288 IF isHigh THEN
  3303. 3289 QbeGen.CopyOp("0", qr)
  3304. 3290 ELSE
  3305. 3291 QbeGen.CopyOp("1", qr)
  3306. 3292 END;
  3307. 3293 t := SymTab.IntType();
  3308. 3294 QbeGen.CopyOp(qr, q)
  3309. 3295 ELSIF isStr THEN
  3310. 3296 (* fold: content length at
  3311. 3297 compile time *)
  3312. 3298 IF SymTab.StrLen(s) = 3 THEN
  3313. 3299 c1 := 1
  3314. 3300 ELSE
  3315. 3301 c1 :=
  3316. 3302 SymTab.StrLen(s) - 2
  3317. 3303 END;
  3318. 3304 IF isHigh THEN
  3319. 3305 DEC(c1)
  3320. 3306 END;
  3321. 3307 QbeGen.IntStr(c1, qr);
  3322. 3308 t := SymTab.IntType();
  3323. 3309 QbeGen.CopyOp(qr, q)
  3324. 3310 ELSIF dt = SymTab.InvalidType THEN
  3325. 3311 t := SymTab.InvalidType;
  3326. 3312 QbeGen.CopyOp("0", q)
  3327. 3313 ELSIF SymTab.ClassOf(dt) #
  3328. 3314 SymTab.ClArray THEN
  3329. 3315 SemError(217);
  3330. 3316 t := SymTab.InvalidType;
  3331. 3317 QbeGen.CopyOp("0", q)
  3332. 3318 ELSE
  3333. 3319 IF isHigh THEN
  3334. 3320 IF SymTab.IsOpenArray(dt) THEN
  3335. 3321 QbeGen.OpenHi(qd, qr)
  3336. 3322 ELSE
  3337. 3323 QbeGen.IntStr(
  3338. 3324 SymTab.ArrayHi(dt), qr)
  3339. 3325 END
  3340. 3326 ELSE
  3341. 3327 IF SymTab.IsOpenArray(dt) THEN
  3342. 3328 QbeGen.LoadCount(qd, qr)
  3343. 3329 ELSE
  3344. 3330 QbeGen.IntStr(VAL(
  3345. 3331 INTEGER,
  3346. 3332 SymTab.ArrayLen(dt)),
  3347. 3333 qr)
  3348. 3334 END
  3349. 3335 END;
  3350. 3336 t := SymTab.IntType();
  3351. 3337 QbeGen.CopyOp(qr, q)
  3352. 3338 END; .)
  3353. 3339 | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
  3354. 3340 (. astNode := AST.MakeNode(AST.NkCall);
  3355. 3341 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "SIZE"));
  3356. 3342 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
  3357. 3343 astCur := astNode; astIsLit := TRUE; .)
  3358. 3344 (. IF dt = SymTab.InvalidType THEN
  3359. 3345 t := SymTab.InvalidType;
  3360. 3346 QbeGen.CopyOp("0", q)
  3361. 3347 ELSE
  3362. 3348 QbeGen.IntStr(VAL(INTEGER,
  3363. 3349 SymTab.ObjectSize(dt)), q);
  3364. 3350 t := SymTab.IntType()
  3365. 3351 END; .)
  3366. 3352 | ( "SHIFT" (. isMax := FALSE; .)
  3367. 3353 | "ROTATE" (. isMax := TRUE; .) )
  3368. 3354 "(" Expr<et, q> (. astArg2 := astCur; .) "," Expr<et2, q2> ")"
  3369. 3355 (. astNode := AST.MakeNode(AST.NkCall);
  3370. 3356 IF isMax THEN AST.SetChild(astNode, 0,
  3371. 3357 AST.MakeLeaf(AST.NkIdent, "ROTATE"))
  3372. 3358 ELSE AST.SetChild(astNode, 0,
  3373. 3359 AST.MakeLeaf(AST.NkIdent, "SHIFT")) END;
  3374. 3360 IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END;
  3375. 3361 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
  3376. 3362 astCur := astNode; astIsLit := TRUE;
  3377. 3363 (* set shift/rotate: isMax
  3378. 3364 doubles as "rotate" *)
  3379. 3365 IF (et # SymTab.InvalidType)
  3380. 3366 AND (SymTab.ClassOf(et) =
  3381. 3367 SymTab.ClSet) THEN
  3382. 3368 QbeGen.SetShift(q, q2,
  3383. 3369 SymTab.SetWords(et),
  3384. 3370 SymTab.SetCount(et), isMax,
  3385. 3371 qt);
  3386. 3372 t := et;
  3387. 3373 QbeGen.CopyOp(qt, q)
  3388. 3374 ELSE SemError(230);
  3389. 3375 t := SymTab.InvalidType;
  3390. 3376 QbeGen.CopyOp("0", q)
  3391. 3377 END; .)
  3392. 3378 | ( "MIN" (. isMax := FALSE; .)
  3393. 3379 | "MAX" (. isMax := TRUE; .) )
  3394. 3380 "(" Design<dt, dk, qd, qn, sfx> ")"
  3395. 3381 (. astNode := AST.MakeNode(AST.NkCall);
  3396. 3382 IF isMax THEN AST.SetChild(astNode, 0,
  3397. 3383 AST.MakeLeaf(AST.NkIdent, "MAX"))
  3398. 3384 ELSE AST.SetChild(astNode, 0,
  3399. 3385 AST.MakeLeaf(AST.NkIdent, "MIN")) END;
  3400. 3386 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
  3401. 3387 astCur := astNode; astIsLit := TRUE;
  3402. 3388 IF (dt # SymTab.InvalidType)
  3403. 3389 AND (SymTab.ClassOf(dt) = SymTab.ClReal) THEN
  3404. 3390 (* REAL/LONGREAL: the
  3405. 3391 implementation bounds *)
  3406. 3392 IF isMax THEN
  3407. 3393 QbeGen.NormReal(
  3408. 3394 "3.402823e38", q)
  3409. 3395 ELSE QbeGen.NormReal(
  3410. 3396 "-3.402823e38", q)
  3411. 3397 END;
  3412. 3398 t := SymTab.RealType()
  3413. 3399 ELSIF (dt #
  3414. 3400 SymTab.InvalidType)
  3415. 3401 AND (SymTab.ClassOf(dt) =
  3416. 3402 SymTab.ClLong) THEN
  3417. 3403 IF isMax THEN
  3418. 3404 QbeGen.CopyOp(
  3419. 3405 "9223372036854775807", q)
  3420. 3406 ELSE QbeGen.CopyOp(
  3421. 3407 "-9223372036854775808", q)
  3422. 3408 END;
  3423. 3409 t := SymTab.LongType()
  3424. 3410 ELSIF SymTab.TypeBounds(dt, lo,
  3425. 3411 hi) THEN
  3426. 3412 IF isMax THEN
  3427. 3413 QbeGen.IntStr(hi, q)
  3428. 3414 ELSE QbeGen.IntStr(lo, q)
  3429. 3415 END;
  3430. 3416 t := SymTab.IntType()
  3431. 3417 ELSE SemError(230);
  3432. 3418 t := SymTab.InvalidType;
  3433. 3419 QbeGen.CopyOp("0", q)
  3434. 3420 END; .)
  3435. 3421 | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
  3436. 3422 (. astNode := AST.MakeNode(AST.NkCall);
  3437. 3423 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ADR"));
  3438. 3424 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
  3439. 3425 astCur := astNode; astIsLit := TRUE; .)
  3440. 3426 (. IF dt = SymTab.InvalidType THEN
  3441. 3427 t := SymTab.InvalidType;
  3442. 3428 QbeGen.CopyOp("0", q)
  3443. 3429 ELSE
  3444. 3430 IF sfx THEN
  3445. 3431 QbeGen.CopyOp(qd, q)
  3446. 3432 ELSIF (dk = SymTab.KindVar)
  3447. 3433 OR (dk = SymTab.KindParam) THEN
  3448. 3434 QbeGen.AddrOf(qn, q)
  3449. 3435 ELSE SemError(230);
  3450. 3436 QbeGen.CopyOp("0", q)
  3451. 3437 END;
  3452. 3438 t := SymTab.AddrType()
  3453. 3439 END; .)
  3454. 3440 | "CHR" "(" Expr<et, q> ")"
  3455. 3441 (. astNode := AST.MakeNode(AST.NkCall);
  3456. 3442 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR"));
  3457. 3443 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
  3458. 3444 astCur := astNode; astIsLit := TRUE; .)
  3459. 3445 (. IF (et # SymTab.InvalidType)
  3460. 3446 AND NOT SymTab.IsIntFamily(et) THEN
  3461. 3447 SemError(211) END;
  3462. 3448 t := SymTab.CharType(); .)
  3463. 3449 | ( "ORD" | "ORDL" ) "(" Expr<et, q> ")"
  3464. 3450 (. astNode := AST.MakeNode(AST.NkCall);
  3465. 3451 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ORD"));
  3466. 3452 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
  3467. 3453 astCur := astNode; astIsLit := TRUE; .)
  3468. 3454 (. IF et # SymTab.InvalidType THEN
  3469. 3455 IF (SymTab.ClassOf(et) #
  3470. 3456 SymTab.ClChar)
  3471. 3457 AND (SymTab.ClassOf(et) #
  3472. 3458 SymTab.ClBool)
  3473. 3459 AND (SymTab.ClassOf(et) #
  3474. 3460 SymTab.ClEnum)
  3475. 3461 AND NOT SymTab.IsIntFamily(et) THEN
  3476. 3462 SemError(211) END
  3477. 3463 END;
  3478. 3464 t := SymTab.IntType(); .)
  3479. 3465 | "CAP" "(" Expr<et, q> ")"
  3480. 3466 (. astNode := AST.MakeNode(AST.NkCall);
  3481. 3467 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CAP"));
  3482. 3468 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
  3483. 3469 astCur := astNode; astIsLit := TRUE; .)
  3484. 3470 (. QbeGen.CapQ(q, qa);
  3485. 3471 QbeGen.CopyOp(qa, q);
  3486. 3472 t := SymTab.CharType(); .)
  3487. 3473 | "UCHR" "(" Expr<et, q> ")"
  3488. 3474 (. astNode := AST.MakeNode(AST.NkCall);
  3489. 3475 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UCHR"));
  3490. 3476 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
  3491. 3477 astCur := astNode; astIsLit := TRUE; .)
  3492. 3478 (. (* UCHR: the UCHAR constructor.
  3493. 3479 CHAR -> UCHAR (identity);
  3494. 3480 INTEGER familly -> UCHAR
  3495. 3481 (codepoint value). *)
  3496. 3482 IF (et # SymTab.InvalidType)
  3497. 3483 AND (SymTab.ClassOf(et) # SymTab.ClChar)
  3498. 3484 AND NOT SymTab.IsIntFamily(et) THEN
  3499. 3485 SemError(211) END;
  3500. 3486 t := SymTab.UCharType(); .)
  3501. 3487 | "CHR8" "(" Expr<et, q> ")"
  3502. 3488 (. astNode := AST.MakeNode(AST.NkCall);
  3503. 3489 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR8"));
  3504. 3490 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
  3505. 3491 astCur := astNode; astIsLit := TRUE; .)
  3506. 3492 (. IF (et # SymTab.InvalidType)
  3507. 3493 AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
  3508. 3494 SemError(211) END;
  3509. 3495 QbeGen.WidenLong(q, qa);
  3510. 3496 QbeGen.CheckRange(qa, "0", "255");
  3511. 3497 t := SymTab.CharType(); .)
  3512. 3498 | "UORD" "(" Expr<et, q> ")"
  3513. 3499 (. astNode := AST.MakeNode(AST.NkCall);
  3514. 3500 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UORD"));
  3515. 3501 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
  3516. 3502 astCur := astNode; astIsLit := TRUE; .)
  3517. 3503 (. (* UORD(u): the codepoint as a
  3518. 3504 32-bit ordinal (INTEGER),
  3519. 3505 cf. ORD for CHAR. *)
  3520. 3506 IF (et # SymTab.InvalidType)
  3521. 3507 AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
  3522. 3508 SemError(211) END;
  3523. 3509 t := SymTab.IntType(); .)
  3524. 3510 | "ABS" "(" Expr<et, q> ")"
  3525. 3511 (. astNode := AST.MakeNode(AST.NkCall);
  3526. 3512 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ABS"));
  3527. 3513 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
  3528. 3514 astCur := astNode; astIsLit := TRUE; .)
  3529. 3515 (. IF (et # SymTab.InvalidType)
  3530. 3516 AND NOT SymTab.IsIntFamily(et)
  3531. 3517 AND (SymTab.ClassOf(et) #
  3532. 3518 SymTab.ClReal) THEN
  3533. 3519 SemError(211)
  3534. 3520 ELSE QbeGen.AbsQ(q, qa,
  3535. 3521 SymTab.ClassOf(et) =
  3536. 3522 SymTab.ClReal);
  3537. 3523 QbeGen.CopyOp(qa, q)
  3538. 3524 END;
  3539. 3525 t := et; .)
  3540. 3526 | "VAL" "(" GetIdent<vn> (. astArg2 := AST.MakeLeaf(AST.NkIdent, vn); .) "," Expr<et, q> ")"
  3541. 3527 (. astNode := AST.MakeNode(AST.NkCall);
  3542. 3528 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
  3543. 3529 IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END;
  3544. 3530 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
  3545. 3531 astCur := astNode; astIsLit := TRUE; .)
  3546. 3532 (. IF NOT SymTab.Lookup(vn) THEN
  3547. 3533 SemError(201);
  3548. 3534 t := SymTab.InvalidType
  3549. 3535 ELSE vt := SymTab.SymType(vn);
  3550. 3536 IF vt = SymTab.InvalidType THEN
  3551. 3537 t := SymTab.InvalidType
  3552. 3538 ELSIF et =
  3553. 3539 SymTab.InvalidType THEN
  3554. 3540 t := vt
  3555. 3541 ELSE
  3556. 3542 c1 := SymTab.ClassOf(et);
  3557. 3543 c2 := SymTab.ClassOf(vt);
  3558. 3544 IF (c1 = SymTab.ClInt)
  3559. 3545 AND (c2 = SymTab.ClLong) THEN
  3560. 3546 QbeGen.WidenLong(q, qa);
  3561. 3547 QbeGen.CopyOp(qa, q);
  3562. 3548 t := vt
  3563. 3549 ELSIF (c1 = SymTab.ClLong)
  3564. 3550 AND (c2 = SymTab.ClInt) THEN
  3565. 3551 QbeGen.NarrowLong(q, qa);
  3566. 3552 QbeGen.CopyOp(qa, q);
  3567. 3553 t := vt
  3568. 3554 ELSIF (c1 = SymTab.ClInt)
  3569. 3555 AND (c2 = SymTab.ClReal) THEN
  3570. 3556 QbeGen.ConvIR(q, qa);
  3571. 3557 QbeGen.CopyOp(qa, q);
  3572. 3558 t := vt
  3573. 3559 ELSIF (c1 = SymTab.ClLong)
  3574. 3560 AND (c2 = SymTab.ClReal) THEN
  3575. 3561 QbeGen.ConvLR(q, qa);
  3576. 3562 QbeGen.CopyOp(qa, q);
  3577. 3563 t := vt
  3578. 3564 ELSIF (c1 = SymTab.ClReal)
  3579. 3565 AND (c2 = SymTab.ClInt) THEN
  3580. 3566 QbeGen.ConvRI(q, qa);
  3581. 3567 QbeGen.CopyOp(qa, q);
  3582. 3568 t := vt
  3583. 3569 ELSIF (c1 = SymTab.ClReal)
  3584. 3570 AND (c2 = SymTab.ClLong) THEN
  3585. 3571 QbeGen.ConvRL(q, qa);
  3586. 3572 QbeGen.CopyOp(qa, q);
  3587. 3573 t := vt
  3588. 3574 ELSIF ((c1 = SymTab.ClInt)
  3589. 3575 OR (c1 =
  3590. 3576 SymTab.ClChar)
  3591. 3577 OR (c1 =
  3592. 3578 SymTab.ClBool)
  3593. 3579 OR (c1 =
  3594. 3580 SymTab.ClEnum))
  3595. 3581 AND ((c2 = SymTab.ClInt)
  3596. 3582 OR (c2 =
  3597. 3583 SymTab.ClChar)
  3598. 3584 OR (c2 =
  3599. 3585 SymTab.ClBool)
  3600. 3586 OR (c2 =
  3601. 3587 SymTab.ClEnum)) THEN
  3602. 3588 t := vt
  3603. 3589 ELSIF (c1 = SymTab.ClPtr)
  3604. 3590 AND (c2 = SymTab.ClPtr) THEN
  3605. 3591 t := vt
  3606. 3592 ELSIF (c1 = SymTab.ClReal)
  3607. 3593 AND (c2 = SymTab.ClReal) THEN
  3608. 3594 t := vt
  3609. 3595 ELSE SemError(230);
  3610. 3596 t := SymTab.InvalidType
  3611. 3597 END
  3612. 3598 END
  3613. 3599 END; .)
  3614. 3600 | "(" Expr<et, q> ")" (. t := et; astIsLit := TRUE; .)
  3615. 3601 | SetLit<st, sq> (. astIsLit := TRUE; t := st;
  3616. 3602 QbeGen.CopyOp(sq, q); .)
  3617. 3603 | ( "NOT" | "~" ) Fact<t2, q2> (. astNot := astCur;
  3618. 3604 IF SymTab.BoolCheck(t2) THEN
  3619. 3605 t := SymTab.BoolType()
  3620. 3606 ELSE SemError(212);
  3621. 3607 t := SymTab.InvalidType END;
  3622. 3608 IF t # SymTab.InvalidType THEN
  3623. 3609 QbeGen.NotQ(q2, q)
  3624. 3610 ELSE QbeGen.CopyOp("0", q)
  3625. 3611 END;
  3626. 3612 astIsLit := TRUE;
  3627. 3613 astCur := AST.MakeUn(
  3628. 3614 AST.NkUnary, AST.OpNot, astNot); .)
  3629. 3615 )
  3630. 3616 (. IF NOT astIsLit THEN astCur := AST.NoNode END; .) .
  3631. 3617 (* Set literals are SET OF [0..255] (8 words); elements validated
  3632. 3618 0..255 statically when foldable (222 otherwise), runtime trap
  3633. 3619 for computed elements. Ranges always lower via SetRange. *)
  3634. 3620 SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  3635. 3621 (. VAR astNode: AST.Node; .)
  3636. 3622 = "{" (. t := SymTab.NewSet(
  3637. 3623 SymTab.NewSubR(0, 255));
  3638. 3624 astNode := AST.MakeNode(AST.NkSetLit);
  3639. 3625 QbeGen.NewSetTemp(8, q);
  3640. 3626 QbeGen.SetZero(q, 8); .)
  3641. 3627 [ SetElem<t, q, astNode> { "," SetElem<t, q, astNode> } ]
  3642. 3628 "}" (. astCur := astNode; .) .
  3643. 3629 (* Typed brace constructor: TypeName{ elems } — BITSET{0} (a set)
  3644. 3630 or ArrayName{...} (an array constructor, GNU Modula-2). The
  3645. 3631 declared type sets the width (set) or element type (array). *)
  3646. 3632 TypedBraceLit<vt: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  3647. 3633 (. VAR nw: CARDINAL;
  3648. 3634 astNode: AST.Node;
  3649. 3635 savedCls: INTEGER; .)
  3650. 3636 = "{" (. savedCls := braceCls;
  3651. 3637 astNode := AST.MakeNode(AST.NkBraceLit);
  3652. 3638 IF vt = SymTab.InvalidType THEN
  3653. 3639 braceCls := -1
  3654. 3640 ELSE braceCls :=
  3655. 3641 SymTab.ClassOf(vt)
  3656. 3642 END;
  3657. 3643 IF braceCls = SymTab.ClSet THEN
  3658. 3644 IF vt = SymTab.InvalidType THEN
  3659. 3645 nw := 8
  3660. 3646 ELSE nw := SymTab.SetWords(vt);
  3661. 3647 IF nw = 0 THEN nw := 8 END
  3662. 3648 END;
  3663. 3649 QbeGen.NewSetTemp(nw, q);
  3664. 3650 QbeGen.SetZero(q, nw)
  3665. 3651 ELSIF (braceCls =
  3666. 3652 SymTab.ClArray)
  3667. 3653 OR (braceCls =
  3668. 3654 SymTab.ClRecord)
  3669. 3655 OR (braceCls =
  3670. 3656 SymTab.ClClass) THEN
  3671. 3657 QbeGen.CtorBegin(vt)
  3672. 3658 ELSE
  3673. 3659 IF vt # SymTab.InvalidType THEN
  3674. 3660 SemError(230) END;
  3675. 3661 braceCls := -1
  3676. 3662 END; .)
  3677. 3663 [ BraceElem<vt, q, astNode> { "," BraceElem<vt, q, astNode> } ]
  3678. 3664 "}" (. IF (braceCls = SymTab.ClArray)
  3679. 3665 OR (braceCls =
  3680. 3666 SymTab.ClRecord)
  3681. 3667 OR (braceCls =
  3682. 3668 SymTab.ClClass) THEN
  3683. 3669 QbeGen.CtorEnd(q)
  3684. 3670 ELSIF braceCls # SymTab.ClSet THEN
  3685. 3671 QbeGen.CopyOp("0", q)
  3686. 3672 END;
  3687. 3673 braceCls := savedCls; .)
  3688. 3674 (. astCur := astNode; .) .
  3689. 3675 BraceElem<vt: SymTab.TypeIndex; VAR sq: QbeGen.QVal; node: AST.Node>
  3690. 3676 (. VAR et, et2: SymTab.TypeIndex;
  3691. 3677 qe, q2: QbeGen.QVal;
  3692. 3678 v, v2, reps, k: INTEGER;
  3693. 3679 elem: SymTab.TypeIndex;
  3694. 3680 lo: INTEGER;
  3695. 3681 span: CARDINAL;
  3696. 3682 cl, cl2: INTEGER;
  3697. 3683 hasR, hasB: BOOLEAN;
  3698. 3684 astEl: AST.Node; .)
  3699. 3685 = (. hasR := FALSE; hasB := FALSE; .)
  3700. 3686 Expr<et, qe> (. astEl := astCur; .)
  3701. 3687 [ ".." Expr<et2, q2> (. astEl := AST.MakeBin(
  3702. 3688 AST.NkSubrange, 0, astEl, astCur);
  3703. 3689 hasR := TRUE; .) ]
  3704. 3690 [ "BY" Expr<et2, q2> (. hasB := TRUE; .) ]
  3705. 3691 (. IF braceCls = SymTab.ClSet THEN
  3706. 3692 IF hasB THEN SemError(230) END;
  3707. 3693 lo := SymTab.SetBaseLo(vt);
  3708. 3694 span := SymTab.SetCount(vt);
  3709. 3695 IF (et = SymTab.InvalidType)
  3710. 3696 OR (hasR AND (et2 =
  3711. 3697 SymTab.InvalidType)) THEN
  3712. 3698 ELSE cl :=
  3713. 3699 SymTab.ClassOf(et);
  3714. 3700 IF hasR THEN
  3715. 3701 cl2 :=
  3716. 3702 SymTab.ClassOf(et2)
  3717. 3703 ELSE cl2 := SymTab.ClInt
  3718. 3704 END;
  3719. 3705 IF NOT SymTab.SetElemClassOk(cl)
  3720. 3706 OR (hasR AND NOT
  3721. 3707 SymTab.SetElemClassOk(cl2))
  3722. 3708 THEN
  3723. 3709 SemError(222)
  3724. 3710 ELSIF hasR
  3725. 3711 AND SymTab.ConstInt(qe, v)
  3726. 3712 AND SymTab.ConstInt(q2,
  3727. 3713 v2)
  3728. 3714 AND ((v < lo)
  3729. 3715 OR (v2 < lo)
  3730. 3716 OR (v >= lo +
  3731. 3717 VAL(INTEGER, span))
  3732. 3718 OR (v2 >= lo +
  3733. 3719 VAL(INTEGER, span))
  3734. 3720 OR (v > v2)) THEN
  3735. 3721 SemError(222)
  3736. 3722 ELSIF hasR THEN
  3737. 3723 QbeGen.SetRange(sq, qe, q2,
  3738. 3724 lo, span)
  3739. 3725 ELSIF SymTab.ConstInt(qe,
  3740. 3726 v)
  3741. 3727 AND ((v < lo)
  3742. 3728 OR (v >= lo +
  3743. 3729 VAL(INTEGER,
  3744. 3730 span))) THEN
  3745. 3731 SemError(222)
  3746. 3732 ELSE QbeGen.SetBit(sq, qe,
  3747. 3733 lo, span)
  3748. 3734 END
  3749. 3735 END
  3750. 3736 ELSIF (braceCls = SymTab.ClArray)
  3751. 3737 OR (braceCls =
  3752. 3738 SymTab.ClRecord)
  3753. 3739 OR (braceCls =
  3754. 3740 SymTab.ClClass) THEN
  3755. 3741 IF hasR THEN SemError(230) END;
  3756. 3742 reps := 1;
  3757. 3743 IF hasB THEN
  3758. 3744 IF SymTab.ConstInt(q2, v2)
  3759. 3745 AND (v2 >= 1) THEN
  3760. 3746 reps := v2
  3761. 3747 ELSE SemError(230)
  3762. 3748 END
  3763. 3749 END;
  3764. 3750 k := 0;
  3765. 3751 WHILE k < reps DO
  3766. 3752 QbeGen.CtorElem(qe);
  3767. 3753 INC(k)
  3768. 3754 END
  3769. 3755 END; .)
  3770. 3756 (. AST.SetChild(node,
  3771. 3757 AST.NChild(node), astEl); .) .
  3772. 3758 SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal; node: AST.Node> (. VAR et, et2: SymTab.TypeIndex;
  3773. 3759 qe, q2: QbeGen.QVal;
  3774. 3760 v, v2: INTEGER;
  3775. 3761 lo: INTEGER;
  3776. 3762 span: CARDINAL;
  3777. 3763 cl, cl2: INTEGER;
  3778. 3764 hasR: BOOLEAN;
  3779. 3765 astEl: AST.Node; .)
  3780. 3766 = (. hasR := FALSE; .)
  3781. 3767 Expr<et, qe> (. astEl := astCur; .)
  3782. 3768 [ ".." Expr<et2, q2> (. astEl := AST.MakeBin(
  3783. 3769 AST.NkSubrange, 0, astEl, astCur);
  3784. 3770 hasR := TRUE; .) ]
  3785. 3771 (. lo := SymTab.SetBaseLo(st);
  3786. 3772 span := SymTab.SetCount(st);
  3787. 3773 IF (et = SymTab.InvalidType)
  3788. 3774 OR (hasR AND (et2 =
  3789. 3775 SymTab.InvalidType)) THEN
  3790. 3776 ELSE cl :=
  3791. 3777 SymTab.ClassOf(et);
  3792. 3778 IF hasR THEN
  3793. 3779 cl2 :=
  3794. 3780 SymTab.ClassOf(et2)
  3795. 3781 ELSE cl2 := SymTab.ClInt
  3796. 3782 END;
  3797. 3783 IF NOT SymTab.SetElemClassOk(cl)
  3798. 3784 OR (hasR AND NOT
  3799. 3785 SymTab.SetElemClassOk(cl2))
  3800. 3786 THEN
  3801. 3787 SemError(222)
  3802. 3788 ELSIF hasR
  3803. 3789 AND SymTab.ConstInt(qe, v)
  3804. 3790 AND SymTab.ConstInt(q2,
  3805. 3791 v2)
  3806. 3792 AND ((v < lo)
  3807. 3793 OR (v2 < lo)
  3808. 3794 OR (v >= lo +
  3809. 3795 VAL(INTEGER, span))
  3810. 3796 OR (v2 >= lo +
  3811. 3797 VAL(INTEGER, span))
  3812. 3798 OR (v > v2)) THEN
  3813. 3799 SemError(222)
  3814. 3800 ELSIF hasR THEN
  3815. 3801 QbeGen.SetRange(sq, qe, q2,
  3816. 3802 lo, span)
  3817. 3803 ELSIF SymTab.ConstInt(qe,
  3818. 3804 v)
  3819. 3805 AND ((v < lo)
  3820. 3806 OR (v >= lo +
  3821. 3807 VAL(INTEGER,
  3822. 3808 span))) THEN
  3823. 3809 SemError(222)
  3824. 3810 ELSE QbeGen.SetBit(sq, qe,
  3825. 3811 lo, span)
  3826. 3812 END
  3827. 3813 END; .)
  3828. 3814 (. AST.SetChild(node,
  3829. 3815 AST.NChild(node), astEl); .) .
  3830. 3816 GetIdent<VAR n: SymTab.Name>
  3831. 3817 = ident (. LexName(n); .) .
  3832. 3818
  3833. 3819 END M2.
  3834. 0 errors
  3835. Statistics:
  3836. nr of terminals: 104 (limit 400)
  3837. nr of non-terminals: 85 (limit 210)
  3838. nr of pragmas: 0 (limit 396)
  3839. nr of symbolnodes: 189 (limit 500)
  3840. nr of graphnodes: 1107 (limit 1500)
  3841. nr of conditionsets: 11 (limit 100)
  3842. nr of charactersets: 16 (limit 250)