M2.atg 139 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459
  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;
  52. CHARACTERS
  53. eol = CHR(13) .
  54. lf = CHR(10) .
  55. letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" .
  56. digit = "0123456789" .
  57. hexDigit = digit + "ABCDEFabcdef" .
  58. noQuote1 = ANY - "'" - eol .
  59. noQuote2 = ANY - '"' - eol .
  60. IGNORE CHR(9) .. CHR(13)
  61. COMMENTS FROM "(*" TO "*)" NESTED
  62. COMMENTS FROM "//" TO lf
  63. TOKENS
  64. ident = letter { letter | digit } .
  65. integer = digit { digit }
  66. | digit { digit } CONTEXT("..")
  67. | "0x" hexDigit { hexDigit }
  68. | "0X" hexDigit { hexDigit } .
  69. real = digit { digit } "." { digit }
  70. [ ( "E" | "e" ) [ "+" | "-" ] digit { digit } ] .
  71. string = "'" { noQuote1 } "'"
  72. | '"' { noQuote2 } '"' .
  73. charConst = digit { digit } ( "C" | "c" ) .
  74. ustring = ( "U" | "u" ) ( "'" { noQuote1 } "'" | '"' { noQuote2 } '"' ) .
  75. PRODUCTIONS
  76. M2
  77. = Unit "." .
  78. (* Units: program modules compile fully; DEFINITION and
  79. IMPLEMENTATION modules parse + check now but lower in step 4
  80. (each ends with one 230); same for nested local modules. *)
  81. Unit
  82. = DefUnit
  83. | ImplUnit
  84. | ProgModule .
  85. (* Step 4.3: one session compiles DEFINITION, its IMPLEMENTATION
  86. and one program (last) into one image. Units share the symbol
  87. table; imports materialize exported names. *)
  88. DefUnit (. VAR m1, m2, pn: SymTab.Name; .)
  89. = "DEFINITION" "MODULE"
  90. GetIdent<m1> (. IF NOT SymTab.BeginDef(m1) THEN
  91. SemError(200) END;
  92. QbeGen.SetModule(m1); .)
  93. ";"
  94. { Import }
  95. { ConstBlock | TypeBlock<TRUE> | VarBlock
  96. | ProcHeading<pn> ";" (. SymTab.CloseProc;
  97. QbeGen.AbortFunc; .) }
  98. "END"
  99. GetIdent<m2> (. IF NOT SymTab.Equal(m1, m2) THEN
  100. SemError(202) END;
  101. SymTab.EndUnit; .) .
  102. ImplUnit (. VAR m1, m2: SymTab.Name; .)
  103. = "IMPLEMENTATION" "MODULE"
  104. GetIdent<m1> (. IF NOT SymTab.BeginImpl(m1) THEN
  105. SemError(201) END;
  106. QbeGen.SetModule(m1); .)
  107. ";"
  108. { Import }
  109. DeclSeq
  110. [ "BEGIN" (. QbeGen.BeginInit(m1); .)
  111. [ StatSeq ] (. QbeGen.EndInit; .) ]
  112. "END"
  113. GetIdent<m2> (. IF NOT SymTab.Equal(m1, m2) THEN
  114. SemError(202) END;
  115. SymTab.EndUnit; .) .
  116. ProgModule (. VAR m1, m2: SymTab.Name; .)
  117. = "MODULE"
  118. GetIdent<m1> (. IF NOT SymTab.BeginProg(m1) THEN
  119. SemError(200) END;
  120. QbeGen.SetModule(m1); .)
  121. [ Priority ]
  122. ";"
  123. { Import }
  124. DeclSeq
  125. [ "BEGIN" (. QbeGen.BeginBody; .)
  126. [ StatSeq ] ]
  127. "END"
  128. GetIdent<m2> (. IF NOT SymTab.Equal(m1, m2) THEN
  129. SemError(202) END;
  130. QbeGen.EndModule(m1);
  131. SymTab.EndUnit; .) .
  132. DeclSeq
  133. = { ConstBlock | TypeBlock<FALSE> | VarBlock | ProcDecl ";"
  134. | NestedModule ";" | ClassItem ";" } .
  135. (* Local module, Wirth form. Declarations lower like top-level ones
  136. (same QBE module prefix); a BEGIN body becomes an init function
  137. that main calls; the EXPORT list is hoisted into the enclosing
  138. scope at END. *)
  139. NestedModule (. VAR m1, m2: SymTab.Name;
  140. expNames: ARRAY [0 .. 63] OF SymTab.Name;
  141. expCount, k: CARDINAL; .)
  142. = "MODULE"
  143. GetIdent<m1> (. IF NOT SymTab.Enter(m1,
  144. SymTab.KindModule) THEN
  145. SemError(200) END;
  146. SymTab.PushScope;
  147. expCount := 0; .)
  148. [ Priority ]
  149. ";"
  150. { Import }
  151. [ "EXPORT" [ "QUALIFIED" ]
  152. GetIdent<expNames[expCount]> (. INC(expCount); .)
  153. { "," GetIdent<expNames[expCount]>
  154. (. INC(expCount); .) }
  155. ";" ]
  156. DeclSeq
  157. [ "BEGIN" (. QbeGen.BeginInit(m1); .)
  158. [ StatSeq ] (. QbeGen.EndInit; .) ]
  159. "END"
  160. GetIdent<m2> (. IF NOT SymTab.Equal(m1, m2) THEN
  161. SemError(202) END;
  162. k := 0;
  163. WHILE k < expCount DO
  164. SymTab.ExportUp(expNames[k]);
  165. INC(k)
  166. END;
  167. SymTab.PopScope; .) .
  168. Priority
  169. = "[" integer "]" (. SemError(230); .) .
  170. (* Imports (4.3): FROM materializes the names (unqualified use);
  171. plain IMPORT only demands the module exists — qualified `L.x`
  172. materializes on first use (Design). *)
  173. (* Unknown modules stay unchecked stubs (legacy, so hand-written
  174. import lines don't fail); a known module's missing export is
  175. 201. *)
  176. Import (. VAR n: SymTab.Name; .)
  177. = "FROM"
  178. GetIdent<n>
  179. "IMPORT"
  180. ImpList<n> ";"
  181. | "IMPORT"
  182. ImpModList ";" .
  183. ImpList<mod: SymTab.Name> (. VAR n: SymTab.Name; .)
  184. = ImpName<mod>
  185. { "," ImpName<mod> } .
  186. (* Pervasive built-ins imported from SYSTEM (e.g. TSIZE) are
  187. accepted and ignored: the built-in applies regardless. *)
  188. ImpName<mod: SymTab.Name> (. VAR n: SymTab.Name; .)
  189. = GetIdent<n> (. IF SymTab.ModKnown(mod)
  190. AND NOT SymTab.ImportFrom(mod, n) THEN
  191. SemError(201) END; .)
  192. | ( "TSIZE" | "SIZE" | "ADR" | "HIGH" | "LEN"
  193. | "CHR" | "ORD" | "ORDL" | "VAL" | "ABS" | "CAP"
  194. | "UCHR" | "CHR8" | "UORD"
  195. | "INC" | "DEC" ) .
  196. ImpModList (. VAR n: SymTab.Name; .)
  197. = GetIdent<n>
  198. { "," GetIdent<n> } .
  199. (* Opaque TYPE declarations (definition modules). The targetless
  200. alias resolves to InvalidType until step 4 completes it. *)
  201. (* Scalar-phase TYPEs: named types, integer subranges, enumerations.
  202. Opaque "TYPE T;" needs isDef (definition units); elsewhere 231.
  203. Composite forms (ARRAY/RECORD/SET/POINTER) arrive with step 3. *)
  204. TypeBlock<isDef: BOOLEAN>
  205. = "TYPE" (. SymTab.BeginTypeBlock; .)
  206. { TypeItem<isDef> ";" | ClassItem ";" }
  207. (. SymTab.EndTypeBlock; .) .
  208. TypeItem<isDef: BOOLEAN> (. VAR n: SymTab.Name;
  209. t, op: SymTab.TypeIndex; .)
  210. = GetIdent<n> (. op := SymTab.OpaqueBase(n);
  211. IF op = SymTab.InvalidType THEN
  212. IF NOT SymTab.Enter(n,
  213. SymTab.KindType) THEN
  214. SemError(200) END
  215. END; .)
  216. ( "=" Type<t, FALSE> (. IF op # SymTab.InvalidType THEN
  217. SymTab.SetTarget(op, t)
  218. ELSE SymTab.SetSymType(n, t)
  219. END; .)
  220. | (. IF op # SymTab.InvalidType THEN
  221. (* stays opaque *)
  222. ELSIF NOT isDef THEN
  223. SemError(231)
  224. ELSE SymTab.SetSymType(n,
  225. SymTab.NewAlias()) END; .) ) .
  226. Type<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
  227. = TypeIdent<t>
  228. | Subrange<t>
  229. | Enum<t>
  230. | ArrayType<t, allowOpen>
  231. | SetType<t>
  232. | RecordType<t>
  233. | PointerType<t>
  234. | ProcType<t> .
  235. PointerType<VAR t: SymTab.TypeIndex> (. VAR base: SymTab.TypeIndex; .)
  236. = "POINTER" "TO" Type<base, FALSE>(. t := SymTab.NewPtr(base); .) .
  237. (* Procedure types (step 8.5): PROCEDURE (params): result. Values
  238. are code pointers; params are collected into the descriptor. *)
  239. ProcType<VAR t: SymTab.TypeIndex> (. VAR res, pt: SymTab.TypeIndex;
  240. isV: BOOLEAN; .)
  241. = "PROCEDURE" (. res := SymTab.InvalidType;
  242. t := SymTab.NewProcType(res); .)
  243. [ "(" [ ProcTypeSection<t> { ";" ProcTypeSection<t> } ] ")" ]
  244. [ ":" TypeIdent<res> (. SymTab.SetProcTypeRes(t, res); .) ] .
  245. ProcTypeSection<t: SymTab.TypeIndex> (. VAR pt: SymTab.TypeIndex;
  246. isV: BOOLEAN;
  247. cnt, k: CARDINAL;
  248. names: ARRAY [0 .. 15] OF SymTab.Name; .)
  249. = (. isV := FALSE; cnt := 0; .)
  250. [ "VAR" (. isV := TRUE; .) ]
  251. GetIdent<names[cnt]> (. INC(cnt); .)
  252. { "," GetIdent<names[cnt]> (. INC(cnt); .) }
  253. ( ":" Type<pt, FALSE> (. k := 0;
  254. WHILE k < cnt DO
  255. SymTab.ProcTypeAdd(t, isV, pt);
  256. INC(k)
  257. END; .)
  258. | (. (* type-only parameter list:
  259. each name is a type (GNU
  260. shorthand used by the
  261. Coco/R scanner frame) *)
  262. k := 0;
  263. WHILE k < cnt DO
  264. IF SymTab.Lookup(names[k])
  265. AND ((SymTab.SymKind(names[k]) = SymTab.KindType)
  266. OR (SymTab.SymKind(names[k]) = SymTab.KindPredef)) THEN
  267. pt := SymTab.SymType(names[k])
  268. ELSE SemError(201);
  269. pt := SymTab.InvalidType
  270. END;
  271. SymTab.ProcTypeAdd(t, isV, pt);
  272. INC(k)
  273. END; .) ) .
  274. (* Arrays: "OF" without bounds is an open formal (allowed only
  275. where allowOpen); "[lo..hi, ...]" nests bounded levels inside
  276. out. Bounds are folded literals (int/char); anything else 230.
  277. Bare-type indices ("ARRAY Color OF") wait for enum ordinals. *)
  278. ArrayType<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
  279. (. VAR elem: SymTab.TypeIndex;
  280. ok: BOOLEAN;
  281. bnds, bndh: ARRAY [0 .. 7] OF INTEGER;
  282. nb, k: CARDINAL; .)
  283. = "ARRAY"
  284. ( "OF" Type<elem, FALSE> (. IF NOT allowOpen THEN
  285. SemError(230) END;
  286. t := SymTab.NewOpenArray(elem); .)
  287. | "[" (. SymTab.BoundBegin; ok := TRUE; .)
  288. BoundPair<ok>
  289. { "," BoundPair<ok> }
  290. "]" (. (* snapshot before the element
  291. type, which reuses the bound
  292. buffer for a nested ARRAY *)
  293. nb := SymTab.BoundCount();
  294. k := 0;
  295. WHILE k < nb DO
  296. bnds[k] := SymTab.BoundLo(k);
  297. bndh[k] := SymTab.BoundHi(k);
  298. INC(k)
  299. END; .)
  300. "OF" Type<elem, FALSE>
  301. (. IF ok THEN
  302. k := nb;
  303. WHILE k > 0 DO
  304. DEC(k);
  305. elem := SymTab.NewArrayB(
  306. elem, bnds[k], bndh[k])
  307. END;
  308. t := elem
  309. ELSE t := SymTab.InvalidType
  310. END; .) ) .
  311. BoundPair<VAR ok: BOOLEAN> (. VAR tlo, thi: SymTab.TypeIndex;
  312. qlo, qhi: QbeGen.QVal;
  313. lo, hi: INTEGER;
  314. cl, cl2: INTEGER; .)
  315. = Expr<tlo, qlo> ".." Expr<thi, qhi>
  316. (. IF (tlo = SymTab.InvalidType)
  317. OR (thi = SymTab.InvalidType) THEN
  318. ok := FALSE
  319. ELSE cl := SymTab.ClassOf(tlo);
  320. cl2 := SymTab.ClassOf(thi);
  321. IF ((cl # SymTab.ClInt)
  322. AND (cl # SymTab.ClChar))
  323. OR ((cl2 # SymTab.ClInt)
  324. AND (cl2 # SymTab.ClChar)) THEN
  325. SemError(230); ok := FALSE
  326. ELSIF NOT SymTab.ConstInt(qlo, lo)
  327. OR NOT SymTab.ConstInt(qhi, hi)
  328. OR (lo > hi) THEN
  329. SemError(230); ok := FALSE
  330. ELSIF NOT SymTab.BoundAdd(lo, hi) THEN
  331. SemError(230); ok := FALSE
  332. END;
  333. END; .) .
  334. (* Sets: multi-word masks over bases ≤ 256 values (bool, char,
  335. bounded subranges; enums wait for ordinals, INTEGER is
  336. unbounded). Literals are SET OF [0..255]; assignment and
  337. comparison across suitable bases are lenient (masks over min
  338. words + zero-check extras), out-of-span literals are 222. *)
  339. SetType<VAR t: SymTab.TypeIndex> (. VAR base: SymTab.TypeIndex;
  340. blo, bhi, bspan: INTEGER;
  341. bcls: INTEGER; .)
  342. = "SET" "OF" Type<base, FALSE>
  343. (. IF base = SymTab.InvalidType THEN
  344. t := SymTab.InvalidType
  345. ELSE bcls :=
  346. SymTab.ClassOf(base);
  347. IF bcls = SymTab.ClBool THEN
  348. blo := 0; bspan := 2
  349. ELSIF bcls = SymTab.ClChar THEN
  350. blo := 0; bspan := 256
  351. ELSIF SymTab.SubBounds(base,
  352. blo, bhi) THEN
  353. bspan := bhi - blo + 1
  354. ELSE bspan := 0 END;
  355. IF (bspan <= 0)
  356. OR (bspan > 256) THEN
  357. SemError(230);
  358. t := SymTab.InvalidType
  359. ELSE t := SymTab.NewSet(base)
  360. END
  361. END; .) .
  362. (* Records: flat blobs; array fields are pointers to static
  363. descriptors (locked amendment), nested records inline. Field
  364. offsets static and declaration-ordered. *)
  365. (* Field list: plain fields and (optionally) one variant part. The
  366. variant part is a `CASE ... END` item; because it starts with the
  367. CASE keyword it is unambiguously distinguishable from a field
  368. (which starts with an identifier). *)
  369. RecordType<VAR t: SymTab.TypeIndex> (. VAR t2: SymTab.TypeIndex;
  370. tagOk: BOOLEAN; .)
  371. = "RECORD" (. t := SymTab.NewRecord(); .)
  372. [ RecItem<t> { ";" [ RecItem<t> ] } ]
  373. "END" .
  374. RecItem<rec: SymTab.TypeIndex> (. VAR tt: SymTab.TypeIndex; .)
  375. = RecField<rec>
  376. | CaseField<rec> (. SymTab.MarkVariant(rec); .) .
  377. (* A variant part: CASE tag : Type OF variants. The layout overlays
  378. every branch from the tag slot (see SymTab.ComputeOffsets). *)
  379. CaseField<rec: SymTab.TypeIndex> (. VAR tagT: SymTab.TypeIndex;
  380. tagN: SymTab.Name; .)
  381. = "CASE" (. SymTab.ResetFields(rec); .)
  382. GetIdent<tagN> (. IF NOT SymTab.FieldPending(rec,
  383. tagN) THEN
  384. SemError(200) END; .)
  385. ":" Type<tagT, FALSE> (. IF (tagT # SymTab.InvalidType)
  386. AND NOT SymTab.IsOrdinal(tagT) THEN
  387. SemError(224)
  388. END;
  389. SymTab.FixPendingF(rec, tagT);
  390. SymTab.SetVariantTag(rec, tagN); .)
  391. "OF"
  392. RecFieldList<rec>
  393. { "|" (. SymTab.ResetFields(rec); .)
  394. RecFieldList<rec> }
  395. "END" .
  396. RecFieldList<rec: SymTab.TypeIndex> (. VAR lt, lq: SymTab.TypeIndex;
  397. lv1, lv2: QbeGen.QVal; .)
  398. = VarLabel<lt, lv1> [ ".." VarLabel<lq, lv2> ] ":"
  399. RecField<rec> { ";" [ RecField<rec> ] } .
  400. (* Variant case label: a constant (or a constant range). Values are
  401. not interpreted (the layout overlays regardless). *)
  402. VarLabel<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  403. (. VAR lname: SymTab.Name; .)
  404. = ( ident (. LexName(lname);
  405. QbeGen.CopyOp("0", q);
  406. t := SymTab.IntType(); .)
  407. | integer (. LexString(lname);
  408. QbeGen.CopyOp("0", q);
  409. t := SymTab.IntType(); .)
  410. | charConst (. LexString(lname);
  411. QbeGen.CopyOp("0", q);
  412. t := SymTab.CharType(); .) ) .
  413. RecField<rec: SymTab.TypeIndex> (. VAR n: SymTab.Name;
  414. t2: SymTab.TypeIndex; .)
  415. = RecIdents<rec> ":" Type<t2, FALSE>(. SymTab.FixPendingF(rec, t2); .) .
  416. RecIdents<rec: SymTab.TypeIndex> (. VAR n: SymTab.Name; .)
  417. = GetIdent<n> (. IF NOT SymTab.FieldPending(rec,
  418. n) THEN
  419. SemError(200) END; .)
  420. { "," GetIdent<n> (. IF NOT SymTab.FieldPending(rec,
  421. n) THEN
  422. SemError(200) END; .) } .
  423. TypeIdent<VAR t: SymTab.TypeIndex> (. VAR n, qid: SymTab.Name;
  424. k: INTEGER;
  425. dotted: BOOLEAN; .)
  426. = GetIdent<n> (. dotted := FALSE;
  427. IF NOT SymTab.Lookup(n) THEN
  428. k := -1;
  429. t := SymTab.ForwardType(n);
  430. IF t = SymTab.InvalidType THEN
  431. SemError(201)
  432. END
  433. ELSE k := SymTab.SymKind(n);
  434. IF (k = SymTab.KindType)
  435. OR (k = SymTab.KindPredef) THEN
  436. t := SymTab.SymType(n)
  437. ELSE t := SymTab.InvalidType
  438. END
  439. END; .)
  440. [ "." GetIdent<qid> (. dotted := TRUE;
  441. IF k = SymTab.KindModule THEN
  442. t := SymTab.QualType(n, qid);
  443. IF t = SymTab.InvalidType THEN
  444. SemError(201)
  445. END
  446. ELSE SemError(221);
  447. t := SymTab.InvalidType
  448. END; .) ]
  449. (. IF NOT dotted THEN
  450. IF (k = SymTab.KindModule)
  451. OR ((k # SymTab.KindType)
  452. AND (k # SymTab.KindPredef)
  453. AND (k # SymTab.KindImport)
  454. AND (k # -1)) THEN
  455. SemError(221)
  456. END
  457. END; .) .
  458. Subrange<VAR t: SymTab.TypeIndex> (. VAR tlo, thi: SymTab.TypeIndex;
  459. qlo, qhi: QbeGen.QVal;
  460. lo, hi: INTEGER; .)
  461. = "[" Expr<tlo, qlo> ".." Expr<thi, qhi>
  462. (. IF (tlo = SymTab.InvalidType)
  463. OR (thi = SymTab.InvalidType) THEN
  464. t := SymTab.InvalidType
  465. ELSIF (SymTab.ClassOf(tlo) #
  466. SymTab.ClInt)
  467. OR (SymTab.ClassOf(thi) #
  468. SymTab.ClInt) THEN
  469. SemError(230);
  470. t := SymTab.InvalidType
  471. ELSIF NOT SymTab.ConstInt(qlo, lo)
  472. OR NOT SymTab.ConstInt(qhi, hi)
  473. OR (lo > hi) THEN
  474. SemError(230);
  475. t := SymTab.InvalidType
  476. ELSE t := SymTab.NewSubR(lo, hi)
  477. END; .)
  478. "]" .
  479. Enum<VAR t: SymTab.TypeIndex> (. VAR n: SymTab.Name;
  480. ord: INTEGER;
  481. qv: QbeGen.QVal; .)
  482. = "(" (. t := SymTab.NewEnum();
  483. ord := 0; .)
  484. GetIdent<n> (. IF NOT SymTab.Enter(n,
  485. SymTab.KindConst) THEN
  486. SemError(200) END;
  487. SymTab.SetSymType(n, t);
  488. QbeGen.IntStr(ord, qv);
  489. SymTab.SetSymVal(n, qv);
  490. INC(ord); .)
  491. { "," GetIdent<n> (. IF NOT SymTab.Enter(n,
  492. SymTab.KindConst) THEN
  493. SemError(200) END;
  494. SymTab.SetSymType(n, t);
  495. QbeGen.IntStr(ord, qv);
  496. SymTab.SetSymVal(n, qv);
  497. INC(ord); .) }
  498. ")" .
  499. (* Clarion-form classes (docs/OOP.txt): declaration + single
  500. inheritance + IMPLEMENTATION blocks. Scopes and member checks
  501. now; lowering (vtable, dispatch, THIS) later — one 230 per
  502. class/impl block. Methods end with ";" per the Table example
  503. (not "," as in the sketch). No underscores in identifiers. *)
  504. (* Single CLASS item in both loops: separating declaration from
  505. IMPLEMENTATION at the loop level needs 2-token lookahead
  506. (CLASS ident vs CLASS IMPLEMENTATION), which LL(1) cannot do.
  507. The second token decides after CLASS is consumed. A misplaced
  508. CLASS IMPLEMENTATION inside TYPE still parses (harmless: the
  509. whole unit ends 230 until lowering). *)
  510. ClassItem
  511. = "CLASS" ( "IMPLEMENTATION" ClassImplRest | ClassRest ) .
  512. ClassRest (. VAR cn, m2, pn: SymTab.Name;
  513. ct: SymTab.TypeIndex; .)
  514. = GetIdent<cn> (. IF NOT SymTab.Enter(cn,
  515. SymTab.KindType) THEN
  516. SemError(200) END;
  517. ct := SymTab.NewClass();
  518. SymTab.SetSymType(cn, ct);
  519. SymTab.PushClassScope(ct); .)
  520. [ Parents<ct> ]
  521. ";"
  522. { ClassField<ct> ";" }
  523. { MethodHeading<pn> ";" (. SymTab.CloseProc;
  524. QbeGen.AbortFunc; .) }
  525. "END"
  526. GetIdent<m2> (. IF NOT SymTab.Equal(cn, m2) THEN
  527. SemError(202) END;
  528. SymTab.PopScope;
  529. SemError(230); .) .
  530. Parents<ct: SymTab.TypeIndex> (. VAR p: SymTab.Name; .)
  531. = "(" Parent1<ct>
  532. { "," GetIdent<p> (. SemError(230); .) }
  533. ")" .
  534. Parent1<ct: SymTab.TypeIndex> (. VAR p: SymTab.Name;
  535. pt: SymTab.TypeIndex; .)
  536. = GetIdent<p> (. IF NOT SymTab.Lookup(p) THEN
  537. SemError(201)
  538. ELSE pt := SymTab.SymType(p);
  539. IF SymTab.ClassOf(pt) #
  540. SymTab.ClClass THEN
  541. SemError(230)
  542. ELSE SymTab.SetParent(ct, pt)
  543. END
  544. END; .) .
  545. ClassField<ct: SymTab.TypeIndex> (. VAR n, rhs: SymTab.Name;
  546. t: SymTab.TypeIndex; .)
  547. = GetIdent<n>
  548. ( "=" GetIdent<rhs> (. IF NOT SymTab.Enter(n,
  549. SymTab.KindConst) THEN
  550. SemError(200) END;
  551. IF SymTab.Lookup(rhs) THEN
  552. SymTab.SetSymType(n,
  553. SymTab.SymType(rhs))
  554. END; .)
  555. | (. IF NOT SymTab.FieldPending(ct,
  556. n) THEN
  557. SemError(200) END; .)
  558. { "," GetIdent<n> (. IF NOT SymTab.FieldPending(ct,
  559. n) THEN
  560. SemError(200) END; .) }
  561. ":" Type<t, FALSE> (. SymTab.FixPendingF(ct, t); .) ) .
  562. MethodHeading<VAR pn: SymTab.Name> (. VAR wantVirt: BOOLEAN; .)
  563. = (. wantVirt := FALSE; .)
  564. [ "VIRTUAL" (. wantVirt := TRUE; .) ]
  565. ProcHeading<pn> (. IF wantVirt THEN
  566. SymTab.MarkVirtual END; .) .
  567. ClassImplRest (. VAR cn, m2: SymTab.Name;
  568. ct: SymTab.TypeIndex; .)
  569. = GetIdent<cn> (. IF NOT SymTab.Lookup(cn) THEN
  570. SemError(201);
  571. ct := SymTab.InvalidType
  572. ELSE ct := SymTab.SymType(cn);
  573. IF SymTab.ClassOf(ct) #
  574. SymTab.ClClass THEN
  575. SemError(230);
  576. ct := SymTab.InvalidType
  577. END
  578. END;
  579. IF ct #
  580. SymTab.InvalidType THEN
  581. IF NOT SymTab.PushClassMembers(
  582. ct) THEN
  583. SemError(230) END
  584. END; .)
  585. ";" { MethodImpl<ct> ";" }
  586. [ "BEGIN"
  587. [ StatSeq ] ]
  588. "END"
  589. GetIdent<m2> (. IF NOT SymTab.Equal(cn, m2) THEN
  590. SemError(202) END;
  591. SymTab.PopScope;
  592. SemError(230); .) .
  593. MethodImpl<ct: SymTab.TypeIndex> (. VAR pn: SymTab.Name; .)
  594. = (. QbeGen.SetNoEmit(TRUE); .)
  595. MethodHeading<pn> ";"
  596. (. IF (ct #
  597. SymTab.InvalidType)
  598. AND NOT SymTab.MethodExists(ct,
  599. pn) THEN
  600. SemError(201) END; .)
  601. ( "FORWARD" (. SymTab.MarkFwd;
  602. SymTab.CloseProc; .)
  603. | Block<pn> (. SymTab.CloseProc; .) )
  604. (. QbeGen.AbortFunc;
  605. QbeGen.SetNoEmit(FALSE);
  606. SemError(230); .) .
  607. ConstBlock
  608. = "CONST" { ConstDecl ";" } .
  609. ConstDecl (. VAR n: SymTab.Name;
  610. t: SymTab.TypeIndex;
  611. qv: QbeGen.QVal;
  612. cls: INTEGER; .)
  613. = GetIdent<n> (. IF NOT SymTab.Enter(n,
  614. SymTab.KindConst) THEN
  615. SemError(200) END; .)
  616. "="
  617. Expr<t, qv> (. SymTab.SetSymType(n, t);
  618. cls := SymTab.ClassOf(t);
  619. IF cls = SymTab.ClStr THEN
  620. SemError(230)
  621. ELSIF NOT QbeGen.IsImm(qv) THEN
  622. SemError(230) END;
  623. SymTab.SetSymVal(n, qv);
  624. QbeGen.DeclConst(n, qv, t); .) .
  625. VarBlock
  626. = "VAR" { VarDecl ";" } .
  627. VarDecl (. VAR nm: SymTab.Name;
  628. t: SymTab.TypeIndex;
  629. i: CARDINAL;
  630. cls: INTEGER; .)
  631. = VarIdents ":"
  632. Type<t, FALSE> (. cls := SymTab.ClassOf(t);
  633. IF (t # SymTab.InvalidType)
  634. AND (cls # SymTab.ClInt)
  635. AND (cls # SymTab.ClBool)
  636. AND (cls # SymTab.ClChar)
  637. AND (cls # SymTab.ClReal)
  638. AND (cls # SymTab.ClArray)
  639. AND (cls # SymTab.ClSet)
  640. AND (cls # SymTab.ClRecord)
  641. AND (cls # SymTab.ClPtr)
  642. AND (cls # SymTab.ClLong)
  643. AND (cls # SymTab.ClProc)
  644. AND (cls # SymTab.ClUChar)
  645. AND (cls # SymTab.ClUStr)
  646. AND (cls # SymTab.ClEnum) THEN
  647. SemError(230) END;
  648. IF QbeGen.LocFull() THEN
  649. SemError(233) END;
  650. i := 0;
  651. WHILE i < SymTab.PendCount() DO
  652. SymTab.PendName(i, nm);
  653. QbeGen.DeclVar(nm, t);
  654. INC(i)
  655. END;
  656. (* a plain VAR list, not a
  657. heading: the signature
  658. result is discarded *)
  659. IF NOT SymTab.FixPending(t) THEN
  660. END; .) .
  661. VarIdents (. VAR n: SymTab.Name; .)
  662. = GetIdent<n> (. IF NOT SymTab.EnterPending(n,
  663. SymTab.KindVar) THEN
  664. SemError(200) END; .)
  665. { ","
  666. GetIdent<n> (. IF NOT SymTab.EnterPending(n,
  667. SymTab.KindVar) THEN
  668. SemError(200) END; .) } .
  669. ParIdents<isV: BOOLEAN> (. VAR n: SymTab.Name; .)
  670. = GetIdent<n> (. IF NOT SymTab.EnterParam(n, isV) THEN
  671. SemError(200) END; .)
  672. { "," GetIdent<n> (. IF NOT SymTab.EnterParam(n, isV) THEN
  673. SemError(200) END; .) } .
  674. (* Procedure headings enter scopes/params/result and buffer the
  675. QBE header; bodies lower to functions (4.1, module level only).
  676. FORWARD marks; the body heading re-enters (signature compare
  677. deferred). Nested procedures parse + check, lowering = 4.2. *)
  678. ProcHeading<VAR pn: SymTab.Name> (. VAR t: SymTab.TypeIndex;
  679. mg: QbeGen.QVal; .)
  680. = "PROCEDURE"
  681. GetIdent<pn> (. IF NOT SymTab.EnterProc(pn) THEN
  682. IF NOT SymTab.ReenterProc(pn) THEN
  683. IF NOT SymTab.ResumeProc(pn) THEN
  684. SemError(200) END
  685. END
  686. END;
  687. QbeGen.Mangled(pn,
  688. SymTab.ProcUid(pn), mg);
  689. QbeGen.BeginFunc(mg); .)
  690. [ FormalParams ]
  691. [ ":" TypeIdent<t> (. IF NOT SymTab.SetProcRes(t) THEN
  692. SemError(235) END;
  693. QbeGen.SetFuncRes(t);
  694. IF (t #
  695. SymTab.InvalidType)
  696. AND ((SymTab.ClassOf(t)
  697. = SymTab.ClArray)
  698. OR (SymTab.ClassOf(t)
  699. = SymTab.ClRecord)
  700. OR (SymTab.ClassOf(t)
  701. = SymTab.ClSet)
  702. OR (SymTab.ClassOf(t)
  703. = SymTab.ClClass)) THEN
  704. SemError(230) END; .) ] .
  705. FormalParams
  706. = "(" [ ParamSection { ";" ParamSection } ] ")" .
  707. ParamSection (. VAR t: SymTab.TypeIndex;
  708. nm: SymTab.Name;
  709. i: CARDINAL;
  710. isV: BOOLEAN; .)
  711. = (. isV := FALSE; .)
  712. [ "VAR" (. isV := TRUE; .) ]
  713. ParIdents<isV> ":" Type<t, TRUE> (. i := 0;
  714. WHILE i < SymTab.PendCount() DO
  715. SymTab.PendName(i, nm);
  716. (* value open arrays are
  717. passed as descriptor
  718. addresses (no copy):
  719. same representation as
  720. VAR formals *)
  721. IF NOT QbeGen.FuncParam(nm,
  722. isV
  723. OR SymTab.IsOpenArray(t),
  724. t) THEN
  725. SemError(233) END;
  726. INC(i)
  727. END;
  728. IF NOT SymTab.FixPending(t) THEN
  729. SemError(235) END; .) .
  730. (* Nested procedures lower like top-level ones (4.2): the
  731. static link gives them their parent's frame. Methods keep
  732. parse-now/230-later. *)
  733. ProcDecl (. VAR pn: SymTab.Name; .)
  734. = ProcHeading<pn> ";"
  735. ( "FORWARD" (. SymTab.MarkFwd;
  736. SymTab.CloseProc;
  737. QbeGen.AbortFunc; .)
  738. | "EXTERNAL" (. SymTab.MarkExternal("");
  739. SymTab.CloseProc;
  740. QbeGen.AbortFunc; .)
  741. | (. QbeGen.EndFuncHeader; .)
  742. Block<pn> (. SymTab.CloseProc;
  743. QbeGen.EndFunc(
  744. SymTab.ProcRes(pn)); .) ) .
  745. Block<pn: SymTab.Name> (. VAR m2: SymTab.Name; .)
  746. = DeclSeq
  747. [ "BEGIN"
  748. [ StatSeq ] ]
  749. "END"
  750. GetIdent<m2> (. IF NOT SymTab.Equal(pn, m2) THEN
  751. SemError(202) END; .) .
  752. StatSeq
  753. = Statement { ";" [ Statement ] } .
  754. (* Trailing/empty statements (`a; ; b`, Coco/R's generated `;;`)
  755. are accepted: the statement after ';' is optional. *)
  756. Statement (. VAR lx: QbeGen.QVal; .)
  757. = AssOrCall
  758. | IfStat
  759. | WhileStat
  760. | RepeatStat
  761. | LoopStat
  762. | ForStat
  763. | CaseStat
  764. | WithStat
  765. | ReturnStat
  766. | HaltStat
  767. | NewStat
  768. | DisposeStat
  769. | IncDecStat
  770. | "EXIT" (. IF QbeGen.TopLoop(lx) THEN
  771. QbeGen.Jmp(lx)
  772. ELSE SemError(230) END; .) .
  773. (* INC(v [,step]) / DEC(v [,step]) as builtin statements over an
  774. integer designator. *)
  775. IncDecStat (. VAR dt, et2: SymTab.TypeIndex;
  776. dk: INTEGER;
  777. qd, qv, qn2, qstep:
  778. QbeGen.QVal;
  779. qn: SymTab.Name;
  780. sfx, isInc: BOOLEAN; .)
  781. = (. isInc := TRUE; .)
  782. ( "INC" (. isInc := TRUE; .)
  783. | "DEC" (. isInc := FALSE; .) )
  784. "(" (. QbeGen.CopyOp("1", qstep); .)
  785. Design<dt, dk, qd, qn, sfx>
  786. [ "," Expr<et2, qstep> ]
  787. ")" (. IF dt = SymTab.InvalidType THEN
  788. ELSIF (dk # SymTab.KindVar)
  789. AND (dk # SymTab.KindParam)
  790. AND (dk # SymTab.KindField) THEN
  791. SemError(210)
  792. ELSIF NOT SymTab.IsIntFamily(dt) THEN
  793. SemError(211)
  794. ELSE
  795. IF sfx
  796. OR (dk = SymTab.KindField) THEN
  797. QbeGen.ElemLoad(qd, dt, qv)
  798. ELSE QbeGen.LoadVar(qn,
  799. FALSE, qv)
  800. END;
  801. QbeGen.NewTemp(qn2);
  802. IF isInc THEN
  803. QbeGen.Op3("add", qn2, qv,
  804. qstep, FALSE)
  805. ELSE QbeGen.Op3("sub", qn2, qv,
  806. qstep, FALSE)
  807. END;
  808. IF sfx
  809. OR (dk = SymTab.KindField) THEN
  810. QbeGen.ElemStore(qd, qn2,
  811. dt)
  812. ELSE QbeGen.StoreVar(qn,
  813. qn2, FALSE)
  814. END
  815. END; .) .
  816. (* NEW/DISPOSE as builtin statements (no call syntax until step 4).
  817. Targets are pointer designators; DISPOSE nils afterwards (safer
  818. than Wirth-undefined; documented). DISPOSE is shallow. *)
  819. NewStat (. VAR dt: SymTab.TypeIndex;
  820. dk: INTEGER;
  821. qd, qm: QbeGen.QVal;
  822. qn: SymTab.Name;
  823. sfx: BOOLEAN;
  824. bt: SymTab.TypeIndex; .)
  825. = "NEW" "(" Design<dt, dk, qd, qn, sfx> ")"
  826. (. IF dt = SymTab.InvalidType THEN
  827. ELSIF (dk # SymTab.KindVar)
  828. AND (dk # SymTab.KindParam)
  829. AND (dk # SymTab.KindField) THEN
  830. SemError(210)
  831. ELSIF SymTab.ClassOf(dt) #
  832. SymTab.ClPtr THEN
  833. SemError(219)
  834. ELSE bt := SymTab.PtrBase(dt);
  835. IF bt #
  836. SymTab.InvalidType THEN
  837. QbeGen.NewHeap(bt, qm);
  838. QbeGen.InitHeap(qm, bt);
  839. IF sfx
  840. OR (dk =
  841. SymTab.KindField) THEN
  842. QbeGen.ElemStore(qd, qm,
  843. dt)
  844. ELSE QbeGen.StorePtr(qn,
  845. qm)
  846. END
  847. END
  848. END; .) .
  849. DisposeStat (. VAR dt: SymTab.TypeIndex;
  850. dk: INTEGER;
  851. qd, qv: QbeGen.QVal;
  852. qn: SymTab.Name;
  853. sfx: BOOLEAN; .)
  854. = "DISPOSE" "(" Design<dt, dk, qd, qn, sfx> ")"
  855. (. IF dt = SymTab.InvalidType THEN
  856. ELSIF (dk # SymTab.KindVar)
  857. AND (dk # SymTab.KindParam)
  858. AND (dk # SymTab.KindField) THEN
  859. SemError(210)
  860. ELSIF SymTab.ClassOf(dt) #
  861. SymTab.ClPtr THEN
  862. SemError(219)
  863. ELSE
  864. IF sfx
  865. OR (dk =
  866. SymTab.KindField) THEN
  867. QbeGen.ElemLoad(qd, dt,
  868. qv)
  869. ELSE QbeGen.LoadPtr(qn, qv)
  870. END;
  871. QbeGen.FreeHeap(qv);
  872. IF sfx
  873. OR (dk =
  874. SymTab.KindField) THEN
  875. QbeGen.ElemStore(qd, "0",
  876. dt)
  877. ELSE QbeGen.StorePtr(qn,
  878. "0")
  879. END
  880. END; .) .
  881. (* WITH pushes each record's fields (inner wins) plus its base
  882. address; field designators resolve through both stacks. *)
  883. WithStat (. VAR nW: CARDINAL; .)
  884. = "WITH" (. nW := 0; .)
  885. WithItem<nW> { "," WithItem<nW> }
  886. "DO" [ StatSeq ] "END"
  887. (. WHILE nW > 0 DO
  888. SymTab.PopScope;
  889. QbeGen.PopWith;
  890. DEC(nW)
  891. END; .) .
  892. WithItem<VAR nW: CARDINAL> (. VAR dt: SymTab.TypeIndex;
  893. dk: INTEGER;
  894. qd, qe: QbeGen.QVal;
  895. qn: SymTab.Name;
  896. sfx: BOOLEAN; .)
  897. = Design<dt, dk, qd, qn, sfx>
  898. (. IF dt = SymTab.InvalidType THEN
  899. ELSIF (SymTab.ClassOf(dt) #
  900. SymTab.ClRecord)
  901. AND (SymTab.ClassOf(dt) #
  902. SymTab.ClClass) THEN
  903. SemError(215)
  904. ELSIF SymTab.PushRecord(dt) THEN
  905. QbeGen.PushWith(qd);
  906. INC(nW)
  907. END; .) .
  908. (* Assignment or procedure-statement call (4.1, module level).
  909. Bare `P;` is a syntax error; function-as-statement is 233. *)
  910. AssOrCall (. VAR dt, et: SymTab.TypeIndex;
  911. dk: INTEGER;
  912. qd, qe, qt, ql: QbeGen.QVal;
  913. qn: SymTab.Name;
  914. ct2, res0: SymTab.TypeIndex;
  915. q2, mg0: QbeGen.QVal;
  916. isR, conv, wconv: BOOLEAN;
  917. called, sfx: BOOLEAN; .)
  918. = Design<dt, dk, qd, qn, sfx>
  919. ( ":="
  920. Expr<et, qe> (. IF (dt # SymTab.InvalidType)
  921. AND (dk # SymTab.KindVar)
  922. AND (dk # SymTab.KindParam)
  923. AND (dk # SymTab.KindField) THEN
  924. SemError(210)
  925. ELSIF NOT SymTab.Assignable(et,
  926. dt) THEN
  927. SemError(210)
  928. ELSIF (dt # SymTab.InvalidType)
  929. AND (SymTab.ClassOf(dt) =
  930. SymTab.ClClass) THEN
  931. SemError(230) END;
  932. isR := (dt #
  933. SymTab.InvalidType)
  934. AND (SymTab.ClassOf(dt)
  935. = SymTab.ClReal);
  936. conv := isR
  937. AND SymTab.IsIntFamily(et);
  938. wconv := (dt #
  939. SymTab.InvalidType)
  940. AND SymTab.IsLongFamily(dt)
  941. AND SymTab.IsIntFamily(et);
  942. IF ((dk = SymTab.KindVar)
  943. OR (dk = SymTab.KindParam)
  944. OR (dk = SymTab.KindField))
  945. AND (dt # SymTab.InvalidType)
  946. AND (et # SymTab.InvalidType)
  947. AND (SymTab.ClassOf(dt) #
  948. SymTab.ClClass) THEN
  949. IF sfx
  950. OR (dk = SymTab.KindField) THEN
  951. IF SymTab.ClassOf(dt) =
  952. SymTab.ClArray THEN
  953. IF (et # SymTab.InvalidType)
  954. AND (SymTab.ClassOf(et) = SymTab.ClUStr)
  955. AND SymTab.IsUCharArray(dt) THEN
  956. QbeGen.UAssign(qd, qe)
  957. ELSIF SymTab.StrCompat(dt,
  958. et) THEN
  959. QbeGen.StrAssign(qd,
  960. qe)
  961. ELSE
  962. QbeGen.CopyArray(qd,
  963. qe, dt)
  964. END
  965. ELSIF SymTab.ClassOf(dt) =
  966. SymTab.ClSet THEN
  967. QbeGen.CopySet(qd, qe,
  968. SymTab.SetWords(dt),
  969. SymTab.SetWords(et))
  970. ELSIF SymTab.ClassOf(dt) =
  971. SymTab.ClRecord THEN
  972. QbeGen.CopyRecord(qd, qe,
  973. dt)
  974. ELSIF SymTab.IsLongFamily(dt) THEN
  975. IF wconv THEN
  976. QbeGen.WidenLong(qe, ql);
  977. QbeGen.ElemStore(qd, ql,
  978. dt)
  979. ELSE QbeGen.ElemStore(qd, qe,
  980. dt)
  981. END
  982. ELSIF conv THEN
  983. QbeGen.ConvIR(qe, qt);
  984. QbeGen.ElemStore(qd, qt,
  985. dt)
  986. ELSE QbeGen.ElemStore(qd, qe,
  987. dt)
  988. END
  989. ELSIF SymTab.ClassOf(dt) =
  990. SymTab.ClArray THEN
  991. IF (et # SymTab.InvalidType)
  992. AND (SymTab.ClassOf(et) = SymTab.ClUStr)
  993. AND SymTab.IsUCharArray(dt) THEN
  994. QbeGen.UAssign(qd, qe)
  995. ELSIF SymTab.StrCompat(dt,
  996. et) THEN
  997. QbeGen.StrAssign(qd, qe)
  998. ELSE
  999. QbeGen.CopyArray(qd, qe,
  1000. dt)
  1001. END
  1002. ELSIF SymTab.ClassOf(dt) =
  1003. SymTab.ClSet THEN
  1004. QbeGen.CopySet(qd, qe,
  1005. SymTab.SetWords(dt),
  1006. SymTab.SetWords(et))
  1007. ELSIF SymTab.ClassOf(dt) =
  1008. SymTab.ClRecord THEN
  1009. QbeGen.CopyRecord(qd, qe, dt)
  1010. ELSIF (SymTab.ClassOf(dt) =
  1011. SymTab.ClPtr)
  1012. OR (SymTab.ClassOf(dt) =
  1013. SymTab.ClProc) THEN
  1014. QbeGen.StorePtr(qn, qe)
  1015. ELSIF SymTab.IsLongFamily(dt) THEN
  1016. IF wconv THEN
  1017. QbeGen.WidenLong(qe, ql);
  1018. QbeGen.StoreLong(qn, ql)
  1019. ELSE QbeGen.StoreLong(qn, qe)
  1020. END
  1021. ELSIF conv THEN
  1022. QbeGen.ConvIR(qe, qt);
  1023. QbeGen.StoreVar(qn, qt, TRUE)
  1024. ELSE
  1025. QbeGen.StoreVar(qn, qe, isR)
  1026. END
  1027. END; .)
  1028. | ArgList<qn, dt, qd, FALSE, ct2, q2, called>
  1029. | (* bare `P;`: proper parameterless
  1030. procedure call; anything else
  1031. here is 233 (was a bare syntax
  1032. error before 4.2) *)
  1033. (. IF (dk = SymTab.KindProc)
  1034. AND NOT sfx THEN
  1035. res0 := SymTab.ProcRes(qn);
  1036. IF res0 #
  1037. SymTab.InvalidType THEN
  1038. SemError(233)
  1039. ELSIF SymTab.ProcNPar(qn) #
  1040. 0 THEN
  1041. SemError(233)
  1042. ELSE QbeGen.Mangled(qn,
  1043. SymTab.ProcUid(qn), mg0);
  1044. QbeGen.CallBegin(mg0,
  1045. res0,
  1046. SymTab.ProcDepthOf(qn),
  1047. SymTab.IsExternal(qn));
  1048. QbeGen.CallEnd(FALSE, q2)
  1049. END
  1050. ELSE SemError(233)
  1051. END; .) ) .
  1052. (* Actual-parameter list shared by statement and expression calls.
  1053. want selects CallEnd's result handling; t/q carry the call
  1054. value (statement calls discard). Arity/type failures are 233;
  1055. evaluation code still emits so the .ssa stays assembleable. *)
  1056. ArgList<pn: SymTab.Name; pt: SymTab.TypeIndex; callee: QbeGen.QVal;
  1057. want: BOOLEAN;
  1058. VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
  1059. VAR called: BOOLEAN> (. VAR i: CARDINAL;
  1060. res: SymTab.TypeIndex;
  1061. mg: QbeGen.QVal;
  1062. ok, ind: BOOLEAN; .)
  1063. = "(" (. called := TRUE;
  1064. ok := TRUE;
  1065. ind := FALSE;
  1066. IF SymTab.SymKind(pn) =
  1067. SymTab.KindProc THEN
  1068. res := SymTab.ProcRes(pn);
  1069. QbeGen.Mangled(pn,
  1070. SymTab.ProcUid(pn), mg);
  1071. QbeGen.CallBegin(mg, res,
  1072. SymTab.ProcDepthOf(pn),
  1073. SymTab.IsExternal(pn))
  1074. ELSIF (pt # SymTab.InvalidType)
  1075. AND (SymTab.ClassOf(pt) = SymTab.ClProc) THEN
  1076. ind := TRUE;
  1077. res :=
  1078. SymTab.ProcTypeRes(pt);
  1079. QbeGen.CallBeginInd(callee,
  1080. res, FALSE)
  1081. ELSE SemError(233);
  1082. ok := FALSE;
  1083. res := SymTab.InvalidType
  1084. END;
  1085. i := 0; .)
  1086. [ ActParam<pn, pt, ind, i> (. INC(i); .)
  1087. { "," ActParam<pn, pt, ind, i> (. INC(i); .) } ]
  1088. ")" (. IF ok THEN
  1089. IF ind THEN
  1090. IF i #
  1091. SymTab.ProcTypeNPar(pt) THEN
  1092. SemError(233); ok := FALSE
  1093. END
  1094. ELSIF i #
  1095. SymTab.ProcNPar(pn) THEN
  1096. SemError(233); ok := FALSE
  1097. END
  1098. END;
  1099. IF NOT ok THEN
  1100. t := SymTab.InvalidType;
  1101. QbeGen.CopyOp("0", q)
  1102. ELSIF want THEN
  1103. IF res =
  1104. SymTab.InvalidType THEN
  1105. SemError(233);
  1106. t := SymTab.InvalidType;
  1107. QbeGen.CopyOp("0", q)
  1108. ELSE t := res;
  1109. QbeGen.CallEnd(TRUE, q)
  1110. END
  1111. ELSE
  1112. IF res #
  1113. SymTab.InvalidType THEN
  1114. SemError(233)
  1115. END;
  1116. t := SymTab.InvalidType;
  1117. QbeGen.CopyOp("0", q);
  1118. QbeGen.CallEnd(FALSE, q)
  1119. END; .) .
  1120. (* One actual: VAR formals take recorded designator addresses
  1121. (233 otherwise); value formals take converted expressions. *)
  1122. ActParam<pn: SymTab.Name; pt: SymTab.TypeIndex; ind: BOOLEAN;
  1123. i: CARDINAL> (. VAR at, ft: SymTab.TypeIndex;
  1124. qe, qa, qt: QbeGen.QVal;
  1125. isV, conv: BOOLEAN; .)
  1126. = Expr<at, qe> (. IF ind THEN
  1127. ft :=
  1128. SymTab.ProcTypeParamType(pt,
  1129. i);
  1130. isV :=
  1131. SymTab.ProcTypeParamIsVar(pt,
  1132. i)
  1133. ELSE
  1134. ft := SymTab.ParamType(pn, i);
  1135. isV := SymTab.ParamIsVar(pn, i)
  1136. END;
  1137. IF (at = SymTab.InvalidType)
  1138. OR (ft =
  1139. SymTab.InvalidType) THEN
  1140. ELSIF isV THEN
  1141. IF (SymTab.ClassOf(at)
  1142. = SymTab.ClChar)
  1143. AND (SymTab.ClassOf(ft) = SymTab.ClArray)
  1144. AND (SymTab.ClassOf(SymTab.ArrayElem(ft))
  1145. = SymTab.ClChar)
  1146. AND QbeGen.IsImm(qe) THEN
  1147. (* 1-char string
  1148. literal passed to
  1149. a VAR ARRAY OF CHAR *)
  1150. QbeGen.DeclCharStr(qe,
  1151. qa);
  1152. IF NOT QbeGen.CallArg(qa,
  1153. "l") THEN
  1154. SemError(233)
  1155. END
  1156. ELSIF NOT QbeGen.AddrOfVal(qe,
  1157. qa) THEN
  1158. SemError(233)
  1159. ELSIF NOT SymTab.VarParamOk(at,
  1160. ft) THEN
  1161. SemError(233)
  1162. ELSIF NOT QbeGen.CallArg(qa,
  1163. "l") THEN
  1164. SemError(233)
  1165. END
  1166. ELSE
  1167. IF (SymTab.ClassOf(at)
  1168. = SymTab.ClChar)
  1169. AND (SymTab.ClassOf(ft) = SymTab.ClArray)
  1170. AND (SymTab.ClassOf(SymTab.ArrayElem(ft))
  1171. = SymTab.ClChar)
  1172. AND QbeGen.IsImm(qe) THEN
  1173. (* 1-char string
  1174. literal passed to
  1175. ARRAY OF CHAR *)
  1176. QbeGen.DeclCharStr(qe,
  1177. qa);
  1178. IF NOT QbeGen.CallArg(qa,
  1179. "l") THEN
  1180. SemError(233)
  1181. END
  1182. ELSIF NOT SymTab.Assignable(at,
  1183. ft) THEN
  1184. SemError(233)
  1185. ELSE
  1186. conv := (SymTab.ClassOf(
  1187. ft) = SymTab.ClReal)
  1188. AND SymTab.IsIntFamily(at);
  1189. IF conv THEN
  1190. QbeGen.ConvIR(qe, qt);
  1191. IF NOT QbeGen.CallArg(qt,
  1192. "d") THEN
  1193. SemError(233)
  1194. END
  1195. ELSIF NOT QbeGen.CallArg(qe,
  1196. QbeGen.ArgClass(ft)) THEN
  1197. SemError(233)
  1198. END
  1199. END
  1200. END; .) .
  1201. IfStat (. VAR t: SymTab.TypeIndex;
  1202. q, lThen, lElse, lEnd:
  1203. QbeGen.QVal;
  1204. hasElse: BOOLEAN; .)
  1205. = "IF" (. hasElse := FALSE; .)
  1206. Expr<t, q> (. IF NOT SymTab.BoolCheck(t) THEN
  1207. SemError(214) END;
  1208. QbeGen.NewLabel(lThen);
  1209. QbeGen.NewLabel(lElse);
  1210. QbeGen.NewLabel(lEnd);
  1211. QbeGen.Jnz(q, lThen, lElse);
  1212. QbeGen.EmitLabel(lThen); .)
  1213. "THEN" [ StatSeq ] (. QbeGen.Jmp(lEnd); .)
  1214. { "ELSIF" (. QbeGen.EmitLabel(lElse);
  1215. QbeGen.NewLabel(lElse); .)
  1216. Expr<t, q> (. IF NOT SymTab.BoolCheck(t) THEN
  1217. SemError(214) END;
  1218. QbeGen.NewLabel(lThen);
  1219. QbeGen.Jnz(q, lThen, lElse);
  1220. QbeGen.EmitLabel(lThen); .)
  1221. "THEN" [ StatSeq ] (. QbeGen.Jmp(lEnd); .) }
  1222. [ "ELSE" (. QbeGen.EmitLabel(lElse);
  1223. hasElse := TRUE; .)
  1224. [ StatSeq ] ]
  1225. "END" (. IF hasElse THEN
  1226. QbeGen.EmitLabel(lEnd)
  1227. ELSE QbeGen.EmitLabel(lElse);
  1228. QbeGen.EmitLabel(lEnd)
  1229. END; .) .
  1230. WhileStat (. VAR t: SymTab.TypeIndex;
  1231. q, lTop, lBody, lEnd:
  1232. QbeGen.QVal; .)
  1233. = "WHILE" (. QbeGen.NewLabel(lTop);
  1234. QbeGen.NewLabel(lBody);
  1235. QbeGen.NewLabel(lEnd);
  1236. QbeGen.EmitLabel(lTop); .)
  1237. Expr<t, q> (. IF NOT SymTab.BoolCheck(t) THEN
  1238. SemError(214) END;
  1239. QbeGen.Jnz(q, lBody, lEnd);
  1240. QbeGen.EmitLabel(lBody); .)
  1241. "DO" [ StatSeq ] (. QbeGen.Jmp(lTop); .)
  1242. "END" (. QbeGen.EmitLabel(lEnd); .) .
  1243. RepeatStat (. VAR t: SymTab.TypeIndex;
  1244. q, lTop, lEnd: QbeGen.QVal; .)
  1245. = "REPEAT" (. QbeGen.NewLabel(lTop);
  1246. QbeGen.NewLabel(lEnd);
  1247. QbeGen.EmitLabel(lTop); .)
  1248. [ StatSeq ]
  1249. "UNTIL" Expr<t, q> (. IF NOT SymTab.BoolCheck(t) THEN
  1250. SemError(214) END;
  1251. QbeGen.Jnz(q, lEnd, lTop);
  1252. QbeGen.EmitLabel(lEnd); .) .
  1253. LoopStat (. VAR lTop, lEnd: QbeGen.QVal; .)
  1254. = "LOOP" (. QbeGen.NewLabel(lTop);
  1255. QbeGen.NewLabel(lEnd);
  1256. QbeGen.PushLoop(lEnd);
  1257. QbeGen.EmitLabel(lTop); .)
  1258. [ StatSeq ]
  1259. "END" (. QbeGen.Jmp(lTop);
  1260. QbeGen.PopLoop;
  1261. QbeGen.EmitLabel(lEnd); .) .
  1262. (* FOR with static-sign BY (literal, non-zero; 220 otherwise).
  1263. Runtime direction would need a compare-select; the literal
  1264. sign picks cslew/csegew at "DO" time. *)
  1265. ForStat (. VAR lv: SymTab.Name;
  1266. tlo, thi, tby:
  1267. SymTab.TypeIndex;
  1268. qlo, qhi, qby, qt, qk, qb:
  1269. QbeGen.QVal;
  1270. lTop, lBody, lEnd:
  1271. QbeGen.QVal;
  1272. by: INTEGER;
  1273. ok: BOOLEAN; .)
  1274. = "FOR" (. by := 1; .)
  1275. GetIdent<lv> (. ok := SymTab.Lookup(lv);
  1276. IF NOT ok THEN
  1277. SemError(201)
  1278. ELSIF (SymTab.SymKind(lv) #
  1279. SymTab.KindVar)
  1280. AND (SymTab.SymKind(lv) #
  1281. SymTab.KindParam) THEN
  1282. SemError(220); ok := FALSE
  1283. ELSIF NOT SymTab.IsIntFamily(
  1284. SymTab.SymType(lv)) THEN
  1285. SemError(220); ok := FALSE
  1286. END; .)
  1287. ":=" Expr<tlo, qlo> (. IF NOT SymTab.IsIntFamily(tlo) THEN
  1288. SemError(220); ok := FALSE
  1289. END; .)
  1290. "TO" Expr<thi, qhi> (. IF NOT SymTab.IsIntFamily(thi) THEN
  1291. SemError(220); ok := FALSE
  1292. END; .)
  1293. [ "BY" Expr<tby, qby> (. IF (tby #
  1294. SymTab.InvalidType)
  1295. AND NOT SymTab.IsIntFamily(tby) THEN
  1296. SemError(220); ok := FALSE
  1297. END;
  1298. IF NOT SymTab.ConstInt(qby, by) THEN
  1299. SemError(230); by := 1
  1300. ELSIF by = 0 THEN
  1301. SemError(220); by := 1
  1302. END; .) ]
  1303. "DO" (. IF ok THEN
  1304. QbeGen.StoreVar(lv, qlo,
  1305. FALSE) END;
  1306. QbeGen.NewLabel(lTop);
  1307. QbeGen.NewLabel(lBody);
  1308. QbeGen.NewLabel(lEnd);
  1309. QbeGen.EmitLabel(lTop);
  1310. QbeGen.LoadVar(lv, FALSE, qt);
  1311. QbeGen.NewTemp(qk);
  1312. IF by > 0 THEN
  1313. QbeGen.Op3("cslew", qk,
  1314. qt, qhi, FALSE)
  1315. ELSE QbeGen.Op3("csgew", qk,
  1316. qt, qhi, FALSE)
  1317. END;
  1318. QbeGen.Jnz(qk, lBody, lEnd);
  1319. QbeGen.EmitLabel(lBody); .)
  1320. [ StatSeq ]
  1321. "END" (. IF ok THEN
  1322. QbeGen.LoadVar(lv, FALSE,
  1323. qt);
  1324. QbeGen.IntStr(by, qb);
  1325. QbeGen.NewTemp(qk);
  1326. QbeGen.Op3("add", qk,
  1327. qt, qb, FALSE);
  1328. QbeGen.StoreVar(lv, qk,
  1329. FALSE) END;
  1330. QbeGen.Jmp(lTop);
  1331. QbeGen.EmitLabel(lEnd); .) .
  1332. CaseStat (. VAR tsel: SymTab.TypeIndex;
  1333. qsel, lEnd: QbeGen.QVal; .)
  1334. = "CASE" Expr<tsel, qsel> (. QbeGen.NewLabel(lEnd); .)
  1335. "OF" CaseAlt<tsel, qsel, lEnd>
  1336. { "|" CaseAlt<tsel, qsel, lEnd> }
  1337. [ "ELSE" [ StatSeq ] ]
  1338. "END" (. QbeGen.EmitLabel(lEnd); .) .
  1339. (* Compare-chain lowering: each alternative ends its match-tests
  1340. with "jmp lAfter", so the no-match fallthrough skips the body:
  1341. "cmp; jnz(lBody,lF); lF: ... ; jmp lAfter; lBody: S; jmp lEnd;
  1342. lAfter:". Falls into the next alternative, ELSE, or END. *)
  1343. CaseAlt<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
  1344. lEnd: QbeGen.QVal> (. VAR lBody, lAfter: QbeGen.QVal; .)
  1345. = (. QbeGen.NewLabel(lBody);
  1346. QbeGen.NewLabel(lAfter); .)
  1347. CaseLabel<tsel, qsel, lBody>
  1348. { "," CaseLabel<tsel, qsel, lBody> }
  1349. ":" (. QbeGen.Jmp(lAfter);
  1350. QbeGen.EmitLabel(lBody); .)
  1351. [ StatSeq ] (. QbeGen.Jmp(lEnd);
  1352. QbeGen.EmitLabel(lAfter); .) .
  1353. CaseLabel<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
  1354. lBody: QbeGen.QVal> (. VAR t2, t3: SymTab.TypeIndex;
  1355. q2, q3, qc, qd, qe:
  1356. QbeGen.QVal;
  1357. lNext: QbeGen.QVal; .)
  1358. = Expr<t2, q2> (. IF (t2 #
  1359. SymTab.InvalidType)
  1360. AND (tsel #
  1361. SymTab.InvalidType)
  1362. AND ((SymTab.ClassOf(t2) =
  1363. SymTab.ClSet)
  1364. OR (SymTab.ClassOf(tsel) =
  1365. SymTab.ClSet)) THEN
  1366. SemError(230)
  1367. ELSIF (t2 #
  1368. SymTab.InvalidType)
  1369. AND (tsel #
  1370. SymTab.InvalidType)
  1371. AND NOT SymTab.EqCheck(t2,
  1372. tsel) THEN
  1373. SemError(213) END;
  1374. IF NOT QbeGen.IsImm(q2) THEN
  1375. SemError(230);
  1376. QbeGen.CopyOp("0", q2)
  1377. END;
  1378. QbeGen.NewLabel(lNext);
  1379. QbeGen.Cmp(SymTab.OpEq,
  1380. qsel, q2, qc, FALSE);
  1381. QbeGen.Jnz(qc, lBody, lNext);
  1382. QbeGen.EmitLabel(lNext); .)
  1383. [ ".." Expr<t3, q3> (. IF (t3 #
  1384. SymTab.InvalidType)
  1385. AND (tsel #
  1386. SymTab.InvalidType)
  1387. AND NOT SymTab.EqCheck(t3,
  1388. tsel) THEN
  1389. SemError(213) END;
  1390. IF NOT QbeGen.IsImm(q3) THEN
  1391. SemError(230);
  1392. QbeGen.CopyOp("0", q3)
  1393. END;
  1394. QbeGen.Cmp(SymTab.OpGe,
  1395. qsel, q2, qc, FALSE);
  1396. QbeGen.Cmp(SymTab.OpLe,
  1397. qsel, q3, qd, FALSE);
  1398. QbeGen.NewTemp(qe);
  1399. QbeGen.Op3("and", qe, qc, qd,
  1400. FALSE);
  1401. QbeGen.NewLabel(lNext);
  1402. QbeGen.Jnz(qe, lBody, lNext);
  1403. QbeGen.EmitLabel(lNext); .) ] .
  1404. ReturnStat (. VAR t: SymTab.TypeIndex;
  1405. q, qt: QbeGen.QVal;
  1406. res: SymTab.TypeIndex;
  1407. hadE, conv: BOOLEAN; .)
  1408. = "RETURN" (. hadE := FALSE; .)
  1409. [ Expr<t, q> (. hadE := TRUE; .) ]
  1410. (. conv := FALSE;
  1411. IF NOT SymTab.InProc() THEN
  1412. SemError(232)
  1413. ELSE res := SymTab.CurRes();
  1414. IF NOT hadE THEN
  1415. IF res #
  1416. SymTab.InvalidType THEN
  1417. SemError(232)
  1418. ELSE QbeGen.EmitRet(q,
  1419. FALSE)
  1420. END
  1421. ELSIF (res =
  1422. SymTab.InvalidType)
  1423. OR (t #
  1424. SymTab.InvalidType)
  1425. AND NOT SymTab.Assignable(t,
  1426. res) THEN
  1427. SemError(232)
  1428. ELSE
  1429. conv := (SymTab.ClassOf(
  1430. res) = SymTab.ClReal)
  1431. AND SymTab.IsIntFamily(t);
  1432. IF conv THEN
  1433. QbeGen.ConvIR(q, qt);
  1434. QbeGen.EmitRet(qt, TRUE)
  1435. ELSE QbeGen.EmitRet(q, TRUE)
  1436. END
  1437. END
  1438. END; .) .
  1439. HaltStat (. VAR t: SymTab.TypeIndex;
  1440. q: QbeGen.QVal; .)
  1441. = "HALT" [ "(" Expr<t, q> ")" ] (. QbeGen.HaltQ; .) .
  1442. (* Designator: scalar loads, array addresses, and index suffixes.
  1443. Each index descends one level (bounds-checked, trap on breach);
  1444. nested levels reload the inner descriptor address. q ends as the
  1445. value (scalars), the descriptor address (plain arrays), or the
  1446. element address (indexed); sfx marks the indexed form. *)
  1447. Design<VAR t: SymTab.TypeIndex; VAR k: INTEGER;
  1448. VAR q: QbeGen.QVal; VAR qn: SymTab.Name; VAR sfx: BOOLEAN>
  1449. (. VAR n, fn, mal: SymTab.Name;
  1450. cls: INTEGER;
  1451. curT, it, eT, bt:
  1452. SymTab.TypeIndex;
  1453. iq, ql, qlo, qhi, qe:
  1454. QbeGen.QVal;
  1455. lo, hi: INTEGER;
  1456. fo: INTEGER;
  1457. isOpen: BOOLEAN;
  1458. qb, cv: QbeGen.QVal; .)
  1459. = GetIdent<n> (. QbeGen.CopyOp(n, qn);
  1460. sfx := FALSE;
  1461. IF NOT SymTab.Lookup(n) THEN
  1462. SemError(201);
  1463. t := SymTab.InvalidType;
  1464. k := -1;
  1465. QbeGen.CopyOp("0", q)
  1466. ELSE
  1467. t := SymTab.SymType(n);
  1468. k := SymTab.SymKind(n);
  1469. IF k = SymTab.KindConst THEN
  1470. IF SymTab.Equal(n,
  1471. "TRUE") THEN
  1472. t := SymTab.BoolType();
  1473. QbeGen.CopyOp("1", q)
  1474. ELSIF SymTab.Equal(n,
  1475. "FALSE") THEN
  1476. t := SymTab.BoolType();
  1477. QbeGen.CopyOp("0", q)
  1478. ELSIF SymTab.Equal(n,
  1479. "NIL") THEN
  1480. QbeGen.CopyOp("0", q)
  1481. ELSE
  1482. cls :=
  1483. SymTab.ClassOf(t);
  1484. IF (t #
  1485. SymTab.InvalidType)
  1486. AND ((cls = SymTab.ClInt)
  1487. OR (cls
  1488. = SymTab.ClChar)
  1489. OR (cls
  1490. = SymTab.ClEnum)
  1491. OR (cls
  1492. = SymTab.ClReal)
  1493. OR (cls
  1494. = SymTab.ClNil)) THEN
  1495. IF cls = SymTab.ClNil THEN
  1496. QbeGen.CopyOp("0", q)
  1497. ELSIF ((cls
  1498. = SymTab.ClInt)
  1499. OR (cls
  1500. = SymTab.ClChar)
  1501. OR (cls
  1502. = SymTab.ClEnum))
  1503. AND SymTab.GetSymVal(n, cv)
  1504. AND QbeGen.IsImm(cv) THEN
  1505. QbeGen.CopyOp(cv, q)
  1506. ELSE
  1507. QbeGen.LoadVar(n,
  1508. cls = SymTab.ClReal,
  1509. q)
  1510. END
  1511. ELSE
  1512. IF t #
  1513. SymTab.InvalidType THEN
  1514. SemError(230)
  1515. END;
  1516. QbeGen.CopyOp("0", q)
  1517. END
  1518. END
  1519. ELSIF (k = SymTab.KindVar)
  1520. OR (k = SymTab.KindParam) THEN
  1521. cls :=
  1522. SymTab.ClassOf(t);
  1523. IF (cls = SymTab.ClInt)
  1524. OR (cls = SymTab.ClBool)
  1525. OR (cls = SymTab.ClChar)
  1526. OR (cls = SymTab.ClUChar)
  1527. OR (cls = SymTab.ClEnum)
  1528. OR (cls
  1529. = SymTab.ClReal) THEN
  1530. QbeGen.LoadVar(n,
  1531. cls = SymTab.ClReal, q)
  1532. ELSIF (cls = SymTab.ClPtr)
  1533. OR (cls = SymTab.ClProc) THEN
  1534. QbeGen.LoadPtr(n, q)
  1535. ELSIF cls = SymTab.ClLong THEN
  1536. QbeGen.LoadLong(n, q)
  1537. ELSIF (cls
  1538. = SymTab.ClArray)
  1539. OR (cls
  1540. = SymTab.ClSet)
  1541. OR (cls
  1542. = SymTab.ClRecord)
  1543. OR (cls
  1544. = SymTab.ClUStr)
  1545. OR (cls
  1546. = SymTab.ClClass) THEN
  1547. QbeGen.AddrOf(n, q)
  1548. ELSE SemError(230);
  1549. QbeGen.CopyOp("0", q)
  1550. END
  1551. ELSE QbeGen.CopyOp("0", q);
  1552. IF k = SymTab.KindImport THEN
  1553. SemError(230)
  1554. ELSIF k =
  1555. SymTab.KindProc THEN
  1556. (* bare procedure name:
  1557. a following ArgList
  1558. makes it a call;
  1559. otherwise Fact
  1560. reports 230 *)
  1561. ELSE
  1562. IF k = SymTab.KindField THEN
  1563. IF QbeGen.TopWith(qb) THEN
  1564. fo :=
  1565. SymTab.FieldOffset(
  1566. SymTab.FieldOwner(n),
  1567. n);
  1568. QbeGen.FieldAddr(qb,
  1569. fo, q);
  1570. sfx := TRUE
  1571. ELSE SemError(230);
  1572. QbeGen.CopyOp("0", q)
  1573. END
  1574. END
  1575. END
  1576. END
  1577. END; .)
  1578. { "[" Expr<it, iq>
  1579. (. IF t = SymTab.InvalidType THEN
  1580. ELSIF SymTab.ClassOf(t) #
  1581. SymTab.ClArray THEN
  1582. SemError(217);
  1583. t := SymTab.InvalidType
  1584. ELSIF NOT SymTab.IsIntFamily(it)
  1585. AND (SymTab.ClassOf(it) #
  1586. SymTab.ClChar) THEN
  1587. SemError(218);
  1588. t := SymTab.InvalidType
  1589. ELSE
  1590. QbeGen.WidenIndex(iq, ql);
  1591. isOpen :=
  1592. SymTab.IsOpenArray(t);
  1593. IF isOpen THEN
  1594. QbeGen.CopyOp("0", qlo);
  1595. IF SymTab.IsCharArray(t)
  1596. OR SymTab.IsUCharArray(t) THEN
  1597. QbeGen.OpenHiChar(q, qhi)
  1598. ELSE QbeGen.OpenHi(q, qhi)
  1599. END
  1600. ELSE
  1601. lo := SymTab.ArrayLo(t);
  1602. hi := SymTab.ArrayHi(t);
  1603. IF SymTab.IsCharArray(t)
  1604. OR SymTab.IsUCharArray(t) THEN
  1605. hi := hi + 1
  1606. END;
  1607. QbeGen.IntStr(lo, qlo);
  1608. QbeGen.IntStr(hi, qhi)
  1609. END;
  1610. QbeGen.CheckRange(ql, qlo,
  1611. qhi);
  1612. eT := SymTab.ArrayElem(t);
  1613. QbeGen.ElemAddr(q, ql, qlo,
  1614. t, qe);
  1615. IF SymTab.ClassOf(eT) =
  1616. SymTab.ClArray THEN
  1617. QbeGen.ElemLoad(qe, eT, q)
  1618. ELSE QbeGen.CopyOp(qe, q)
  1619. END;
  1620. t := eT; sfx := TRUE
  1621. END; .)
  1622. { "," Expr<it, iq>
  1623. (. IF t = SymTab.InvalidType THEN
  1624. ELSIF SymTab.ClassOf(t) #
  1625. SymTab.ClArray THEN
  1626. SemError(217);
  1627. t := SymTab.InvalidType
  1628. ELSIF NOT SymTab.IsIntFamily(it)
  1629. AND (SymTab.ClassOf(it) #
  1630. SymTab.ClChar) THEN
  1631. SemError(218);
  1632. t := SymTab.InvalidType
  1633. ELSE
  1634. QbeGen.WidenIndex(iq, ql);
  1635. isOpen :=
  1636. SymTab.IsOpenArray(t);
  1637. IF isOpen THEN
  1638. QbeGen.CopyOp("0", qlo);
  1639. IF SymTab.IsCharArray(t)
  1640. OR SymTab.IsUCharArray(t) THEN
  1641. QbeGen.OpenHiChar(q, qhi)
  1642. ELSE QbeGen.OpenHi(q, qhi)
  1643. END
  1644. ELSE
  1645. lo := SymTab.ArrayLo(t);
  1646. hi := SymTab.ArrayHi(t);
  1647. IF SymTab.IsCharArray(t)
  1648. OR SymTab.IsUCharArray(t) THEN
  1649. hi := hi + 1
  1650. END;
  1651. QbeGen.IntStr(lo, qlo);
  1652. QbeGen.IntStr(hi, qhi)
  1653. END;
  1654. QbeGen.CheckRange(ql, qlo,
  1655. qhi);
  1656. eT := SymTab.ArrayElem(t);
  1657. QbeGen.ElemAddr(q, ql, qlo,
  1658. t, qe);
  1659. IF SymTab.ClassOf(eT) =
  1660. SymTab.ClArray THEN
  1661. QbeGen.ElemLoad(qe, eT, q)
  1662. ELSE QbeGen.CopyOp(qe, q)
  1663. END;
  1664. t := eT; sfx := TRUE
  1665. END; .) }
  1666. "]"
  1667. | "." GetIdent<fn>
  1668. (. IF k = SymTab.KindModule THEN
  1669. (* qualified L.x: materialize
  1670. the export, then load it *)
  1671. IF NOT SymTab.MaterializeAlias(n,
  1672. fn, mal) THEN
  1673. SemError(201);
  1674. t := SymTab.InvalidType;
  1675. QbeGen.CopyOp("0", q)
  1676. ELSE
  1677. QbeGen.CopyOp(mal, qn);
  1678. t := SymTab.SymType(mal);
  1679. k := SymTab.SymKind(mal);
  1680. sfx := FALSE;
  1681. IF k = SymTab.KindProc THEN
  1682. (* call: ArgList supplies
  1683. the value *)
  1684. QbeGen.CopyOp("0", q)
  1685. ELSIF NOT QbeGen.LoadDesignator(
  1686. mal, t, k, q) THEN
  1687. SemError(230);
  1688. QbeGen.CopyOp("0", q)
  1689. END
  1690. END
  1691. ELSIF t = SymTab.InvalidType THEN
  1692. ELSIF (SymTab.ClassOf(t) #
  1693. SymTab.ClRecord)
  1694. AND (SymTab.ClassOf(t) #
  1695. SymTab.ClClass) THEN
  1696. SemError(215);
  1697. t := SymTab.InvalidType
  1698. ELSIF NOT SymTab.FieldExists(t,
  1699. fn) THEN
  1700. SemError(216);
  1701. t := SymTab.InvalidType
  1702. ELSE
  1703. fo := SymTab.FieldOffset(t,
  1704. fn);
  1705. t := SymTab.FieldType(t, fn);
  1706. QbeGen.FieldAddr(q, fo, qe);
  1707. (* array fields are inline:
  1708. the field address is the
  1709. descriptor, like records *)
  1710. QbeGen.CopyOp(qe, q);
  1711. sfx := TRUE
  1712. END; .)
  1713. | "^"
  1714. (. IF t = SymTab.InvalidType THEN
  1715. ELSIF SymTab.ClassOf(t) #
  1716. SymTab.ClPtr THEN
  1717. SemError(219);
  1718. t := SymTab.InvalidType
  1719. ELSE
  1720. bt := SymTab.PtrBase(t);
  1721. IF bt = SymTab.InvalidType THEN
  1722. ELSE
  1723. IF sfx THEN
  1724. QbeGen.ElemLoad(q, t,
  1725. qb);
  1726. QbeGen.CopyOp(qb, q)
  1727. END;
  1728. t := bt;
  1729. (* q holds the pointee
  1730. address: Fact loads
  1731. scalars/pointers and uses
  1732. the address for
  1733. aggregates; the VAR-actual
  1734. note is q itself. *)
  1735. sfx := TRUE
  1736. END
  1737. END; .) } .
  1738. Expr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  1739. (. VAR t2: SymTab.TypeIndex;
  1740. op: INTEGER;
  1741. q2, qt, wl: QbeGen.QVal;
  1742. isR: BOOLEAN; .)
  1743. = SimExpr<t, q>
  1744. [ Rel<op> SimExpr<t2, q2>
  1745. (. IF op = SymTab.OpIn THEN
  1746. IF SymTab.InCheck(t, t2) THEN
  1747. IF (t = SymTab.InvalidType)
  1748. OR (t2 = SymTab.InvalidType) THEN
  1749. t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
  1750. ELSE
  1751. QbeGen.InSet(q, q2, SymTab.SetBaseLo(t2),
  1752. SymTab.SetCount(t2), qt);
  1753. t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
  1754. END
  1755. ELSE SemError(222); t := SymTab.InvalidType;
  1756. QbeGen.CopyOp("0", q)
  1757. END
  1758. ELSIF SymTab.RelCheck(t, t2, op) THEN
  1759. IF (t = SymTab.InvalidType)
  1760. OR (t2 = SymTab.InvalidType) THEN
  1761. t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
  1762. ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
  1763. OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN
  1764. IF (op # SymTab.OpEq) AND (op # SymTab.OpNeq1)
  1765. AND (op # SymTab.OpNeq2) THEN
  1766. SemError(213); t := SymTab.InvalidType;
  1767. QbeGen.CopyOp("0", q)
  1768. ELSE
  1769. QbeGen.CmpL(op, q, q2, qt);
  1770. t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
  1771. END
  1772. ELSIF (SymTab.ClassOf(t) = SymTab.ClSet)
  1773. OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
  1774. QbeGen.CmpSet(op, q, q2,
  1775. SymTab.SetWords(t), SymTab.SetWords(t2), qt);
  1776. t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
  1777. ELSIF SymTab.StrCompat(t, t2) THEN
  1778. QbeGen.StrEq(op, q, q2, qt);
  1779. t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
  1780. ELSIF SymTab.IsLongFamily(t)
  1781. OR SymTab.IsLongFamily(t2) THEN
  1782. IF SymTab.IsIntFamily(t) THEN
  1783. QbeGen.WidenLong(q, wl); QbeGen.CopyOp(wl, q)
  1784. END;
  1785. IF SymTab.IsIntFamily(t2) THEN
  1786. QbeGen.WidenLong(q2, wl); QbeGen.CopyOp(wl, q2)
  1787. END;
  1788. QbeGen.CmpLong(op, q, q2, qt);
  1789. t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
  1790. ELSE
  1791. isR := SymTab.ClassOf(t) = SymTab.ClReal;
  1792. t := SymTab.BoolType();
  1793. QbeGen.Cmp(op, q, q2, qt, isR);
  1794. QbeGen.CopyOp(qt, q)
  1795. END
  1796. ELSE SemError(213); t := SymTab.InvalidType;
  1797. QbeGen.CopyOp("0", q)
  1798. END; .) ] .
  1799. Rel<VAR op: INTEGER>
  1800. = "=" (. op := SymTab.OpEq; .)
  1801. | "#" (. op := SymTab.OpNeq1; .)
  1802. | "<" (. op := SymTab.OpLt; .)
  1803. | "<=" (. op := SymTab.OpLe; .)
  1804. | ">" (. op := SymTab.OpGt; .)
  1805. | ">=" (. op := SymTab.OpGe; .)
  1806. | "IN" (. op := SymTab.OpIn; .) .
  1807. SimExpr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  1808. (. VAR t2, res2, lt, rt:
  1809. SymTab.TypeIndex;
  1810. op: INTEGER;
  1811. q2, qt, wq, qf:
  1812. QbeGen.QVal;
  1813. neg, isR, isL, folded:
  1814. BOOLEAN;
  1815. lw, rw, mw: CARDINAL;
  1816. lTrue, lNext, lDone, qr, qs:
  1817. QbeGen.QVal; .)
  1818. = (. neg := FALSE; .)
  1819. [ "+" | "-" (. neg := TRUE; .) ]
  1820. Term<t, q> (. IF neg THEN
  1821. IF QbeGen.IsImm(q) THEN
  1822. QbeGen.NegFold(q, q)
  1823. ELSE QbeGen.NewTemp(qt);
  1824. QbeGen.NegQ(q, qt,
  1825. SymTab.ClassOf(t)
  1826. = SymTab.ClReal);
  1827. QbeGen.CopyOp(qt, q)
  1828. END
  1829. END; .)
  1830. { AddOp<op> (. IF op = SymTab.OpOr THEN
  1831. QbeGen.DelayBegin END; .)
  1832. Term<t2, q2> (. IF op = SymTab.OpOr THEN
  1833. QbeGen.DelayEnd END; .)
  1834. (. IF op = SymTab.OpOr THEN
  1835. (* short-circuit: if q is true the RHS is skipped *)
  1836. IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
  1837. t := SymTab.BoolType()
  1838. ELSE SemError(212); t := SymTab.InvalidType END;
  1839. IF t # SymTab.InvalidType THEN
  1840. QbeGen.Slot4(qs);
  1841. QbeGen.NewLabel(lTrue);
  1842. QbeGen.NewLabel(lNext);
  1843. QbeGen.NewLabel(lDone);
  1844. QbeGen.Jnz(q, lTrue, lNext);
  1845. QbeGen.EmitLabel(lTrue);
  1846. QbeGen.StoreW(qs, "1");
  1847. QbeGen.Jmp(lDone);
  1848. QbeGen.EmitLabel(lNext);
  1849. QbeGen.DelayFlush;
  1850. QbeGen.StoreW(qs, q2);
  1851. QbeGen.Jmp(lDone);
  1852. QbeGen.EmitLabel(lDone);
  1853. QbeGen.LoadW(qs, qr);
  1854. QbeGen.CopyOp(qr, q)
  1855. ELSE QbeGen.DelayFlush; QbeGen.CopyOp("0", q)
  1856. END
  1857. ELSIF (op = SymTab.OpAdd)
  1858. AND (SymTab.StrCompat(t, t2)
  1859. OR (SymTab.IsStrType(t)
  1860. AND (SymTab.ClassOf(t2) = SymTab.ClChar))
  1861. OR ((SymTab.ClassOf(t) = SymTab.ClChar)
  1862. AND SymTab.IsStrType(t2))) THEN
  1863. (* string concatenation; a CHAR operand becomes a
  1864. 1-character string literal *)
  1865. IF SymTab.StrCompat(t, t2) THEN
  1866. QbeGen.StrCat(q, q2, qt)
  1867. ELSIF SymTab.IsStrType(t) THEN
  1868. QbeGen.DeclCharStr(q2, qs);
  1869. QbeGen.StrCat(q, qs, qt)
  1870. ELSE
  1871. QbeGen.DeclCharStr(q, qs);
  1872. QbeGen.StrCat(qs, q2, qt)
  1873. END;
  1874. t := SymTab.NewStr();
  1875. QbeGen.CopyOp(qt, q)
  1876. ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
  1877. AND (SymTab.ClassOf(t) = SymTab.ClSet)
  1878. AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
  1879. lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
  1880. mw := lw;
  1881. IF rw > mw THEN mw := rw END;
  1882. IF op = SymTab.OpAdd THEN
  1883. QbeGen.SetBinOp(0, q, q2, lw, rw, qt)
  1884. ELSE
  1885. QbeGen.SetBinOp(2, q, q2, lw, rw, qt)
  1886. END;
  1887. t := SymTab.NewSet(
  1888. SymTab.NewSubR(0,
  1889. VAL(INTEGER, mw) * 32 - 1));
  1890. QbeGen.CopyOp(qt, q)
  1891. ELSE
  1892. IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
  1893. lt := t; rt := t2; t := res2
  1894. ELSE SemError(211); t := SymTab.InvalidType END;
  1895. IF t # SymTab.InvalidType THEN
  1896. isL := SymTab.IsLongFamily(t);
  1897. isR := SymTab.ClassOf(t) = SymTab.ClReal;
  1898. folded := FALSE;
  1899. IF (NOT isL) AND (NOT isR)
  1900. AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
  1901. IF op = SymTab.OpAdd THEN
  1902. folded := QbeGen.Fold2(0, q, q2, qf)
  1903. ELSE
  1904. folded := QbeGen.Fold2(1, q, q2, qf)
  1905. END
  1906. END;
  1907. IF folded THEN QbeGen.CopyOp(qf, q)
  1908. ELSE
  1909. IF isL THEN
  1910. IF SymTab.IsIntFamily(lt) THEN
  1911. QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
  1912. END;
  1913. IF SymTab.IsIntFamily(rt) THEN
  1914. QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
  1915. END;
  1916. QbeGen.NewTemp(qt);
  1917. IF op = SymTab.OpAdd THEN
  1918. QbeGen.Op3L("add", qt, q, q2)
  1919. ELSE
  1920. QbeGen.Op3L("sub", qt, q, q2)
  1921. END
  1922. ELSE
  1923. QbeGen.NewTemp(qt);
  1924. IF op = SymTab.OpAdd THEN
  1925. QbeGen.Op3("add", qt, q, q2, isR)
  1926. ELSE
  1927. QbeGen.Op3("sub", qt, q, q2, isR)
  1928. END
  1929. END;
  1930. QbeGen.CopyOp(qt, q)
  1931. END
  1932. ELSE QbeGen.CopyOp("0", q)
  1933. END
  1934. END; .) } .
  1935. AddOp<VAR op: INTEGER>
  1936. = "+" (. op := SymTab.OpAdd; .)
  1937. | "-" (. op := SymTab.OpSub; .)
  1938. | "OR" (. op := SymTab.OpOr; .) .
  1939. Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  1940. (. VAR t2, res2, lt, rt:
  1941. SymTab.TypeIndex;
  1942. op: INTEGER;
  1943. q2, qt, wq, qf:
  1944. QbeGen.QVal;
  1945. isR, isL, folded: BOOLEAN;
  1946. lw, rw, mw: CARDINAL;
  1947. lNext, lFalse, lDone, qr, qs:
  1948. QbeGen.QVal; .)
  1949. = Fact<t, q> { MulOp<op> (. IF op = SymTab.OpAnd THEN
  1950. QbeGen.DelayBegin END; .)
  1951. Fact<t2, q2> (. IF op = SymTab.OpAnd THEN
  1952. QbeGen.DelayEnd END; .)
  1953. (. IF op = SymTab.OpAnd THEN
  1954. (* short-circuit: if q is false the RHS is skipped *)
  1955. IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
  1956. t := SymTab.BoolType()
  1957. ELSE SemError(212); t := SymTab.InvalidType END;
  1958. IF t # SymTab.InvalidType THEN
  1959. QbeGen.Slot4(qs);
  1960. QbeGen.NewLabel(lNext);
  1961. QbeGen.NewLabel(lFalse);
  1962. QbeGen.NewLabel(lDone);
  1963. QbeGen.Jnz(q, lNext, lFalse);
  1964. QbeGen.EmitLabel(lNext);
  1965. QbeGen.DelayFlush;
  1966. QbeGen.StoreW(qs, q2);
  1967. QbeGen.Jmp(lDone);
  1968. QbeGen.EmitLabel(lFalse);
  1969. QbeGen.StoreW(qs, "0");
  1970. QbeGen.Jmp(lDone);
  1971. QbeGen.EmitLabel(lDone);
  1972. QbeGen.LoadW(qs, qr);
  1973. QbeGen.CopyOp(qr, q)
  1974. ELSE QbeGen.DelayFlush; QbeGen.CopyOp("0", q)
  1975. END
  1976. ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
  1977. AND (SymTab.ClassOf(t) = SymTab.ClSet)
  1978. AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
  1979. lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
  1980. mw := lw;
  1981. IF rw > mw THEN mw := rw END;
  1982. IF op = SymTab.OpTimes THEN
  1983. QbeGen.SetBinOp(1, q, q2, lw, rw, qt)
  1984. ELSE
  1985. QbeGen.SetBinOp(3, q, q2, lw, rw, qt)
  1986. END;
  1987. t := SymTab.NewSet(
  1988. SymTab.NewSubR(0,
  1989. VAL(INTEGER, mw) * 32 - 1));
  1990. QbeGen.CopyOp(qt, q)
  1991. ELSE
  1992. IF SymTab.ArithCheck(t, t2,
  1993. (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
  1994. res2) THEN
  1995. lt := t; rt := t2; t := res2
  1996. ELSE SemError(211); t := SymTab.InvalidType END;
  1997. IF t # SymTab.InvalidType THEN
  1998. isL := SymTab.IsLongFamily(t);
  1999. isR := SymTab.ClassOf(t) = SymTab.ClReal;
  2000. folded := FALSE;
  2001. IF (NOT isL) AND (NOT isR)
  2002. AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
  2003. IF op = SymTab.OpTimes THEN
  2004. folded := QbeGen.Fold2(2, q, q2, qf)
  2005. ELSIF op = SymTab.OpDiv THEN
  2006. folded := QbeGen.Fold2(3, q, q2, qf)
  2007. ELSIF op = SymTab.OpMod THEN
  2008. folded := QbeGen.Fold2(4, q, q2, qf)
  2009. END
  2010. END;
  2011. IF folded THEN QbeGen.CopyOp(qf, q)
  2012. ELSE
  2013. IF isL THEN
  2014. IF SymTab.IsIntFamily(lt) THEN
  2015. QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
  2016. END;
  2017. IF SymTab.IsIntFamily(rt) THEN
  2018. QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
  2019. END;
  2020. QbeGen.NewTemp(qt);
  2021. IF op = SymTab.OpTimes THEN
  2022. QbeGen.Op3L("mul", qt, q, q2)
  2023. ELSIF (op = SymTab.OpDiv)
  2024. OR (op = SymTab.OpSlash) THEN
  2025. QbeGen.Op3L("div", qt, q, q2)
  2026. ELSE
  2027. QbeGen.Op3L("rem", qt, q, q2)
  2028. END
  2029. ELSE
  2030. QbeGen.NewTemp(qt);
  2031. IF op = SymTab.OpTimes THEN
  2032. QbeGen.Op3("mul", qt, q, q2, isR)
  2033. ELSIF (op = SymTab.OpDiv)
  2034. OR (op = SymTab.OpSlash) THEN
  2035. QbeGen.Op3("div", qt, q, q2, isR)
  2036. ELSE
  2037. QbeGen.Op3("rem", qt, q, q2, isR)
  2038. END
  2039. END;
  2040. QbeGen.CopyOp(qt, q)
  2041. END
  2042. ELSE QbeGen.CopyOp("0", q)
  2043. END
  2044. END; .) } .
  2045. MulOp<VAR op: INTEGER>
  2046. = "*" (. op := SymTab.OpTimes; .)
  2047. | "/" (. op := SymTab.OpSlash; .)
  2048. | "DIV" (. op := SymTab.OpDiv; .)
  2049. | "MOD" (. op := SymTab.OpMod; .)
  2050. | ( "AND" | "&" ) (. op := SymTab.OpAnd; .) .
  2051. Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  2052. (. VAR s: ARRAY [0 .. 255] OF CHAR;
  2053. et, dt, t2, st, ct2:
  2054. SymTab.TypeIndex;
  2055. dk: INTEGER;
  2056. qd, q2, sq, qa, qm0, qr:
  2057. QbeGen.QVal;
  2058. qn, vn: SymTab.Name;
  2059. vt: SymTab.TypeIndex;
  2060. c1, c2: INTEGER;
  2061. called, isHigh, sfx, isCh,
  2062. isU, uok, isStr: BOOLEAN;
  2063. ucp: INTEGER; .)
  2064. = integer (. LexString(s);
  2065. QbeGen.NormInt(s, q);
  2066. t := SymTab.IntType(); .)
  2067. | charConst (. LexString(s);
  2068. QbeGen.NormLit(s, q, isCh);
  2069. t := SymTab.CharType(); .)
  2070. | real (. LexString(s);
  2071. QbeGen.NormReal(s, q);
  2072. t := SymTab.RealType(); .)
  2073. | string (. LexString(s);
  2074. IF SymTab.StrLen(s) = 3 THEN
  2075. t := SymTab.CharType();
  2076. QbeGen.IntStr(
  2077. QbeGen.CharVal(s), q)
  2078. ELSE t := SymTab.NewStr();
  2079. QbeGen.DeclStr(s, q);
  2080. (* a literal's value IS its
  2081. static descriptor address *)
  2082. QbeGen.NoteAddr(q, q)
  2083. END; .)
  2084. | ustring (. LexString(s);
  2085. QbeGen.DeclUStr(s, q, isU, ucp,
  2086. uok);
  2087. IF NOT uok THEN
  2088. SemError(234);
  2089. t := SymTab.InvalidType
  2090. ELSIF isU THEN
  2091. t := SymTab.UCharType();
  2092. QbeGen.IntStr(ucp, q)
  2093. ELSE
  2094. t := SymTab.NewUStr();
  2095. QbeGen.NoteAddr(q, q)
  2096. END; .)
  2097. | Design<dt, dk, qd, qn, sfx> (. called := FALSE;
  2098. t := dt;
  2099. IF sfx THEN
  2100. IF dt =
  2101. SymTab.InvalidType THEN
  2102. QbeGen.CopyOp("0", q)
  2103. ELSIF (SymTab.ClassOf(dt) =
  2104. SymTab.ClRecord)
  2105. OR (SymTab.ClassOf(dt) =
  2106. SymTab.ClSet)
  2107. OR (SymTab.ClassOf(dt) =
  2108. SymTab.ClArray)
  2109. OR (SymTab.ClassOf(dt) =
  2110. SymTab.ClClass) THEN
  2111. QbeGen.CopyOp(qd, q)
  2112. ELSE QbeGen.ElemLoad(qd, dt,
  2113. q)
  2114. END
  2115. ELSE QbeGen.CopyOp(qd, q)
  2116. END;
  2117. IF (dk = SymTab.KindVar)
  2118. OR (dk = SymTab.KindParam)
  2119. OR (dk =
  2120. SymTab.KindField) THEN
  2121. IF sfx THEN
  2122. QbeGen.NoteAddr(q, qd)
  2123. ELSE
  2124. QbeGen.AddrOf(qn, qa);
  2125. QbeGen.NoteAddr(q, qa)
  2126. END
  2127. ELSIF sfx
  2128. AND (dt #
  2129. SymTab.InvalidType)
  2130. AND ((SymTab.ClassOf(dt) =
  2131. SymTab.ClArray)
  2132. OR (SymTab.ClassOf(dt) =
  2133. SymTab.ClSet)
  2134. OR (SymTab.ClassOf(dt) =
  2135. SymTab.ClRecord)) THEN
  2136. QbeGen.NoteAddr(qd, qd)
  2137. END; .)
  2138. [ TypedSetLit<dt, q> (. t := dt; .) ]
  2139. [ ArgList<qn, dt, qd, TRUE, ct2, q2, called>
  2140. (. t := ct2;
  2141. QbeGen.CopyOp(q2, q); .) ]
  2142. (. IF NOT called
  2143. AND (dk = SymTab.KindProc) THEN
  2144. (* bare zero-arg function
  2145. call (parentheses may be
  2146. omitted); a proper or
  2147. parameterised proc here
  2148. is 230 *)
  2149. IF (SymTab.ProcNPar(qn) = 0)
  2150. AND (SymTab.ProcRes(qn) #
  2151. SymTab.InvalidType) THEN
  2152. QbeGen.Mangled(qn,
  2153. SymTab.ProcUid(qn), qm0);
  2154. QbeGen.CallBegin(qm0,
  2155. SymTab.ProcRes(qn),
  2156. SymTab.ProcDepthOf(qn),
  2157. SymTab.IsExternal(qn));
  2158. QbeGen.CallEnd(TRUE, q);
  2159. t := SymTab.ProcRes(qn)
  2160. ELSE
  2161. (* procedure used as a
  2162. value (assign to a
  2163. procedure variable):
  2164. its code address *)
  2165. t := SymTab.ProcTypeOf(qn);
  2166. QbeGen.Mangled(qn,
  2167. SymTab.ProcUid(qn), qm0);
  2168. QbeGen.ProcAddr(qm0, q)
  2169. END
  2170. END; .)
  2171. | ( "HIGH" (. isHigh := TRUE; .)
  2172. | ( "LEN" | "LENGTH" ) (. isHigh := FALSE; .) )
  2173. "(" ( Design<dt, dk, qd, qn, sfx> (. isStr := FALSE; .)
  2174. | string (. LexString(s);
  2175. isStr := TRUE;
  2176. IF SymTab.StrLen(s) = 3 THEN
  2177. dt := SymTab.CharType();
  2178. QbeGen.IntStr(QbeGen.CharVal(s),
  2179. qd)
  2180. ELSE
  2181. dt := SymTab.NewStr();
  2182. QbeGen.DeclStr(s, qd);
  2183. QbeGen.NoteAddr(qd, qd)
  2184. END;
  2185. dk := -1;
  2186. qn[0] := CHR(0); .) )
  2187. ")"
  2188. (. IF isStr THEN
  2189. (* fold: content length at
  2190. compile time *)
  2191. IF SymTab.StrLen(s) = 3 THEN
  2192. c1 := 1
  2193. ELSE
  2194. c1 :=
  2195. SymTab.StrLen(s) - 2
  2196. END;
  2197. IF isHigh THEN
  2198. DEC(c1)
  2199. END;
  2200. QbeGen.IntStr(c1, qr);
  2201. t := SymTab.IntType();
  2202. QbeGen.CopyOp(qr, q)
  2203. ELSIF dt = SymTab.InvalidType THEN
  2204. t := SymTab.InvalidType;
  2205. QbeGen.CopyOp("0", q)
  2206. ELSIF SymTab.ClassOf(dt) #
  2207. SymTab.ClArray THEN
  2208. SemError(217);
  2209. t := SymTab.InvalidType;
  2210. QbeGen.CopyOp("0", q)
  2211. ELSE
  2212. IF isHigh THEN
  2213. IF SymTab.IsOpenArray(dt) THEN
  2214. QbeGen.OpenHi(qd, qr)
  2215. ELSE
  2216. QbeGen.IntStr(
  2217. SymTab.ArrayHi(dt), qr)
  2218. END
  2219. ELSE
  2220. IF SymTab.IsOpenArray(dt) THEN
  2221. QbeGen.LoadCount(qd, qr)
  2222. ELSE
  2223. QbeGen.IntStr(VAL(
  2224. INTEGER,
  2225. SymTab.ArrayLen(dt)),
  2226. qr)
  2227. END
  2228. END;
  2229. t := SymTab.IntType();
  2230. QbeGen.CopyOp(qr, q)
  2231. END; .)
  2232. | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
  2233. (. IF dt = SymTab.InvalidType THEN
  2234. t := SymTab.InvalidType;
  2235. QbeGen.CopyOp("0", q)
  2236. ELSE
  2237. QbeGen.IntStr(VAL(INTEGER,
  2238. SymTab.ObjectSize(dt)), q);
  2239. t := SymTab.IntType()
  2240. END; .)
  2241. | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
  2242. (. IF dt = SymTab.InvalidType THEN
  2243. t := SymTab.InvalidType;
  2244. QbeGen.CopyOp("0", q)
  2245. ELSE
  2246. IF sfx THEN
  2247. QbeGen.CopyOp(qd, q)
  2248. ELSIF (dk = SymTab.KindVar)
  2249. OR (dk = SymTab.KindParam) THEN
  2250. QbeGen.AddrOf(qn, q)
  2251. ELSE SemError(230);
  2252. QbeGen.CopyOp("0", q)
  2253. END;
  2254. t := SymTab.AddrType()
  2255. END; .)
  2256. | "CHR" "(" Expr<et, q> ")"
  2257. (. IF (et # SymTab.InvalidType)
  2258. AND NOT SymTab.IsIntFamily(et) THEN
  2259. SemError(211) END;
  2260. t := SymTab.CharType(); .)
  2261. | ( "ORD" | "ORDL" ) "(" Expr<et, q> ")"
  2262. (. IF et # SymTab.InvalidType THEN
  2263. IF (SymTab.ClassOf(et) #
  2264. SymTab.ClChar)
  2265. AND (SymTab.ClassOf(et) #
  2266. SymTab.ClBool)
  2267. AND (SymTab.ClassOf(et) #
  2268. SymTab.ClEnum)
  2269. AND NOT SymTab.IsIntFamily(et) THEN
  2270. SemError(211) END
  2271. END;
  2272. t := SymTab.IntType(); .)
  2273. | "CAP" "(" Expr<et, q> ")"
  2274. (. QbeGen.CapQ(q, qa);
  2275. QbeGen.CopyOp(qa, q);
  2276. t := SymTab.CharType(); .)
  2277. | "UCHR" "(" Expr<et, q> ")"
  2278. (. (* UCHR: the UCHAR constructor.
  2279. CHAR -> UCHAR (identity);
  2280. INTEGER familly -> UCHAR
  2281. (codepoint value). *)
  2282. IF (et # SymTab.InvalidType)
  2283. AND (SymTab.ClassOf(et) # SymTab.ClChar)
  2284. AND NOT SymTab.IsIntFamily(et) THEN
  2285. SemError(211) END;
  2286. t := SymTab.UCharType(); .)
  2287. | "CHR8" "(" Expr<et, q> ")"
  2288. (. IF (et # SymTab.InvalidType)
  2289. AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
  2290. SemError(211) END;
  2291. QbeGen.WidenLong(q, qa);
  2292. QbeGen.CheckRange(qa, "0", "255");
  2293. t := SymTab.CharType(); .)
  2294. | "UORD" "(" Expr<et, q> ")"
  2295. (. (* UORD(u): the codepoint as a
  2296. 32-bit ordinal (INTEGER),
  2297. cf. ORD for CHAR. *)
  2298. IF (et # SymTab.InvalidType)
  2299. AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
  2300. SemError(211) END;
  2301. t := SymTab.IntType(); .)
  2302. | "ABS" "(" Expr<et, q> ")"
  2303. (. IF (et # SymTab.InvalidType)
  2304. AND NOT SymTab.IsIntFamily(et)
  2305. AND (SymTab.ClassOf(et) #
  2306. SymTab.ClReal) THEN
  2307. SemError(211)
  2308. ELSE QbeGen.AbsQ(q, qa,
  2309. SymTab.ClassOf(et) =
  2310. SymTab.ClReal);
  2311. QbeGen.CopyOp(qa, q)
  2312. END;
  2313. t := et; .)
  2314. | "VAL" "(" GetIdent<vn> "," Expr<et, q> ")"
  2315. (. IF NOT SymTab.Lookup(vn) THEN
  2316. SemError(201);
  2317. t := SymTab.InvalidType
  2318. ELSE vt := SymTab.SymType(vn);
  2319. IF vt = SymTab.InvalidType THEN
  2320. t := SymTab.InvalidType
  2321. ELSIF et =
  2322. SymTab.InvalidType THEN
  2323. t := vt
  2324. ELSE
  2325. c1 := SymTab.ClassOf(et);
  2326. c2 := SymTab.ClassOf(vt);
  2327. IF ((c1 = SymTab.ClInt)
  2328. OR (c1 =
  2329. SymTab.ClChar)
  2330. OR (c1 =
  2331. SymTab.ClBool)
  2332. OR (c1 =
  2333. SymTab.ClEnum))
  2334. AND ((c2 = SymTab.ClInt)
  2335. OR (c2 =
  2336. SymTab.ClChar)
  2337. OR (c2 =
  2338. SymTab.ClBool)
  2339. OR (c2 =
  2340. SymTab.ClEnum)) THEN
  2341. t := vt
  2342. ELSIF (c1 = SymTab.ClPtr)
  2343. AND (c2 = SymTab.ClPtr) THEN
  2344. t := vt
  2345. ELSIF (c1 = SymTab.ClReal)
  2346. AND (c2 = SymTab.ClReal) THEN
  2347. t := vt
  2348. ELSE SemError(230);
  2349. t := SymTab.InvalidType
  2350. END
  2351. END
  2352. END; .)
  2353. | "(" Expr<et, q> ")" (. t := et; .)
  2354. | SetLit<st, sq> (. t := st;
  2355. QbeGen.CopyOp(sq, q); .)
  2356. | ( "NOT" | "~" ) Fact<t2, q2> (. IF SymTab.BoolCheck(t2) THEN
  2357. t := SymTab.BoolType()
  2358. ELSE SemError(212);
  2359. t := SymTab.InvalidType END;
  2360. IF t # SymTab.InvalidType THEN
  2361. QbeGen.NotQ(q2, q)
  2362. ELSE QbeGen.CopyOp("0", q)
  2363. END; .) .
  2364. (* Set literals are SET OF [0..255] (8 words); elements validated
  2365. 0..255 statically when foldable (222 otherwise), runtime trap
  2366. for computed elements. Ranges always lower via SetRange. *)
  2367. SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  2368. = "{" (. t := SymTab.NewSet(
  2369. SymTab.NewSubR(0, 255));
  2370. QbeGen.NewSetTemp(8, q);
  2371. QbeGen.SetZero(q, 8); .)
  2372. [ SetElem<t, q> { "," SetElem<t, q> } ]
  2373. "}" .
  2374. (* Typed set constructor: TypeName{ elems } — e.g. BITSET{0},
  2375. BITSET{}. The declared type (not SET OF [0..255]) sets the
  2376. width and element span. *)
  2377. TypedSetLit<vt: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  2378. (. VAR nw: CARDINAL; .)
  2379. = "{" (. IF SymTab.ClassOf(vt) #
  2380. SymTab.ClSet THEN
  2381. SemError(230); nw := 8
  2382. ELSE nw := SymTab.SetWords(vt);
  2383. IF nw = 0 THEN nw := 8 END
  2384. END;
  2385. QbeGen.NewSetTemp(nw, q);
  2386. QbeGen.SetZero(q, nw); .)
  2387. [ SetElem<vt, q> { "," SetElem<vt, q> } ]
  2388. "}" .
  2389. SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal> (. VAR et, et2: SymTab.TypeIndex;
  2390. qe, q2: QbeGen.QVal;
  2391. v, v2: INTEGER;
  2392. lo: INTEGER;
  2393. span: CARDINAL;
  2394. cl, cl2: INTEGER;
  2395. hasR: BOOLEAN; .)
  2396. = (. hasR := FALSE; .)
  2397. Expr<et, qe>
  2398. [ ".." Expr<et2, q2> (. hasR := TRUE; .) ]
  2399. (. lo := SymTab.SetBaseLo(st);
  2400. span := SymTab.SetCount(st);
  2401. IF (et = SymTab.InvalidType)
  2402. OR (hasR AND (et2 =
  2403. SymTab.InvalidType)) THEN
  2404. ELSE cl :=
  2405. SymTab.ClassOf(et);
  2406. IF hasR THEN
  2407. cl2 :=
  2408. SymTab.ClassOf(et2)
  2409. ELSE cl2 := SymTab.ClInt
  2410. END;
  2411. IF ((cl # SymTab.ClInt)
  2412. AND (cl # SymTab.ClChar)
  2413. AND (cl # SymTab.ClBool))
  2414. OR (hasR AND
  2415. ((cl2
  2416. # SymTab.ClInt)
  2417. AND (cl2
  2418. # SymTab.ClChar)
  2419. AND (cl2
  2420. # SymTab.ClBool))) THEN
  2421. SemError(222)
  2422. ELSIF hasR
  2423. AND SymTab.ConstInt(qe, v)
  2424. AND SymTab.ConstInt(q2,
  2425. v2)
  2426. AND ((v < lo)
  2427. OR (v2 < lo)
  2428. OR (v >= lo +
  2429. VAL(INTEGER, span))
  2430. OR (v2 >= lo +
  2431. VAL(INTEGER, span))
  2432. OR (v > v2)) THEN
  2433. SemError(222)
  2434. ELSIF hasR THEN
  2435. QbeGen.SetRange(sq, qe, q2,
  2436. lo, span)
  2437. ELSIF SymTab.ConstInt(qe,
  2438. v)
  2439. AND ((v < lo)
  2440. OR (v >= lo +
  2441. VAL(INTEGER,
  2442. span))) THEN
  2443. SemError(222)
  2444. ELSE QbeGen.SetBit(sq, qe,
  2445. lo, span)
  2446. END
  2447. END; .) .
  2448. GetIdent<VAR n: SymTab.Name>
  2449. = ident (. LexName(n); .) .
  2450. END M2.