M2.atg 241 KB

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