Coco/R - Compiler-Compiler V1.53 Released by Pat Terry 17 September 2002 Source file: M2.atg Grammar Tests: Deletable symbols: DeclSeq Undefined nonterminals: -- none -- Unreachable nonterminals: -- none -- Circular derivations: -- none -- Underivable nonterminals: -- none -- LL(1) conditions: LL(1) error in ProcTypeSection: ident is the start of several alternatives. LL(1) error in TypeBlock: "CLASS" is the start & successor of a deletable structure Listing: 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/.ssa; 6 assemble with qbe, link with cc. 7 8 Test convention: a global VAR ExitCode : INTEGER makes generated 9 $main return its value as the process exit code, else return 0. 10 11 Semantic errors reuse the V1/V2/Test2 family: 200 duplicate, 12 201 undeclared, 202 module name mismatch, 210 bad assignment, 13 211 bad arithmetic, 221 not a type, 230 not supported yet, 14 231 opaque type outside definition. 15 Scalar-phase TYPEs (named, integer subrange, enum) check fully; 16 composite forms wait for step 3. Procedure headings (formals, 17 result, FORWARD) enter scopes now; bodies parse + check with one 18 230 at END (lowering = step 4). 19 Statements: assignment, IF/ELSIF/ELSE, WHILE, REPEAT/UNTIL, 20 LOOP/EXIT (230 outside LOOP), FOR/TO/static-sign-BY, full CASE 21 (labels, ranges, ELSE; compare-chain), RETURN with 232 checks 22 (outside proc / value mismatch / missing value). WITH waits for 23 records (step 3). Boolean connectives are eager (or/and/xor); 24 relations yield 0/1 via cXXw. 25 Clarion-form classes (docs/OOP.txt): CLASS decl + single 26 inheritance + CLASS IMPLEMENTATION blocks, methods with ";" 27 (per the Table example, not the sketch's ","), VIRTUAL flagged. 28 Scopes and member checks now; lowering later (one 230 per 29 class/impl block). Classic identifiers: no underscores, so the 30 Table example's _names stay lexically out of reach. 31 Step 3.1 arrays: "ARRAY [lo..hi, ...] OF T" (folded literal 32 bounds, int/char) and open "ARRAY OF T" formals; index suffixes 33 with per-level checks (217/218, trap on breach via $abort); 34 whole-array ":=" with runtime count check + blit; string 35 literals lower as descriptors (1-char stays CHAR, empty works); 36 array/string "=" is 213 (no built-in whole comparison). 37 Step 3.3 sets: multi-word masks (no header, static words) over 38 bases ≤ 256 values; literals are SET OF [0..255] (222 on 39 out-of-span); + - * / as or/and/xor-not, IN with span trap, 40 =/# word-wise (lenient cross-base); CASE labels reject sets. 41 Step 3.4 records: flat blobs; array fields are pointers to static 42 descriptors (locked amendment — one layout per type); nested 43 records inline; static declaration-order offsets; field chains 44 mix with indexes; WITH pushes fields + bases (215/216); 45 whole-record deep copy; record/set/class "=" is 213. 46 Step 3.6 pointers: vars (l), NIL as a real type (FNil — assignment 47 and =/# work, everything else 210-214/222), ^ deref with sfx 48 discipline (address flows, load at use; chains compose), 49 pointer =/# via ceql/cnel (< > etc. are 213), NEW/DISPOSE as 50 builtin statements via extern malloc/free (recursive skeleton 51 init; DISPOSE shallow and nils, deviating from Wirth-undefined); 52 nil-deref is raw (no check). *) 53 54 IMPORT SymTab, QbeGen, AST, Lower; 55 56 VAR 57 (* Two-phase frontend (docs/plan-two-phase.md). When TRUE the 58 productions ALSO build AST nodes alongside the legacy emit path. 59 Slice 1: the nodes are inert scaffolding — nothing reads them, so 60 the emitted output is unchanged. *) 61 twoPhase: BOOLEAN; 62 63 (* Result slot for the expression-AST builder (slice 2). Every 64 Expr/SimExpr/Term/Fact leaves its node here; the combination 65 productions save it into locals before parsing the next operand. 66 `astIsLit` in Fact is per-invocation, so a nested Fact cannot make 67 an outer non-literal Fact look literal. *) 68 astCur: AST.Node; 69 70 (* Actual-argument nodes collected by ActParam for the call being 71 parsed by ArgList (slice 4). Fact resets the count before the 72 optional ArgList and then folds the nodes into an NkCall. *) 73 astNArgs: CARDINAL; 74 astArgs: ARRAY [0 .. 31] OF AST.Node; 75 76 (* Statement-AST result slot (slice 5): the most recently parsed 77 statement. StatSeq folds these into an NkBlock. *) 78 astStmt: AST.Node; 79 80 (* Declaration-AST result slot (slice 6): the most recently built 81 declaration; DeclSeq folds these into an NkDeclSeq. *) 82 astDecl: AST.Node; 83 84 (* The local declarations of the most recent Block (a procedure body); 85 ProcDecl stores them as the proc node's child 2. *) 86 astBlkDecls: AST.Node; 87 88 (* Unit-AST root (slice 7): NkUnit(name, decls, body). *) 89 astUnit: AST.Node; 90 91 (* Test-only: when TRUE the program unit is re-emitted from the AST via 92 Lower right after the legacy EndModule (before EndUnit closes the 93 module scope, so Lower can still resolve names). *) 94 lowerRequested: BOOLEAN; 95 96 (* Import accumulator (slice 11): `{ Import }` appends NkImport 97 nodes here; each unit stores them as NkUnit child[3]. *) 98 astImp, astImpTail: AST.Node; 99 100 (* Class-AST accumulators (slice 13): the class node currently being 101 parsed and its parent/field/method lists. Classes are not nested 102 inside one another, so module-level state is safe. *) 103 astCls, astClsP, astClsPTail, astClsF, astClsFTail, 104 astClsM, astClsMTail, astMethod: AST.Node; 105 106 (* Class of the method named by the last `obj.Method` designator 107 (InvalidType when the callee is an ordinary procedure). Set by 108 Design, consumed by the following ArgList. *) 109 methCls: SymTab.TypeIndex; 110 (* Class of the type of the innermost `TypeName{...}` brace 111 constructor (ClSet or ClArray); dispatches BraceElem. *) 112 braceCls: INTEGER; 113 (* Module-level VAR declarations whose type was still an unresolved 114 forward alias at declaration time; emitted once the TYPE block 115 completes (module scope only). *) 116 nPendVar: CARDINAL; 117 pendVarName: ARRAY [0 .. 255] OF SymTab.Name; 118 pendVarT: ARRAY [0 .. 255] OF SymTab.TypeIndex; 119 (* Forward module-level variables referenced from a procedure body. *) 120 nFvarRefs: CARDINAL; 121 fvarId: ARRAY [0 .. 255] OF INTEGER; 122 fvarSlot: ARRAY [0 .. 255] OF INTEGER; 123 124 PROCEDURE FlushPend; 125 (* Emit module-level globals whose forward type is now resolved. *) 126 VAR k: CARDINAL; 127 BEGIN 128 k := 0; 129 WHILE k < nPendVar DO 130 QbeGen.DeclVar(pendVarName[k], pendVarT[k]); 131 INC(k) 132 END; 133 nPendVar := 0 134 END FlushPend; 135 136 PROCEDURE FwdVarNote (id, slot: INTEGER); 137 BEGIN 138 IF nFvarRefs <= HIGH(fvarId) THEN 139 fvarId[nFvarRefs] := id; 140 fvarSlot[nFvarRefs] := slot; 141 INC(nFvarRefs) 142 END 143 END FwdVarNote; 144 145 PROCEDURE FwdVarFlush; 146 (* At module end: resolve every forward reference against the declared 147 names (an unresolved one is 201) and patch its placeholder symbol. *) 148 VAR k: CARDINAL; nm, g: SymTab.Name; cls: INTEGER; oper: CHAR; 149 t: SymTab.TypeIndex; ok: BOOLEAN; 150 BEGIN 151 k := 0; 152 WHILE k < nFvarRefs DO 153 SymTab.FwdVarName(fvarId[k], nm); 154 IF nm[0] # CHR(0) THEN 155 IF NOT SymTab.FwdVarResolve(fvarId[k]) THEN 156 SemError(201) 157 ELSE 158 t := SymTab.FwdVarType(fvarId[k]); 159 cls := SymTab.ClassOf(t); 160 IF cls = SymTab.ClReal THEN oper := "d" 161 ELSIF SymTab.IsLongFamily(t) THEN oper := "l" 162 ELSE oper := "w" 163 END; 164 ok := SymTab.GlobalRef(nm, g); 165 QbeGen.FwdPatch(fvarSlot[k], fvarSlot[k], nm, oper, ok) 166 END 167 END; 168 INC(k) 169 END; 170 nFvarRefs := 0 171 END FwdVarFlush; 172 173 PROCEDURE AstAppend (kind: INTEGER; VAR head, tail: AST.Node; 174 item: AST.Node); 175 (* Appends `item` to a chunked sequence: each node holds up to 176 AST.MaxChild-1 items; child[MaxChild-1] continues into the next 177 chunk. Unbounded, so blocks/decl sequences are not capped at 8. *) 178 VAR n: AST.Node; 179 BEGIN 180 IF item = AST.NoNode THEN RETURN END; 181 IF head = AST.NoNode THEN 182 head := AST.MakeNode(kind); tail := head 183 END; 184 IF AST.NChild(tail) >= AST.MaxChild - 1 THEN 185 n := AST.MakeNode(kind); 186 AST.SetChild(tail, AST.MaxChild - 1, n); 187 tail := n 188 END; 189 AST.SetChild(tail, AST.NChild(tail), item) 190 END AstAppend; 191 192 PROCEDURE AstCallNode (callee: AST.Node) : AST.Node; 193 (* Builds NkCall(callee, actuals...) from astArgs/astNArgs. The actuals 194 are a chunked sequence (AstAppend): a call can have more than 195 MaxChild-1 arguments (the generic ArgList has 9), and SetChild would 196 silently drop the tail. NkBlock marks the continuation chunks. *) 197 VAR n, tail: AST.Node; j: CARDINAL; 198 BEGIN 199 n := AST.MakeNode(AST.NkCall); 200 AST.SetChild(n, 0, callee); 201 tail := n; 202 j := 0; 203 WHILE j < astNArgs DO 204 AstAppend(AST.NkBlock, n, tail, astArgs[j]); 205 INC(j) 206 END; 207 RETURN n 208 END AstCallNode; 209 210 211 212 PROCEDURE GetUnit (): AST.Node; 213 (* The most recently parsed unit's AST root (for the Lower comparison). *) 214 BEGIN 215 RETURN astUnit 216 END GetUnit; 217 218 PROCEDURE SetLower (b: BOOLEAN); 219 (* Enables the test-only Lower re-emit at program-unit end. *) 220 BEGIN 221 lowerRequested := b 222 END SetLower; 223 224 CHARACTERS 225 eol = CHR(13) . 226 lf = CHR(10) . 227 letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" . 228 digit = "0123456789" . 229 hexDigit = digit + "ABCDEFabcdef" . 230 noQuote1 = ANY - "'" - eol . 231 noQuote2 = ANY - '"' - eol . 232 233 IGNORE CHR(9) .. CHR(13) 234 235 COMMENTS FROM "(*" TO "*)" NESTED 236 COMMENTS FROM "//" TO lf 237 238 TOKENS 239 ident = letter { letter | digit | "_" } . 240 integer = digit { digit } 241 | digit { digit } CONTEXT("..") 242 | "0x" hexDigit { hexDigit } 243 | "0X" hexDigit { hexDigit } . 244 real = digit { digit } "." { digit } 245 [ ( "E" | "e" ) [ "+" | "-" ] digit { digit } ] . 246 string = "'" { noQuote1 } "'" 247 | '"' { noQuote2 } '"' . 248 charConst = digit { digit } ( "C" | "c" ) . 249 ustring = ( "U" | "u" ) ( "'" { noQuote1 } "'" | '"' { noQuote2 } '"' ) . 250 251 PRODUCTIONS 252 M2 253 = (. twoPhase := TRUE; astCur := AST.NoNode; astStmt := AST.NoNode; astDecl := AST.NoNode; astImp := AST.NoNode; astImpTail := AST.NoNode; 254 astImp := AST.NoNode; 255 astImpTail := AST.NoNode; .) 256 Unit "." . 257 (* Units: program modules compile fully; DEFINITION and 258 IMPLEMENTATION modules parse + check now but lower in step 4 259 (each ends with one 230); same for nested local modules. *) 260 Unit 261 = DefUnit 262 | ImplUnit 263 | ProgModule . 264 (* Step 4.3: one session compiles DEFINITION, its IMPLEMENTATION 265 and one program (last) into one image. Units share the symbol 266 table; imports materialize exported names. *) 267 DefUnit (. VAR m1, m2, pn: SymTab.Name; 268 astSeq, astTail, astProc: AST.Node; .) 269 = "DEFINITION" "MODULE" 270 GetIdent (. IF NOT SymTab.BeginDef(m1) THEN 271 SemError(200) END; 272 QbeGen.SetModule(m1); .) 273 ";" 274 { Import (. AstAppend(AST.NkDeclSeq, 275 astImp, astImpTail, astDecl); .) } 276 [ "EXPORT" [ "QUALIFIED" ] (. (* definition-module export 277 list: parsed, and the 278 names are already exported 279 by the module scope *) .) 280 GetIdent { "," GetIdent } ";" ] 281 (. astSeq := AST.NoNode; 282 astTail := AST.NoNode; .) 283 { ConstBlock (. AstAppend(AST.NkDeclSeq, 284 astSeq, astTail, astDecl); .) 285 | TypeBlock (. AstAppend(AST.NkDeclSeq, 286 astSeq, astTail, astDecl); .) 287 | VarBlock (. AstAppend(AST.NkDeclSeq, 288 astSeq, astTail, astDecl); .) 289 | ProcHeading ";" 290 (. (* a heading only: record it so 291 Lower can replay it *) 292 astProc := AST.MakeNode(AST.NkProcDecl); 293 AST.SetOp(astProc, 0); 294 AST.SetChild(astProc, 0, 295 AST.MakeLeaf(AST.NkIdent, pn)); 296 AstAppend(AST.NkDeclSeq, 297 astSeq, astTail, astProc); 298 Lower.NoteProcNode(astProc); 299 Lower.ScopeLeave; 300 SymTab.CloseProc; 301 QbeGen.AbortFunc; .) } 302 (. astUnit := AST.MakeNode(AST.NkUnit); 303 AST.SetChild(astUnit, 0, 304 AST.MakeLeaf(AST.NkIdent, m1)); 305 AST.SetChild(astUnit, 1, astSeq); 306 AST.SetChild(astUnit, 3, astImp); 307 astDecl := AST.NoNode; 308 astStmt := AST.NoNode; .) 309 "END" 310 GetIdent (. IF NOT SymTab.Equal(m1, m2) THEN 311 SemError(202) END; 312 SymTab.EndUnit; .) . 313 ImplUnit (. VAR m1, m2: SymTab.Name; 314 k: CARDINAL; 315 fname: SymTab.Name; 316 unres: BOOLEAN; 317 astNode: AST.Node; .) 318 = "IMPLEMENTATION" "MODULE" 319 GetIdent (. IF NOT SymTab.BeginImpl(m1) THEN 320 SemError(201) END; 321 astStmt := AST.NoNode; 322 astDecl := AST.NoNode; 323 astImp := AST.NoNode; 324 astImpTail := AST.NoNode; 325 nPendVar := 0; 326 QbeGen.SetModule(m1); .) 327 ";" 328 { Import (. AstAppend(AST.NkDeclSeq, 329 astImp, astImpTail, astDecl); .) } 330 DeclSeq (. astStmt := AST.NoNode; .) 331 [ "BEGIN" (. FlushPend; 332 k := 0; 333 WHILE k < SymTab.FwdPending() DO 334 SymTab.FwdInfo(k, fname, unres); 335 IF unres THEN SemError(201) END; 336 INC(k) 337 END; 338 SymTab.FwdClear; 339 FwdVarFlush; 340 QbeGen.BeginInit(m1); .) 341 [ StatSeq ] (. QbeGen.EndInit; .) ] 342 "END" 343 GetIdent (. FlushPend; 344 k := 0; 345 WHILE k < SymTab.FwdPending() DO 346 SymTab.FwdInfo(k, fname, unres); 347 IF unres THEN SemError(201) END; 348 INC(k) 349 END; 350 SymTab.FwdClear; 351 FwdVarFlush; 352 astNode := AST.MakeNode(AST.NkUnit); 353 AST.SetChild(astNode, 0, 354 AST.MakeLeaf(AST.NkIdent, m1)); 355 AST.SetChild(astNode, 1, astDecl); 356 AST.SetChild(astNode, 2, astStmt); 357 AST.SetChild(astNode, 3, astImp); 358 astUnit := astNode; 359 IF NOT SymTab.Equal(m1, m2) THEN 360 SemError(202) END; 361 SymTab.EndUnit; .) . 362 ProgModule (. VAR m1, m2: SymTab.Name; 363 k: CARDINAL; 364 fname: SymTab.Name; 365 unres: BOOLEAN; 366 astNode: AST.Node; .) 367 = "MODULE" 368 GetIdent (. IF NOT SymTab.BeginProg(m1) THEN 369 SemError(200) END; 370 astStmt := AST.NoNode; 371 astDecl := AST.NoNode; 372 astImp := AST.NoNode; 373 astImpTail := AST.NoNode; 374 nPendVar := 0; 375 QbeGen.SetModule(m1); .) 376 [ Priority ] 377 ";" 378 { Import (. AstAppend(AST.NkDeclSeq, 379 astImp, astImpTail, astDecl); .) } 380 DeclSeq (. astStmt := AST.NoNode; .) 381 [ "BEGIN" (. FlushPend; 382 k := 0; 383 WHILE k < SymTab.FwdPending() DO 384 SymTab.FwdInfo(k, fname, unres); 385 IF unres THEN SemError(201) END; 386 INC(k) 387 END; 388 SymTab.FwdClear; 389 FwdVarFlush; 390 QbeGen.BeginBody; .) 391 [ StatSeq ] ] 392 "END" 393 GetIdent (. FlushPend; 394 k := 0; 395 WHILE k < SymTab.FwdPending() DO 396 SymTab.FwdInfo(k, fname, unres); 397 IF unres THEN SemError(201) END; 398 INC(k) 399 END; 400 SymTab.FwdClear; 401 FwdVarFlush; 402 IF NOT SymTab.Equal(m1, m2) THEN 403 SemError(202) END; 404 astNode := AST.MakeNode(AST.NkUnit); 405 AST.SetChild(astNode, 0, 406 AST.MakeLeaf(AST.NkIdent, m1)); 407 AST.SetChild(astNode, 1, astDecl); 408 AST.SetChild(astNode, 2, astStmt); 409 AST.SetChild(astNode, 3, astImp); 410 astUnit := astNode; 411 QbeGen.EndModule(m1); 412 SymTab.EndUnit; .) . 413 DeclSeq (. VAR astSeq, astTail: AST.Node; .) 414 = (. astSeq := AST.NoNode; 415 astTail := AST.NoNode; .) 416 { (. astDecl := AST.NoNode; .) 417 ( ConstBlock | TypeBlock | VarBlock | ProcDecl ";" 418 | NestedModule ";" | ClassItem ";" ) 419 (. AstAppend(AST.NkDeclSeq, 420 astSeq, astTail, astDecl); .) } 421 (. astDecl := astSeq; .) . 422 (* Local module, Wirth form. Declarations lower like top-level ones 423 (same QBE module prefix); a BEGIN body becomes an init function 424 that main calls; the EXPORT list is hoisted into the enclosing 425 scope at END. *) 426 NestedModule (. VAR m1, m2: SymTab.Name; 427 expNames: ARRAY [0 .. 63] OF SymTab.Name; 428 expCount, k: CARDINAL; 429 astNode, nImp, nImpTail: 430 AST.Node; .) 431 = "MODULE" 432 GetIdent (. IF NOT SymTab.Enter(m1, 433 SymTab.KindModule) THEN 434 SemError(200) END; 435 SymTab.PushScope; 436 expCount := 0; 437 astNode := AST.MakeNode(AST.NkUnit); 438 AST.SetChild(astNode, 0, 439 AST.MakeLeaf(AST.NkIdent, m1)); 440 astStmt := AST.NoNode; 441 astDecl := AST.NoNode; 442 nImp := AST.NoNode; 443 nImpTail := AST.NoNode; .) 444 [ Priority ] 445 ";" 446 { Import (. AstAppend(AST.NkDeclSeq, 447 nImp, nImpTail, astDecl); .) } 448 [ "EXPORT" [ "QUALIFIED" ] 449 GetIdent (. INC(expCount); .) 450 { "," GetIdent 451 (. INC(expCount); .) } 452 ";" ] 453 DeclSeq (. astStmt := AST.NoNode; .) 454 [ "BEGIN" (. astStmt := AST.NoNode; 455 QbeGen.BeginInit(m1); .) 456 [ StatSeq ] (. QbeGen.EndInit; .) ] 457 "END" 458 GetIdent (. AST.SetChild(astNode, 1, astDecl); 459 AST.SetChild(astNode, 2, astStmt); 460 AST.SetChild(astNode, 3, nImp); 461 astDecl := astNode; 462 IF NOT SymTab.Equal(m1, m2) THEN 463 SemError(202) END; 464 k := 0; 465 WHILE k < expCount DO 466 SymTab.ExportUp(expNames[k]); 467 INC(k) 468 END; 469 SymTab.PopScope; .) . 470 Priority 471 = "[" integer "]" (. SemError(230); .) . 472 (* Imports (4.3): FROM materializes the names (unqualified use); 473 plain IMPORT only demands the module exists — qualified `L.x` 474 materializes on first use (Design). *) 475 (* Unknown modules stay unchecked stubs (legacy, so hand-written 476 import lines don't fail); a known module's missing export is 477 201. *) 478 Import (. VAR n: SymTab.Name; 479 astImport: AST.Node; .) 480 = "FROM" 481 GetIdent (. astImport := AST.MakeNode(AST.NkImport); 482 AST.SetChild(astImport, 0, 483 AST.MakeLeaf(AST.NkIdent, n)); .) 484 "IMPORT" 485 ImpList ";" (. astDecl := astImport; .) 486 | "IMPORT" (. astImport := AST.MakeNode(AST.NkImport); .) 487 ImpModList ";" (. astDecl := astImport; .) . 488 ImpList 489 (. VAR n: SymTab.Name; .) 490 = ImpName 491 { "," ImpName } . 492 (* Pervasive built-ins imported from SYSTEM (e.g. TSIZE) are 493 accepted and ignored: the built-in applies regardless. *) 494 ImpName 495 (. VAR n: SymTab.Name; .) 496 = GetIdent (. AST.SetChild(node, AST.NChild(node), 497 AST.MakeLeaf(AST.NkIdent, n)); 498 IF SymTab.Equal(mod, "libc") THEN 499 (* intrinsic C library: 500 permissive external *) 501 IF NOT SymTab.DeclareCProc(n) THEN 502 SemError(201) END 503 ELSIF SymTab.ModKnown(mod) 504 AND NOT SymTab.ImportFrom(mod, n) THEN 505 SemError(201) END; .) 506 | ( "TSIZE" | "SIZE" | "ADR" | "HIGH" | "LEN" 507 | "CHR" | "ORD" | "ORDL" | "VAL" | "ABS" | "CAP" 508 | "UCHR" | "CHR8" | "UORD" 509 | "INC" | "DEC" ) . 510 ImpModList (. VAR n: SymTab.Name; .) 511 = GetIdent (. AST.SetChild(node, AST.NChild(node), 512 AST.MakeLeaf(AST.NkIdent, n)); .) 513 { "," GetIdent (. AST.SetChild(node, AST.NChild(node), 514 AST.MakeLeaf(AST.NkIdent, n)); .) } . 515 (* Opaque TYPE declarations (definition modules). The targetless 516 alias resolves to InvalidType until step 4 completes it. *) 517 (* Scalar-phase TYPEs: named types, integer subranges, enumerations. 518 Opaque "TYPE T;" needs isDef (definition units); elsewhere 231. 519 Composite forms (ARRAY/RECORD/SET/POINTER) arrive with step 3. *) 520 TypeBlock (. VAR astSeq, astTail: AST.Node; .) 521 = "TYPE" (. SymTab.BeginTypeBlock; 522 astSeq := AST.NoNode; 523 astTail := AST.NoNode; .) 524 { (. astDecl := AST.NoNode; .) 525 ( TypeItem ";" | ClassItem ";" ) 526 (. AstAppend(AST.NkDeclSeq, 527 astSeq, astTail, astDecl); .) } 528 (. SymTab.EndTypeBlock; 529 astDecl := astSeq; .) . 530 TypeItem (. VAR n: SymTab.Name; 531 t, op: SymTab.TypeIndex; 532 astNode: AST.Node; .) 533 = GetIdent (. op := SymTab.OpaqueBase(n); 534 IF op = SymTab.InvalidType THEN 535 IF NOT SymTab.Enter(n, 536 SymTab.KindType) THEN 537 SemError(200) END 538 END; .) 539 ( "=" Type (. astNode := AST.MakeNode(AST.NkTypeDecl); 540 AST.SetChild(astNode, 0, 541 AST.MakeLeaf(AST.NkIdent, n)); 542 AST.SetTy(astNode, t); 543 astDecl := astNode; 544 IF op # SymTab.InvalidType THEN 545 SymTab.SetTarget(op, t) 546 ELSE SymTab.SetSymType(n, t) 547 END; .) 548 | (. IF op # SymTab.InvalidType THEN 549 (* stays opaque *) 550 ELSIF NOT isDef THEN 551 SemError(231) 552 ELSE SymTab.SetSymType(n, 553 SymTab.NewAlias()) END; .) ) . 554 Type 555 = TypeIdent [ Subrange ] (* anchored subrange: T[lo..hi] *) 556 | Subrange 557 | Enum 558 | ArrayType 559 | SetType 560 | RecordType 561 | PointerType 562 | ProcType . 563 PointerType (. VAR base: SymTab.TypeIndex; .) 564 = "POINTER" "TO" Type(. t := SymTab.NewPtr(base); .) . 565 (* Procedure types (step 8.5): PROCEDURE (params): result. Values 566 are code pointers; params are collected into the descriptor. *) 567 ProcType (. VAR res, pt: SymTab.TypeIndex; 568 isV: BOOLEAN; .) 569 = "PROCEDURE" (. res := SymTab.InvalidType; 570 t := SymTab.NewProcType(res); .) 571 [ "(" [ ProcTypeSection { ";" ProcTypeSection } ] ")" ] 572 [ ":" TypeIdent (. SymTab.SetProcTypeRes(t, res); .) ] . 573 ProcTypeSection (. VAR pt: SymTab.TypeIndex; 574 isV: BOOLEAN; 575 cnt, k: CARDINAL; 576 names: ARRAY [0 .. 15] OF SymTab.Name; .) 577 = (. isV := FALSE; cnt := 0; .) 578 [ "VAR" (. isV := TRUE; .) ] 579 ( GetIdent (. INC(cnt); .) 580 { "," GetIdent (. INC(cnt); .) } 581 ( ":" Type (. k := 0; 582 WHILE k < cnt DO 583 SymTab.ProcTypeAdd(t, isV, pt); 584 INC(k) 585 END; .) 586 | (. (* type-only parameter list: 587 each name is a type (GNU 588 shorthand used by the 589 Coco/R scanner frame) *) 590 k := 0; 591 WHILE k < cnt DO 592 IF SymTab.Lookup(names[k]) 593 AND ((SymTab.SymKind(names[k]) = SymTab.KindType) 594 OR (SymTab.SymKind(names[k]) = SymTab.KindPredef)) THEN 595 pt := SymTab.SymType(names[k]) 596 ELSE SemError(201); 597 pt := SymTab.InvalidType 598 END; 599 SymTab.ProcTypeAdd(t, isV, pt); 600 INC(k) 601 END; .) ) 602 | Type (. (* unnamed parameter (PIM): 603 e.g. PROCEDURE (VAR ARRAY OF REAL) *) 604 SymTab.ProcTypeAdd(t, isV, pt); .) ) . 605 (* Arrays: "OF" without bounds is an open formal (allowed only 606 where allowOpen); "[lo..hi, ...]" nests bounded levels inside 607 out. Bounds are folded literals (int/char); anything else 230. 608 Bare-type indices ("ARRAY Color OF") wait for enum ordinals. *) 609 ArrayType 610 (. VAR elem: SymTab.TypeIndex; 611 ok: BOOLEAN; 612 bnds, bndh: ARRAY [0 .. 7] OF INTEGER; 613 nb, k: CARDINAL; 614 idx: SymTab.TypeIndex; 615 ilo, ihi: INTEGER; .) 616 = "ARRAY" 617 ( "OF" Type (. IF NOT allowOpen THEN 618 SemError(230) END; 619 t := SymTab.NewOpenArray(elem); .) 620 | TypeIdent [ Subrange ] 621 "OF" Type (. (* index-type array: the index 622 type's ordinal bounds give the 623 [lo..hi] pair *) 624 IF SymTab.TypeBounds(idx, ilo, 625 ihi) 626 THEN t := SymTab.NewArrayB(elem, 627 ilo, ihi) 628 ELSE SemError(230); 629 t := SymTab.InvalidType 630 END; .) 631 | "[" (. SymTab.BoundBegin; ok := TRUE; .) 632 BoundPair 633 { "," BoundPair } 634 "]" (. (* snapshot before the element 635 type, which reuses the bound 636 buffer for a nested ARRAY *) 637 nb := SymTab.BoundCount(); 638 k := 0; 639 WHILE k < nb DO 640 bnds[k] := SymTab.BoundLo(k); 641 bndh[k] := SymTab.BoundHi(k); 642 INC(k) 643 END; .) 644 "OF" Type 645 (. IF ok THEN 646 k := nb; 647 WHILE k > 0 DO 648 DEC(k); 649 elem := SymTab.NewArrayB( 650 elem, bnds[k], bndh[k]) 651 END; 652 t := elem 653 ELSE t := SymTab.InvalidType 654 END; .) ) . 655 BoundPair (. VAR tlo, thi: SymTab.TypeIndex; 656 qlo, qhi: QbeGen.QVal; 657 lo, hi: INTEGER; 658 cl, cl2: INTEGER; .) 659 = Expr ".." Expr 660 (. IF (tlo = SymTab.InvalidType) 661 OR (thi = SymTab.InvalidType) THEN 662 ok := FALSE 663 ELSE cl := SymTab.ClassOf(tlo); 664 cl2 := SymTab.ClassOf(thi); 665 IF ((cl # SymTab.ClInt) 666 AND (cl # SymTab.ClChar)) 667 OR ((cl2 # SymTab.ClInt) 668 AND (cl2 # SymTab.ClChar)) THEN 669 SemError(230); ok := FALSE 670 ELSIF NOT SymTab.ConstInt(qlo, lo) 671 OR NOT SymTab.ConstInt(qhi, hi) 672 OR (lo > hi) THEN 673 SemError(230); ok := FALSE 674 ELSIF NOT SymTab.BoundAdd(lo, hi) THEN 675 SemError(230); ok := FALSE 676 END; 677 END; .) . 678 (* Sets: multi-word masks over bases ≤ 256 values (bool, char, 679 bounded subranges; enums wait for ordinals, INTEGER is 680 unbounded). Literals are SET OF [0..255]; assignment and 681 comparison across suitable bases are lenient (masks over min 682 words + zero-check extras), out-of-span literals are 222. *) 683 SetType (. VAR base: SymTab.TypeIndex; 684 blo, bhi, bspan: INTEGER; 685 bcls: INTEGER; .) 686 = "SET" "OF" Type 687 (. IF base = SymTab.InvalidType THEN 688 t := SymTab.InvalidType 689 ELSE bcls := 690 SymTab.ClassOf(base); 691 IF bcls = SymTab.ClBool THEN 692 blo := 0; bspan := 2 693 ELSIF bcls = SymTab.ClChar THEN 694 blo := 0; bspan := 256 695 ELSIF bcls = SymTab.ClEnum THEN 696 blo := 0; 697 bspan := VAL(INTEGER, 698 SymTab.EnumCount(base)) 699 ELSIF SymTab.SubBounds(base, 700 blo, bhi) THEN 701 bspan := bhi - blo + 1 702 ELSE bspan := 0 END; 703 IF (bspan <= 0) 704 OR (bspan > 65536) THEN 705 SemError(230); 706 t := SymTab.InvalidType 707 ELSE t := SymTab.NewSet(base) 708 END 709 END; .) . 710 (* Records: flat blobs; array fields are pointers to static 711 descriptors (locked amendment), nested records inline. Field 712 offsets static and declaration-ordered. *) 713 (* Field list: plain fields and (optionally) one variant part. The 714 variant part is a `CASE ... END` item; because it starts with the 715 CASE keyword it is unambiguously distinguishable from a field 716 (which starts with an identifier). *) 717 RecordType (. VAR t2: SymTab.TypeIndex; 718 tagOk: BOOLEAN; .) 719 = "RECORD" (. t := SymTab.NewRecord(); .) 720 [ RecItem { ";" [ RecItem ] } ] 721 "END" . 722 RecItem (. VAR tt: SymTab.TypeIndex; .) 723 = RecField 724 | CaseField (. SymTab.MarkVariant(rec); .) . 725 (* A variant part: CASE tag : Type OF variants. The layout overlays 726 every branch from the tag slot (see SymTab.ComputeOffsets). *) 727 CaseField (. VAR tagT: SymTab.TypeIndex; 728 tagN: SymTab.Name; .) 729 = "CASE" (. SymTab.ResetFields(rec); .) 730 GetIdent (. IF NOT SymTab.FieldPending(rec, 731 tagN) THEN 732 SemError(200) END; .) 733 ":" Type (. IF (tagT # SymTab.InvalidType) 734 AND NOT SymTab.IsOrdinal(tagT) THEN 735 SemError(224) 736 END; 737 SymTab.FixPendingF(rec, tagT); 738 SymTab.SetVariantTag(rec, tagN); .) 739 "OF" 740 RecFieldList 741 { "|" (. SymTab.ResetFields(rec); .) 742 RecFieldList } 743 "END" . 744 RecFieldList (. VAR lt, lq: SymTab.TypeIndex; 745 lv1, lv2: QbeGen.QVal; .) 746 = VarLabel [ ".." VarLabel ] ":" 747 RecField { ";" [ RecField ] } . 748 (* Variant case label: a constant (or a constant range). Values are 749 not interpreted (the layout overlays regardless). *) 750 VarLabel 751 (. VAR lname: SymTab.Name; .) 752 = ( ident (. LexName(lname); 753 QbeGen.CopyOp("0", q); 754 t := SymTab.IntType(); .) 755 | integer (. LexString(lname); 756 QbeGen.CopyOp("0", q); 757 t := SymTab.IntType(); .) 758 | charConst (. LexString(lname); 759 QbeGen.CopyOp("0", q); 760 t := SymTab.CharType(); .) ) . 761 RecField (. VAR n: SymTab.Name; 762 t2: SymTab.TypeIndex; .) 763 = RecIdents ":" Type(. SymTab.FixPendingF(rec, t2); .) . 764 RecIdents (. VAR n: SymTab.Name; .) 765 = GetIdent (. IF NOT SymTab.FieldPending(rec, 766 n) THEN 767 SemError(200) END; .) 768 { "," GetIdent (. IF NOT SymTab.FieldPending(rec, 769 n) THEN 770 SemError(200) END; .) } . 771 TypeIdent (. VAR n, qid: SymTab.Name; 772 k: INTEGER; 773 dotted: BOOLEAN; .) 774 = GetIdent (. dotted := FALSE; 775 IF NOT SymTab.Lookup(n) THEN 776 k := -1; 777 t := SymTab.ForwardType(n); 778 IF t = SymTab.InvalidType THEN 779 SemError(201) 780 END 781 ELSE k := SymTab.SymKind(n); 782 IF (k = SymTab.KindType) 783 OR (k = SymTab.KindPredef) THEN 784 t := SymTab.SymType(n) 785 ELSE t := SymTab.InvalidType 786 END 787 END; .) 788 [ "." GetIdent (. dotted := TRUE; 789 IF k = SymTab.KindModule THEN 790 t := SymTab.QualType(n, qid); 791 IF t = SymTab.InvalidType THEN 792 SemError(201) 793 END 794 ELSE SemError(221); 795 t := SymTab.InvalidType 796 END; .) ] 797 (. IF NOT dotted THEN 798 IF (k = SymTab.KindModule) 799 OR ((k # SymTab.KindType) 800 AND (k # SymTab.KindPredef) 801 AND (k # SymTab.KindImport) 802 AND (k # -1)) THEN 803 SemError(221) 804 END 805 END; .) . 806 Subrange (. VAR tlo, thi: SymTab.TypeIndex; 807 qlo, qhi: QbeGen.QVal; 808 lo, hi: INTEGER; .) 809 = "[" Expr ".." Expr 810 (. IF (tlo = SymTab.InvalidType) 811 OR (thi = SymTab.InvalidType) THEN 812 t := SymTab.InvalidType 813 ELSIF NOT SymTab.IsOrdinal(tlo) 814 OR NOT SymTab.IsOrdinal(thi) THEN 815 SemError(230); 816 t := SymTab.InvalidType 817 ELSIF NOT SymTab.ConstInt(qlo, lo) 818 OR NOT SymTab.ConstInt(qhi, hi) 819 OR (lo > hi) THEN 820 SemError(230); 821 t := SymTab.InvalidType 822 ELSE t := SymTab.NewSubR(lo, hi) 823 END; .) 824 "]" . 825 Enum (. VAR n: SymTab.Name; 826 ord: INTEGER; 827 qv: QbeGen.QVal; .) 828 = "(" (. t := SymTab.NewEnum(); 829 ord := 0; .) 830 GetIdent (. IF NOT SymTab.Enter(n, 831 SymTab.KindConst) THEN 832 SemError(200) END; 833 SymTab.SetSymType(n, t); 834 QbeGen.IntStr(ord, qv); 835 SymTab.SetSymVal(n, qv); 836 Lower.NoteVar(n, 837 SymTab.KindConst, t); 838 Lower.NoteConstVal(qv); 839 INC(ord); .) 840 { "," GetIdent (. IF NOT SymTab.Enter(n, 841 SymTab.KindConst) THEN 842 SemError(200) END; 843 SymTab.SetSymType(n, t); 844 QbeGen.IntStr(ord, qv); 845 SymTab.SetSymVal(n, qv); 846 Lower.NoteVar(n, 847 SymTab.KindConst, t); 848 Lower.NoteConstVal(qv); 849 INC(ord); .) } 850 ")" (. SymTab.SetEnumCount(t, 851 VAL(CARDINAL, ord)); .) . 852 (* Clarion-form classes (docs/OOP.txt): declaration + single 853 inheritance + IMPLEMENTATION blocks. Scopes and member checks 854 now; lowering (vtable, dispatch, THIS) later — one 230 per 855 class/impl block. Methods end with ";" per the Table example 856 (not "," as in the sketch). No underscores in identifiers. *) 857 (* Single CLASS item in both loops: separating declaration from 858 IMPLEMENTATION at the loop level needs 2-token lookahead 859 (CLASS ident vs CLASS IMPLEMENTATION), which LL(1) cannot do. 860 The second token decides after CLASS is consumed. A misplaced 861 CLASS IMPLEMENTATION inside TYPE still parses (harmless: the 862 whole unit ends 230 until lowering). *) 863 ClassItem 864 = "CLASS" ( "IMPLEMENTATION" ClassImplRest | ClassRest ) . 865 ClassRest (. VAR cn, m2, pn: SymTab.Name; 866 ct: SymTab.TypeIndex; .) 867 = GetIdent (. IF NOT SymTab.Enter(cn, 868 SymTab.KindType) THEN 869 SemError(200) END; 870 ct := SymTab.NewClass(); 871 SymTab.SetSymType(cn, ct); 872 SymTab.PushClassScope(ct); 873 astCls := AST.MakeNode(AST.NkClassDecl); 874 AST.SetChild(astCls, 0, 875 AST.MakeLeaf(AST.NkIdent, cn)); 876 astClsP := AST.NoNode; 877 astClsPTail := AST.NoNode; 878 astClsF := AST.NoNode; 879 astClsFTail := AST.NoNode; 880 astClsM := AST.NoNode; 881 astClsMTail := AST.NoNode; .) 882 [ Parents ] 883 ";" 884 { ClassField ";" } 885 { MethodHeading ";" 886 (. Lower.ScopeLeave; 887 SymTab.CloseProc; 888 QbeGen.AbortFunc; .) } 889 "END" 890 GetIdent (. IF NOT SymTab.Equal(cn, m2) THEN 891 SemError(202) END; 892 SymTab.LayoutClass(ct); 893 SymTab.PopScope; 894 AST.SetChild(astCls, 1, astClsP); 895 AST.SetChild(astCls, 2, astClsF); 896 AST.SetChild(astCls, 3, astClsM); 897 astDecl := astCls; .) . 898 Parents (. VAR p: SymTab.Name; .) 899 = "(" Parent1 900 { "," GetIdent

(. SemError(230); .) } 901 ")" . 902 Parent1 (. VAR p: SymTab.Name; 903 pt: SymTab.TypeIndex; .) 904 = GetIdent

(. IF NOT SymTab.Lookup(p) THEN 905 SemError(201) 906 ELSE pt := SymTab.SymType(p); 907 IF SymTab.ClassOf(pt) # 908 SymTab.ClClass THEN 909 SemError(230) 910 ELSE SymTab.SetParent(ct, pt) 911 END 912 END; 913 AstAppend(AST.NkFieldDecl, 914 astClsP, astClsPTail, 915 AST.MakeLeaf(AST.NkIdent, p)); .) . 916 ClassField (. VAR n, rhs: SymTab.Name; 917 t: SymTab.TypeIndex; 918 astNode: AST.Node; .) 919 = GetIdent 920 ( "=" GetIdent (. IF NOT SymTab.Enter(n, 921 SymTab.KindConst) THEN 922 SemError(200) END; 923 astNode := AST.MakeNode(AST.NkConstDecl); 924 AST.SetChild(astNode, 0, 925 AST.MakeLeaf(AST.NkIdent, n)); 926 AST.SetChild(astNode, 1, 927 AST.MakeLeaf(AST.NkIdent, rhs)); 928 AstAppend(AST.NkFieldDecl, 929 astClsF, astClsFTail, astNode); 930 IF SymTab.Lookup(rhs) THEN 931 SymTab.SetSymType(n, 932 SymTab.SymType(rhs)) 933 END; .) 934 | (. IF NOT SymTab.FieldPending(ct, 935 n) THEN 936 SemError(200) END; 937 astNode := AST.MakeNode(AST.NkVarDecl); 938 AST.SetChild(astNode, 0, 939 AST.MakeLeaf(AST.NkIdent, n)); .) 940 { "," GetIdent (. IF NOT SymTab.FieldPending(ct, 941 n) THEN 942 SemError(200) END; 943 AST.SetChild(astNode, 944 AST.NChild(astNode), 945 AST.MakeLeaf(AST.NkIdent, n)); .) } 946 ":" Type (. SymTab.FixPendingF(ct, t); 947 AST.SetTy(astNode, t); 948 AstAppend(AST.NkFieldDecl, 949 astClsF, astClsFTail, astNode); .) ) . 950 MethodHeading 951 (. VAR wantVirt: BOOLEAN; .) 952 = (. wantVirt := FALSE; .) 953 [ "VIRTUAL" (. wantVirt := TRUE; .) ] 954 ProcHeading (. IF wantVirt THEN 955 SymTab.MarkVirtual END; 956 astMethod := AST.MakeNode(AST.NkProcDecl); 957 AST.SetChild(astMethod, 0, 958 AST.MakeLeaf(AST.NkIdent, pn)); 959 IF wantVirt THEN 960 AST.SetOp(astMethod, 3) 961 ELSE AST.SetOp(astMethod, 0) 962 END; 963 AstAppend(AST.NkFieldDecl, 964 astClsM, astClsMTail, astMethod); .) . 965 ClassImplRest (. VAR cn, m2: SymTab.Name; 966 ct: SymTab.TypeIndex; .) 967 = GetIdent (. IF NOT SymTab.Lookup(cn) THEN 968 SemError(201); 969 ct := SymTab.InvalidType 970 ELSE ct := SymTab.SymType(cn); 971 IF SymTab.ClassOf(ct) # 972 SymTab.ClClass THEN 973 SemError(230); 974 ct := SymTab.InvalidType 975 END 976 END; 977 astCls := AST.MakeNode(AST.NkClassDecl); 978 AST.SetOp(astCls, 1); 979 AST.SetChild(astCls, 0, 980 AST.MakeLeaf(AST.NkIdent, cn)); 981 astClsM := AST.NoNode; 982 astClsMTail := AST.NoNode; 983 astStmt := AST.NoNode; 984 IF ct # 985 SymTab.InvalidType THEN 986 IF NOT SymTab.PushClassMembers( 987 ct) THEN 988 SemError(230) END; 989 SymTab.PushImplClass(ct) 990 END; .) 991 ";" { MethodImpl ";" } 992 (. astStmt := AST.NoNode; .) 993 [ "BEGIN" (. astStmt := AST.MakeNode(AST.NkBlock); 994 QbeGen.BeginInit(cn); .) 995 [ StatSeq ] (. QbeGen.EndInit; .) ] 996 "END" 997 GetIdent (. IF NOT SymTab.Equal(cn, m2) THEN 998 SemError(202) END; 999 SymTab.PopImplClass; 1000 SymTab.PopScope; 1001 AST.SetChild(astCls, 1, AST.NoNode); 1002 AST.SetChild(astCls, 2, astStmt); 1003 AST.SetChild(astCls, 3, astClsM); 1004 astDecl := astCls; .) . 1005 MethodImpl (. VAR pn: SymTab.Name; 1006 thisQ: QbeGen.QVal; 1007 methRes: SymTab.TypeIndex; .) 1008 = MethodHeading ";" 1009 (. IF (ct # 1010 SymTab.InvalidType) 1011 AND NOT SymTab.MethodExists(ct, 1012 pn) THEN 1013 SemError(201) END; .) 1014 ( "FORWARD" (. AST.SetOp(astMethod, 1); 1015 SymTab.MarkFwd; 1016 QbeGen.AbortFunc; 1017 Lower.ScopeLeave; 1018 SymTab.CloseProc; .) 1019 | (. QbeGen.EndFuncHeader; 1020 (* bind the receiver: bare 1021 field names resolve 1022 against THIS *) 1023 QbeGen.ThisBase(thisQ); 1024 QbeGen.PushWith(thisQ); .) 1025 Block (. AST.SetChild(astMethod, 1, astStmt); 1026 QbeGen.PopWith; 1027 methRes := SymTab.CurRes(); 1028 Lower.ScopeLeave; 1029 SymTab.CloseProc; 1030 QbeGen.EndFunc(methRes); .) ) . 1031 ConstBlock (. VAR astSeq, astTail: AST.Node; .) 1032 = "CONST" (. astSeq := AST.NoNode; 1033 astTail := AST.NoNode; .) 1034 { ConstDecl ";" (. AstAppend(AST.NkDeclSeq, 1035 astSeq, astTail, astDecl); .) } 1036 (. astDecl := astSeq; .) . 1037 ConstDecl (. VAR n: SymTab.Name; 1038 t: SymTab.TypeIndex; 1039 qv: QbeGen.QVal; 1040 cls: INTEGER; 1041 astNode: AST.Node; .) 1042 = GetIdent (. IF NOT SymTab.Enter(n, 1043 SymTab.KindConst) THEN 1044 SemError(200) END; .) 1045 "=" 1046 Expr (. astNode := AST.MakeNode(AST.NkConstDecl); 1047 AST.SetChild(astNode, 0, 1048 AST.MakeLeaf(AST.NkIdent, n)); 1049 AST.SetChild(astNode, 1, astCur); 1050 AST.SetTy(astNode, t); 1051 astDecl := astNode; 1052 Lower.NoteVar(n, SymTab.KindConst, t); 1053 Lower.NoteConstVal(qv); 1054 SymTab.SetSymType(n, t); 1055 cls := SymTab.ClassOf(t); 1056 IF (cls = SymTab.ClArray) 1057 OR (cls = SymTab.ClRecord) 1058 OR (cls = SymTab.ClClass) 1059 OR (cls = SymTab.ClStr) 1060 OR (cls = SymTab.ClUStr) THEN 1061 (* an aggregate/string 1062 constant: qv is its 1063 descriptor address; no 1064 scalar data *) 1065 SymTab.SetSymVal(n, qv) 1066 ELSIF NOT QbeGen.IsImm(qv) THEN 1067 SemError(230) 1068 ELSE 1069 SymTab.SetSymVal(n, qv); 1070 QbeGen.DeclConst(n, qv, t) 1071 END; .) . 1072 VarBlock (. VAR astSeq, astTail: AST.Node; .) 1073 = "VAR" (. astSeq := AST.NoNode; 1074 astTail := AST.NoNode; .) 1075 { VarDecl ";" (. AstAppend(AST.NkDeclSeq, 1076 astSeq, astTail, astDecl); .) } 1077 (. astDecl := astSeq; .) . 1078 VarDecl (. VAR nm: SymTab.Name; 1079 t: SymTab.TypeIndex; 1080 i: CARDINAL; 1081 cls: INTEGER; 1082 astNode, astTail: AST.Node; .) 1083 = VarIdents ":" 1084 Type (. astNode := AST.MakeNode(AST.NkVarDecl); 1085 astTail := astNode; 1086 i := 0; 1087 WHILE i < SymTab.PendCount() DO 1088 SymTab.PendName(i, nm); 1089 Lower.NoteVar(nm, SymTab.KindVar, t); 1090 (* chunked: a VAR list can 1091 exceed AST.MaxChild *) 1092 AstAppend(AST.NkBlock, 1093 astNode, astTail, 1094 AST.MakeLeaf(AST.NkIdent, nm)); 1095 INC(i) 1096 END; 1097 AST.SetTy(astNode, t); 1098 astDecl := astNode; 1099 cls := SymTab.ClassOf(t); 1100 IF (t # SymTab.InvalidType) 1101 AND NOT SymTab.IsUnresolved(t) 1102 AND (cls # SymTab.ClInt) 1103 AND (cls # SymTab.ClBool) 1104 AND (cls # SymTab.ClChar) 1105 AND (cls # SymTab.ClReal) 1106 AND (cls # SymTab.ClArray) 1107 AND (cls # SymTab.ClSet) 1108 AND (cls # SymTab.ClRecord) 1109 AND (cls # SymTab.ClPtr) 1110 AND (cls # SymTab.ClLong) 1111 AND (cls # SymTab.ClProc) 1112 AND (cls # SymTab.ClUChar) 1113 AND (cls # SymTab.ClUStr) 1114 AND (cls # SymTab.ClEnum) 1115 AND (cls # SymTab.ClClass) THEN 1116 SemError(230) END; 1117 IF QbeGen.LocFull() THEN 1118 SemError(233) END; 1119 i := 0; 1120 IF SymTab.IsUnresolved(t) 1121 AND NOT SymTab.InProc() THEN 1122 (* a forward-typed global: 1123 defer emission until the 1124 TYPE block completes *) 1125 WHILE i < SymTab.PendCount() DO 1126 SymTab.PendName(i, nm); 1127 IF nPendVar <= 1128 HIGH(pendVarName) THEN 1129 pendVarName[nPendVar] := nm; 1130 pendVarT[nPendVar] := t; 1131 INC(nPendVar) 1132 END; 1133 INC(i) 1134 END 1135 ELSE 1136 WHILE i < SymTab.PendCount() DO 1137 SymTab.PendName(i, nm); 1138 QbeGen.DeclVar(nm, t); 1139 INC(i) 1140 END 1141 END; 1142 (* a plain VAR list, not a 1143 heading: the signature 1144 result is discarded *) 1145 IF NOT SymTab.FixPending(t) THEN 1146 END; .) . 1147 VarIdents (. VAR n: SymTab.Name; .) 1148 = GetIdent (. IF NOT SymTab.EnterPending(n, 1149 SymTab.KindVar) THEN 1150 SemError(200) END; .) 1151 { "," 1152 GetIdent (. IF NOT SymTab.EnterPending(n, 1153 SymTab.KindVar) THEN 1154 SemError(200) END; .) } . 1155 ParIdents (. VAR n: SymTab.Name; .) 1156 = GetIdent (. IF NOT SymTab.EnterParam(n, isV) THEN 1157 SemError(200) END; .) 1158 { "," GetIdent (. IF NOT SymTab.EnterParam(n, isV) THEN 1159 SemError(200) END; .) } . 1160 (* Procedure headings enter scopes/params/result and buffer the 1161 QBE header; bodies lower to functions (4.1, module level only). 1162 FORWARD marks; the body heading re-enters (signature compare 1163 deferred). Nested procedures parse + check, lowering = 4.2. *) 1164 ProcHeading 1165 (. VAR t: SymTab.TypeIndex; 1166 mg: QbeGen.QVal; .) 1167 = "PROCEDURE" 1168 GetIdent (. IF methCls # 1169 SymTab.InvalidType THEN 1170 (* a method: resume the 1171 declared symbol (reuse 1172 its uid) *) 1173 IF NOT SymTab.ResumeMethod( 1174 methCls, pn) THEN 1175 SemError(200) END 1176 ELSIF NOT SymTab.EnterProc(pn) THEN 1177 IF NOT SymTab.ReenterProc(pn) THEN 1178 IF NOT SymTab.ResumeProc(pn) THEN 1179 SemError(200) END 1180 END 1181 END; 1182 Lower.ScopeEnter; 1183 Lower.NoteProc(pn, 1184 SymTab.ProcUid(pn), 1185 SymTab.InvalidType, 1186 SymTab.ProcDepthOf(pn), 1187 FALSE); 1188 IF methCls # 1189 SymTab.InvalidType THEN 1190 QbeGen.Mangled(pn, 1191 SymTab.MethUid(), mg) 1192 ELSE 1193 QbeGen.Mangled(pn, 1194 SymTab.ProcUid(pn), mg) 1195 END; 1196 QbeGen.BeginFunc(mg); 1197 IF methCls # 1198 SymTab.InvalidType THEN 1199 (* hidden THIS receiver: 1200 a VAR param of the 1201 class type, pushed as 1202 the WITH base *) 1203 IF NOT SymTab.EnterThisParam( 1204 methCls) THEN 1205 SemError(200) END; 1206 IF NOT QbeGen.FuncParam( 1207 "THIS", TRUE, 1208 methCls) THEN 1209 SemError(233) END 1210 END; .) 1211 [ FormalParams ] 1212 [ ":" TypeIdent (. IF NOT SymTab.SetProcRes(t) THEN 1213 SemError(235) END; 1214 Lower.SetProcRes(t); 1215 QbeGen.SetFuncRes(t); 1216 IF (t # 1217 SymTab.InvalidType) 1218 AND ((SymTab.ClassOf(t) 1219 = SymTab.ClArray) 1220 OR (SymTab.ClassOf(t) 1221 = SymTab.ClRecord) 1222 OR (SymTab.ClassOf(t) 1223 = SymTab.ClSet) 1224 OR (SymTab.ClassOf(t) 1225 = SymTab.ClClass)) THEN 1226 SemError(230) END; .) ] . 1227 FormalParams 1228 = "(" [ ParamSection { ";" ParamSection } ] ")" . 1229 ParamSection (. VAR t: SymTab.TypeIndex; 1230 nm: SymTab.Name; 1231 i: CARDINAL; 1232 isV: BOOLEAN; .) 1233 = (. isV := FALSE; .) 1234 [ "VAR" (. isV := TRUE; .) ] 1235 ParIdents ":" Type (. i := 0; 1236 WHILE i < SymTab.PendCount() DO 1237 SymTab.PendName(i, nm); 1238 Lower.NoteParam(nm, t, isV); 1239 Lower.NoteVar(nm, SymTab.KindParam, t); 1240 (* value open arrays are 1241 passed as descriptor 1242 addresses (no copy): 1243 same representation as 1244 VAR formals *) 1245 IF NOT QbeGen.FuncParam(nm, 1246 isV 1247 OR SymTab.IsOpenArray(t), 1248 t) THEN 1249 SemError(233) END; 1250 INC(i) 1251 END; 1252 IF NOT SymTab.FixPending(t) THEN 1253 SemError(235) END; .) . 1254 (* Nested procedures lower like top-level ones (4.2): the 1255 static link gives them their parent's frame. Methods keep 1256 parse-now/230-later. *) 1257 ProcDecl (. VAR pn: SymTab.Name; 1258 astNode: AST.Node; .) 1259 = ProcHeading ";" 1260 (. astNode := AST.MakeNode(AST.NkProcDecl); 1261 AST.SetOp(astNode, 0); 1262 AST.SetChild(astNode, 0, 1263 AST.MakeLeaf(AST.NkIdent, pn)); 1264 Lower.NoteProcNode(astNode); .) 1265 ( "FORWARD" (. AST.SetOp(astNode, 1); 1266 astDecl := astNode; 1267 Lower.ScopeLeave; 1268 SymTab.MarkFwd; 1269 SymTab.CloseProc; 1270 QbeGen.AbortFunc; .) 1271 | "EXTERNAL" (. AST.SetOp(astNode, 2); 1272 astDecl := astNode; 1273 Lower.MarkProcExternal; 1274 Lower.ScopeLeave; 1275 SymTab.MarkExternal(""); 1276 SymTab.CloseProc; 1277 QbeGen.AbortFunc; .) 1278 | (. QbeGen.EndFuncHeader; .) 1279 Block (. AST.SetChild(astNode, 1, astStmt); 1280 AST.SetChild(astNode, 2, astBlkDecls); 1281 astDecl := astNode; 1282 Lower.ScopeLeave; 1283 SymTab.CloseProc; 1284 QbeGen.EndFunc( 1285 SymTab.ProcRes(pn)); .) ) . 1286 Block (. VAR m2: SymTab.Name; .) 1287 = DeclSeq (. astBlkDecls := astDecl; 1288 astStmt := AST.NoNode; .) 1289 [ "BEGIN" 1290 [ StatSeq ] ] 1291 "END" 1292 GetIdent (. IF NOT SymTab.Equal(pn, m2) THEN 1293 SemError(202) END; .) . 1294 StatSeq (. VAR astSeq, astTail: AST.Node; .) 1295 = (. astSeq := AST.NoNode; 1296 astTail := AST.NoNode; .) 1297 Statement (. AstAppend(AST.NkBlock, 1298 astSeq, astTail, astStmt); .) 1299 { ";" [ Statement (. AstAppend(AST.NkBlock, 1300 astSeq, astTail, astStmt); .) ] } 1301 (. astStmt := astSeq; .) . 1302 (* Trailing/empty statements (`a; ; b`, Coco/R's generated `;;`) 1303 are accepted: the statement after ';' is optional. *) 1304 Statement (. VAR lx: QbeGen.QVal; .) 1305 = (. astStmt := AST.NoNode; .) 1306 ( AssOrCall 1307 | IfStat 1308 | WhileStat 1309 | RepeatStat 1310 | LoopStat 1311 | ForStat 1312 | CaseStat 1313 | WithStat 1314 | ReturnStat 1315 | HaltStat 1316 | NewStat 1317 | DisposeStat 1318 | IncDecStat 1319 | InclExclStat 1320 | "EXIT" (. IF QbeGen.TopLoop(lx) THEN 1321 QbeGen.Jmp(lx) 1322 ELSE SemError(230) END; 1323 astStmt := AST.MakeNode(AST.NkExit); .) ) . 1324 (* INCL(set, elem) / EXCL(set, elem): PIM set-element builtins. *) 1325 InclExclStat (. VAR at, et2: SymTab.TypeIndex; 1326 dk: INTEGER; 1327 qd, qe: QbeGen.QVal; 1328 qn: SymTab.Name; 1329 sfx, isInc: BOOLEAN; 1330 astNode, astD: AST.Node; .) 1331 = ( "INCL" (. isInc := TRUE; .) 1332 | "EXCL" (. isInc := FALSE; .) ) 1333 "(" Design (. astD := astCur; .) "," 1334 Expr ")" 1335 (. astNode := AST.MakeNode(AST.NkCall); 1336 IF isInc THEN 1337 AST.SetChild(astNode, 0, 1338 AST.MakeLeaf(AST.NkIdent, "INCL")) 1339 ELSE AST.SetChild(astNode, 0, 1340 AST.MakeLeaf(AST.NkIdent, "EXCL")) 1341 END; 1342 IF astD # AST.NoNode THEN 1343 AST.SetChild(astNode, 1, astD) END; 1344 IF astCur # AST.NoNode THEN 1345 AST.SetChild(astNode, 2, astCur) END; 1346 astStmt := astNode; .) 1347 (. IF at = SymTab.InvalidType THEN 1348 ELSIF SymTab.ClassOf(at) # 1349 SymTab.ClSet THEN 1350 SemError(222) 1351 ELSE 1352 IF isInc THEN 1353 QbeGen.SetBit(qd, qe, 1354 SymTab.SetBaseLo(at), 1355 SymTab.SetCount(at)) 1356 ELSE 1357 QbeGen.SetClearBit(qd, qe, 1358 SymTab.SetBaseLo(at), 1359 SymTab.SetCount(at)) 1360 END 1361 END; .) . 1362 (* INC(v [,step]) / DEC(v [,step]) as builtin statements over an 1363 integer designator. *) 1364 IncDecStat (. VAR dt, et2: SymTab.TypeIndex; 1365 dk: INTEGER; 1366 qd, qv, qn2, qstep: 1367 QbeGen.QVal; 1368 qn: SymTab.Name; 1369 sfx, isInc: BOOLEAN; 1370 astNode, astD, astStep: 1371 AST.Node; .) 1372 = (. isInc := TRUE; .) 1373 ( "INC" (. isInc := TRUE; .) 1374 | "DEC" (. isInc := FALSE; .) ) 1375 "(" (. QbeGen.CopyOp("1", qstep); astStep := AST.NoNode; .) 1376 Design (. astD := astCur; .) 1377 [ "," Expr (. astStep := astCur; .) ] 1378 ")" (. astNode := AST.MakeNode(AST.NkCall); 1379 IF isInc THEN 1380 AST.SetChild(astNode, 0, 1381 AST.MakeLeaf(AST.NkIdent, "INC")) 1382 ELSE AST.SetChild(astNode, 0, 1383 AST.MakeLeaf(AST.NkIdent, "DEC")) 1384 END; 1385 IF astD # AST.NoNode THEN 1386 AST.SetChild(astNode, 1, astD) END; 1387 IF astStep # AST.NoNode THEN 1388 AST.SetChild(astNode, 2, astStep) END; 1389 astStmt := astNode; .) (. IF dt = SymTab.InvalidType THEN 1390 ELSIF (dk # SymTab.KindVar) 1391 AND (dk # SymTab.KindParam) 1392 AND (dk # SymTab.KindField) THEN 1393 SemError(210) 1394 ELSIF NOT SymTab.IsIntFamily(dt) THEN 1395 SemError(211) 1396 ELSE 1397 IF sfx 1398 OR (dk = SymTab.KindField) THEN 1399 QbeGen.ElemLoad(qd, dt, qv) 1400 ELSE QbeGen.LoadVar(qn, 1401 FALSE, qv) 1402 END; 1403 QbeGen.NewTemp(qn2); 1404 IF isInc THEN 1405 QbeGen.Op3("add", qn2, qv, 1406 qstep, FALSE) 1407 ELSE QbeGen.Op3("sub", qn2, qv, 1408 qstep, FALSE) 1409 END; 1410 IF sfx 1411 OR (dk = SymTab.KindField) THEN 1412 QbeGen.ElemStore(qd, qn2, 1413 dt) 1414 ELSE QbeGen.StoreVar(qn, 1415 qn2, FALSE) 1416 END 1417 END; .) . 1418 (* NEW/DISPOSE as builtin statements (no call syntax until step 4). 1419 Targets are pointer designators; DISPOSE nils afterwards (safer 1420 than Wirth-undefined; documented). DISPOSE is shallow. *) 1421 NewStat (. VAR dt: SymTab.TypeIndex; 1422 dk: INTEGER; 1423 qd, qm: QbeGen.QVal; 1424 qn: SymTab.Name; 1425 sfx: BOOLEAN; 1426 bt: SymTab.TypeIndex; 1427 astNode, astD: AST.Node; .) 1428 = "NEW" "(" Design (. astD := astCur; .) ")" 1429 (. astNode := AST.MakeNode(AST.NkCall); 1430 AST.SetChild(astNode, 0, 1431 AST.MakeLeaf(AST.NkIdent, "NEW")); 1432 IF astD # AST.NoNode THEN 1433 AST.SetChild(astNode, 1, astD) END; 1434 astStmt := astNode; .) 1435 (. IF dt = SymTab.InvalidType THEN 1436 ELSIF (dk # SymTab.KindVar) 1437 AND (dk # SymTab.KindParam) 1438 AND (dk # SymTab.KindField) THEN 1439 SemError(210) 1440 ELSIF SymTab.ClassOf(dt) # 1441 SymTab.ClPtr THEN 1442 SemError(219) 1443 ELSE bt := SymTab.PtrBase(dt); 1444 IF bt # 1445 SymTab.InvalidType THEN 1446 QbeGen.NewHeap(bt, qm); 1447 QbeGen.InitHeap(qm, bt); 1448 IF sfx 1449 OR (dk = 1450 SymTab.KindField) THEN 1451 QbeGen.ElemStore(qd, qm, 1452 dt) 1453 ELSE QbeGen.StorePtr(qn, 1454 qm) 1455 END 1456 END 1457 END; .) . 1458 DisposeStat (. VAR dt: SymTab.TypeIndex; 1459 dk: INTEGER; 1460 qd, qv: QbeGen.QVal; 1461 qn: SymTab.Name; 1462 sfx: BOOLEAN; 1463 astNode, astD: AST.Node; .) 1464 = "DISPOSE" "(" Design (. astD := astCur; .) ")" 1465 (. astNode := AST.MakeNode(AST.NkCall); 1466 AST.SetChild(astNode, 0, 1467 AST.MakeLeaf(AST.NkIdent, "DISPOSE")); 1468 IF astD # AST.NoNode THEN 1469 AST.SetChild(astNode, 1, astD) END; 1470 astStmt := astNode; .) 1471 (. IF dt = SymTab.InvalidType THEN 1472 ELSIF (dk # SymTab.KindVar) 1473 AND (dk # SymTab.KindParam) 1474 AND (dk # SymTab.KindField) THEN 1475 SemError(210) 1476 ELSIF SymTab.ClassOf(dt) # 1477 SymTab.ClPtr THEN 1478 SemError(219) 1479 ELSE 1480 IF sfx 1481 OR (dk = 1482 SymTab.KindField) THEN 1483 QbeGen.ElemLoad(qd, dt, 1484 qv) 1485 ELSE QbeGen.LoadPtr(qn, qv) 1486 END; 1487 QbeGen.FreeHeap(qv); 1488 IF sfx 1489 OR (dk = 1490 SymTab.KindField) THEN 1491 QbeGen.ElemStore(qd, "0", 1492 dt) 1493 ELSE QbeGen.StorePtr(qn, 1494 "0") 1495 END 1496 END; .) . 1497 (* WITH pushes each record's fields (inner wins) plus its base 1498 address; field designators resolve through both stacks. *) 1499 WithStat (. VAR nW: CARDINAL; 1500 astNode: AST.Node; .) 1501 = "WITH" (. nW := 0; 1502 astNode := AST.MakeNode(AST.NkWith); .) 1503 WithItem { "," WithItem } 1504 "DO" (. astStmt := AST.NoNode; .) 1505 [ StatSeq ] "END" (. AST.SetChild(astNode, 1506 AST.NChild(astNode), astStmt); 1507 astStmt := astNode; 1508 WHILE nW > 0 DO 1509 SymTab.PopScope; 1510 QbeGen.PopWith; 1511 DEC(nW) 1512 END; .) . 1513 WithItem 1514 (. VAR dt: SymTab.TypeIndex; 1515 dk: INTEGER; 1516 qd, qe: QbeGen.QVal; 1517 qn: SymTab.Name; 1518 sfx: BOOLEAN; .) 1519 = Design 1520 (. IF astCur # AST.NoNode THEN 1521 AST.SetChild(wnode, 1522 AST.NChild(wnode), astCur) END; 1523 IF dt = SymTab.InvalidType THEN 1524 ELSIF (SymTab.ClassOf(dt) # 1525 SymTab.ClRecord) 1526 AND (SymTab.ClassOf(dt) # 1527 SymTab.ClClass) THEN 1528 SemError(215) 1529 ELSIF SymTab.PushRecord(dt) THEN 1530 QbeGen.PushWith(qd); 1531 INC(nW) 1532 END; .) . 1533 (* Assignment or procedure-statement call (4.1, module level). 1534 Bare `P;` is a syntax error; function-as-statement is 233. *) 1535 AssOrCall (. VAR dt, et: SymTab.TypeIndex; 1536 dk: INTEGER; 1537 qd, qe, qt, ql: QbeGen.QVal; 1538 qn: SymTab.Name; 1539 ct2, res0: SymTab.TypeIndex; 1540 q2, mg0: QbeGen.QVal; 1541 isR, conv, wconv: BOOLEAN; 1542 called, sfx: BOOLEAN; 1543 astLhs: AST.Node; .) 1544 = Design 1545 (. astLhs := astCur; astNArgs := 0; .) 1546 ( ":=" 1547 Expr (. astStmt := AST.MakeBin( 1548 AST.NkAssign, 0, astLhs, astCur); 1549 IF (dt # SymTab.InvalidType) 1550 AND (dk # SymTab.KindVar) 1551 AND (dk # SymTab.KindParam) 1552 AND (dk # SymTab.KindField) THEN 1553 SemError(210) 1554 ELSIF NOT SymTab.Assignable(et, 1555 dt) THEN 1556 SemError(210) 1557 ELSIF (dt # SymTab.InvalidType) 1558 AND (SymTab.ClassOf(dt) = 1559 SymTab.ClClass) THEN 1560 SemError(230) END; 1561 isR := (dt # 1562 SymTab.InvalidType) 1563 AND (SymTab.ClassOf(dt) 1564 = SymTab.ClReal); 1565 conv := isR 1566 AND SymTab.IsIntFamily(et); 1567 wconv := (dt # 1568 SymTab.InvalidType) 1569 AND SymTab.IsLongFamily(dt) 1570 AND SymTab.IsIntFamily(et); 1571 IF ((dk = SymTab.KindVar) 1572 OR (dk = SymTab.KindParam) 1573 OR (dk = SymTab.KindField)) 1574 AND (dt # SymTab.InvalidType) 1575 AND (et # SymTab.InvalidType) 1576 AND (SymTab.ClassOf(dt) # 1577 SymTab.ClClass) THEN 1578 IF sfx 1579 OR (dk = SymTab.KindField) THEN 1580 IF SymTab.ClassOf(dt) = 1581 SymTab.ClArray THEN 1582 IF (et # SymTab.InvalidType) 1583 AND (SymTab.ClassOf(et) = SymTab.ClUStr) 1584 AND SymTab.IsUCharArray(dt) THEN 1585 QbeGen.UAssign(qd, qe) 1586 ELSIF SymTab.StrCompat(dt, 1587 et) THEN 1588 QbeGen.StrAssign(qd, 1589 qe) 1590 ELSE 1591 QbeGen.CopyArray(qd, 1592 qe, dt) 1593 END 1594 ELSIF SymTab.ClassOf(dt) = 1595 SymTab.ClSet THEN 1596 QbeGen.CopySet(qd, qe, 1597 SymTab.SetWords(dt), 1598 SymTab.SetWords(et)) 1599 ELSIF SymTab.ClassOf(dt) = 1600 SymTab.ClRecord THEN 1601 QbeGen.CopyRecord(qd, qe, 1602 dt) 1603 ELSIF SymTab.IsLongFamily(dt) THEN 1604 IF wconv THEN 1605 QbeGen.WidenLong(qe, ql); 1606 QbeGen.ElemStore(qd, ql, 1607 dt) 1608 ELSE QbeGen.ElemStore(qd, qe, 1609 dt) 1610 END 1611 ELSIF conv THEN 1612 QbeGen.ConvIR(qe, qt); 1613 QbeGen.ElemStore(qd, qt, 1614 dt) 1615 ELSE QbeGen.ElemStore(qd, qe, 1616 dt) 1617 END 1618 ELSIF SymTab.ClassOf(dt) = 1619 SymTab.ClArray THEN 1620 IF (et # SymTab.InvalidType) 1621 AND (SymTab.ClassOf(et) = SymTab.ClUStr) 1622 AND SymTab.IsUCharArray(dt) THEN 1623 QbeGen.UAssign(qd, qe) 1624 ELSIF SymTab.StrCompat(dt, 1625 et) THEN 1626 QbeGen.StrAssign(qd, qe) 1627 ELSE 1628 QbeGen.CopyArray(qd, qe, 1629 dt) 1630 END 1631 ELSIF SymTab.ClassOf(dt) = 1632 SymTab.ClSet THEN 1633 QbeGen.CopySet(qd, qe, 1634 SymTab.SetWords(dt), 1635 SymTab.SetWords(et)) 1636 ELSIF SymTab.ClassOf(dt) = 1637 SymTab.ClRecord THEN 1638 QbeGen.CopyRecord(qd, qe, dt) 1639 ELSIF (SymTab.ClassOf(dt) = 1640 SymTab.ClPtr) 1641 OR (SymTab.ClassOf(dt) = 1642 SymTab.ClProc) THEN 1643 QbeGen.StorePtr(qn, qe) 1644 ELSIF SymTab.IsLongFamily(dt) THEN 1645 IF wconv THEN 1646 QbeGen.WidenLong(qe, ql); 1647 QbeGen.StoreLong(qn, ql) 1648 ELSE QbeGen.StoreLong(qn, qe) 1649 END 1650 ELSIF conv THEN 1651 QbeGen.ConvIR(qe, qt); 1652 QbeGen.StoreVar(qn, qt, TRUE) 1653 ELSE 1654 QbeGen.StoreVar(qn, qe, isR) 1655 END 1656 END; .) 1657 | ArgList 1658 (. astStmt := AstCallNode(astLhs); .) 1659 | (* bare `P;`: proper parameterless 1660 procedure call; anything else 1661 here is 233 (was a bare syntax 1662 error before 4.2) *) 1663 (. astStmt := AstCallNode(astLhs); 1664 IF (dk = SymTab.KindProc) 1665 AND NOT sfx THEN 1666 res0 := SymTab.ProcRes(qn); 1667 IF res0 # 1668 SymTab.InvalidType THEN 1669 SemError(233) 1670 ELSIF SymTab.ProcNPar(qn) # 1671 0 THEN 1672 SemError(233) 1673 ELSE QbeGen.Mangled(qn, 1674 SymTab.ProcUid(qn), mg0); 1675 QbeGen.CallBegin(mg0, 1676 res0, 1677 SymTab.ProcDepthOf(qn), 1678 SymTab.IsExternal(qn)); 1679 QbeGen.CallEnd(FALSE, q2) 1680 END 1681 ELSE SemError(233) 1682 END; .) ) . 1683 (* Actual-parameter list shared by statement and expression calls. 1684 want selects CallEnd's result handling; t/q carry the call 1685 value (statement calls discard). Arity/type failures are 233; 1686 evaluation code still emits so the .ssa stays assembleable. *) 1687 ArgList (. VAR i, np: CARDINAL; 1691 vs: INTEGER; 1692 res: SymTab.TypeIndex; 1693 mg: QbeGen.QVal; 1694 ok, ind, isMeth, va: BOOLEAN; .) 1695 = "(" (. called := TRUE; 1696 ok := TRUE; 1697 ind := FALSE; 1698 isMeth := methCls # 1699 SymTab.InvalidType; 1700 IF isMeth THEN 1701 (* class method: the 1702 receiver is armed. 1703 Virtual -> dispatch 1704 through the vtable; 1705 otherwise a static 1706 call. *) 1707 res := SymTab.ClassMethodRes( 1708 methCls, pn); 1709 vs := SymTab.VirtSlot( 1710 methCls, pn); 1711 IF vs >= 0 THEN 1712 QbeGen.VirtCallBegin( 1713 callee, vs, res) 1714 ELSE 1715 QbeGen.Mangled(pn, 1716 SymTab.ClassMethodUid( 1717 methCls, pn), mg); 1718 QbeGen.CallBegin(mg, res, 0, 1719 FALSE) 1720 END 1721 ELSIF SymTab.SymKind(pn) = 1722 SymTab.KindProc THEN 1723 res := SymTab.ProcRes(pn); 1724 QbeGen.Mangled(pn, 1725 SymTab.ProcUid(pn), mg); 1726 QbeGen.CallBegin(mg, res, 1727 SymTab.ProcDepthOf(pn), 1728 SymTab.IsExternal(pn)) 1729 ELSIF (pt # SymTab.InvalidType) 1730 AND (SymTab.ClassOf(pt) = SymTab.ClProc) THEN 1731 ind := TRUE; 1732 res := 1733 SymTab.ProcTypeRes(pt); 1734 QbeGen.CallBeginInd(callee, 1735 res, FALSE) 1736 ELSE SemError(233); 1737 ok := FALSE; 1738 res := SymTab.InvalidType 1739 END; 1740 i := 0; .) 1741 [ ActParam (. INC(i); .) 1742 { "," ActParam (. INC(i); .) } ] 1743 ")" (. IF ok THEN 1744 IF isMeth THEN 1745 np := SymTab.ClassMethodNPar( 1746 methCls, pn) 1747 ELSIF ind THEN 1748 np := SymTab.ProcTypeNPar(pt) 1749 ELSE np := SymTab.ProcNPar(pn) 1750 END; 1751 va := (NOT isMeth) AND (NOT ind) 1752 AND (SymTab.SymKind(pn) = 1753 SymTab.KindProc) 1754 AND SymTab.Varargs(pn); 1755 IF (i # np) AND NOT va THEN 1756 SemError(233); ok := FALSE 1757 END 1758 END; 1759 IF NOT ok THEN 1760 t := SymTab.InvalidType; 1761 QbeGen.CopyOp("0", q) 1762 ELSIF want THEN 1763 IF res = 1764 SymTab.InvalidType THEN 1765 SemError(233); 1766 t := SymTab.InvalidType; 1767 QbeGen.CopyOp("0", q) 1768 ELSE t := res; 1769 QbeGen.CallEnd(TRUE, q) 1770 END 1771 ELSE 1772 IF res # 1773 SymTab.InvalidType THEN 1774 SemError(233) 1775 END; 1776 t := SymTab.InvalidType; 1777 QbeGen.CopyOp("0", q); 1778 QbeGen.CallEnd(FALSE, q) 1779 END; .) . 1780 (* One actual: VAR formals take recorded designator addresses 1781 (233 otherwise); value formals take converted expressions. *) 1782 ActParam 1784 (. VAR at, ft: SymTab.TypeIndex; 1785 qe, qa, qt: QbeGen.QVal; 1786 isV, conv, va: BOOLEAN; 1787 cl: CHAR; 1788 savedN, aj: CARDINAL; 1789 savedArgs: ARRAY [0 .. 31] 1790 OF AST.Node; .) 1791 = (. (* Parsing the actual can clobber 1792 the enclosing call's argument 1793 list (Factor resets astNArgs), 1794 so save/restore it. *) 1795 savedN := astNArgs; aj := 0; 1796 WHILE aj <= HIGH(astArgs) DO 1797 savedArgs[aj] := astArgs[aj]; 1798 INC(aj) 1799 END; .) 1800 Expr (. astNArgs := savedN; aj := 0; 1801 WHILE aj <= HIGH(astArgs) DO 1802 astArgs[aj] := savedArgs[aj]; 1803 INC(aj) 1804 END; 1805 IF astNArgs <= HIGH(astArgs) THEN 1806 astArgs[astNArgs] := astCur; 1807 INC(astNArgs) 1808 END; 1809 va := (NOT ind) 1810 AND (methCls = 1811 SymTab.InvalidType) 1812 AND (SymTab.SymKind(pn) = 1813 SymTab.KindProc) 1814 AND SymTab.Varargs(pn); 1815 IF ind THEN 1816 ft := 1817 SymTab.ProcTypeParamType(pt, 1818 i); 1819 isV := 1820 SymTab.ProcTypeParamIsVar(pt, 1821 i) 1822 ELSIF methCls # 1823 SymTab.InvalidType THEN 1824 ft := 1825 SymTab.ClassMethodParamType( 1826 methCls, pn, i); 1827 isV := 1828 SymTab.ClassMethodParamIsVar( 1829 methCls, pn, i) 1830 ELSE 1831 ft := SymTab.ParamType(pn, i); 1832 isV := SymTab.ParamIsVar(pn, i) 1833 END; 1834 IF (at = SymTab.InvalidType) THEN 1835 ELSIF ft = SymTab.InvalidType THEN 1836 IF va THEN 1837 QbeGen.CArgAdd(qe, at, qa, cl) 1838 END 1839 ELSIF isV THEN 1840 IF (SymTab.ClassOf(at) 1841 = SymTab.ClChar) 1842 AND (SymTab.ClassOf(ft) = SymTab.ClArray) 1843 AND (SymTab.ClassOf(SymTab.ArrayElem(ft)) 1844 = SymTab.ClChar) 1845 AND QbeGen.IsImm(qe) THEN 1846 (* 1-char string 1847 literal passed to 1848 a VAR ARRAY OF CHAR *) 1849 QbeGen.DeclCharStr(qe, 1850 qa); 1851 IF NOT QbeGen.CallArg(qa, 1852 "l") THEN 1853 SemError(233) 1854 END 1855 ELSIF NOT QbeGen.AddrOfVal(qe, 1856 qa) THEN 1857 SemError(233) 1858 ELSIF NOT SymTab.VarParamOk(at, 1859 ft) THEN 1860 SemError(233) 1861 ELSIF NOT QbeGen.CallArg(qa, 1862 "l") THEN 1863 SemError(233) 1864 END 1865 ELSE 1866 IF (SymTab.ClassOf(at) 1867 = SymTab.ClChar) 1868 AND (SymTab.ClassOf(ft) = SymTab.ClArray) 1869 AND (SymTab.ClassOf(SymTab.ArrayElem(ft)) 1870 = SymTab.ClChar) 1871 AND QbeGen.IsImm(qe) THEN 1872 (* 1-char string 1873 literal passed to 1874 ARRAY OF CHAR *) 1875 QbeGen.DeclCharStr(qe, 1876 qa); 1877 IF NOT QbeGen.CallArg(qa, 1878 "l") THEN 1879 SemError(233) 1880 END 1881 ELSIF NOT SymTab.Assignable(at, 1882 ft) THEN 1883 SemError(233) 1884 ELSE 1885 conv := (SymTab.ClassOf( 1886 ft) = SymTab.ClReal) 1887 AND SymTab.IsIntFamily(at); 1888 IF conv THEN 1889 QbeGen.ConvIR(qe, qt); 1890 IF NOT QbeGen.CallArg(qt, 1891 "d") THEN 1892 SemError(233) 1893 END 1894 ELSIF NOT QbeGen.CallArg(qe, 1895 QbeGen.ArgClass(ft)) THEN 1896 SemError(233) 1897 END 1898 END 1899 END; .) . 1900 IfStat (. VAR t: SymTab.TypeIndex; 1901 q, lThen, lElse, lEnd: 1902 QbeGen.QVal; 1903 hasElse: BOOLEAN; 1904 astCond, astIf, astLast, 1905 astNode: AST.Node; .) 1906 = "IF" (. hasElse := FALSE; .) 1907 Expr (. astCond := astCur; astStmt := AST.NoNode; 1908 IF NOT SymTab.BoolCheck(t) THEN 1909 SemError(214) END; 1910 QbeGen.NewLabel(lThen); 1911 QbeGen.NewLabel(lElse); 1912 QbeGen.NewLabel(lEnd); 1913 QbeGen.Jnz(q, lThen, lElse); 1914 QbeGen.EmitLabel(lThen); .) 1915 "THEN" [ StatSeq ] (. astNode := AST.MakeNode(AST.NkIf); 1916 AST.SetChild(astNode, 0, astCond); 1917 AST.SetChild(astNode, 1, astStmt); 1918 astIf := astNode; 1919 astLast := astNode; 1920 QbeGen.Jmp(lEnd); .) 1921 { "ELSIF" (. QbeGen.EmitLabel(lElse); 1922 QbeGen.NewLabel(lElse); .) 1923 Expr (. astCond := astCur; astStmt := AST.NoNode; 1924 IF NOT SymTab.BoolCheck(t) THEN 1925 SemError(214) END; 1926 QbeGen.NewLabel(lThen); 1927 QbeGen.Jnz(q, lThen, lElse); 1928 QbeGen.EmitLabel(lThen); .) 1929 "THEN" [ StatSeq ] (. astNode := AST.MakeNode(AST.NkIf); 1930 AST.SetChild(astNode, 0, astCond); 1931 AST.SetChild(astNode, 1, astStmt); 1932 AST.SetChild(astLast, 2, astNode); 1933 astLast := astNode; 1934 QbeGen.Jmp(lEnd); .) } 1935 [ "ELSE" (. QbeGen.EmitLabel(lElse); 1936 hasElse := TRUE; 1937 astStmt := AST.NoNode; .) 1938 [ StatSeq ] (. AST.SetChild(astLast, 2, astStmt); .) ] 1939 "END" (. astStmt := astIf; 1940 IF hasElse THEN 1941 QbeGen.EmitLabel(lEnd) 1942 ELSE QbeGen.EmitLabel(lElse); 1943 QbeGen.EmitLabel(lEnd) 1944 END; .) . 1945 WhileStat (. VAR t: SymTab.TypeIndex; 1946 q, lTop, lBody, lEnd: 1947 QbeGen.QVal; 1948 astCond, astNode: AST.Node; .) 1949 = "WHILE" (. astStmt := AST.NoNode; 1950 QbeGen.NewLabel(lTop); 1951 QbeGen.NewLabel(lBody); 1952 QbeGen.NewLabel(lEnd); 1953 QbeGen.EmitLabel(lTop); .) 1954 Expr (. astCond := astCur; 1955 IF NOT SymTab.BoolCheck(t) THEN 1956 SemError(214) END; 1957 QbeGen.Jnz(q, lBody, lEnd); 1958 QbeGen.EmitLabel(lBody); .) 1959 "DO" [ StatSeq ] (. astNode := AST.MakeNode(AST.NkWhile); 1960 AST.SetChild(astNode, 0, astCond); 1961 AST.SetChild(astNode, 1, astStmt); 1962 astStmt := astNode; 1963 QbeGen.Jmp(lTop); .) 1964 "END" (. QbeGen.EmitLabel(lEnd); .) . 1965 RepeatStat (. VAR t: SymTab.TypeIndex; 1966 q, lTop, lEnd: QbeGen.QVal; 1967 astCond, astBody, astNode: 1968 AST.Node; .) 1969 = "REPEAT" (. astStmt := AST.NoNode; 1970 QbeGen.NewLabel(lTop); 1971 QbeGen.NewLabel(lEnd); 1972 QbeGen.EmitLabel(lTop); .) 1973 [ StatSeq ] (. astBody := astStmt; .) 1974 "UNTIL" Expr (. astCond := astCur; 1975 astNode := AST.MakeNode(AST.NkRepeat); 1976 AST.SetChild(astNode, 0, astBody); 1977 AST.SetChild(astNode, 1, astCond); 1978 astStmt := astNode; 1979 IF NOT SymTab.BoolCheck(t) THEN 1980 SemError(214) END; 1981 QbeGen.Jnz(q, lEnd, lTop); 1982 QbeGen.EmitLabel(lEnd); .) . 1983 LoopStat (. VAR lTop, lEnd: QbeGen.QVal; astNode: AST.Node; .) 1984 = "LOOP" (. QbeGen.NewLabel(lTop); 1985 astStmt := AST.NoNode; 1986 QbeGen.NewLabel(lEnd); 1987 QbeGen.PushLoop(lEnd); 1988 QbeGen.EmitLabel(lTop); .) 1989 [ StatSeq ] 1990 "END" (. astNode := AST.MakeNode(AST.NkLoop); 1991 AST.SetChild(astNode, 0, astStmt); 1992 astStmt := astNode; 1993 QbeGen.Jmp(lTop); 1994 QbeGen.PopLoop; 1995 QbeGen.EmitLabel(lEnd); .) . 1996 (* FOR with static-sign BY (literal, non-zero; 220 otherwise). 1997 Runtime direction would need a compare-select; the literal 1998 sign picks cslew/csegew at "DO" time. *) 1999 ForStat (. VAR lv: SymTab.Name; 2000 tlo, thi, tby: 2001 SymTab.TypeIndex; 2002 qlo, qhi, qby, qt, qk, qb: 2003 QbeGen.QVal; 2004 lTop, lBody, lEnd: 2005 QbeGen.QVal; 2006 by: INTEGER; 2007 ok: BOOLEAN; 2008 astVar, astLo, astHi, astBy, 2009 astNode: AST.Node; .) 2010 = "FOR" (. by := 1; .) 2011 GetIdent (. astVar := AST.MakeLeaf(AST.NkIdent, lv); 2012 astStmt := AST.NoNode; 2013 astBy := AST.NoNode; 2014 ok := SymTab.Lookup(lv); 2015 IF NOT ok THEN 2016 SemError(201) 2017 ELSIF (SymTab.SymKind(lv) # 2018 SymTab.KindVar) 2019 AND (SymTab.SymKind(lv) # 2020 SymTab.KindParam) THEN 2021 SemError(220); ok := FALSE 2022 ELSIF NOT SymTab.IsIntFamily( 2023 SymTab.SymType(lv)) THEN 2024 SemError(220); ok := FALSE 2025 END; .) 2026 ":=" Expr (. astLo := astCur; 2027 IF NOT SymTab.IsIntFamily(tlo) THEN 2028 SemError(220); ok := FALSE 2029 END; .) 2030 "TO" Expr (. astHi := astCur; 2031 IF NOT SymTab.IsIntFamily(thi) THEN 2032 SemError(220); ok := FALSE 2033 END; .) 2034 [ "BY" Expr (. astBy := astCur; 2035 IF (tby # 2036 SymTab.InvalidType) 2037 AND NOT SymTab.IsIntFamily(tby) THEN 2038 SemError(220); ok := FALSE 2039 END; 2040 IF NOT SymTab.ConstInt(qby, by) THEN 2041 SemError(230); by := 1 2042 ELSIF by = 0 THEN 2043 SemError(220); by := 1 2044 END; .) ] 2045 "DO" (. IF ok THEN 2046 QbeGen.StoreVar(lv, qlo, 2047 FALSE) END; 2048 QbeGen.NewLabel(lTop); 2049 QbeGen.NewLabel(lBody); 2050 QbeGen.NewLabel(lEnd); 2051 QbeGen.EmitLabel(lTop); 2052 QbeGen.LoadVar(lv, FALSE, qt); 2053 QbeGen.NewTemp(qk); 2054 IF by > 0 THEN 2055 QbeGen.Op3("cslew", qk, 2056 qt, qhi, FALSE) 2057 ELSE QbeGen.Op3("csgew", qk, 2058 qt, qhi, FALSE) 2059 END; 2060 QbeGen.Jnz(qk, lBody, lEnd); 2061 QbeGen.EmitLabel(lBody); .) 2062 [ StatSeq ] 2063 "END" (. astNode := AST.MakeNode(AST.NkFor); 2064 AST.SetChild(astNode, 0, astVar); 2065 AST.SetChild(astNode, 1, astLo); 2066 AST.SetChild(astNode, 2, astHi); 2067 AST.SetChild(astNode, 3, astBy); 2068 AST.SetChild(astNode, 4, astStmt); 2069 astStmt := astNode; 2070 IF ok THEN 2071 QbeGen.LoadVar(lv, FALSE, 2072 qt); 2073 QbeGen.IntStr(by, qb); 2074 QbeGen.NewTemp(qk); 2075 QbeGen.Op3("add", qk, 2076 qt, qb, FALSE); 2077 QbeGen.StoreVar(lv, qk, 2078 FALSE) END; 2079 QbeGen.Jmp(lTop); 2080 QbeGen.EmitLabel(lEnd); .) . 2081 CaseStat (. VAR tsel: SymTab.TypeIndex; 2082 qsel, lEnd: QbeGen.QVal; 2083 arm, astNode, astArms, 2084 astArmsTail: AST.Node; .) 2085 = "CASE" Expr (. astNode := AST.MakeNode(AST.NkCase); 2086 AST.SetChild(astNode, 0, astCur); 2087 astArms := AST.NoNode; 2088 astArmsTail := AST.NoNode; 2089 QbeGen.NewLabel(lEnd); .) 2090 "OF" CaseAlt 2091 { "|" CaseAlt } 2092 [ "ELSE" (. astStmt := AST.NoNode; .) 2093 [ StatSeq ] (. arm := AST.MakeNode(AST.NkCaseArm); 2094 AST.SetOp(arm, 1); 2095 AST.SetChild(arm, 0, astStmt); 2096 AstAppend(AST.NkBlock, 2097 astArms, astArmsTail, arm); .) ] 2098 "END" (. AST.SetChild(astNode, 1, astArms); 2099 astStmt := astNode; 2100 QbeGen.EmitLabel(lEnd); .) . 2101 (* Compare-chain lowering: each alternative ends its match-tests 2102 with "jmp lAfter", so the no-match fallthrough skips the body: 2103 "cmp; jnz(lBody,lF); lF: ... ; jmp lAfter; lBody: S; jmp lEnd; 2104 lAfter:". Falls into the next alternative, ELSE, or END. *) 2105 CaseAlt 2107 (. VAR lBody, lAfter: QbeGen.QVal; 2108 arm: AST.Node; .) 2109 = (. arm := AST.MakeNode(AST.NkCaseArm); 2110 QbeGen.NewLabel(lBody); 2111 QbeGen.NewLabel(lAfter); .) 2112 CaseLabel 2113 { "," CaseLabel } 2114 ":" (. astStmt := AST.NoNode; 2115 QbeGen.Jmp(lAfter); 2116 QbeGen.EmitLabel(lBody); .) 2117 [ StatSeq ] (. AST.SetChild(arm, AST.NChild(arm), 2118 astStmt); 2119 AstAppend(AST.NkBlock, 2120 arms, armsTail, arm); 2121 QbeGen.Jmp(lEnd); 2122 QbeGen.EmitLabel(lAfter); .) . 2123 CaseLabel 2125 (. VAR t2, t3: SymTab.TypeIndex; 2126 q2, q3, qc, qd, qe: 2127 QbeGen.QVal; 2128 astLab: AST.Node; 2129 lNext: QbeGen.QVal; .) 2130 = Expr (. astLab := astCur; 2131 IF (t2 # 2132 SymTab.InvalidType) 2133 AND (tsel # 2134 SymTab.InvalidType) 2135 AND ((SymTab.ClassOf(t2) = 2136 SymTab.ClSet) 2137 OR (SymTab.ClassOf(tsel) = 2138 SymTab.ClSet)) THEN 2139 SemError(230) 2140 ELSIF (t2 # 2141 SymTab.InvalidType) 2142 AND (tsel # 2143 SymTab.InvalidType) 2144 AND NOT SymTab.EqCheck(t2, 2145 tsel) THEN 2146 SemError(213) END; 2147 IF NOT QbeGen.IsImm(q2) THEN 2148 SemError(230); 2149 QbeGen.CopyOp("0", q2) 2150 END; 2151 QbeGen.NewLabel(lNext); 2152 QbeGen.Cmp(SymTab.OpEq, 2153 qsel, q2, qc, FALSE); 2154 QbeGen.Jnz(qc, lBody, lNext); 2155 QbeGen.EmitLabel(lNext); .) 2156 [ ".." Expr (. astLab := AST.MakeBin( 2157 AST.NkSubrange, 0, astLab, astCur); 2158 IF (t3 # 2159 SymTab.InvalidType) 2160 AND (tsel # 2161 SymTab.InvalidType) 2162 AND NOT SymTab.EqCheck(t3, 2163 tsel) THEN 2164 SemError(213) END; 2165 IF NOT QbeGen.IsImm(q3) THEN 2166 SemError(230); 2167 QbeGen.CopyOp("0", q3) 2168 END; 2169 QbeGen.Cmp(SymTab.OpGe, 2170 qsel, q2, qc, FALSE); 2171 QbeGen.Cmp(SymTab.OpLe, 2172 qsel, q3, qd, FALSE); 2173 QbeGen.NewTemp(qe); 2174 QbeGen.Op3("and", qe, qc, qd, 2175 FALSE); 2176 QbeGen.NewLabel(lNext); 2177 QbeGen.Jnz(qe, lBody, lNext); 2178 QbeGen.EmitLabel(lNext); .) ] 2179 (. AST.SetChild(arm, 2180 AST.NChild(arm), astLab); .) . 2181 ReturnStat (. VAR t: SymTab.TypeIndex; 2182 q, qt: QbeGen.QVal; 2183 res: SymTab.TypeIndex; 2184 hadE, conv: BOOLEAN; 2185 astVal, astNode: AST.Node; .) 2186 = "RETURN" (. hadE := FALSE; astStmt := AST.NoNode; .) 2187 [ Expr (. hadE := TRUE; astVal := astCur; .) ] 2188 (. astNode := AST.MakeNode(AST.NkReturn); 2189 IF hadE THEN 2190 AST.SetChild(astNode, 0, astVal) 2191 END; 2192 astStmt := astNode; 2193 conv := FALSE; 2194 IF NOT SymTab.InProc() THEN 2195 SemError(232) 2196 ELSE res := SymTab.CurRes(); 2197 IF NOT hadE THEN 2198 IF res # 2199 SymTab.InvalidType THEN 2200 SemError(232) 2201 ELSE QbeGen.EmitRet(q, 2202 FALSE) 2203 END 2204 ELSIF (res = 2205 SymTab.InvalidType) 2206 OR (t # 2207 SymTab.InvalidType) 2208 AND NOT SymTab.Assignable(t, 2209 res) THEN 2210 SemError(232) 2211 ELSE 2212 conv := (SymTab.ClassOf( 2213 res) = SymTab.ClReal) 2214 AND SymTab.IsIntFamily(t); 2215 IF conv THEN 2216 QbeGen.ConvIR(q, qt); 2217 QbeGen.EmitRet(qt, TRUE) 2218 ELSE QbeGen.EmitRet(q, TRUE) 2219 END 2220 END 2221 END; .) . 2222 HaltStat (. VAR t: SymTab.TypeIndex; 2223 q: QbeGen.QVal; 2224 astVal, astNode: AST.Node; .) 2225 = "HALT" (. astVal := AST.NoNode; .) 2226 [ "(" Expr (. astVal := astCur; .) ")" ] 2227 (. astNode := AST.MakeNode(AST.NkHalt); 2228 IF astVal # AST.NoNode THEN 2229 AST.SetChild(astNode, 0, astVal) 2230 END; 2231 astStmt := astNode; 2232 QbeGen.HaltQ; .) . 2233 (* Designator: scalar loads, array addresses, and index suffixes. 2234 Each index descends one level (bounds-checked, trap on breach); 2235 nested levels reload the inner descriptor address. q ends as the 2236 value (scalars), the descriptor address (plain arrays), or the 2237 element address (indexed); sfx marks the indexed form. *) 2238 Design 2240 (. VAR n, fn, mal: SymTab.Name; 2241 cls: INTEGER; 2242 ic: SymTab.TypeIndex; 2243 curT, it, eT, bt: 2244 SymTab.TypeIndex; 2245 iq, ql, qlo, qhi, qe: 2246 QbeGen.QVal; 2247 lo, hi: INTEGER; 2248 fo: INTEGER; 2249 isOpen: BOOLEAN; 2250 qb, cv: QbeGen.QVal; 2251 fid, fref, slot: INTEGER; 2252 r: BOOLEAN; 2253 astDes, astSel: AST.Node; .) 2254 = GetIdent (. methCls := SymTab.InvalidType; 2255 QbeGen.CopyOp(n, qn); 2256 sfx := FALSE; 2257 fid := 0; fref := 0; slot := 0; 2258 IF NOT SymTab.Lookup(n) THEN 2259 (* a bare method name inside 2260 a CLASS IMPLEMENTATION 2261 is a sibling call on 2262 THIS *) 2263 ic := SymTab.CurImplClass(); 2264 IF (ic # 2265 SymTab.InvalidType) 2266 AND SymTab.MethodExists(ic, n) THEN 2267 sfx := FALSE; 2268 QbeGen.ThisBase(q); 2269 QbeGen.ArmRecv(q); 2270 methCls := ic; 2271 k := SymTab.KindProc; 2272 t := SymTab.InvalidType 2273 ELSIF SymTab.InProc() THEN 2274 (* not declared yet: a 2275 forward reference to a 2276 module-level variable 2277 declared further down. *) 2278 k := SymTab.KindVar; 2279 r := SymTab.FwdVarRef(n, k, 2280 fref, t); 2281 slot := QbeGen.FwdDesignator(); 2282 FwdVarNote(fref, slot); 2283 fid := slot; 2284 QbeGen.FwdAddrOper(fid, q); 2285 sfx := TRUE 2286 ELSE 2287 SemError(201); 2288 t := 2289 SymTab.InvalidType; 2290 k := -1; 2291 QbeGen.CopyOp("0", q) 2292 END 2293 ELSE 2294 t := SymTab.SymType(n); 2295 k := SymTab.SymKind(n); 2296 IF k = SymTab.KindConst THEN 2297 IF SymTab.Equal(n, 2298 "TRUE") THEN 2299 t := SymTab.BoolType(); 2300 QbeGen.CopyOp("1", q) 2301 ELSIF SymTab.Equal(n, 2302 "FALSE") THEN 2303 t := SymTab.BoolType(); 2304 QbeGen.CopyOp("0", q) 2305 ELSIF SymTab.Equal(n, 2306 "NIL") THEN 2307 QbeGen.CopyOp("0", q) 2308 ELSE 2309 cls := 2310 SymTab.ClassOf(t); 2311 IF (t # 2312 SymTab.InvalidType) 2313 AND ((cls = SymTab.ClInt) 2314 OR (cls 2315 = SymTab.ClChar) 2316 OR (cls 2317 = SymTab.ClEnum) 2318 OR (cls 2319 = SymTab.ClReal) 2320 OR (cls 2321 = SymTab.ClLong) 2322 OR (cls 2323 = SymTab.ClNil)) THEN 2324 IF cls = SymTab.ClNil THEN 2325 QbeGen.CopyOp("0", q) 2326 ELSIF ((cls 2327 = SymTab.ClInt) 2328 OR (cls 2329 = SymTab.ClChar) 2330 OR (cls 2331 = SymTab.ClEnum) 2332 OR (cls 2333 = SymTab.ClLong)) 2334 AND SymTab.GetSymVal(n, cv) 2335 AND QbeGen.IsImm(cv) THEN 2336 QbeGen.CopyOp(cv, q) 2337 ELSE 2338 QbeGen.LoadVar(n, 2339 cls = SymTab.ClReal, 2340 q) 2341 END 2342 ELSIF (cls = SymTab.ClArray) 2343 OR (cls = SymTab.ClRecord) 2344 OR (cls = SymTab.ClClass) 2345 OR (cls = SymTab.ClStr) 2346 OR (cls = SymTab.ClUStr) THEN 2347 (* aggregate constant: 2348 its value IS the 2349 descriptor address *) 2350 IF SymTab.GetSymVal(n, cv) THEN 2351 QbeGen.CopyOp(cv, q) 2352 ELSE 2353 QbeGen.CopyOp("0", q) 2354 END 2355 ELSE 2356 IF t # 2357 SymTab.InvalidType THEN 2358 SemError(230) 2359 END; 2360 QbeGen.CopyOp("0", q) 2361 END 2362 END 2363 ELSIF (k = SymTab.KindVar) 2364 OR (k = SymTab.KindParam) THEN 2365 cls := 2366 SymTab.ClassOf(t); 2367 IF (cls = SymTab.ClInt) 2368 OR (cls = SymTab.ClBool) 2369 OR (cls = SymTab.ClChar) 2370 OR (cls = SymTab.ClUChar) 2371 OR (cls = SymTab.ClEnum) 2372 OR (cls 2373 = SymTab.ClReal) THEN 2374 QbeGen.LoadVar(n, 2375 cls = SymTab.ClReal, q) 2376 ELSIF (cls = SymTab.ClPtr) 2377 OR (cls = SymTab.ClProc) THEN 2378 QbeGen.LoadPtr(n, q) 2379 ELSIF cls = SymTab.ClLong THEN 2380 QbeGen.LoadLong(n, q) 2381 ELSIF (cls 2382 = SymTab.ClArray) 2383 OR (cls 2384 = SymTab.ClSet) 2385 OR (cls 2386 = SymTab.ClRecord) 2387 OR (cls 2388 = SymTab.ClUStr) 2389 OR (cls 2390 = SymTab.ClClass) THEN 2391 QbeGen.AddrOf(n, q) 2392 ELSE SemError(230); 2393 QbeGen.CopyOp("0", q) 2394 END 2395 ELSE QbeGen.CopyOp("0", q); 2396 IF k = SymTab.KindImport THEN 2397 SemError(230) 2398 ELSIF k = 2399 SymTab.KindProc THEN 2400 (* bare procedure name: 2401 a following ArgList 2402 makes it a call; 2403 otherwise Fact 2404 reports 230 *) 2405 ELSE 2406 IF k = SymTab.KindField THEN 2407 IF QbeGen.TopWith(qb) THEN 2408 fo := 2409 SymTab.FieldOffset( 2410 SymTab.FieldOwner(n), 2411 n); 2412 QbeGen.FieldAddr(qb, 2413 fo, q); 2414 sfx := TRUE 2415 ELSE SemError(230); 2416 QbeGen.CopyOp("0", q) 2417 END 2418 END 2419 END 2420 END 2421 END; .) 2422 (. astDes := AST.MakeNode(AST.NkDesignator); 2423 AST.SetChild(astDes, AST.NChild(astDes), AST.MakeLeaf(AST.NkIdent, n)); .) 2424 { "[" Expr 2425 (. AST.SetChild(astDes, AST.NChild(astDes), 2426 AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN 2427 ELSIF SymTab.ClassOf(t) # 2428 SymTab.ClArray THEN 2429 SemError(217); 2430 t := SymTab.InvalidType 2431 ELSIF NOT SymTab.IsIntFamily(it) 2432 AND (SymTab.ClassOf(it) # 2433 SymTab.ClChar) 2434 AND (SymTab.ClassOf(it) # 2435 SymTab.ClEnum) THEN 2436 SemError(218); 2437 t := SymTab.InvalidType 2438 ELSE 2439 QbeGen.WidenIndex(iq, ql); 2440 isOpen := 2441 SymTab.IsOpenArray(t); 2442 IF isOpen THEN 2443 QbeGen.CopyOp("0", qlo); 2444 IF SymTab.IsCharArray(t) 2445 OR SymTab.IsUCharArray(t) THEN 2446 QbeGen.OpenHiChar(q, qhi) 2447 ELSE QbeGen.OpenHi(q, qhi) 2448 END 2449 ELSE 2450 lo := SymTab.ArrayLo(t); 2451 hi := SymTab.ArrayHi(t); 2452 IF SymTab.IsCharArray(t) 2453 OR SymTab.IsUCharArray(t) THEN 2454 hi := hi + 1 2455 END; 2456 QbeGen.IntStr(lo, qlo); 2457 QbeGen.IntStr(hi, qhi) 2458 END; 2459 QbeGen.CheckRange(ql, qlo, 2460 qhi); 2461 eT := SymTab.ArrayElem(t); 2462 QbeGen.ElemAddr(q, ql, qlo, 2463 t, qe); 2464 IF SymTab.ClassOf(eT) = 2465 SymTab.ClArray THEN 2466 QbeGen.ElemLoad(qe, eT, q) 2467 ELSE QbeGen.CopyOp(qe, q) 2468 END; 2469 t := eT; sfx := TRUE 2470 END; .) 2471 { "," Expr 2472 (. AST.SetChild(astDes, AST.NChild(astDes), 2473 AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN 2474 ELSIF SymTab.ClassOf(t) # 2475 SymTab.ClArray THEN 2476 SemError(217); 2477 t := SymTab.InvalidType 2478 ELSIF NOT SymTab.IsIntFamily(it) 2479 AND (SymTab.ClassOf(it) # 2480 SymTab.ClChar) 2481 AND (SymTab.ClassOf(it) # 2482 SymTab.ClEnum) THEN 2483 SemError(218); 2484 t := SymTab.InvalidType 2485 ELSE 2486 QbeGen.WidenIndex(iq, ql); 2487 isOpen := 2488 SymTab.IsOpenArray(t); 2489 IF isOpen THEN 2490 QbeGen.CopyOp("0", qlo); 2491 IF SymTab.IsCharArray(t) 2492 OR SymTab.IsUCharArray(t) THEN 2493 QbeGen.OpenHiChar(q, qhi) 2494 ELSE QbeGen.OpenHi(q, qhi) 2495 END 2496 ELSE 2497 lo := SymTab.ArrayLo(t); 2498 hi := SymTab.ArrayHi(t); 2499 IF SymTab.IsCharArray(t) 2500 OR SymTab.IsUCharArray(t) THEN 2501 hi := hi + 1 2502 END; 2503 QbeGen.IntStr(lo, qlo); 2504 QbeGen.IntStr(hi, qhi) 2505 END; 2506 QbeGen.CheckRange(ql, qlo, 2507 qhi); 2508 eT := SymTab.ArrayElem(t); 2509 QbeGen.ElemAddr(q, ql, qlo, 2510 t, qe); 2511 IF SymTab.ClassOf(eT) = 2512 SymTab.ClArray THEN 2513 QbeGen.ElemLoad(qe, eT, q) 2514 ELSE QbeGen.CopyOp(qe, q) 2515 END; 2516 t := eT; sfx := TRUE 2517 END; .) } 2518 "]" 2519 | "." GetIdent 2520 (. astSel := AST.MakeNode(AST.NkSelector); 2521 AST.SetOp(astSel, AST.SelField); 2522 AST.SetChild(astSel, 0, AST.MakeLeaf(AST.NkIdent, fn)); 2523 AST.SetChild(astDes, AST.NChild(astDes), astSel); IF k = SymTab.KindModule THEN 2524 (* qualified L.x: materialize 2525 the export, then load it *) 2526 IF NOT SymTab.MaterializeAlias(n, 2527 fn, mal) THEN 2528 SemError(201); 2529 t := SymTab.InvalidType; 2530 QbeGen.CopyOp("0", q) 2531 ELSE 2532 QbeGen.CopyOp(mal, qn); 2533 t := SymTab.SymType(mal); 2534 k := SymTab.SymKind(mal); 2535 sfx := FALSE; 2536 IF k = SymTab.KindProc THEN 2537 (* call: ArgList supplies 2538 the value *) 2539 QbeGen.CopyOp("0", q) 2540 ELSIF NOT QbeGen.LoadDesignator( 2541 mal, t, k, q) THEN 2542 SemError(230); 2543 QbeGen.CopyOp("0", q) 2544 END 2545 END 2546 ELSIF t = SymTab.InvalidType THEN 2547 ELSIF (SymTab.ClassOf(t) # 2548 SymTab.ClRecord) 2549 AND (SymTab.ClassOf(t) # 2550 SymTab.ClClass) THEN 2551 SemError(215); 2552 t := SymTab.InvalidType 2553 ELSIF (SymTab.ClassOf(t) = 2554 SymTab.ClClass) 2555 AND SymTab.MethodExists(t, fn) THEN 2556 (* obj.Method: bind the 2557 method and pass obj as 2558 the hidden receiver; q 2559 already holds the 2560 object's address *) 2561 QbeGen.ArmRecv(q); 2562 QbeGen.CopyOp(fn, n); 2563 QbeGen.CopyOp(fn, qn); 2564 methCls := t; 2565 k := SymTab.KindProc; 2566 t := SymTab.InvalidType 2567 ELSIF NOT SymTab.FieldExists(t, 2568 fn) THEN 2569 SemError(216); 2570 t := SymTab.InvalidType 2571 ELSE 2572 fo := SymTab.FieldOffset(t, 2573 fn); 2574 t := SymTab.FieldType(t, fn); 2575 QbeGen.FieldAddr(q, fo, qe); 2576 (* array fields are inline: 2577 the field address is the 2578 descriptor, like records *) 2579 QbeGen.CopyOp(qe, q); 2580 sfx := TRUE 2581 END; .) 2582 | "^" 2583 (. astSel := AST.MakeNode(AST.NkSelector); 2584 AST.SetOp(astSel, AST.SelDeref); 2585 AST.SetChild(astDes, AST.NChild(astDes), astSel); IF t = SymTab.InvalidType THEN 2586 ELSIF SymTab.ClassOf(t) # 2587 SymTab.ClPtr THEN 2588 SemError(219); 2589 t := SymTab.InvalidType 2590 ELSE 2591 bt := SymTab.PtrBase(t); 2592 IF bt = SymTab.InvalidType THEN 2593 ELSE 2594 IF sfx THEN 2595 QbeGen.ElemLoad(q, t, 2596 qb); 2597 QbeGen.CopyOp(qb, q) 2598 END; 2599 t := bt; 2600 (* q holds the pointee 2601 address: Fact loads 2602 scalars/pointers and uses 2603 the address for 2604 aggregates; the VAR-actual 2605 note is q itself. *) 2606 sfx := TRUE 2607 END 2608 END; .) } (. astCur := astDes; .) . 2609 (* Result suffix (ISO component after a function call): `F()^`, 2610 `F()[i]`, `F().field`. The call result is in t/q with sfx FALSE 2611 (a value, or a descriptor address for aggregates); each component 2612 descends one level exactly like the Design components. *) 2613 ResultComp (. VAR it, eT, bt: SymTab.TypeIndex; 2615 iq, ql, qlo, qhi, qe, qb: 2616 QbeGen.QVal; 2617 lo, hi, fo: INTEGER; 2618 isOpen: BOOLEAN; 2619 fname: SymTab.Name; 2620 astWrap, astSel: AST.Node; .) 2621 = "[" Expr 2622 (. IF AST.Kind(node) # AST.NkDesignator THEN 2623 astWrap := AST.MakeNode( 2624 AST.NkDesignator); 2625 AST.SetChild(astWrap, 0, node); 2626 node := astWrap 2627 END; 2628 AST.SetChild(node, AST.NChild(node), 2629 AST.MakeUn(AST.NkSelector, 2630 AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN 2631 ELSIF SymTab.ClassOf(t) # 2632 SymTab.ClArray THEN 2633 SemError(217); 2634 t := SymTab.InvalidType 2635 ELSIF NOT SymTab.IsIntFamily(it) 2636 AND (SymTab.ClassOf(it) # SymTab.ClChar) 2637 AND (SymTab.ClassOf(it) # SymTab.ClEnum) THEN 2638 SemError(218); 2639 t := SymTab.InvalidType 2640 ELSE 2641 QbeGen.WidenIndex(iq, ql); 2642 isOpen := 2643 SymTab.IsOpenArray(t); 2644 IF isOpen THEN 2645 QbeGen.CopyOp("0", qlo); 2646 IF SymTab.IsCharArray(t) 2647 OR SymTab.IsUCharArray(t) THEN 2648 QbeGen.OpenHiChar(q, qhi) 2649 ELSE QbeGen.OpenHi(q, qhi) 2650 END 2651 ELSE 2652 lo := SymTab.ArrayLo(t); 2653 hi := SymTab.ArrayHi(t); 2654 IF SymTab.IsCharArray(t) 2655 OR SymTab.IsUCharArray(t) THEN 2656 hi := hi + 1 2657 END; 2658 QbeGen.IntStr(lo, qlo); 2659 QbeGen.IntStr(hi, qhi) 2660 END; 2661 QbeGen.CheckRange(ql, qlo, 2662 qhi); 2663 eT := SymTab.ArrayElem(t); 2664 QbeGen.ElemAddr(q, ql, qlo, 2665 t, qe); 2666 IF SymTab.ClassOf(eT) = 2667 SymTab.ClArray THEN 2668 QbeGen.ElemLoad(qe, eT, q) 2669 ELSE QbeGen.CopyOp(qe, q) 2670 END; 2671 t := eT; sfx := TRUE 2672 END; .) 2673 "]" 2674 | "." GetIdent 2675 (. IF AST.Kind(node) # AST.NkDesignator THEN 2676 astWrap := AST.MakeNode( 2677 AST.NkDesignator); 2678 AST.SetChild(astWrap, 0, node); 2679 node := astWrap 2680 END; 2681 AST.SetChild(node, AST.NChild(node), 2682 AST.MakeUn(AST.NkSelector, 2683 AST.SelField, 2684 AST.MakeLeaf(AST.NkIdent, 2685 fname))); IF t = SymTab.InvalidType THEN 2686 ELSIF (SymTab.ClassOf(t) # 2687 SymTab.ClRecord) 2688 AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN 2689 SemError(215); 2690 t := SymTab.InvalidType 2691 ELSIF NOT SymTab.FieldExists(t, 2692 fname) THEN 2693 SemError(216); 2694 t := SymTab.InvalidType 2695 ELSE 2696 fo := SymTab.FieldOffset(t, 2697 fname); 2698 t := SymTab.FieldType(t, fname); 2699 QbeGen.FieldAddr(q, fo, qe); 2700 QbeGen.CopyOp(qe, q); 2701 sfx := TRUE 2702 END; .) 2703 | "^" (. IF AST.Kind(node) # AST.NkDesignator THEN 2704 astWrap := AST.MakeNode( 2705 AST.NkDesignator); 2706 AST.SetChild(astWrap, 0, node); 2707 node := astWrap 2708 END; 2709 astSel := AST.MakeNode(AST.NkSelector); 2710 AST.SetOp(astSel, AST.SelDeref); 2711 AST.SetChild(node, 2712 AST.NChild(node), astSel); IF t = SymTab.InvalidType THEN 2713 ELSIF SymTab.ClassOf(t) # 2714 SymTab.ClPtr THEN 2715 SemError(219); 2716 t := SymTab.InvalidType 2717 ELSE 2718 bt := SymTab.PtrBase(t); 2719 IF bt # SymTab.InvalidType THEN 2720 IF sfx THEN 2721 QbeGen.ElemLoad(q, t, qb); 2722 QbeGen.CopyOp(qb, q) 2723 END; 2724 t := bt; sfx := TRUE 2725 END 2726 END; .) . 2727 Expr 2728 (. VAR t2: SymTab.TypeIndex; 2729 op: INTEGER; 2730 q2, qt, wl: QbeGen.QVal; 2731 astA, astB: AST.Node; 2732 astOp: INTEGER; 2733 astMade: BOOLEAN; 2734 isR: BOOLEAN; .) 2735 = SimExpr (. astA := astCur; astMade := FALSE; .) 2736 [ Rel SimExpr 2737 (. astB := astCur; astMade := TRUE; 2738 astOp := AST.OpEq; 2739 IF op = SymTab.OpNeq1 THEN astOp := AST.OpNe 2740 ELSIF op = SymTab.OpNeq2 THEN astOp := AST.OpNe 2741 ELSIF op = SymTab.OpLt THEN astOp := AST.OpLt 2742 ELSIF op = SymTab.OpLe THEN astOp := AST.OpLe 2743 ELSIF op = SymTab.OpGt THEN astOp := AST.OpGt 2744 ELSIF op = SymTab.OpGe THEN astOp := AST.OpGe 2745 ELSIF op = SymTab.OpIn THEN astOp := AST.OpIn 2746 END; 2747 IF op = SymTab.OpIn THEN 2748 IF SymTab.InCheck(t, t2) THEN 2749 IF (t = SymTab.InvalidType) 2750 OR (t2 = SymTab.InvalidType) THEN 2751 t := SymTab.BoolType(); QbeGen.CopyOp("0", q) 2752 ELSE 2753 QbeGen.InSet(q, q2, SymTab.SetBaseLo(t2), 2754 SymTab.SetCount(t2), qt); 2755 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q) 2756 END 2757 ELSE SemError(222); t := SymTab.InvalidType; 2758 QbeGen.CopyOp("0", q) 2759 END 2760 ELSIF SymTab.RelCheck(t, t2, op) THEN 2761 IF (t = SymTab.InvalidType) 2762 OR (t2 = SymTab.InvalidType) THEN 2763 t := SymTab.BoolType(); QbeGen.CopyOp("0", q) 2764 ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr) 2765 OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN 2766 IF SymTab.IsFwdVar(t) OR SymTab.IsFwdVar(t2) THEN 2767 QbeGen.Cmp(op, q, q2, qt, FALSE); 2768 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q) 2769 ELSIF (op # SymTab.OpEq) AND (op # SymTab.OpNeq1) 2770 AND (op # SymTab.OpNeq2) THEN 2771 SemError(213); t := SymTab.InvalidType; 2772 QbeGen.CopyOp("0", q) 2773 ELSE 2774 QbeGen.CmpL(op, q, q2, qt); 2775 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q) 2776 END 2777 ELSIF (SymTab.ClassOf(t) = SymTab.ClSet) 2778 OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN 2779 QbeGen.CmpSet(op, q, q2, 2780 SymTab.SetWords(t), SymTab.SetWords(t2), qt); 2781 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q) 2782 ELSIF SymTab.StrCompat(t, t2) THEN 2783 QbeGen.StrEq(op, q, q2, qt); 2784 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q) 2785 ELSIF SymTab.IsLongFamily(t) 2786 OR SymTab.IsLongFamily(t2) THEN 2787 IF SymTab.IsIntFamily(t) THEN 2788 QbeGen.WidenLong(q, wl); QbeGen.CopyOp(wl, q) 2789 END; 2790 IF SymTab.IsIntFamily(t2) THEN 2791 QbeGen.WidenLong(q2, wl); QbeGen.CopyOp(wl, q2) 2792 END; 2793 QbeGen.CmpLong(op, q, q2, qt); 2794 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q) 2795 ELSE 2796 isR := SymTab.ClassOf(t) = SymTab.ClReal; 2797 t := SymTab.BoolType(); 2798 QbeGen.Cmp(op, q, q2, qt, isR); 2799 QbeGen.CopyOp(qt, q) 2800 END 2801 ELSE SemError(213); t := SymTab.InvalidType; 2802 QbeGen.CopyOp("0", q) 2803 END; 2804 astCur := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB); .) ] 2805 (. IF NOT astMade THEN astCur := astA END; .) . 2806 Rel 2807 = "=" (. op := SymTab.OpEq; .) 2808 | "#" (. op := SymTab.OpNeq1; .) 2809 | "<" (. op := SymTab.OpLt; .) 2810 | "<=" (. op := SymTab.OpLe; .) 2811 | ">" (. op := SymTab.OpGt; .) 2812 | ">=" (. op := SymTab.OpGe; .) 2813 | "IN" (. op := SymTab.OpIn; .) . 2814 SimExpr 2815 (. VAR t2, res2, lt, rt: 2816 SymTab.TypeIndex; 2817 op: INTEGER; 2818 q2, qt, wq, qf, q2a, q2b: 2819 QbeGen.QVal; 2820 neg, isR, isL, folded: 2821 BOOLEAN; 2822 fok: BOOLEAN; 2823 lw, rw, mw: CARDINAL; 2824 lTrue, lNext, lDone, qr, qs: QbeGen.QVal; 2825 astA, astB: AST.Node; 2826 astSign, astOp: INTEGER; .) 2827 = (. neg := FALSE; astSign := 0; .) 2828 [ "+" (. neg := TRUE; astSign := 1; .) 2829 | "-" (. neg := TRUE; astSign := -1; .) ] 2830 Term (. astA := astCur; IF neg THEN 2831 IF QbeGen.IsImm(q) THEN 2832 QbeGen.NegFold(q, q) 2833 ELSE QbeGen.NewTemp(qt); 2834 QbeGen.NegQ(q, qt, 2835 SymTab.ClassOf(t) 2836 = SymTab.ClReal); 2837 QbeGen.CopyOp(qt, q) 2838 END 2839 END; 2840 IF astSign < 0 THEN 2841 astCur := AST.MakeUn( 2842 AST.NkUnary, AST.OpSub, astA); 2843 astA := astCur 2844 END; .) 2845 { AddOp (. IF op = SymTab.OpOr THEN 2846 QbeGen.DelayBegin END; .) 2847 Term (. astB := astCur; IF op = SymTab.OpOr THEN 2848 QbeGen.DelayEnd END; .) 2849 (. astOp := AST.OpAdd; 2850 IF op = SymTab.OpSub THEN astOp := AST.OpSub 2851 ELSIF op = SymTab.OpOr THEN astOp := AST.OpOr END; 2852 astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB); 2853 astCur := astA; 2854 IF op = SymTab.OpOr THEN 2855 (* short-circuit: if q is true the RHS is skipped *) 2856 IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN 2857 t := SymTab.BoolType() 2858 ELSE SemError(212); t := SymTab.InvalidType END; 2859 IF t # SymTab.InvalidType THEN 2860 QbeGen.Slot4(qs); 2861 QbeGen.NewLabel(lTrue); 2862 QbeGen.NewLabel(lNext); 2863 QbeGen.NewLabel(lDone); 2864 QbeGen.Jnz(q, lTrue, lNext); 2865 QbeGen.EmitLabel(lTrue); 2866 QbeGen.StoreW(qs, "1"); 2867 QbeGen.Jmp(lDone); 2868 QbeGen.EmitLabel(lNext); 2869 QbeGen.DelayFlush; 2870 QbeGen.StoreW(qs, q2); 2871 QbeGen.Jmp(lDone); 2872 QbeGen.EmitLabel(lDone); 2873 QbeGen.LoadW(qs, qr); 2874 QbeGen.CopyOp(qr, q) 2875 ELSE QbeGen.DelayFlush; QbeGen.CopyOp("0", q) 2876 END 2877 ELSIF (op = SymTab.OpAdd) 2878 AND (SymTab.UStrCompat(t, t2) 2879 OR ((SymTab.ClassOf(t) = SymTab.ClUChar) 2880 AND (SymTab.ClassOf(t2) = SymTab.ClUStr)) 2881 OR ((SymTab.ClassOf(t) = SymTab.ClUStr) 2882 AND (SymTab.ClassOf(t2) = SymTab.ClUChar)) 2883 OR ((SymTab.ClassOf(t) = SymTab.ClUChar) 2884 AND (SymTab.ClassOf(t2) = SymTab.ClUChar))) THEN 2885 (* UString concatenation: a UCHAR operand becomes a 2886 1-codepoint UString; the result is a descriptor in the 2887 shim's concat buffer. Work on copies so neither 2888 operand is clobbered. *) 2889 IF SymTab.ClassOf(t) = SymTab.ClUStr THEN 2890 QbeGen.CopyOp(q, q2a) 2891 ELSE 2892 QbeGen.UStrFrom(q, q2a) 2893 END; 2894 IF SymTab.ClassOf(t2) = SymTab.ClUStr THEN 2895 QbeGen.UStrCat(q2a, q2, qt) 2896 ELSE 2897 QbeGen.UStrFrom(q2, q2b); 2898 QbeGen.UStrCat(q2a, q2b, qt) 2899 END; 2900 t := SymTab.NewUStr(); 2901 QbeGen.CopyOp(qt, q) 2902 ELSIF (op = SymTab.OpAdd) 2903 AND (SymTab.StrCompat(t, t2) 2904 OR (SymTab.IsStrType(t) 2905 AND (SymTab.ClassOf(t2) = SymTab.ClChar)) 2906 OR ((SymTab.ClassOf(t) = SymTab.ClChar) 2907 AND SymTab.IsStrType(t2))) THEN 2908 (* string concatenation; a CHAR operand becomes a 2909 1-character string literal. When both operands are 2910 constants, fold to a single string literal so a 2911 constructor element stays compile-time. *) 2912 QbeGen.StrFold(q, q2, SymTab.ClassOf(t), SymTab.ClassOf(t2), 2913 qt, fok); 2914 IF NOT fok THEN 2915 IF SymTab.StrCompat(t, t2) THEN 2916 QbeGen.StrCat(q, q2, qt) 2917 ELSIF SymTab.IsStrType(t) THEN 2918 QbeGen.DeclCharStr(q2, qs); 2919 QbeGen.StrCat(q, qs, qt) 2920 ELSE 2921 QbeGen.DeclCharStr(q, qs); 2922 QbeGen.StrCat(qs, q2, qt) 2923 END 2924 END; 2925 t := SymTab.NewStr(); 2926 QbeGen.CopyOp(qt, q) 2927 ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType) 2928 AND (SymTab.ClassOf(t) = SymTab.ClSet) 2929 AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN 2930 lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2); 2931 mw := lw; 2932 IF rw > mw THEN mw := rw END; 2933 IF op = SymTab.OpAdd THEN 2934 QbeGen.SetBinOp(0, q, q2, lw, rw, qt) 2935 ELSE 2936 QbeGen.SetBinOp(2, q, q2, lw, rw, qt) 2937 END; 2938 t := SymTab.NewSet( 2939 SymTab.NewSubR(0, 2940 VAL(INTEGER, mw) * 32 - 1)); 2941 QbeGen.CopyOp(qt, q) 2942 ELSE 2943 IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN 2944 lt := t; rt := t2; t := res2 2945 ELSE SemError(211); t := SymTab.InvalidType END; 2946 IF t # SymTab.InvalidType THEN 2947 isL := SymTab.IsLongFamily(t); 2948 isR := SymTab.ClassOf(t) = SymTab.ClReal; 2949 folded := FALSE; 2950 IF (NOT isL) AND (NOT isR) 2951 AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN 2952 IF op = SymTab.OpAdd THEN 2953 folded := QbeGen.Fold2(0, q, q2, qf) 2954 ELSE 2955 folded := QbeGen.Fold2(1, q, q2, qf) 2956 END 2957 END; 2958 IF folded THEN QbeGen.CopyOp(qf, q) 2959 ELSE 2960 IF isL THEN 2961 IF SymTab.IsIntFamily(lt) THEN 2962 QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q) 2963 END; 2964 IF SymTab.IsIntFamily(rt) THEN 2965 QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2) 2966 END; 2967 QbeGen.NewTemp(qt); 2968 IF op = SymTab.OpAdd THEN 2969 QbeGen.Op3L("add", qt, q, q2) 2970 ELSE 2971 QbeGen.Op3L("sub", qt, q, q2) 2972 END 2973 ELSE 2974 QbeGen.NewTemp(qt); 2975 IF op = SymTab.OpAdd THEN 2976 QbeGen.Op3("add", qt, q, q2, isR) 2977 ELSE 2978 QbeGen.Op3("sub", qt, q, q2, isR) 2979 END 2980 END; 2981 QbeGen.CopyOp(qt, q) 2982 END 2983 ELSE QbeGen.CopyOp("0", q) 2984 END 2985 END; .) } . 2986 AddOp 2987 = "+" (. op := SymTab.OpAdd; .) 2988 | "-" (. op := SymTab.OpSub; .) 2989 | "OR" (. op := SymTab.OpOr; .) . 2990 Term 2991 (. VAR t2, res2, lt, rt: 2992 SymTab.TypeIndex; 2993 op: INTEGER; 2994 q2, qt, wq, qf: 2995 QbeGen.QVal; 2996 isR, isL, folded: BOOLEAN; 2997 lw, rw, mw: CARDINAL; 2998 lNext, lFalse, lDone, qr, qs: QbeGen.QVal; 2999 astA, astB: AST.Node; 3000 astOp: INTEGER; .) 3001 = Fact (. astA := astCur; .) { MulOp (. IF op = SymTab.OpAnd THEN 3002 QbeGen.DelayBegin END; .) 3003 Fact (. astB := astCur; IF op = SymTab.OpAnd THEN 3004 QbeGen.DelayEnd END; .) 3005 (. astOp := AST.OpMul; 3006 IF op = SymTab.OpSlash THEN astOp := AST.OpDiv 3007 ELSIF op = SymTab.OpDiv THEN astOp := AST.OpDiv 3008 ELSIF op = SymTab.OpMod THEN astOp := AST.OpMod 3009 ELSIF op = SymTab.OpAnd THEN astOp := AST.OpAnd END; 3010 astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB); 3011 astCur := astA; 3012 IF op = SymTab.OpAnd THEN 3013 (* short-circuit: if q is false the RHS is skipped *) 3014 IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN 3015 t := SymTab.BoolType() 3016 ELSE SemError(212); t := SymTab.InvalidType END; 3017 IF t # SymTab.InvalidType THEN 3018 QbeGen.Slot4(qs); 3019 QbeGen.NewLabel(lNext); 3020 QbeGen.NewLabel(lFalse); 3021 QbeGen.NewLabel(lDone); 3022 QbeGen.Jnz(q, lNext, lFalse); 3023 QbeGen.EmitLabel(lNext); 3024 QbeGen.DelayFlush; 3025 QbeGen.StoreW(qs, q2); 3026 QbeGen.Jmp(lDone); 3027 QbeGen.EmitLabel(lFalse); 3028 QbeGen.StoreW(qs, "0"); 3029 QbeGen.Jmp(lDone); 3030 QbeGen.EmitLabel(lDone); 3031 QbeGen.LoadW(qs, qr); 3032 QbeGen.CopyOp(qr, q) 3033 ELSE QbeGen.DelayFlush; QbeGen.CopyOp("0", q) 3034 END 3035 ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType) 3036 AND (SymTab.ClassOf(t) = SymTab.ClSet) 3037 AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN 3038 lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2); 3039 mw := lw; 3040 IF rw > mw THEN mw := rw END; 3041 IF op = SymTab.OpTimes THEN 3042 QbeGen.SetBinOp(1, q, q2, lw, rw, qt) 3043 ELSE 3044 QbeGen.SetBinOp(3, q, q2, lw, rw, qt) 3045 END; 3046 t := SymTab.NewSet( 3047 SymTab.NewSubR(0, 3048 VAL(INTEGER, mw) * 32 - 1)); 3049 QbeGen.CopyOp(qt, q) 3050 ELSE 3051 IF SymTab.ArithCheck(t, t2, 3052 (op = SymTab.OpDiv) OR (op = SymTab.OpMod), 3053 res2) THEN 3054 lt := t; rt := t2; t := res2 3055 ELSE SemError(211); t := SymTab.InvalidType END; 3056 IF t # SymTab.InvalidType THEN 3057 isL := SymTab.IsLongFamily(t); 3058 isR := SymTab.ClassOf(t) = SymTab.ClReal; 3059 folded := FALSE; 3060 IF (NOT isL) AND (NOT isR) 3061 AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN 3062 IF op = SymTab.OpTimes THEN 3063 folded := QbeGen.Fold2(2, q, q2, qf) 3064 ELSIF op = SymTab.OpDiv THEN 3065 folded := QbeGen.Fold2(3, q, q2, qf) 3066 ELSIF op = SymTab.OpMod THEN 3067 folded := QbeGen.Fold2(4, q, q2, qf) 3068 END 3069 END; 3070 IF folded THEN QbeGen.CopyOp(qf, q) 3071 ELSE 3072 IF isL THEN 3073 IF SymTab.IsIntFamily(lt) THEN 3074 QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q) 3075 END; 3076 IF SymTab.IsIntFamily(rt) THEN 3077 QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2) 3078 END; 3079 QbeGen.NewTemp(qt); 3080 IF op = SymTab.OpTimes THEN 3081 QbeGen.Op3L("mul", qt, q, q2) 3082 ELSIF (op = SymTab.OpDiv) 3083 OR (op = SymTab.OpSlash) THEN 3084 QbeGen.Op3L("div", qt, q, q2) 3085 ELSE 3086 QbeGen.Op3L("rem", qt, q, q2) 3087 END 3088 ELSE 3089 QbeGen.NewTemp(qt); 3090 IF op = SymTab.OpTimes THEN 3091 QbeGen.Op3("mul", qt, q, q2, isR) 3092 ELSIF (op = SymTab.OpDiv) 3093 OR (op = SymTab.OpSlash) THEN 3094 QbeGen.Op3("div", qt, q, q2, isR) 3095 ELSE 3096 QbeGen.Op3("rem", qt, q, q2, isR) 3097 END 3098 END; 3099 QbeGen.CopyOp(qt, q) 3100 END 3101 ELSE QbeGen.CopyOp("0", q) 3102 END 3103 END; .) } . 3104 MulOp 3105 = "*" (. op := SymTab.OpTimes; .) 3106 | "/" (. op := SymTab.OpSlash; .) 3107 | "DIV" (. op := SymTab.OpDiv; .) 3108 | "MOD" (. op := SymTab.OpMod; .) 3109 | ( "AND" | "&" ) (. op := SymTab.OpAnd; .) . 3110 Fact 3111 (. VAR s: ARRAY [0 .. 255] OF CHAR; 3112 et, dt, t2, st, ct2, et2: 3113 SymTab.TypeIndex; 3114 dk: INTEGER; 3115 qd, q2, sq, qa, qm0, qr, qt: 3116 QbeGen.QVal; 3117 qn, vn: SymTab.Name; 3118 vt: SymTab.TypeIndex; 3119 c1, c2: INTEGER; 3120 lo, hi: INTEGER; 3121 isMax: BOOLEAN; 3122 called, isHigh, sfx, isCh, 3123 isU, uok, isStr: BOOLEAN; 3124 ucp: INTEGER; astIsLit: BOOLEAN; 3125 astD: AST.Node; 3126 astCall: BOOLEAN; 3127 astNode, astNot: AST.Node; 3128 j: CARDINAL; 3129 astArg2: AST.Node; 3130 astBrace: AST.Node; 3131 astRes: AST.Node; .) 3132 = (. astIsLit := FALSE; .) 3133 ( integer (. LexString(s); 3134 QbeGen.NormInt(s, q); IF twoPhase THEN astIsLit := TRUE; astCur := AST.MakeLeaf(AST.NkIntLit, s) END; 3135 t := SymTab.IntType(); .) 3136 | charConst (. LexString(s); 3137 QbeGen.NormLit(s, q, isCh); 3138 IF twoPhase THEN 3139 astIsLit := TRUE; 3140 astCur := AST.MakeLeaf( 3141 AST.NkCharLit, s) 3142 END; 3143 t := SymTab.CharType(); .) 3144 | real (. LexString(s); 3145 QbeGen.NormReal(s, q); 3146 IF twoPhase THEN 3147 astIsLit := TRUE; 3148 astCur := AST.MakeLeaf( 3149 AST.NkRealLit, s) 3150 END; 3151 t := SymTab.RealType(); .) 3152 | string (. LexString(s); 3153 IF twoPhase THEN 3154 astIsLit := TRUE; 3155 astCur := AST.MakeLeaf( 3156 AST.NkStrLit, s) 3157 END; 3158 IF SymTab.StrLen(s) = 3 THEN 3159 t := SymTab.CharType(); 3160 QbeGen.IntStr( 3161 QbeGen.CharVal(s), q) 3162 ELSE t := SymTab.NewStr(); 3163 QbeGen.DeclStr(s, q); 3164 (* a literal's value IS its 3165 static descriptor address *) 3166 QbeGen.NoteAddr(q, q) 3167 END; .) 3168 | ustring (. LexString(s); 3169 IF twoPhase THEN 3170 astIsLit := TRUE; 3171 astCur := AST.MakeLeaf( 3172 AST.NkStrLit, s) 3173 END; 3174 QbeGen.DeclUStr(s, q, isU, ucp, 3175 uok); 3176 IF NOT uok THEN 3177 SemError(234); 3178 t := SymTab.InvalidType 3179 ELSIF isU THEN 3180 t := SymTab.UCharType(); 3181 QbeGen.IntStr(ucp, q) 3182 ELSE 3183 t := SymTab.NewUStr(); 3184 QbeGen.NoteAddr(q, q) 3185 END; .) 3186 | Design (. astD := astCur; astCall := FALSE; astBrace := AST.NoNode; 3187 astNArgs := 0; called := FALSE; 3188 t := dt; 3189 IF sfx THEN 3190 IF dt = 3191 SymTab.InvalidType THEN 3192 QbeGen.CopyOp("0", q) 3193 ELSIF (SymTab.ClassOf(dt) = 3194 SymTab.ClRecord) 3195 OR (SymTab.ClassOf(dt) = 3196 SymTab.ClSet) 3197 OR (SymTab.ClassOf(dt) = 3198 SymTab.ClArray) 3199 OR (SymTab.ClassOf(dt) = 3200 SymTab.ClClass) THEN 3201 QbeGen.CopyOp(qd, q) 3202 ELSE QbeGen.ElemLoad(qd, dt, 3203 q) 3204 END 3205 ELSE QbeGen.CopyOp(qd, q) 3206 END; 3207 IF (dk = SymTab.KindVar) 3208 OR (dk = SymTab.KindParam) 3209 OR (dk = 3210 SymTab.KindField) THEN 3211 IF sfx THEN 3212 QbeGen.NoteAddr(q, qd) 3213 ELSE 3214 QbeGen.AddrOf(qn, qa); 3215 QbeGen.NoteAddr(q, qa) 3216 END 3217 ELSIF sfx 3218 AND (dt # 3219 SymTab.InvalidType) 3220 AND ((SymTab.ClassOf(dt) = 3221 SymTab.ClArray) 3222 OR (SymTab.ClassOf(dt) = 3223 SymTab.ClSet) 3224 OR (SymTab.ClassOf(dt) = 3225 SymTab.ClRecord)) THEN 3226 QbeGen.NoteAddr(qd, qd) 3227 END; .) 3228 [ TypedBraceLit (. t := dt; astCall := TRUE; 3229 astBrace := astCur; .) ] 3230 [ ArgList 3231 (. astCall := TRUE; 3232 astNode := AstCallNode(astD); 3233 astRes := astNode; 3234 t := ct2; 3235 QbeGen.CopyOp(q2, q); 3236 sfx := FALSE; .) 3237 { ResultComp } 3238 (. IF sfx THEN 3239 IF t = SymTab.InvalidType THEN 3240 QbeGen.CopyOp("0", q) 3241 ELSIF (SymTab.ClassOf(t) # 3242 SymTab.ClRecord) 3243 AND (SymTab.ClassOf(t) # SymTab.ClSet) 3244 AND (SymTab.ClassOf(t) # SymTab.ClArray) 3245 AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN 3246 QbeGen.ElemLoad(q, t, q2); 3247 QbeGen.CopyOp(q2, q) 3248 END 3249 END; .) ] 3250 (. IF called THEN 3251 astCur := astRes 3252 ELSIF astCall THEN 3253 astCur := astBrace 3254 ELSE astCur := astD 3255 END; 3256 astIsLit := TRUE; 3257 IF NOT called 3258 AND (dk = SymTab.KindProc) THEN 3259 (* bare zero-arg function 3260 call (parentheses may be 3261 omitted); a proper or 3262 parameterised proc here 3263 is 230 *) 3264 IF (SymTab.ProcNPar(qn) = 0) 3265 AND (SymTab.ProcRes(qn) # 3266 SymTab.InvalidType) THEN 3267 QbeGen.Mangled(qn, 3268 SymTab.ProcUid(qn), qm0); 3269 QbeGen.CallBegin(qm0, 3270 SymTab.ProcRes(qn), 3271 SymTab.ProcDepthOf(qn), 3272 SymTab.IsExternal(qn)); 3273 QbeGen.CallEnd(TRUE, q); 3274 t := SymTab.ProcRes(qn) 3275 ELSE 3276 (* procedure used as a 3277 value (assign to a 3278 procedure variable): 3279 its code address *) 3280 t := SymTab.ProcTypeOf(qn); 3281 QbeGen.Mangled(qn, 3282 SymTab.ProcUid(qn), qm0); 3283 QbeGen.ProcAddr(qm0, q) 3284 END 3285 END; .) 3286 | ( "HIGH" (. isHigh := TRUE; .) 3287 | ( "LEN" | "LENGTH" ) (. isHigh := FALSE; .) ) 3288 "(" ( Design (. isStr := FALSE; 3289 isU := FALSE; .) 3290 | string (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s); 3291 isStr := TRUE; 3292 isU := FALSE; 3293 IF SymTab.StrLen(s) = 3 THEN 3294 dt := SymTab.CharType(); 3295 QbeGen.IntStr(QbeGen.CharVal(s), 3296 qd) 3297 ELSE 3298 dt := SymTab.NewStr(); 3299 QbeGen.DeclStr(s, qd); 3300 QbeGen.NoteAddr(qd, qd) 3301 END; 3302 dk := -1; 3303 qn[0] := CHR(0); .) 3304 | ustring (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s); 3305 QbeGen.DeclUStr(s, qd, isU, ucp, 3306 uok); 3307 isStr := FALSE; 3308 IF NOT uok THEN 3309 SemError(234); 3310 dt := SymTab.InvalidType 3311 ELSIF isU THEN 3312 (* one codepoint: a UCHAR; 3313 LEN is 1, HIGH is 0 *) 3314 dt := SymTab.UCharType(); 3315 QbeGen.IntStr(ucp, qd) 3316 ELSE 3317 dt := SymTab.NewUStr(); 3318 QbeGen.NoteAddr(qd, qd) 3319 END; 3320 dk := -1; 3321 qn[0] := CHR(0); .) ) 3322 ")" 3323 (. astNode := AST.MakeNode(AST.NkCall); 3324 IF isHigh THEN AST.SetChild(astNode, 0, 3325 AST.MakeLeaf(AST.NkIdent, "HIGH")) 3326 ELSE AST.SetChild(astNode, 0, 3327 AST.MakeLeaf(AST.NkIdent, "LEN")) END; 3328 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3329 astCur := astNode; astIsLit := TRUE; 3330 IF (dt # SymTab.InvalidType) 3331 AND (SymTab.ClassOf(dt) = SymTab.ClUStr) THEN 3332 (* UString: the count is 3333 the descriptor header *) 3334 IF isHigh THEN 3335 QbeGen.UStrLen(qd, qr); 3336 QbeGen.DecQ(qr) 3337 ELSE 3338 QbeGen.UStrLen(qd, qr) 3339 END; 3340 t := SymTab.IntType(); 3341 QbeGen.CopyOp(qr, q) 3342 ELSIF (dt # SymTab.InvalidType) 3343 AND (SymTab.ClassOf(dt) = SymTab.ClUChar) THEN 3344 (* single UCHAR codepoint *) 3345 IF isHigh THEN 3346 QbeGen.CopyOp("0", qr) 3347 ELSE 3348 QbeGen.CopyOp("1", qr) 3349 END; 3350 t := SymTab.IntType(); 3351 QbeGen.CopyOp(qr, q) 3352 ELSIF isStr THEN 3353 (* fold: content length at 3354 compile time *) 3355 IF SymTab.StrLen(s) = 3 THEN 3356 c1 := 1 3357 ELSE 3358 c1 := 3359 SymTab.StrLen(s) - 2 3360 END; 3361 IF isHigh THEN 3362 DEC(c1) 3363 END; 3364 QbeGen.IntStr(c1, qr); 3365 t := SymTab.IntType(); 3366 QbeGen.CopyOp(qr, q) 3367 ELSIF dt = SymTab.InvalidType THEN 3368 t := SymTab.InvalidType; 3369 QbeGen.CopyOp("0", q) 3370 ELSIF SymTab.ClassOf(dt) # 3371 SymTab.ClArray THEN 3372 SemError(217); 3373 t := SymTab.InvalidType; 3374 QbeGen.CopyOp("0", q) 3375 ELSE 3376 IF isHigh THEN 3377 IF SymTab.IsOpenArray(dt) THEN 3378 QbeGen.OpenHi(qd, qr) 3379 ELSE 3380 QbeGen.IntStr( 3381 SymTab.ArrayHi(dt), qr) 3382 END 3383 ELSE 3384 IF SymTab.IsOpenArray(dt) THEN 3385 QbeGen.LoadCount(qd, qr) 3386 ELSE 3387 QbeGen.IntStr(VAL( 3388 INTEGER, 3389 SymTab.ArrayLen(dt)), 3390 qr) 3391 END 3392 END; 3393 t := SymTab.IntType(); 3394 QbeGen.CopyOp(qr, q) 3395 END; .) 3396 | ( "SIZE" | "TSIZE" ) "(" Design ")" 3397 (. astNode := AST.MakeNode(AST.NkCall); 3398 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "SIZE")); 3399 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3400 astCur := astNode; astIsLit := TRUE; .) 3401 (. IF dt = SymTab.InvalidType THEN 3402 t := SymTab.InvalidType; 3403 QbeGen.CopyOp("0", q) 3404 ELSE 3405 QbeGen.IntStr(VAL(INTEGER, 3406 SymTab.ObjectSize(dt)), q); 3407 t := SymTab.IntType() 3408 END; .) 3409 | ( "SHIFT" (. isMax := FALSE; .) 3410 | "ROTATE" (. isMax := TRUE; .) ) 3411 "(" Expr (. astArg2 := astCur; .) "," Expr ")" 3412 (. astNode := AST.MakeNode(AST.NkCall); 3413 IF isMax THEN AST.SetChild(astNode, 0, 3414 AST.MakeLeaf(AST.NkIdent, "ROTATE")) 3415 ELSE AST.SetChild(astNode, 0, 3416 AST.MakeLeaf(AST.NkIdent, "SHIFT")) END; 3417 IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END; 3418 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END; 3419 astCur := astNode; astIsLit := TRUE; 3420 (* set shift/rotate: isMax 3421 doubles as "rotate" *) 3422 IF (et # SymTab.InvalidType) 3423 AND (SymTab.ClassOf(et) = 3424 SymTab.ClSet) THEN 3425 QbeGen.SetShift(q, q2, 3426 SymTab.SetWords(et), 3427 SymTab.SetCount(et), isMax, 3428 qt); 3429 t := et; 3430 QbeGen.CopyOp(qt, q) 3431 ELSE SemError(230); 3432 t := SymTab.InvalidType; 3433 QbeGen.CopyOp("0", q) 3434 END; .) 3435 | ( "MIN" (. isMax := FALSE; .) 3436 | "MAX" (. isMax := TRUE; .) ) 3437 "(" Design ")" 3438 (. astNode := AST.MakeNode(AST.NkCall); 3439 IF isMax THEN AST.SetChild(astNode, 0, 3440 AST.MakeLeaf(AST.NkIdent, "MAX")) 3441 ELSE AST.SetChild(astNode, 0, 3442 AST.MakeLeaf(AST.NkIdent, "MIN")) END; 3443 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3444 astCur := astNode; astIsLit := TRUE; 3445 IF (dt # SymTab.InvalidType) 3446 AND (SymTab.ClassOf(dt) = SymTab.ClReal) THEN 3447 (* REAL/LONGREAL: the 3448 implementation bounds *) 3449 IF isMax THEN 3450 QbeGen.NormReal( 3451 "3.402823e38", q) 3452 ELSE QbeGen.NormReal( 3453 "-3.402823e38", q) 3454 END; 3455 t := SymTab.RealType() 3456 ELSIF (dt # 3457 SymTab.InvalidType) 3458 AND (SymTab.ClassOf(dt) = 3459 SymTab.ClLong) THEN 3460 IF isMax THEN 3461 QbeGen.CopyOp( 3462 "9223372036854775807", q) 3463 ELSE QbeGen.CopyOp( 3464 "-9223372036854775808", q) 3465 END; 3466 t := SymTab.LongType() 3467 ELSIF SymTab.TypeBounds(dt, lo, 3468 hi) THEN 3469 IF isMax THEN 3470 QbeGen.IntStr(hi, q) 3471 ELSE QbeGen.IntStr(lo, q) 3472 END; 3473 t := SymTab.IntType() 3474 ELSE SemError(230); 3475 t := SymTab.InvalidType; 3476 QbeGen.CopyOp("0", q) 3477 END; .) 3478 | "ADR" "(" Design ")" 3479 (. astNode := AST.MakeNode(AST.NkCall); 3480 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ADR")); 3481 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3482 astCur := astNode; astIsLit := TRUE; .) 3483 (. IF dt = SymTab.InvalidType THEN 3484 t := SymTab.InvalidType; 3485 QbeGen.CopyOp("0", q) 3486 ELSE 3487 IF sfx THEN 3488 QbeGen.CopyOp(qd, q) 3489 ELSIF (dk = SymTab.KindVar) 3490 OR (dk = SymTab.KindParam) THEN 3491 QbeGen.AddrOf(qn, q) 3492 ELSE SemError(230); 3493 QbeGen.CopyOp("0", q) 3494 END; 3495 t := SymTab.AddrType() 3496 END; .) 3497 | "CHR" "(" Expr ")" 3498 (. astNode := AST.MakeNode(AST.NkCall); 3499 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR")); 3500 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3501 astCur := astNode; astIsLit := TRUE; .) 3502 (. IF (et # SymTab.InvalidType) 3503 AND NOT SymTab.IsIntFamily(et) THEN 3504 SemError(211) END; 3505 t := SymTab.CharType(); .) 3506 | ( "ORD" | "ORDL" ) "(" Expr ")" 3507 (. astNode := AST.MakeNode(AST.NkCall); 3508 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ORD")); 3509 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3510 astCur := astNode; astIsLit := TRUE; .) 3511 (. IF et # SymTab.InvalidType THEN 3512 IF (SymTab.ClassOf(et) # 3513 SymTab.ClChar) 3514 AND (SymTab.ClassOf(et) # 3515 SymTab.ClBool) 3516 AND (SymTab.ClassOf(et) # 3517 SymTab.ClEnum) 3518 AND NOT SymTab.IsIntFamily(et) THEN 3519 SemError(211) END 3520 END; 3521 t := SymTab.IntType(); .) 3522 | "CAP" "(" Expr ")" 3523 (. astNode := AST.MakeNode(AST.NkCall); 3524 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CAP")); 3525 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3526 astCur := astNode; astIsLit := TRUE; .) 3527 (. QbeGen.CapQ(q, qa); 3528 QbeGen.CopyOp(qa, q); 3529 t := SymTab.CharType(); .) 3530 | "UCHR" "(" Expr ")" 3531 (. astNode := AST.MakeNode(AST.NkCall); 3532 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UCHR")); 3533 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3534 astCur := astNode; astIsLit := TRUE; .) 3535 (. (* UCHR: the UCHAR constructor. 3536 CHAR -> UCHAR (identity); 3537 INTEGER familly -> UCHAR 3538 (codepoint value). *) 3539 IF (et # SymTab.InvalidType) 3540 AND (SymTab.ClassOf(et) # SymTab.ClChar) 3541 AND NOT SymTab.IsIntFamily(et) THEN 3542 SemError(211) END; 3543 t := SymTab.UCharType(); .) 3544 | "CHR8" "(" Expr ")" 3545 (. astNode := AST.MakeNode(AST.NkCall); 3546 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR8")); 3547 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3548 astCur := astNode; astIsLit := TRUE; .) 3549 (. IF (et # SymTab.InvalidType) 3550 AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN 3551 SemError(211) END; 3552 QbeGen.WidenLong(q, qa); 3553 QbeGen.CheckRange(qa, "0", "255"); 3554 t := SymTab.CharType(); .) 3555 | "UORD" "(" Expr ")" 3556 (. astNode := AST.MakeNode(AST.NkCall); 3557 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UORD")); 3558 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3559 astCur := astNode; astIsLit := TRUE; .) 3560 (. (* UORD(u): the codepoint as a 3561 32-bit ordinal (INTEGER), 3562 cf. ORD for CHAR. *) 3563 IF (et # SymTab.InvalidType) 3564 AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN 3565 SemError(211) END; 3566 t := SymTab.IntType(); .) 3567 | "ABS" "(" Expr ")" 3568 (. astNode := AST.MakeNode(AST.NkCall); 3569 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ABS")); 3570 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3571 astCur := astNode; astIsLit := TRUE; .) 3572 (. IF (et # SymTab.InvalidType) 3573 AND NOT SymTab.IsIntFamily(et) 3574 AND (SymTab.ClassOf(et) # 3575 SymTab.ClReal) THEN 3576 SemError(211) 3577 ELSE QbeGen.AbsQ(q, qa, 3578 SymTab.ClassOf(et) = 3579 SymTab.ClReal); 3580 QbeGen.CopyOp(qa, q) 3581 END; 3582 t := et; .) 3583 | "VAL" "(" GetIdent (. astArg2 := AST.MakeLeaf(AST.NkIdent, vn); .) "," Expr ")" 3584 (. astNode := AST.MakeNode(AST.NkCall); 3585 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL")); 3586 IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END; 3587 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END; 3588 astCur := astNode; astIsLit := TRUE; .) 3589 (. IF NOT SymTab.Lookup(vn) THEN 3590 SemError(201); 3591 t := SymTab.InvalidType 3592 ELSE vt := SymTab.SymType(vn); 3593 IF vt = SymTab.InvalidType THEN 3594 t := SymTab.InvalidType 3595 ELSIF et = 3596 SymTab.InvalidType THEN 3597 t := vt 3598 ELSE 3599 c1 := SymTab.ClassOf(et); 3600 c2 := SymTab.ClassOf(vt); 3601 IF (c1 = SymTab.ClInt) 3602 AND (c2 = SymTab.ClLong) THEN 3603 QbeGen.WidenLong(q, qa); 3604 QbeGen.CopyOp(qa, q); 3605 t := vt 3606 ELSIF (c1 = SymTab.ClLong) 3607 AND (c2 = SymTab.ClInt) THEN 3608 QbeGen.NarrowLong(q, qa); 3609 QbeGen.CopyOp(qa, q); 3610 t := vt 3611 ELSIF (c1 = SymTab.ClInt) 3612 AND (c2 = SymTab.ClReal) THEN 3613 QbeGen.ConvIR(q, qa); 3614 QbeGen.CopyOp(qa, q); 3615 t := vt 3616 ELSIF (c1 = SymTab.ClLong) 3617 AND (c2 = SymTab.ClReal) THEN 3618 QbeGen.ConvLR(q, qa); 3619 QbeGen.CopyOp(qa, q); 3620 t := vt 3621 ELSIF (c1 = SymTab.ClReal) 3622 AND (c2 = SymTab.ClInt) THEN 3623 QbeGen.ConvRI(q, qa); 3624 QbeGen.CopyOp(qa, q); 3625 t := vt 3626 ELSIF (c1 = SymTab.ClReal) 3627 AND (c2 = SymTab.ClLong) THEN 3628 QbeGen.ConvRL(q, qa); 3629 QbeGen.CopyOp(qa, q); 3630 t := vt 3631 ELSIF ((c1 = SymTab.ClInt) 3632 OR (c1 = 3633 SymTab.ClChar) 3634 OR (c1 = 3635 SymTab.ClBool) 3636 OR (c1 = 3637 SymTab.ClEnum)) 3638 AND ((c2 = SymTab.ClInt) 3639 OR (c2 = 3640 SymTab.ClChar) 3641 OR (c2 = 3642 SymTab.ClBool) 3643 OR (c2 = 3644 SymTab.ClEnum)) THEN 3645 t := vt 3646 ELSIF (c1 = SymTab.ClPtr) 3647 AND (c2 = SymTab.ClPtr) THEN 3648 t := vt 3649 ELSIF (c1 = SymTab.ClReal) 3650 AND (c2 = SymTab.ClReal) THEN 3651 t := vt 3652 ELSE SemError(230); 3653 t := SymTab.InvalidType 3654 END 3655 END 3656 END; .) 3657 | "(" Expr ")" (. t := et; astIsLit := TRUE; .) 3658 | SetLit (. astIsLit := TRUE; t := st; 3659 QbeGen.CopyOp(sq, q); .) 3660 | ( "NOT" | "~" ) Fact (. astNot := astCur; 3661 IF SymTab.BoolCheck(t2) THEN 3662 t := SymTab.BoolType() 3663 ELSE SemError(212); 3664 t := SymTab.InvalidType END; 3665 IF t # SymTab.InvalidType THEN 3666 QbeGen.NotQ(q2, q) 3667 ELSE QbeGen.CopyOp("0", q) 3668 END; 3669 astIsLit := TRUE; 3670 astCur := AST.MakeUn( 3671 AST.NkUnary, AST.OpNot, astNot); .) 3672 ) 3673 (. IF NOT astIsLit THEN astCur := AST.NoNode END; .) . 3674 (* Set literals are SET OF [0..255] (8 words); elements validated 3675 0..255 statically when foldable (222 otherwise), runtime trap 3676 for computed elements. Ranges always lower via SetRange. *) 3677 SetLit 3678 (. VAR astNode: AST.Node; .) 3679 = "{" (. t := SymTab.NewSet( 3680 SymTab.NewSubR(0, 255)); 3681 astNode := AST.MakeNode(AST.NkSetLit); 3682 QbeGen.NewSetTemp(8, q); 3683 QbeGen.SetZero(q, 8); .) 3684 [ SetElem { "," SetElem } ] 3685 "}" (. astCur := astNode; .) . 3686 (* Typed brace constructor: TypeName{ elems } — BITSET{0} (a set) 3687 or ArrayName{...} (an array constructor, GNU Modula-2). The 3688 declared type sets the width (set) or element type (array). *) 3689 TypedBraceLit 3690 (. VAR nw: CARDINAL; 3691 astNode, astTail: AST.Node; 3692 savedCls: INTEGER; .) 3693 = "{" (. savedCls := braceCls; 3694 astNode := AST.MakeNode(AST.NkBraceLit); 3695 AST.SetTy(astNode, vt); 3696 astTail := astNode; 3697 IF vt = SymTab.InvalidType THEN 3698 braceCls := -1 3699 ELSE braceCls := 3700 SymTab.ClassOf(vt) 3701 END; 3702 IF braceCls = SymTab.ClSet THEN 3703 IF vt = SymTab.InvalidType THEN 3704 nw := 8 3705 ELSE nw := SymTab.SetWords(vt); 3706 IF nw = 0 THEN nw := 8 END 3707 END; 3708 QbeGen.NewSetTemp(nw, q); 3709 QbeGen.SetZero(q, nw) 3710 ELSIF (braceCls = 3711 SymTab.ClArray) 3712 OR (braceCls = 3713 SymTab.ClRecord) 3714 OR (braceCls = 3715 SymTab.ClClass) THEN 3716 QbeGen.CtorBegin(vt) 3717 ELSE 3718 IF vt # SymTab.InvalidType THEN 3719 SemError(230) END; 3720 braceCls := -1 3721 END; .) 3722 [ BraceElem 3723 { "," BraceElem } ] 3724 "}" (. IF (braceCls = SymTab.ClArray) 3725 OR (braceCls = 3726 SymTab.ClRecord) 3727 OR (braceCls = 3728 SymTab.ClClass) THEN 3729 QbeGen.CtorEnd(q) 3730 ELSIF braceCls # SymTab.ClSet THEN 3731 QbeGen.CopyOp("0", q) 3732 END; 3733 braceCls := savedCls; .) 3734 (. astCur := astNode; .) . 3735 BraceElem 3737 (. VAR et, et2: SymTab.TypeIndex; 3738 qe, q2: QbeGen.QVal; 3739 v, v2, reps, k: INTEGER; 3740 elem: SymTab.TypeIndex; 3741 lo: INTEGER; 3742 span: CARDINAL; 3743 cl, cl2: INTEGER; 3744 hasR, hasB: BOOLEAN; 3745 astEl: AST.Node; .) 3746 = (. hasR := FALSE; hasB := FALSE; 3747 reps := 1; .) 3748 Expr (. astEl := astCur; .) 3749 [ ".." Expr (. astEl := AST.MakeBin( 3750 AST.NkSubrange, 0, astEl, astCur); 3751 hasR := TRUE; .) ] 3752 [ "BY" Expr (. hasB := TRUE; .) ] 3753 (. IF braceCls = SymTab.ClSet THEN 3754 IF hasB THEN SemError(230) END; 3755 lo := SymTab.SetBaseLo(vt); 3756 span := SymTab.SetCount(vt); 3757 IF (et = SymTab.InvalidType) 3758 OR (hasR AND (et2 = 3759 SymTab.InvalidType)) THEN 3760 ELSE cl := 3761 SymTab.ClassOf(et); 3762 IF hasR THEN 3763 cl2 := 3764 SymTab.ClassOf(et2) 3765 ELSE cl2 := SymTab.ClInt 3766 END; 3767 IF NOT SymTab.SetElemClassOk(cl) 3768 OR (hasR AND NOT 3769 SymTab.SetElemClassOk(cl2)) 3770 THEN 3771 SemError(222) 3772 ELSIF hasR 3773 AND SymTab.ConstInt(qe, v) 3774 AND SymTab.ConstInt(q2, 3775 v2) 3776 AND ((v < lo) 3777 OR (v2 < lo) 3778 OR (v >= lo + 3779 VAL(INTEGER, span)) 3780 OR (v2 >= lo + 3781 VAL(INTEGER, span)) 3782 OR (v > v2)) THEN 3783 SemError(222) 3784 ELSIF hasR THEN 3785 QbeGen.SetRange(sq, qe, q2, 3786 lo, span) 3787 ELSIF SymTab.ConstInt(qe, 3788 v) 3789 AND ((v < lo) 3790 OR (v >= lo + 3791 VAL(INTEGER, 3792 span))) THEN 3793 SemError(222) 3794 ELSE QbeGen.SetBit(sq, qe, 3795 lo, span) 3796 END 3797 END 3798 ELSIF (braceCls = SymTab.ClArray) 3799 OR (braceCls = 3800 SymTab.ClRecord) 3801 OR (braceCls = 3802 SymTab.ClClass) THEN 3803 IF hasR THEN SemError(230) END; 3804 reps := 1; 3805 IF hasB THEN 3806 IF SymTab.ConstInt(q2, v2) 3807 AND (v2 >= 1) THEN 3808 reps := v2 3809 ELSE SemError(230) 3810 END 3811 END; 3812 k := 0; 3813 WHILE k < reps DO 3814 QbeGen.CtorElem(qe); 3815 INC(k) 3816 END 3817 END; .) 3818 (. (* the BY form repeats the 3819 element; keep the AST in 3820 step with CtorElem *) 3821 k := 0; 3822 WHILE k < reps DO 3823 AstAppend(AST.NkBlock, 3824 node, tail, astEl); 3825 INC(k) 3826 END; .) . 3827 SetElem (. VAR et, et2: SymTab.TypeIndex; 3828 qe, q2: QbeGen.QVal; 3829 v, v2: INTEGER; 3830 lo: INTEGER; 3831 span: CARDINAL; 3832 cl, cl2: INTEGER; 3833 hasR: BOOLEAN; 3834 astEl: AST.Node; .) 3835 = (. hasR := FALSE; .) 3836 Expr (. astEl := astCur; .) 3837 [ ".." Expr (. astEl := AST.MakeBin( 3838 AST.NkSubrange, 0, astEl, astCur); 3839 hasR := TRUE; .) ] 3840 (. lo := SymTab.SetBaseLo(st); 3841 span := SymTab.SetCount(st); 3842 IF (et = SymTab.InvalidType) 3843 OR (hasR AND (et2 = 3844 SymTab.InvalidType)) THEN 3845 ELSE cl := 3846 SymTab.ClassOf(et); 3847 IF hasR THEN 3848 cl2 := 3849 SymTab.ClassOf(et2) 3850 ELSE cl2 := SymTab.ClInt 3851 END; 3852 IF NOT SymTab.SetElemClassOk(cl) 3853 OR (hasR AND NOT 3854 SymTab.SetElemClassOk(cl2)) 3855 THEN 3856 SemError(222) 3857 ELSIF hasR 3858 AND SymTab.ConstInt(qe, v) 3859 AND SymTab.ConstInt(q2, 3860 v2) 3861 AND ((v < lo) 3862 OR (v2 < lo) 3863 OR (v >= lo + 3864 VAL(INTEGER, span)) 3865 OR (v2 >= lo + 3866 VAL(INTEGER, span)) 3867 OR (v > v2)) THEN 3868 SemError(222) 3869 ELSIF hasR THEN 3870 QbeGen.SetRange(sq, qe, q2, 3871 lo, span) 3872 ELSIF SymTab.ConstInt(qe, 3873 v) 3874 AND ((v < lo) 3875 OR (v >= lo + 3876 VAL(INTEGER, 3877 span))) THEN 3878 SemError(222) 3879 ELSE QbeGen.SetBit(sq, qe, 3880 lo, span) 3881 END 3882 END; .) 3883 (. AST.SetChild(node, 3884 AST.NChild(node), astEl); .) . 3885 GetIdent 3886 = ident (. LexName(n); .) . 3887 3888 END M2. 0 errors Statistics: nr of terminals: 104 (limit 400) nr of non-terminals: 85 (limit 210) nr of pragmas: 0 (limit 396) nr of symbolnodes: 189 (limit 500) nr of graphnodes: 1114 (limit 1500) nr of conditionsets: 11 (limit 100) nr of charactersets: 16 (limit 250)