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 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; 55 56 CHARACTERS 57 eol = CHR(13) . 58 lf = CHR(10) . 59 letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" . 60 digit = "0123456789" . 61 hexDigit = digit + "ABCDEFabcdef" . 62 noQuote1 = ANY - "'" - eol . 63 noQuote2 = ANY - '"' - eol . 64 65 IGNORE CHR(9) .. CHR(13) 66 67 COMMENTS FROM "(*" TO "*)" NESTED 68 COMMENTS FROM "//" TO lf 69 70 TOKENS 71 ident = letter { letter | digit } . 72 integer = digit { digit } 73 | digit { digit } CONTEXT("..") 74 | "0x" hexDigit { hexDigit } 75 | "0X" hexDigit { hexDigit } . 76 real = digit { digit } "." { digit } 77 [ ( "E" | "e" ) [ "+" | "-" ] digit { digit } ] . 78 string = "'" { noQuote1 } "'" 79 | '"' { noQuote2 } '"' . 80 81 PRODUCTIONS 82 M2 83 = Unit "." . 84 (* Units: program modules compile fully; DEFINITION and 85 IMPLEMENTATION modules parse + check now but lower in step 4 86 (each ends with one 230); same for nested local modules. *) 87 Unit 88 = DefUnit 89 | ImplUnit 90 | ProgModule . 91 (* Step 4.3: one session compiles DEFINITION, its IMPLEMENTATION 92 and one program (last) into one image. Units share the symbol 93 table; imports materialize exported names. *) 94 DefUnit (. VAR m1, m2, pn: SymTab.Name; .) 95 = "DEFINITION" "MODULE" 96 GetIdent (. IF ~SymTab.BeginDef(m1) THEN 97 SemError(200) END; .) 98 ";" 99 { Import } 100 { ConstBlock | TypeBlock | VarBlock 101 | ProcHeading ";" (. SymTab.CloseProc; 102 QbeGen.AbortFunc; .) } 103 "END" 104 GetIdent (. IF ~SymTab.Equal(m1, m2) THEN 105 SemError(202) END; 106 SymTab.EndUnit; .) . 107 ImplUnit (. VAR m1, m2: SymTab.Name; .) 108 = "IMPLEMENTATION" "MODULE" 109 GetIdent (. IF ~SymTab.BeginImpl(m1) THEN 110 SemError(201) END; .) 111 ";" 112 { Import } 113 DeclSeq 114 [ "BEGIN" (. QbeGen.BeginInit(m1); .) 115 [ StatSeq ] (. QbeGen.EndInit; .) ] 116 "END" 117 GetIdent (. IF ~SymTab.Equal(m1, m2) THEN 118 SemError(202) END; 119 SymTab.EndUnit; .) . 120 ProgModule (. VAR m1, m2: SymTab.Name; .) 121 = "MODULE" 122 GetIdent (. IF ~SymTab.BeginProg(m1) THEN 123 SemError(200) END; .) 124 [ Priority ] 125 ";" 126 { Import } 127 DeclSeq 128 [ "BEGIN" (. QbeGen.BeginBody; .) 129 [ StatSeq ] ] 130 "END" 131 GetIdent (. IF ~SymTab.Equal(m1, m2) THEN 132 SemError(202) END; 133 QbeGen.EndModule(m1); 134 SymTab.EndUnit; .) . 135 DeclSeq 136 = { ConstBlock | TypeBlock | VarBlock | ProcDecl ";" 137 | NestedModule ";" | ClassItem ";" } . 138 (* Local module, Wirth form. Parses + checks fully (own scope); 139 lowering waits for step 4, marked by one 230 at END. *) 140 NestedModule (. VAR m1, m2: SymTab.Name; .) 141 = "MODULE" 142 GetIdent (. IF ~SymTab.Enter(m1, 143 SymTab.KindModule) THEN 144 SemError(200) END; 145 SymTab.PushScope; .) 146 [ Priority ] 147 ";" 148 { Import } 149 [ Export ] 150 DeclSeq 151 [ "BEGIN" 152 [ StatSeq ] ] 153 "END" 154 GetIdent (. IF ~SymTab.Equal(m1, m2) THEN 155 SemError(202) END; 156 SymTab.PopScope; 157 SemError(230); .) . 158 Priority 159 = "[" integer "]" (. SemError(230); .) . 160 Export (. VAR nm: SymTab.Name; .) 161 = "EXPORT" (* names wire up in step 4 *) 162 [ "QUALIFIED" ] 163 GetIdent 164 { "," GetIdent } 165 ";" . 166 (* Imports (4.3): FROM materializes the names (unqualified use); 167 plain IMPORT only demands the module exists — qualified `L.x` 168 materializes on first use (Design). *) 169 (* Unknown modules stay unchecked stubs (legacy, so hand-written 170 import lines don't fail); a known module's missing export is 171 201. *) 172 Import (. VAR n: SymTab.Name; .) 173 = "FROM" 174 GetIdent 175 "IMPORT" 176 ImpList ";" 177 | "IMPORT" 178 ImpModList ";" . 179 ImpList (. VAR n: SymTab.Name; .) 180 = GetIdent (. IF SymTab.ModKnown(mod) 181 & ~SymTab.ImportFrom(mod, n) THEN 182 SemError(201) END; .) 183 { "," 184 GetIdent (. IF SymTab.ModKnown(mod) 185 & ~SymTab.ImportFrom(mod, n) THEN 186 SemError(201) END; .) } . 187 ImpModList (. VAR n: SymTab.Name; .) 188 = GetIdent 189 { "," GetIdent } . 190 (* Opaque TYPE declarations (definition modules). The targetless 191 alias resolves to InvalidType until step 4 completes it. *) 192 (* Scalar-phase TYPEs: named types, integer subranges, enumerations. 193 Opaque "TYPE T;" needs isDef (definition units); elsewhere 231. 194 Composite forms (ARRAY/RECORD/SET/POINTER) arrive with step 3. *) 195 TypeBlock 196 = "TYPE" { TypeItem ";" | ClassItem ";" } . 197 TypeItem (. VAR n: SymTab.Name; 198 t, op: SymTab.TypeIndex; .) 199 = GetIdent (. op := SymTab.OpaqueBase(n); 200 IF op = SymTab.InvalidType THEN 201 IF ~SymTab.Enter(n, 202 SymTab.KindType) THEN 203 SemError(200) END 204 END; .) 205 ( "=" Type (. IF op # SymTab.InvalidType THEN 206 SymTab.SetTarget(op, t) 207 ELSE SymTab.SetSymType(n, t) 208 END; .) 209 | (. IF op # SymTab.InvalidType THEN 210 (* stays opaque *) 211 ELSIF ~isDef THEN 212 SemError(231) 213 ELSE SymTab.SetSymType(n, 214 SymTab.NewAlias()) END; .) ) . 215 Type 216 = TypeIdent 217 | Subrange 218 | Enum 219 | ArrayType 220 | SetType 221 | RecordType 222 | PointerType . 223 PointerType (. VAR base: SymTab.TypeIndex; .) 224 = "POINTER" "TO" Type(. t := SymTab.NewPtr(base); .) . 225 (* Arrays: "OF" without bounds is an open formal (allowed only 226 where allowOpen); "[lo..hi, ...]" nests bounded levels inside 227 out. Bounds are folded literals (int/char); anything else 230. 228 Bare-type indices ("ARRAY Color OF") wait for enum ordinals. *) 229 ArrayType 230 (. VAR elem: SymTab.TypeIndex; 231 ok: BOOLEAN; .) 232 = "ARRAY" 233 ( "OF" Type (. IF ~allowOpen THEN 234 SemError(230) END; 235 t := SymTab.NewOpenArray(elem); .) 236 | "[" (. SymTab.BoundBegin; ok := TRUE; .) 237 BoundPair 238 { "," BoundPair } 239 "]" "OF" Type 240 (. IF ok THEN 241 t := SymTab.NestArray(elem) 242 ELSE t := SymTab.InvalidType 243 END; .) ) . 244 BoundPair (. VAR tlo, thi: SymTab.TypeIndex; 245 qlo, qhi: QbeGen.QVal; 246 lo, hi: INTEGER; 247 cl, cl2: INTEGER; .) 248 = Expr ".." Expr 249 (. IF (tlo = SymTab.InvalidType) 250 OR (thi = SymTab.InvalidType) THEN 251 ok := FALSE 252 ELSE cl := SymTab.ClassOf(tlo); 253 cl2 := SymTab.ClassOf(thi); 254 IF ((cl # SymTab.ClInt) 255 & (cl # SymTab.ClChar)) 256 OR ((cl2 # SymTab.ClInt) 257 & (cl2 # SymTab.ClChar)) THEN 258 SemError(230); ok := FALSE 259 ELSIF ~SymTab.ConstInt(qlo, lo) 260 OR ~SymTab.ConstInt(qhi, hi) 261 OR (lo > hi) THEN 262 SemError(230); ok := FALSE 263 ELSIF ~SymTab.BoundAdd(lo, hi) THEN 264 SemError(230); ok := FALSE 265 END; 266 END; .) . 267 (* Sets: multi-word masks over bases ≤ 256 values (bool, char, 268 bounded subranges; enums wait for ordinals, INTEGER is 269 unbounded). Literals are SET OF [0..255]; assignment and 270 comparison across suitable bases are lenient (masks over min 271 words + zero-check extras), out-of-span literals are 222. *) 272 SetType (. VAR base: SymTab.TypeIndex; 273 blo, bhi, bspan: INTEGER; 274 bcls: INTEGER; .) 275 = "SET" "OF" Type 276 (. IF base = SymTab.InvalidType THEN 277 t := SymTab.InvalidType 278 ELSE bcls := 279 SymTab.ClassOf(base); 280 IF bcls = SymTab.ClBool THEN 281 blo := 0; bspan := 2 282 ELSIF bcls = SymTab.ClChar THEN 283 blo := 0; bspan := 256 284 ELSIF SymTab.SubBounds(base, 285 blo, bhi) THEN 286 bspan := bhi - blo + 1 287 ELSE bspan := 0 END; 288 IF (bspan <= 0) 289 OR (bspan > 256) THEN 290 SemError(230); 291 t := SymTab.InvalidType 292 ELSE t := SymTab.NewSet(base) 293 END 294 END; .) . 295 (* Records: flat blobs; array fields are pointers to static 296 descriptors (locked amendment), nested records inline. Field 297 offsets static and declaration-ordered. *) 298 RecordType (. VAR t2: SymTab.TypeIndex; .) 299 = "RECORD" (. t := SymTab.NewRecord(); .) 300 [ RecField { ";" RecField } ] 301 "END" . 302 RecField (. VAR n: SymTab.Name; 303 t2: SymTab.TypeIndex; .) 304 = RecIdents ":" Type(. SymTab.FixPendingF(rec, t2); .) . 305 RecIdents (. VAR n: SymTab.Name; .) 306 = GetIdent (. IF ~SymTab.FieldPending(rec, 307 n) THEN 308 SemError(200) END; .) 309 { "," GetIdent (. IF ~SymTab.FieldPending(rec, 310 n) THEN 311 SemError(200) END; .) } . 312 TypeIdent (. VAR n: SymTab.Name; 313 k: INTEGER; .) 314 = GetIdent (. IF ~SymTab.Lookup(n) THEN 315 SemError(201); 316 t := SymTab.InvalidType 317 ELSE k := SymTab.SymKind(n); 318 IF (k = SymTab.KindType) 319 OR (k = SymTab.KindPredef) THEN 320 t := SymTab.SymType(n) 321 ELSIF k = SymTab.KindImport THEN 322 t := SymTab.InvalidType 323 ELSE SemError(221); 324 t := SymTab.InvalidType 325 END 326 END; .) . 327 Subrange (. VAR tlo, thi: SymTab.TypeIndex; 328 qlo, qhi: QbeGen.QVal; 329 lo, hi: INTEGER; .) 330 = "[" Expr ".." Expr 331 (. IF (tlo = SymTab.InvalidType) 332 OR (thi = SymTab.InvalidType) THEN 333 t := SymTab.InvalidType 334 ELSIF (SymTab.ClassOf(tlo) # 335 SymTab.ClInt) 336 OR (SymTab.ClassOf(thi) # 337 SymTab.ClInt) THEN 338 SemError(230); 339 t := SymTab.InvalidType 340 ELSIF ~SymTab.ConstInt(qlo, lo) 341 OR ~SymTab.ConstInt(qhi, hi) 342 OR (lo > hi) THEN 343 SemError(230); 344 t := SymTab.InvalidType 345 ELSE t := SymTab.NewSubR(lo, hi) 346 END; .) 347 "]" . 348 Enum (. VAR n: SymTab.Name; .) 349 = "(" (. t := SymTab.NewEnum(); .) 350 GetIdent (. IF ~SymTab.Enter(n, 351 SymTab.KindConst) THEN 352 SemError(200) END; 353 SymTab.SetSymType(n, t); .) 354 { "," GetIdent (. IF ~SymTab.Enter(n, 355 SymTab.KindConst) THEN 356 SemError(200) END; 357 SymTab.SetSymType(n, t); .) } 358 ")" . 359 (* Clarion-form classes (docs/OOP.txt): declaration + single 360 inheritance + IMPLEMENTATION blocks. Scopes and member checks 361 now; lowering (vtable, dispatch, THIS) later — one 230 per 362 class/impl block. Methods end with ";" per the Table example 363 (not "," as in the sketch). No underscores in identifiers. *) 364 (* Single CLASS item in both loops: separating declaration from 365 IMPLEMENTATION at the loop level needs 2-token lookahead 366 (CLASS ident vs CLASS IMPLEMENTATION), which LL(1) cannot do. 367 The second token decides after CLASS is consumed. A misplaced 368 CLASS IMPLEMENTATION inside TYPE still parses (harmless: the 369 whole unit ends 230 until lowering). *) 370 ClassItem 371 = "CLASS" ( "IMPLEMENTATION" ClassImplRest | ClassRest ) . 372 ClassRest (. VAR cn, m2, pn: SymTab.Name; 373 ct: SymTab.TypeIndex; .) 374 = GetIdent (. IF ~SymTab.Enter(cn, 375 SymTab.KindType) THEN 376 SemError(200) END; 377 ct := SymTab.NewClass(); 378 SymTab.SetSymType(cn, ct); 379 SymTab.PushClassScope(ct); .) 380 [ Parents ] 381 ";" 382 { ClassField ";" } 383 { MethodHeading ";" (. SymTab.CloseProc; 384 QbeGen.AbortFunc; .) } 385 "END" 386 GetIdent (. IF ~SymTab.Equal(cn, m2) THEN 387 SemError(202) END; 388 SymTab.PopScope; 389 SemError(230); .) . 390 Parents (. VAR p: SymTab.Name; .) 391 = "(" Parent1 392 { "," GetIdent

(. SemError(230); .) } 393 ")" . 394 Parent1 (. VAR p: SymTab.Name; 395 pt: SymTab.TypeIndex; .) 396 = GetIdent

(. IF ~SymTab.Lookup(p) THEN 397 SemError(201) 398 ELSE pt := SymTab.SymType(p); 399 IF SymTab.ClassOf(pt) # 400 SymTab.ClClass THEN 401 SemError(230) 402 ELSE SymTab.SetParent(ct, pt) 403 END 404 END; .) . 405 ClassField (. VAR n, rhs: SymTab.Name; 406 t: SymTab.TypeIndex; .) 407 = GetIdent 408 ( "=" GetIdent (. IF ~SymTab.Enter(n, 409 SymTab.KindConst) THEN 410 SemError(200) END; 411 IF SymTab.Lookup(rhs) THEN 412 SymTab.SetSymType(n, 413 SymTab.SymType(rhs)) 414 END; .) 415 | (. IF ~SymTab.FieldPending(ct, 416 n) THEN 417 SemError(200) END; .) 418 { "," GetIdent (. IF ~SymTab.FieldPending(ct, 419 n) THEN 420 SemError(200) END; .) } 421 ":" Type (. SymTab.FixPendingF(ct, t); .) ) . 422 MethodHeading (. VAR wantVirt: BOOLEAN; .) 423 = (. wantVirt := FALSE; .) 424 [ "VIRTUAL" (. wantVirt := TRUE; .) ] 425 ProcHeading (. IF wantVirt THEN 426 SymTab.MarkVirtual END; .) . 427 ClassImplRest (. VAR cn, m2: SymTab.Name; 428 ct: SymTab.TypeIndex; .) 429 = GetIdent (. IF ~SymTab.Lookup(cn) THEN 430 SemError(201); 431 ct := SymTab.InvalidType 432 ELSE ct := SymTab.SymType(cn); 433 IF SymTab.ClassOf(ct) # 434 SymTab.ClClass THEN 435 SemError(230); 436 ct := SymTab.InvalidType 437 END 438 END; 439 IF ct # 440 SymTab.InvalidType THEN 441 IF ~SymTab.PushClassMembers( 442 ct) THEN 443 SemError(230) END 444 END; .) 445 ";" { MethodImpl ";" } 446 [ "BEGIN" 447 [ StatSeq ] ] 448 "END" 449 GetIdent (. IF ~SymTab.Equal(cn, m2) THEN 450 SemError(202) END; 451 SymTab.PopScope; 452 SemError(230); .) . 453 MethodImpl (. VAR pn: SymTab.Name; .) 454 = (. QbeGen.SetNoEmit(TRUE); .) 455 MethodHeading ";" 456 (. IF (ct # 457 SymTab.InvalidType) 458 & ~SymTab.MethodExists(ct, 459 pn) THEN 460 SemError(201) END; .) 461 ( "FORWARD" (. SymTab.MarkFwd; 462 SymTab.CloseProc; .) 463 | Block (. SymTab.CloseProc; .) ) 464 (. QbeGen.AbortFunc; 465 QbeGen.SetNoEmit(FALSE); 466 SemError(230); .) . 467 ConstBlock 468 = "CONST" { ConstDecl ";" } . 469 ConstDecl (. VAR n: SymTab.Name; 470 t: SymTab.TypeIndex; 471 qv: QbeGen.QVal; 472 cls: INTEGER; .) 473 = GetIdent (. IF ~SymTab.Enter(n, 474 SymTab.KindConst) THEN 475 SemError(200) END; .) 476 "=" 477 Expr (. SymTab.SetSymType(n, t); 478 cls := SymTab.ClassOf(t); 479 IF cls = SymTab.ClStr THEN 480 SemError(230) 481 ELSIF ~QbeGen.IsImm(qv) THEN 482 SemError(230) END; 483 QbeGen.DeclConst(n, qv, t); .) . 484 VarBlock 485 = "VAR" { VarDecl ";" } . 486 VarDecl (. VAR nm: SymTab.Name; 487 t: SymTab.TypeIndex; 488 i: CARDINAL; 489 cls: INTEGER; .) 490 = VarIdents ":" 491 Type (. cls := SymTab.ClassOf(t); 492 IF (t # SymTab.InvalidType) 493 & (cls # SymTab.ClInt) 494 & (cls # SymTab.ClBool) 495 & (cls # SymTab.ClChar) 496 & (cls # SymTab.ClReal) 497 & (cls # SymTab.ClArray) 498 & (cls # SymTab.ClSet) 499 & (cls # SymTab.ClRecord) 500 & (cls # SymTab.ClPtr) THEN 501 SemError(230) END; 502 IF QbeGen.LocFull() THEN 503 SemError(233) END; 504 i := 0; 505 WHILE i < SymTab.PendCount() DO 506 SymTab.PendName(i, nm); 507 QbeGen.DeclVar(nm, t); 508 INC(i) 509 END; 510 SymTab.FixPending(t); .) . 511 VarIdents (. VAR n: SymTab.Name; .) 512 = GetIdent (. IF ~SymTab.EnterPending(n, 513 SymTab.KindVar) THEN 514 SemError(200) END; .) 515 { "," 516 GetIdent (. IF ~SymTab.EnterPending(n, 517 SymTab.KindVar) THEN 518 SemError(200) END; .) } . 519 ParIdents (. VAR n: SymTab.Name; .) 520 = GetIdent (. IF ~SymTab.EnterParam(n, isV) THEN 521 SemError(200) END; .) 522 { "," GetIdent (. IF ~SymTab.EnterParam(n, isV) THEN 523 SemError(200) END; .) } . 524 (* Procedure headings enter scopes/params/result and buffer the 525 QBE header; bodies lower to functions (4.1, module level only). 526 FORWARD marks; the body heading re-enters (signature compare 527 deferred). Nested procedures parse + check, lowering = 4.2. *) 528 ProcHeading (. VAR t: SymTab.TypeIndex; 529 mg: QbeGen.QVal; .) 530 = "PROCEDURE" 531 GetIdent (. IF ~SymTab.EnterProc(pn) THEN 532 IF ~SymTab.ReenterProc(pn) THEN 533 IF ~SymTab.ResumeProc(pn) THEN 534 SemError(200) END 535 END 536 END; 537 QbeGen.Mangled(pn, 538 SymTab.ProcUid(pn), mg); 539 QbeGen.BeginFunc(mg); .) 540 [ FormalParams ] 541 [ ":" TypeIdent (. SymTab.SetProcRes(t); 542 QbeGen.SetFuncRes(t); 543 IF (t # 544 SymTab.InvalidType) 545 & ((SymTab.ClassOf(t) 546 = SymTab.ClArray) 547 OR (SymTab.ClassOf(t) 548 = SymTab.ClRecord) 549 OR (SymTab.ClassOf(t) 550 = SymTab.ClSet) 551 OR (SymTab.ClassOf(t) 552 = SymTab.ClClass)) THEN 553 SemError(230) END; .) ] . 554 FormalParams 555 = "(" [ ParamSection { ";" ParamSection } ] ")" . 556 ParamSection (. VAR t: SymTab.TypeIndex; 557 nm: SymTab.Name; 558 i: CARDINAL; 559 isV: BOOLEAN; .) 560 = (. isV := FALSE; .) 561 [ "VAR" (. isV := TRUE; .) ] 562 ParIdents ":" Type (. i := 0; 563 WHILE i < SymTab.PendCount() DO 564 SymTab.PendName(i, nm); 565 IF ~QbeGen.FuncParam(nm, 566 isV, t) THEN 567 SemError(233) END; 568 INC(i) 569 END; 570 SymTab.FixPending(t); 571 IF ~isV 572 & SymTab.IsOpenArray(t) THEN 573 SemError(230) END; .) . 574 (* Nested procedures lower like top-level ones (4.2): the 575 static link gives them their parent's frame. Methods keep 576 parse-now/230-later. *) 577 ProcDecl (. VAR pn: SymTab.Name; .) 578 = ProcHeading ";" 579 ( "FORWARD" (. SymTab.MarkFwd; 580 SymTab.CloseProc; 581 QbeGen.AbortFunc; .) 582 | "EXTERNAL" (. SymTab.MarkExternal(""); 583 SymTab.CloseProc; 584 QbeGen.AbortFunc; .) 585 | (. QbeGen.EndFuncHeader; .) 586 Block (. SymTab.CloseProc; 587 QbeGen.EndFunc( 588 SymTab.ProcRes(pn)); .) ) . 589 Block (. VAR m2: SymTab.Name; .) 590 = DeclSeq 591 [ "BEGIN" 592 [ StatSeq ] ] 593 "END" 594 GetIdent (. IF ~SymTab.Equal(pn, m2) THEN 595 SemError(202) END; .) . 596 StatSeq 597 = Statement { ";" Statement } . 598 Statement (. VAR lx: QbeGen.QVal; .) 599 = AssOrCall 600 | IfStat 601 | WhileStat 602 | RepeatStat 603 | LoopStat 604 | ForStat 605 | CaseStat 606 | WithStat 607 | ReturnStat 608 | NewStat 609 | DisposeStat 610 | "EXIT" (. IF QbeGen.TopLoop(lx) THEN 611 QbeGen.Jmp(lx) 612 ELSE SemError(230) END; .) . 613 (* NEW/DISPOSE as builtin statements (no call syntax until step 4). 614 Targets are pointer designators; DISPOSE nils afterwards (safer 615 than Wirth-undefined; documented). DISPOSE is shallow. *) 616 NewStat (. VAR dt: SymTab.TypeIndex; 617 dk: INTEGER; 618 qd, qm: QbeGen.QVal; 619 qn: SymTab.Name; 620 sfx: BOOLEAN; 621 bt: SymTab.TypeIndex; .) 622 = "NEW" "(" Design ")" 623 (. IF dt = SymTab.InvalidType THEN 624 ELSIF (dk # SymTab.KindVar) 625 & (dk # SymTab.KindParam) 626 & (dk # SymTab.KindField) THEN 627 SemError(210) 628 ELSIF SymTab.ClassOf(dt) # 629 SymTab.ClPtr THEN 630 SemError(219) 631 ELSE bt := SymTab.PtrBase(dt); 632 IF bt # 633 SymTab.InvalidType THEN 634 QbeGen.NewHeap(bt, qm); 635 QbeGen.InitHeap(qm, bt); 636 IF sfx 637 OR (dk = 638 SymTab.KindField) THEN 639 QbeGen.ElemStore(qd, qm, 640 dt) 641 ELSE QbeGen.StorePtr(qn, 642 qm) 643 END 644 END 645 END; .) . 646 DisposeStat (. VAR dt: SymTab.TypeIndex; 647 dk: INTEGER; 648 qd, qv: QbeGen.QVal; 649 qn: SymTab.Name; 650 sfx: BOOLEAN; .) 651 = "DISPOSE" "(" Design ")" 652 (. IF dt = SymTab.InvalidType THEN 653 ELSIF (dk # SymTab.KindVar) 654 & (dk # SymTab.KindParam) 655 & (dk # SymTab.KindField) THEN 656 SemError(210) 657 ELSIF SymTab.ClassOf(dt) # 658 SymTab.ClPtr THEN 659 SemError(219) 660 ELSE 661 IF sfx 662 OR (dk = 663 SymTab.KindField) THEN 664 QbeGen.ElemLoad(qd, dt, 665 qv) 666 ELSE QbeGen.LoadPtr(qn, qv) 667 END; 668 QbeGen.FreeHeap(qv); 669 IF sfx 670 OR (dk = 671 SymTab.KindField) THEN 672 QbeGen.ElemStore(qd, "0", 673 dt) 674 ELSE QbeGen.StorePtr(qn, 675 "0") 676 END 677 END; .) . 678 (* WITH pushes each record's fields (inner wins) plus its base 679 address; field designators resolve through both stacks. *) 680 WithStat (. VAR nW: CARDINAL; .) 681 = "WITH" (. nW := 0; .) 682 WithItem { "," WithItem } 683 "DO" StatSeq "END" 684 (. WHILE nW > 0 DO 685 SymTab.PopScope; 686 QbeGen.PopWith; 687 DEC(nW) 688 END; .) . 689 WithItem (. VAR dt: SymTab.TypeIndex; 690 dk: INTEGER; 691 qd, qe: QbeGen.QVal; 692 qn: SymTab.Name; 693 sfx: BOOLEAN; .) 694 = Design 695 (. IF dt = SymTab.InvalidType THEN 696 ELSIF (SymTab.ClassOf(dt) # 697 SymTab.ClRecord) 698 & (SymTab.ClassOf(dt) # 699 SymTab.ClClass) THEN 700 SemError(215) 701 ELSIF SymTab.PushRecord(dt) THEN 702 QbeGen.PushWith(qd); 703 INC(nW) 704 END; .) . 705 (* Assignment or procedure-statement call (4.1, module level). 706 Bare `P;` is a syntax error; function-as-statement is 233. *) 707 AssOrCall (. VAR dt, et: SymTab.TypeIndex; 708 dk: INTEGER; 709 qd, qe, qt: QbeGen.QVal; 710 qn: SymTab.Name; 711 ct2, res0: SymTab.TypeIndex; 712 q2, mg0: QbeGen.QVal; 713 isR, conv: BOOLEAN; 714 called, sfx: BOOLEAN; .) 715 = Design 716 ( ":=" 717 Expr (. IF (dt # SymTab.InvalidType) 718 & (dk # SymTab.KindVar) 719 & (dk # SymTab.KindParam) 720 & (dk # SymTab.KindField) THEN 721 SemError(210) 722 ELSIF ~SymTab.Assignable(et, 723 dt) THEN 724 SemError(210) 725 ELSIF (dt # SymTab.InvalidType) 726 & (SymTab.ClassOf(dt) = 727 SymTab.ClClass) THEN 728 SemError(230) END; 729 isR := (dt # 730 SymTab.InvalidType) 731 & (SymTab.ClassOf(dt) 732 = SymTab.ClReal); 733 conv := isR 734 & SymTab.IsIntFamily(et); 735 IF ((dk = SymTab.KindVar) 736 OR (dk = SymTab.KindParam) 737 OR (dk = SymTab.KindField)) 738 & (dt # SymTab.InvalidType) 739 & (et # SymTab.InvalidType) 740 & (SymTab.ClassOf(dt) # 741 SymTab.ClClass) THEN 742 IF sfx 743 OR (dk = SymTab.KindField) THEN 744 IF SymTab.ClassOf(dt) = 745 SymTab.ClArray THEN 746 QbeGen.CopyArray(qd, qe, 747 dt) 748 ELSIF SymTab.ClassOf(dt) = 749 SymTab.ClSet THEN 750 QbeGen.CopySet(qd, qe, 751 SymTab.SetWords(dt), 752 SymTab.SetWords(et)) 753 ELSIF SymTab.ClassOf(dt) = 754 SymTab.ClRecord THEN 755 QbeGen.CopyRecord(qd, qe, 756 dt) 757 ELSIF conv THEN 758 QbeGen.ConvIR(qe, qt); 759 QbeGen.ElemStore(qd, qt, 760 dt) 761 ELSE QbeGen.ElemStore(qd, qe, 762 dt) 763 END 764 ELSIF SymTab.ClassOf(dt) = 765 SymTab.ClArray THEN 766 QbeGen.CopyArray(qd, qe, dt) 767 ELSIF SymTab.ClassOf(dt) = 768 SymTab.ClSet THEN 769 QbeGen.CopySet(qd, qe, 770 SymTab.SetWords(dt), 771 SymTab.SetWords(et)) 772 ELSIF SymTab.ClassOf(dt) = 773 SymTab.ClRecord THEN 774 QbeGen.CopyRecord(qd, qe, dt) 775 ELSIF SymTab.ClassOf(dt) = 776 SymTab.ClPtr THEN 777 QbeGen.StorePtr(qn, qe) 778 ELSIF conv THEN 779 QbeGen.ConvIR(qe, qt); 780 QbeGen.StoreVar(qn, qt, TRUE) 781 ELSE 782 QbeGen.StoreVar(qn, qe, isR) 783 END 784 END; .) 785 | ArgList 786 | (* bare `P;`: proper parameterless 787 procedure call; anything else 788 here is 233 (was a bare syntax 789 error before 4.2) *) 790 (. IF (dk = SymTab.KindProc) 791 & ~sfx THEN 792 res0 := SymTab.ProcRes(qn); 793 IF res0 # 794 SymTab.InvalidType THEN 795 SemError(233) 796 ELSIF SymTab.ProcNPar(qn) # 797 0 THEN 798 SemError(233) 799 ELSE QbeGen.Mangled(qn, 800 SymTab.ProcUid(qn), mg0); 801 QbeGen.CallBegin(mg0, 802 res0, 803 SymTab.ProcDepthOf(qn), 804 SymTab.IsExternal(qn)); 805 QbeGen.CallEnd(FALSE, q2) 806 END 807 ELSE SemError(233) 808 END; .) ) . 809 (* Actual-parameter list shared by statement and expression calls. 810 want selects CallEnd's result handling; t/q carry the call 811 value (statement calls discard). Arity/type failures are 233; 812 evaluation code still emits so the .ssa stays assembleable. *) 813 ArgList (. VAR i: CARDINAL; 816 res: SymTab.TypeIndex; 817 mg: QbeGen.QVal; 818 ok: BOOLEAN; .) 819 = "(" (. called := TRUE; 820 res := SymTab.ProcRes(pn); 821 ok := TRUE; 822 IF SymTab.SymKind(pn) # 823 SymTab.KindProc THEN 824 SemError(233); ok := FALSE 825 ELSE QbeGen.Mangled(pn, 826 SymTab.ProcUid(pn), mg); 827 QbeGen.CallBegin(mg, res, 828 SymTab.ProcDepthOf(pn), 829 SymTab.IsExternal(pn)) 830 END; 831 i := 0; .) 832 [ ActParam (. INC(i); .) 833 { "," ActParam (. INC(i); .) } ] 834 ")" (. IF ok THEN 835 IF i # 836 SymTab.ProcNPar(pn) THEN 837 SemError(233); ok := FALSE 838 END 839 END; 840 IF ~ok THEN 841 t := SymTab.InvalidType; 842 QbeGen.CopyOp("0", q) 843 ELSIF want THEN 844 IF res = 845 SymTab.InvalidType THEN 846 SemError(233); 847 t := SymTab.InvalidType; 848 QbeGen.CopyOp("0", q) 849 ELSE t := res; 850 QbeGen.CallEnd(TRUE, q) 851 END 852 ELSE 853 IF res # 854 SymTab.InvalidType THEN 855 SemError(233) 856 END; 857 t := SymTab.InvalidType; 858 QbeGen.CopyOp("0", q); 859 QbeGen.CallEnd(FALSE, q) 860 END; .) . 861 (* One actual: VAR formals take recorded designator addresses 862 (233 otherwise); value formals take converted expressions. *) 863 ActParam(. VAR at, ft: SymTab.TypeIndex; 864 qe, qa, qt: QbeGen.QVal; 865 isV, conv: BOOLEAN; .) 866 = Expr (. ft := SymTab.ParamType(pn, i); 867 isV := SymTab.ParamIsVar(pn, i); 868 IF (at = SymTab.InvalidType) 869 OR (ft = 870 SymTab.InvalidType) THEN 871 ELSIF isV THEN 872 IF ~QbeGen.AddrOfVal(qe, 873 qa) THEN 874 SemError(233) 875 ELSIF ~SymTab.VarParamOk(at, 876 ft) THEN 877 SemError(233) 878 ELSIF ~QbeGen.CallArg(qa, 879 "l") THEN 880 SemError(233) 881 END 882 ELSE 883 IF ~SymTab.Assignable(at, 884 ft) THEN 885 SemError(233) 886 ELSE 887 conv := (SymTab.ClassOf( 888 ft) = SymTab.ClReal) 889 & SymTab.IsIntFamily(at); 890 IF conv THEN 891 QbeGen.ConvIR(qe, qt); 892 IF ~QbeGen.CallArg(qt, 893 "d") THEN 894 SemError(233) 895 END 896 ELSIF ~QbeGen.CallArg(qe, 897 QbeGen.ArgClass(ft)) THEN 898 SemError(233) 899 END 900 END 901 END; .) . 902 IfStat (. VAR t: SymTab.TypeIndex; 903 q, lThen, lElse, lEnd: 904 QbeGen.QVal; 905 hasElse: BOOLEAN; .) 906 = "IF" (. hasElse := FALSE; .) 907 Expr (. IF ~SymTab.BoolCheck(t) THEN 908 SemError(214) END; 909 QbeGen.NewLabel(lThen); 910 QbeGen.NewLabel(lElse); 911 QbeGen.NewLabel(lEnd); 912 QbeGen.Jnz(q, lThen, lElse); 913 QbeGen.EmitLabel(lThen); .) 914 "THEN" StatSeq (. QbeGen.Jmp(lEnd); .) 915 { "ELSIF" (. QbeGen.EmitLabel(lElse); 916 QbeGen.NewLabel(lElse); .) 917 Expr (. IF ~SymTab.BoolCheck(t) THEN 918 SemError(214) END; 919 QbeGen.NewLabel(lThen); 920 QbeGen.Jnz(q, lThen, lElse); 921 QbeGen.EmitLabel(lThen); .) 922 "THEN" StatSeq (. QbeGen.Jmp(lEnd); .) } 923 [ "ELSE" (. QbeGen.EmitLabel(lElse); 924 hasElse := TRUE; .) 925 StatSeq ] 926 "END" (. IF hasElse THEN 927 QbeGen.EmitLabel(lEnd) 928 ELSE QbeGen.EmitLabel(lElse); 929 QbeGen.EmitLabel(lEnd) 930 END; .) . 931 WhileStat (. VAR t: SymTab.TypeIndex; 932 q, lTop, lBody, lEnd: 933 QbeGen.QVal; .) 934 = "WHILE" (. QbeGen.NewLabel(lTop); 935 QbeGen.NewLabel(lBody); 936 QbeGen.NewLabel(lEnd); 937 QbeGen.EmitLabel(lTop); .) 938 Expr (. IF ~SymTab.BoolCheck(t) THEN 939 SemError(214) END; 940 QbeGen.Jnz(q, lBody, lEnd); 941 QbeGen.EmitLabel(lBody); .) 942 "DO" StatSeq (. QbeGen.Jmp(lTop); .) 943 "END" (. QbeGen.EmitLabel(lEnd); .) . 944 RepeatStat (. VAR t: SymTab.TypeIndex; 945 q, lTop, lEnd: QbeGen.QVal; .) 946 = "REPEAT" (. QbeGen.NewLabel(lTop); 947 QbeGen.NewLabel(lEnd); 948 QbeGen.EmitLabel(lTop); .) 949 StatSeq 950 "UNTIL" Expr (. IF ~SymTab.BoolCheck(t) THEN 951 SemError(214) END; 952 QbeGen.Jnz(q, lEnd, lTop); 953 QbeGen.EmitLabel(lEnd); .) . 954 LoopStat (. VAR lTop, lEnd: QbeGen.QVal; .) 955 = "LOOP" (. QbeGen.NewLabel(lTop); 956 QbeGen.NewLabel(lEnd); 957 QbeGen.PushLoop(lEnd); 958 QbeGen.EmitLabel(lTop); .) 959 StatSeq 960 "END" (. QbeGen.Jmp(lTop); 961 QbeGen.PopLoop; 962 QbeGen.EmitLabel(lEnd); .) . 963 (* FOR with static-sign BY (literal, non-zero; 220 otherwise). 964 Runtime direction would need a compare-select; the literal 965 sign picks cslew/csegew at "DO" time. *) 966 ForStat (. VAR lv: SymTab.Name; 967 tlo, thi, tby: 968 SymTab.TypeIndex; 969 qlo, qhi, qby, qt, qk, qb: 970 QbeGen.QVal; 971 lTop, lBody, lEnd: 972 QbeGen.QVal; 973 by: INTEGER; 974 ok: BOOLEAN; .) 975 = "FOR" (. by := 1; .) 976 GetIdent (. ok := SymTab.Lookup(lv); 977 IF ~ok THEN 978 SemError(201) 979 ELSIF (SymTab.SymKind(lv) # 980 SymTab.KindVar) 981 & (SymTab.SymKind(lv) # 982 SymTab.KindParam) THEN 983 SemError(220); ok := FALSE 984 ELSIF ~SymTab.IsIntFamily( 985 SymTab.SymType(lv)) THEN 986 SemError(220); ok := FALSE 987 END; .) 988 ":=" Expr (. IF ~SymTab.IsIntFamily(tlo) THEN 989 SemError(220); ok := FALSE 990 END; .) 991 "TO" Expr (. IF ~SymTab.IsIntFamily(thi) THEN 992 SemError(220); ok := FALSE 993 END; .) 994 [ "BY" Expr (. IF (tby # 995 SymTab.InvalidType) 996 & ~SymTab.IsIntFamily(tby) THEN 997 SemError(220); ok := FALSE 998 END; 999 IF ~SymTab.ConstInt(qby, by) THEN 1000 SemError(230); by := 1 1001 ELSIF by = 0 THEN 1002 SemError(220); by := 1 1003 END; .) ] 1004 "DO" (. IF ok THEN 1005 QbeGen.StoreVar(lv, qlo, 1006 FALSE) END; 1007 QbeGen.NewLabel(lTop); 1008 QbeGen.NewLabel(lBody); 1009 QbeGen.NewLabel(lEnd); 1010 QbeGen.EmitLabel(lTop); 1011 QbeGen.LoadVar(lv, FALSE, qt); 1012 QbeGen.NewTemp(qk); 1013 IF by > 0 THEN 1014 QbeGen.Op3("cslew", qk, 1015 qt, qhi, FALSE) 1016 ELSE QbeGen.Op3("csgew", qk, 1017 qt, qhi, FALSE) 1018 END; 1019 QbeGen.Jnz(qk, lBody, lEnd); 1020 QbeGen.EmitLabel(lBody); .) 1021 StatSeq 1022 "END" (. IF ok THEN 1023 QbeGen.LoadVar(lv, FALSE, 1024 qt); 1025 QbeGen.IntStr(by, qb); 1026 QbeGen.NewTemp(qk); 1027 QbeGen.Op3("add", qk, 1028 qt, qb, FALSE); 1029 QbeGen.StoreVar(lv, qk, 1030 FALSE) END; 1031 QbeGen.Jmp(lTop); 1032 QbeGen.EmitLabel(lEnd); .) . 1033 CaseStat (. VAR tsel: SymTab.TypeIndex; 1034 qsel, lEnd: QbeGen.QVal; .) 1035 = "CASE" Expr (. QbeGen.NewLabel(lEnd); .) 1036 "OF" CaseAlt 1037 { "|" CaseAlt } 1038 [ "ELSE" StatSeq ] 1039 "END" (. QbeGen.EmitLabel(lEnd); .) . 1040 (* Compare-chain lowering: each alternative ends its match-tests 1041 with "jmp lAfter", so the no-match fallthrough skips the body: 1042 "cmp; jnz(lBody,lF); lF: ... ; jmp lAfter; lBody: S; jmp lEnd; 1043 lAfter:". Falls into the next alternative, ELSE, or END. *) 1044 CaseAlt (. VAR lBody, lAfter: QbeGen.QVal; .) 1046 = (. QbeGen.NewLabel(lBody); 1047 QbeGen.NewLabel(lAfter); .) 1048 CaseLabel 1049 { "," CaseLabel } 1050 ":" (. QbeGen.Jmp(lAfter); 1051 QbeGen.EmitLabel(lBody); .) 1052 StatSeq (. QbeGen.Jmp(lEnd); 1053 QbeGen.EmitLabel(lAfter); .) . 1054 CaseLabel (. VAR t2, t3: SymTab.TypeIndex; 1056 q2, q3, qc, qd, qe: 1057 QbeGen.QVal; 1058 lNext: QbeGen.QVal; .) 1059 = Expr (. IF (t2 # 1060 SymTab.InvalidType) 1061 & (tsel # 1062 SymTab.InvalidType) 1063 & ((SymTab.ClassOf(t2) = 1064 SymTab.ClSet) 1065 OR (SymTab.ClassOf(tsel) = 1066 SymTab.ClSet)) THEN 1067 SemError(230) 1068 ELSIF (t2 # 1069 SymTab.InvalidType) 1070 & (tsel # 1071 SymTab.InvalidType) 1072 & ~SymTab.EqCheck(t2, 1073 tsel) THEN 1074 SemError(213) END; 1075 IF ~QbeGen.IsImm(q2) THEN 1076 SemError(230); 1077 QbeGen.CopyOp("0", q2) 1078 END; 1079 QbeGen.NewLabel(lNext); 1080 QbeGen.Cmp(SymTab.OpEq, 1081 qsel, q2, qc, FALSE); 1082 QbeGen.Jnz(qc, lBody, lNext); 1083 QbeGen.EmitLabel(lNext); .) 1084 [ ".." Expr (. IF (t3 # 1085 SymTab.InvalidType) 1086 & (tsel # 1087 SymTab.InvalidType) 1088 & ~SymTab.EqCheck(t3, 1089 tsel) THEN 1090 SemError(213) END; 1091 IF ~QbeGen.IsImm(q3) THEN 1092 SemError(230); 1093 QbeGen.CopyOp("0", q3) 1094 END; 1095 QbeGen.Cmp(SymTab.OpGe, 1096 qsel, q2, qc, FALSE); 1097 QbeGen.Cmp(SymTab.OpLe, 1098 qsel, q3, qd, FALSE); 1099 QbeGen.NewTemp(qe); 1100 QbeGen.Op3("and", qe, qc, qd, 1101 FALSE); 1102 QbeGen.NewLabel(lNext); 1103 QbeGen.Jnz(qe, lBody, lNext); 1104 QbeGen.EmitLabel(lNext); .) ] . 1105 ReturnStat (. VAR t: SymTab.TypeIndex; 1106 q, qt: QbeGen.QVal; 1107 res: SymTab.TypeIndex; 1108 hadE, conv: BOOLEAN; .) 1109 = "RETURN" (. hadE := FALSE; .) 1110 [ Expr (. hadE := TRUE; .) ] 1111 (. conv := FALSE; 1112 IF ~SymTab.InProc() THEN 1113 SemError(232) 1114 ELSE res := SymTab.CurRes(); 1115 IF ~hadE THEN 1116 IF res # 1117 SymTab.InvalidType THEN 1118 SemError(232) 1119 ELSE QbeGen.EmitRet(q, 1120 FALSE) 1121 END 1122 ELSIF (res = 1123 SymTab.InvalidType) 1124 OR (t # 1125 SymTab.InvalidType) 1126 & ~SymTab.Assignable(t, 1127 res) THEN 1128 SemError(232) 1129 ELSE 1130 conv := (SymTab.ClassOf( 1131 res) = SymTab.ClReal) 1132 & SymTab.IsIntFamily(t); 1133 IF conv THEN 1134 QbeGen.ConvIR(q, qt); 1135 QbeGen.EmitRet(qt, TRUE) 1136 ELSE QbeGen.EmitRet(q, TRUE) 1137 END 1138 END 1139 END; .) . 1140 (* Designator: scalar loads, array addresses, and index suffixes. 1141 Each index descends one level (bounds-checked, trap on breach); 1142 nested levels reload the inner descriptor address. q ends as the 1143 value (scalars), the descriptor address (plain arrays), or the 1144 element address (indexed); sfx marks the indexed form. *) 1145 Design 1147 (. VAR n, fn: SymTab.Name; 1148 cls: INTEGER; 1149 curT, it, eT, bt: 1150 SymTab.TypeIndex; 1151 iq, ql, qlo, qhi, qe: 1152 QbeGen.QVal; 1153 lo, hi: INTEGER; 1154 fo: INTEGER; 1155 isOpen: BOOLEAN; 1156 qb: QbeGen.QVal; .) 1157 = GetIdent (. QbeGen.CopyOp(n, qn); 1158 sfx := FALSE; 1159 IF ~SymTab.Lookup(n) THEN 1160 SemError(201); 1161 t := SymTab.InvalidType; 1162 k := -1; 1163 QbeGen.CopyOp("0", q) 1164 ELSE 1165 t := SymTab.SymType(n); 1166 k := SymTab.SymKind(n); 1167 IF k = SymTab.KindConst THEN 1168 IF SymTab.Equal(n, 1169 "TRUE") THEN 1170 t := SymTab.BoolType(); 1171 QbeGen.CopyOp("1", q) 1172 ELSIF SymTab.Equal(n, 1173 "FALSE") THEN 1174 t := SymTab.BoolType(); 1175 QbeGen.CopyOp("0", q) 1176 ELSIF SymTab.Equal(n, 1177 "NIL") THEN 1178 QbeGen.CopyOp("0", q) 1179 ELSE 1180 cls := 1181 SymTab.ClassOf(t); 1182 IF (t # 1183 SymTab.InvalidType) 1184 & ((cls = SymTab.ClInt) 1185 OR (cls 1186 = SymTab.ClChar) 1187 OR (cls 1188 = SymTab.ClReal) 1189 OR (cls 1190 = SymTab.ClNil)) THEN 1191 IF cls = SymTab.ClNil THEN 1192 QbeGen.CopyOp("0", q) 1193 ELSE 1194 QbeGen.LoadVar(n, 1195 cls = SymTab.ClReal, 1196 q) 1197 END 1198 ELSE 1199 IF t # 1200 SymTab.InvalidType THEN 1201 SemError(230) 1202 END; 1203 QbeGen.CopyOp("0", q) 1204 END 1205 END 1206 ELSIF (k = SymTab.KindVar) 1207 OR (k = SymTab.KindParam) THEN 1208 cls := 1209 SymTab.ClassOf(t); 1210 IF (cls = SymTab.ClInt) 1211 OR (cls = SymTab.ClBool) 1212 OR (cls = SymTab.ClChar) 1213 OR (cls 1214 = SymTab.ClReal) THEN 1215 QbeGen.LoadVar(n, 1216 cls = SymTab.ClReal, q) 1217 ELSIF cls = SymTab.ClPtr THEN 1218 QbeGen.LoadPtr(n, q) 1219 ELSIF (cls 1220 = SymTab.ClArray) 1221 OR (cls 1222 = SymTab.ClSet) 1223 OR (cls 1224 = SymTab.ClRecord) 1225 OR (cls 1226 = SymTab.ClClass) THEN 1227 QbeGen.AddrOf(n, q) 1228 ELSE SemError(230); 1229 QbeGen.CopyOp("0", q) 1230 END 1231 ELSE QbeGen.CopyOp("0", q); 1232 IF k = SymTab.KindImport THEN 1233 SemError(230) 1234 ELSIF k = 1235 SymTab.KindProc THEN 1236 (* bare procedure name: 1237 a following ArgList 1238 makes it a call; 1239 otherwise Fact 1240 reports 230 *) 1241 ELSE 1242 IF k = SymTab.KindField THEN 1243 IF QbeGen.TopWith(qb) THEN 1244 fo := 1245 SymTab.FieldOffset( 1246 SymTab.FieldOwner(n), 1247 n); 1248 QbeGen.FieldAddr(qb, 1249 fo, q); 1250 sfx := TRUE 1251 ELSE SemError(230); 1252 QbeGen.CopyOp("0", q) 1253 END 1254 END 1255 END 1256 END 1257 END; .) 1258 { "[" Expr 1259 (. IF t = SymTab.InvalidType THEN 1260 ELSIF SymTab.ClassOf(t) # 1261 SymTab.ClArray THEN 1262 SemError(217); 1263 t := SymTab.InvalidType 1264 ELSIF ~SymTab.IsIntFamily(it) 1265 & (SymTab.ClassOf(it) # 1266 SymTab.ClChar) THEN 1267 SemError(218); 1268 t := SymTab.InvalidType 1269 ELSE 1270 QbeGen.WidenIndex(iq, ql); 1271 isOpen := 1272 SymTab.IsOpenArray(t); 1273 IF isOpen THEN 1274 QbeGen.CopyOp("0", qlo); 1275 QbeGen.OpenHi(q, qhi) 1276 ELSE 1277 lo := SymTab.ArrayLo(t); 1278 hi := SymTab.ArrayHi(t); 1279 QbeGen.IntStr(lo, qlo); 1280 QbeGen.IntStr(hi, qhi) 1281 END; 1282 QbeGen.CheckRange(ql, qlo, 1283 qhi); 1284 eT := SymTab.ArrayElem(t); 1285 QbeGen.ElemAddr(q, ql, qlo, 1286 t, qe); 1287 IF SymTab.ClassOf(eT) = 1288 SymTab.ClArray THEN 1289 QbeGen.ElemLoad(qe, eT, q) 1290 ELSE QbeGen.CopyOp(qe, q) 1291 END; 1292 t := eT; sfx := TRUE 1293 END; .) 1294 { "," Expr 1295 (. IF t = SymTab.InvalidType THEN 1296 ELSIF SymTab.ClassOf(t) # 1297 SymTab.ClArray THEN 1298 SemError(217); 1299 t := SymTab.InvalidType 1300 ELSIF ~SymTab.IsIntFamily(it) 1301 & (SymTab.ClassOf(it) # 1302 SymTab.ClChar) THEN 1303 SemError(218); 1304 t := SymTab.InvalidType 1305 ELSE 1306 QbeGen.WidenIndex(iq, ql); 1307 isOpen := 1308 SymTab.IsOpenArray(t); 1309 IF isOpen THEN 1310 QbeGen.CopyOp("0", qlo); 1311 QbeGen.OpenHi(q, qhi) 1312 ELSE 1313 lo := SymTab.ArrayLo(t); 1314 hi := SymTab.ArrayHi(t); 1315 QbeGen.IntStr(lo, qlo); 1316 QbeGen.IntStr(hi, qhi) 1317 END; 1318 QbeGen.CheckRange(ql, qlo, 1319 qhi); 1320 eT := SymTab.ArrayElem(t); 1321 QbeGen.ElemAddr(q, ql, qlo, 1322 t, qe); 1323 IF SymTab.ClassOf(eT) = 1324 SymTab.ClArray THEN 1325 QbeGen.ElemLoad(qe, eT, q) 1326 ELSE QbeGen.CopyOp(qe, q) 1327 END; 1328 t := eT; sfx := TRUE 1329 END; .) } 1330 "]" 1331 | "." GetIdent 1332 (. IF k = SymTab.KindModule THEN 1333 (* qualified L.x: materialize 1334 the export, then load it *) 1335 IF ~SymTab.Materialize(n, 1336 fn) THEN 1337 SemError(201); 1338 t := SymTab.InvalidType; 1339 QbeGen.CopyOp("0", q) 1340 ELSE 1341 QbeGen.CopyOp(fn, qn); 1342 t := SymTab.SymType(fn); 1343 k := SymTab.SymKind(fn); 1344 sfx := FALSE; 1345 IF k = SymTab.KindProc THEN 1346 (* call: ArgList supplies 1347 the value *) 1348 QbeGen.CopyOp("0", q) 1349 ELSIF ~QbeGen.LoadDesignator( 1350 fn, t, k, q) THEN 1351 SemError(230); 1352 QbeGen.CopyOp("0", q) 1353 END 1354 END 1355 ELSIF t = SymTab.InvalidType THEN 1356 ELSIF (SymTab.ClassOf(t) # 1357 SymTab.ClRecord) 1358 & (SymTab.ClassOf(t) # 1359 SymTab.ClClass) THEN 1360 SemError(215); 1361 t := SymTab.InvalidType 1362 ELSIF ~SymTab.FieldExists(t, 1363 fn) THEN 1364 SemError(216); 1365 t := SymTab.InvalidType 1366 ELSE 1367 fo := SymTab.FieldOffset(t, 1368 fn); 1369 t := SymTab.FieldType(t, fn); 1370 QbeGen.FieldAddr(q, fo, qe); 1371 IF SymTab.ClassOf(t) = 1372 SymTab.ClArray THEN 1373 QbeGen.ElemLoad(qe, t, q) 1374 ELSE QbeGen.CopyOp(qe, q) 1375 END; 1376 sfx := TRUE 1377 END; .) 1378 | "^" 1379 (. IF t = SymTab.InvalidType THEN 1380 ELSIF SymTab.ClassOf(t) # 1381 SymTab.ClPtr THEN 1382 SemError(219); 1383 t := SymTab.InvalidType 1384 ELSE 1385 bt := SymTab.PtrBase(t); 1386 IF bt = SymTab.InvalidType THEN 1387 ELSE 1388 IF sfx THEN 1389 QbeGen.ElemLoad(q, t, 1390 qb); 1391 QbeGen.CopyOp(qb, q) 1392 END; 1393 t := bt; 1394 IF (SymTab.ClassOf(bt) = 1395 SymTab.ClInt) 1396 OR (SymTab.ClassOf(bt) = 1397 SymTab.ClBool) 1398 OR (SymTab.ClassOf(bt) = 1399 SymTab.ClChar) 1400 OR (SymTab.ClassOf(bt) = 1401 SymTab.ClReal) THEN 1402 sfx := TRUE 1403 ELSE sfx := FALSE 1404 END 1405 END 1406 END; .) } . 1407 Expr 1408 (. VAR t2: SymTab.TypeIndex; 1409 op: INTEGER; 1410 q2, qt: QbeGen.QVal; 1411 isR: BOOLEAN; .) 1412 = SimExpr 1413 [ Rel SimExpr 1414 (. IF op = SymTab.OpIn THEN 1415 IF SymTab.InCheck(t, t2) THEN 1416 IF (t = SymTab.InvalidType) 1417 OR (t2 = SymTab.InvalidType) THEN 1418 t := SymTab.BoolType(); QbeGen.CopyOp("0", q) 1419 ELSE 1420 QbeGen.InSet(q, q2, SymTab.SetBaseLo(t2), 1421 SymTab.SetCount(t2), qt); 1422 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q) 1423 END 1424 ELSE SemError(222); t := SymTab.InvalidType; 1425 QbeGen.CopyOp("0", q) 1426 END 1427 ELSIF SymTab.RelCheck(t, t2, op) THEN 1428 IF (t = SymTab.InvalidType) 1429 OR (t2 = SymTab.InvalidType) THEN 1430 t := SymTab.BoolType(); QbeGen.CopyOp("0", q) 1431 ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr) 1432 OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN 1433 IF (op # SymTab.OpEq) & (op # SymTab.OpNeq1) 1434 & (op # SymTab.OpNeq2) THEN 1435 SemError(213); t := SymTab.InvalidType; 1436 QbeGen.CopyOp("0", q) 1437 ELSE 1438 QbeGen.CmpL(op, q, q2, qt); 1439 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q) 1440 END 1441 ELSIF (SymTab.ClassOf(t) = SymTab.ClSet) 1442 OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN 1443 QbeGen.CmpSet(op, q, q2, 1444 SymTab.SetWords(t), SymTab.SetWords(t2), qt); 1445 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q) 1446 ELSE 1447 isR := SymTab.ClassOf(t) = SymTab.ClReal; 1448 t := SymTab.BoolType(); 1449 QbeGen.Cmp(op, q, q2, qt, isR); 1450 QbeGen.CopyOp(qt, q) 1451 END 1452 ELSE SemError(213); t := SymTab.InvalidType; 1453 QbeGen.CopyOp("0", q) 1454 END; .) ] . 1455 Rel 1456 = "=" (. op := SymTab.OpEq; .) 1457 | "#" (. op := SymTab.OpNeq1; .) 1458 | "<" (. op := SymTab.OpLt; .) 1459 | "<=" (. op := SymTab.OpLe; .) 1460 | ">" (. op := SymTab.OpGt; .) 1461 | ">=" (. op := SymTab.OpGe; .) 1462 | "IN" (. op := SymTab.OpIn; .) . 1463 SimExpr 1464 (. VAR t2, res2: SymTab.TypeIndex; 1465 op: INTEGER; 1466 q2, qt: QbeGen.QVal; 1467 neg, isR: BOOLEAN; 1468 lw, rw, mw: CARDINAL; .) 1469 = (. neg := FALSE; .) 1470 [ "+" | "-" (. neg := TRUE; .) ] 1471 Term (. IF neg THEN 1472 IF QbeGen.IsImm(q) THEN 1473 QbeGen.NegFold(q, q) 1474 ELSE QbeGen.NewTemp(qt); 1475 QbeGen.NegQ(q, qt, 1476 SymTab.ClassOf(t) 1477 = SymTab.ClReal); 1478 QbeGen.CopyOp(qt, q) 1479 END 1480 END; .) 1481 { AddOp Term 1482 (. IF op = SymTab.OpOr THEN 1483 IF SymTab.BoolCheck(t) & SymTab.BoolCheck(t2) THEN 1484 t := SymTab.BoolType() 1485 ELSE SemError(212); t := SymTab.InvalidType END; 1486 IF t # SymTab.InvalidType THEN 1487 QbeGen.NewTemp(qt); 1488 QbeGen.Op3("or", qt, q, q2, FALSE); 1489 QbeGen.CopyOp(qt, q) 1490 ELSE QbeGen.CopyOp("0", q) 1491 END 1492 ELSIF (t # SymTab.InvalidType) & (t2 # SymTab.InvalidType) 1493 & (SymTab.ClassOf(t) = SymTab.ClSet) 1494 & (SymTab.ClassOf(t2) = SymTab.ClSet) THEN 1495 lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2); 1496 mw := lw; 1497 IF rw > mw THEN mw := rw END; 1498 IF op = SymTab.OpAdd THEN 1499 QbeGen.SetBinOp(0, q, q2, lw, rw, qt) 1500 ELSE 1501 QbeGen.SetBinOp(2, q, q2, lw, rw, qt) 1502 END; 1503 t := SymTab.NewSet( 1504 SymTab.NewSubR(0, 1505 VAL(INTEGER, mw) * 32 - 1)); 1506 QbeGen.CopyOp(qt, q) 1507 ELSE 1508 IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN 1509 t := res2 1510 ELSE SemError(211); t := SymTab.InvalidType END; 1511 isR := SymTab.ClassOf(t) = SymTab.ClReal; 1512 IF t # SymTab.InvalidType THEN 1513 QbeGen.NewTemp(qt); 1514 IF op = SymTab.OpAdd THEN 1515 QbeGen.Op3("add", qt, q, q2, isR) 1516 ELSE 1517 QbeGen.Op3("sub", qt, q, q2, isR) 1518 END; 1519 QbeGen.CopyOp(qt, q) 1520 ELSE QbeGen.CopyOp("0", q) 1521 END 1522 END; .) } . 1523 AddOp 1524 = "+" (. op := SymTab.OpAdd; .) 1525 | "-" (. op := SymTab.OpSub; .) 1526 | "OR" (. op := SymTab.OpOr; .) . 1527 Term 1528 (. VAR t2, res2: SymTab.TypeIndex; 1529 op: INTEGER; 1530 q2, qt: QbeGen.QVal; 1531 isR: BOOLEAN; 1532 lw, rw, mw: CARDINAL; .) 1533 = Fact { MulOp Fact 1534 (. IF op = SymTab.OpAnd THEN 1535 IF SymTab.BoolCheck(t) & SymTab.BoolCheck(t2) THEN 1536 t := SymTab.BoolType() 1537 ELSE SemError(212); t := SymTab.InvalidType END; 1538 IF t # SymTab.InvalidType THEN 1539 QbeGen.NewTemp(qt); 1540 QbeGen.Op3("and", qt, q, q2, FALSE); 1541 QbeGen.CopyOp(qt, q) 1542 ELSE QbeGen.CopyOp("0", q) 1543 END 1544 ELSIF (t # SymTab.InvalidType) & (t2 # SymTab.InvalidType) 1545 & (SymTab.ClassOf(t) = SymTab.ClSet) 1546 & (SymTab.ClassOf(t2) = SymTab.ClSet) THEN 1547 lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2); 1548 mw := lw; 1549 IF rw > mw THEN mw := rw END; 1550 IF op = SymTab.OpTimes THEN 1551 QbeGen.SetBinOp(1, q, q2, lw, rw, qt) 1552 ELSE 1553 QbeGen.SetBinOp(3, q, q2, lw, rw, qt) 1554 END; 1555 t := SymTab.NewSet( 1556 SymTab.NewSubR(0, 1557 VAL(INTEGER, mw) * 32 - 1)); 1558 QbeGen.CopyOp(qt, q) 1559 ELSE 1560 IF SymTab.ArithCheck(t, t2, 1561 (op = SymTab.OpDiv) OR (op = SymTab.OpMod), 1562 res2) THEN t := res2 1563 ELSE SemError(211); t := SymTab.InvalidType END; 1564 isR := SymTab.ClassOf(t) = SymTab.ClReal; 1565 IF t # SymTab.InvalidType THEN 1566 QbeGen.NewTemp(qt); 1567 IF op = SymTab.OpTimes THEN 1568 QbeGen.Op3("mul", qt, q, q2, isR) 1569 ELSIF (op = SymTab.OpDiv) 1570 OR (op = SymTab.OpSlash) THEN 1571 QbeGen.Op3("div", qt, q, q2, isR) 1572 ELSE 1573 QbeGen.Op3("rem", qt, q, q2, isR) 1574 END; 1575 QbeGen.CopyOp(qt, q) 1576 ELSE QbeGen.CopyOp("0", q) 1577 END 1578 END; .) } . 1579 MulOp 1580 = "*" (. op := SymTab.OpTimes; .) 1581 | "/" (. op := SymTab.OpSlash; .) 1582 | "DIV" (. op := SymTab.OpDiv; .) 1583 | "MOD" (. op := SymTab.OpMod; .) 1584 | "AND" (. op := SymTab.OpAnd; .) . 1585 Fact 1586 (. VAR s: ARRAY [0 .. 255] OF CHAR; 1587 et, dt, t2, st, ct2: 1588 SymTab.TypeIndex; 1589 dk: INTEGER; 1590 qd, q2, sq, qa, qm0, qr: 1591 QbeGen.QVal; 1592 qn: SymTab.Name; 1593 called, isHigh, sfx: 1594 BOOLEAN; .) 1595 = integer (. LexString(s); 1596 QbeGen.NormInt(s, q); 1597 t := SymTab.IntType(); .) 1598 | real (. LexString(s); 1599 QbeGen.NormReal(s, q); 1600 t := SymTab.RealType(); .) 1601 | string (. LexString(s); 1602 IF SymTab.StrLen(s) = 3 THEN 1603 t := SymTab.CharType(); 1604 QbeGen.IntStr( 1605 QbeGen.CharVal(s), q) 1606 ELSE t := SymTab.NewStr(); 1607 QbeGen.DeclStr(s, q); 1608 (* a literal's value IS its 1609 static descriptor address *) 1610 QbeGen.NoteAddr(q, q) 1611 END; .) 1612 | Design (. called := FALSE; 1613 t := dt; 1614 IF sfx THEN 1615 IF dt = 1616 SymTab.InvalidType THEN 1617 QbeGen.CopyOp("0", q) 1618 ELSIF (SymTab.ClassOf(dt) = 1619 SymTab.ClRecord) 1620 OR (SymTab.ClassOf(dt) = 1621 SymTab.ClSet) 1622 OR (SymTab.ClassOf(dt) = 1623 SymTab.ClClass) THEN 1624 QbeGen.CopyOp(qd, q) 1625 ELSE QbeGen.ElemLoad(qd, dt, 1626 q) 1627 END 1628 ELSE QbeGen.CopyOp(qd, q) 1629 END; 1630 IF (dk = SymTab.KindVar) 1631 OR (dk = SymTab.KindParam) 1632 OR (dk = 1633 SymTab.KindField) THEN 1634 IF sfx THEN 1635 QbeGen.NoteAddr(q, qd) 1636 ELSE 1637 QbeGen.AddrOf(qn, qa); 1638 QbeGen.NoteAddr(q, qa) 1639 END 1640 ELSIF sfx 1641 & (dt # 1642 SymTab.InvalidType) 1643 & ((SymTab.ClassOf(dt) = 1644 SymTab.ClArray) 1645 OR (SymTab.ClassOf(dt) = 1646 SymTab.ClSet) 1647 OR (SymTab.ClassOf(dt) = 1648 SymTab.ClRecord)) THEN 1649 QbeGen.NoteAddr(qd, qd) 1650 END; .) 1651 [ ArgList 1652 (. t := ct2; 1653 QbeGen.CopyOp(q2, q); .) ] 1654 (. IF ~called 1655 & (dk = SymTab.KindProc) THEN 1656 (* bare zero-arg function 1657 call (parentheses may be 1658 omitted); a proper or 1659 parameterised proc here 1660 is 230 *) 1661 IF (SymTab.ProcNPar(qn) = 0) 1662 & (SymTab.ProcRes(qn) # 1663 SymTab.InvalidType) THEN 1664 QbeGen.Mangled(qn, 1665 SymTab.ProcUid(qn), qm0); 1666 QbeGen.CallBegin(qm0, 1667 SymTab.ProcRes(qn), 1668 SymTab.ProcDepthOf(qn), 1669 SymTab.IsExternal(qn)); 1670 QbeGen.CallEnd(TRUE, q); 1671 t := SymTab.ProcRes(qn) 1672 ELSE SemError(230) 1673 END 1674 END; .) 1675 | ( "HIGH" (. isHigh := TRUE; .) 1676 | "LEN" (. isHigh := FALSE; .) ) 1677 "(" Design ")" 1678 (. IF dt = SymTab.InvalidType THEN 1679 ELSIF SymTab.ClassOf(dt) # 1680 SymTab.ClArray THEN 1681 SemError(217); 1682 t := SymTab.InvalidType; 1683 QbeGen.CopyOp("0", q) 1684 ELSE 1685 IF isHigh THEN 1686 IF SymTab.IsOpenArray(dt) THEN 1687 QbeGen.OpenHi(qd, qr) 1688 ELSE 1689 QbeGen.IntStr( 1690 SymTab.ArrayHi(dt), qr) 1691 END 1692 ELSE 1693 IF SymTab.IsOpenArray(dt) THEN 1694 QbeGen.LoadCount(qd, qr) 1695 ELSE 1696 QbeGen.IntStr(VAL( 1697 INTEGER, 1698 SymTab.ArrayLen(dt)), 1699 qr) 1700 END 1701 END; 1702 t := SymTab.IntType(); 1703 QbeGen.CopyOp(qr, q) 1704 END; .) 1705 | "(" Expr ")" (. t := et; .) 1706 | SetLit (. t := st; 1707 QbeGen.CopyOp(sq, q); .) 1708 | "NOT" Fact (. IF SymTab.BoolCheck(t2) THEN 1709 t := SymTab.BoolType() 1710 ELSE SemError(212); 1711 t := SymTab.InvalidType END; 1712 IF t # SymTab.InvalidType THEN 1713 QbeGen.NotQ(q2, q) 1714 ELSE QbeGen.CopyOp("0", q) 1715 END; .) . 1716 (* Set literals are SET OF [0..255] (8 words); elements validated 1717 0..255 statically when foldable (222 otherwise), runtime trap 1718 for computed elements. Ranges always lower via SetRange. *) 1719 SetLit 1720 = "{" (. t := SymTab.NewSet( 1721 SymTab.NewSubR(0, 255)); 1722 QbeGen.NewSetTemp(8, q); 1723 QbeGen.SetZero(q, 8); .) 1724 [ SetElem { "," SetElem } ] 1725 "}" . 1726 SetElem (. VAR et, et2: SymTab.TypeIndex; 1727 qe, q2: QbeGen.QVal; 1728 v, v2: INTEGER; 1729 lo: INTEGER; 1730 span: CARDINAL; 1731 cl, cl2: INTEGER; 1732 hasR: BOOLEAN; .) 1733 = (. hasR := FALSE; .) 1734 Expr 1735 [ ".." Expr (. hasR := TRUE; .) ] 1736 (. lo := SymTab.SetBaseLo(st); 1737 span := SymTab.SetCount(st); 1738 IF (et = SymTab.InvalidType) 1739 OR (hasR & (et2 = 1740 SymTab.InvalidType)) THEN 1741 ELSE cl := 1742 SymTab.ClassOf(et); 1743 IF hasR THEN 1744 cl2 := 1745 SymTab.ClassOf(et2) 1746 ELSE cl2 := SymTab.ClInt 1747 END; 1748 IF ((cl # SymTab.ClInt) 1749 & (cl # SymTab.ClChar) 1750 & (cl # SymTab.ClBool)) 1751 OR (hasR & 1752 ((cl2 1753 # SymTab.ClInt) 1754 & (cl2 1755 # SymTab.ClChar) 1756 & (cl2 1757 # SymTab.ClBool))) THEN 1758 SemError(222) 1759 ELSIF hasR 1760 & SymTab.ConstInt(qe, v) 1761 & SymTab.ConstInt(q2, 1762 v2) 1763 & ((v < lo) 1764 OR (v2 < lo) 1765 OR (v >= lo + 1766 VAL(INTEGER, span)) 1767 OR (v2 >= lo + 1768 VAL(INTEGER, span)) 1769 OR (v > v2)) THEN 1770 SemError(222) 1771 ELSIF hasR THEN 1772 QbeGen.SetRange(sq, qe, q2, 1773 lo, span) 1774 ELSIF SymTab.ConstInt(qe, 1775 v) 1776 & ((v < lo) 1777 OR (v >= lo + 1778 VAL(INTEGER, 1779 span))) THEN 1780 SemError(222) 1781 ELSE QbeGen.SetBit(sq, qe, 1782 lo, span) 1783 END 1784 END; .) . 1785 GetIdent 1786 = ident (. LexName(n); .) . 1787 1788 END M2. 0 errors Statistics: nr of terminals: 78 (limit 400) nr of non-terminals: 73 (limit 210) nr of pragmas: 0 (limit 422) nr of symbolnodes: 151 (limit 500) nr of graphnodes: 681 (limit 1500) nr of conditionsets: 7 (limit 100) nr of charactersets: 11 (limit 250)