Coco/R - Compiler-Compiler V1.53 Released by Pat Terry 17 September 2002 Source file: M2.atg Grammar Tests: Deletable symbols: DesignTail 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 parse (docs/plan-two-phase-parse.md), milestone 1. When 58 TRUE each outermost procedure/method body is shadow-skipped at the 59 token level and the skip verified before the body parses normally. 60 Set by the driver (-notwophase turns it off); default on. 61 Blocks being parsed so only outermost bodies probe. *) 62 twoPhaseParse: BOOLEAN; 63 64 (* Two-phase parse spans (milestone 2a): one entry per outermost body 65 shadow-skipped while twoPhaseParse is on — procedure name and the 66 buffer offset its body starts at (the lookahead token's nextPos). 67 Per-parse; nothing consumes the table yet. *) 68 nSpans: CARDINAL; 69 spanName: ARRAY [0 .. 1023] OF SymTab.Name; 70 spanStart: ARRAY [0 .. 1023] OF M2S.INT32; 71 spanIdx: ARRAY [0 .. 1023] OF CARDINAL; 72 spanTy: ARRAY [0 .. 1023] OF INTEGER; 73 spanNode: ARRAY [0 .. 1023] OF AST.Node; 74 75 (* Two-phase parse (milestone 2c): phase-1 skips a module-level proc 76 body (DeferSkip) and phase 2 re-parses it at unit end (RepassAll). 77 `deferredBody` reports the skip to ProcDecl's close choice; 78 `repassing` disables deferral during phase 2; `allowDefer` limits 79 deferral to plain ProcDecls (methods stay inline); `curProcNode` is 80 the NkProcDecl whose body is about to be parsed. *) 81 deferredBody: BOOLEAN; 82 repassing: BOOLEAN; 83 allowDefer: BOOLEAN; 84 curProcNode: AST.Node; 85 86 (* The last actual argument parsed by ActParam: folded value and type. 87 A conversion T(x) has exactly one actual, so these let Fact 88 constant-fold it (needed for `CONST c = T(x)`). *) 89 convQ: QbeGen.QVal; 90 convT: SymTab.TypeIndex; 91 92 (* Result slot for the expression-AST builder (slice 2). Every 93 Expr/SimExpr/Term/Fact leaves its node here; the combination 94 productions save it into locals before parsing the next operand. 95 `astIsLit` in Fact is per-invocation, so a nested Fact cannot make 96 an outer non-literal Fact look literal. *) 97 astCur: AST.Node; 98 99 (* Actual-argument nodes collected by ActParam for the call being 100 parsed by ArgList (slice 4). Fact resets the count before the 101 optional ArgList and then folds the nodes into an NkCall. *) 102 astNArgs: CARDINAL; 103 astArgs: ARRAY [0 .. 31] OF AST.Node; 104 105 (* Statement-AST result slot (slice 5): the most recently parsed 106 statement. StatSeq folds these into an NkBlock. *) 107 astStmt: AST.Node; 108 109 (* Declaration-AST result slot (slice 6): the most recently built 110 declaration; DeclSeq folds these into an NkDeclSeq. *) 111 astDecl: AST.Node; 112 113 (* The local declarations of the most recent Block (a procedure body); 114 ProcDecl stores them as the proc node's child 2. *) 115 astBlkDecls: AST.Node; 116 117 (* Unit-AST root (slice 7): NkUnit(name, decls, body). *) 118 astUnit: AST.Node; 119 120 (* Import accumulator (slice 11): `{ Import }` appends NkImport 121 nodes here; each unit stores them as NkUnit child[3]. *) 122 astImp, astImpTail: AST.Node; 123 124 (* Class-AST accumulators (slice 13): the class node currently being 125 parsed and its parent/field/method lists. Classes are not nested 126 inside one another, so module-level state is safe. *) 127 astCls, astClsP, astClsPTail, astClsF, astClsFTail, 128 astClsM, astClsMTail, astMethod: AST.Node; 129 130 (* Class of the method named by the last `obj.Method` designator 131 (InvalidType when the callee is an ordinary procedure). Set by 132 Design, consumed by the following ArgList. *) 133 methCls: SymTab.TypeIndex; 134 (* Class of the type of the innermost `TypeName{...}` brace 135 constructor (ClSet or ClArray); dispatches BraceElem. *) 136 braceCls: INTEGER; 137 (* Module-level VAR declarations whose type was still an unresolved 138 forward alias at declaration time; emitted once the TYPE block 139 completes (module scope only). *) 140 nPendVar: CARDINAL; 141 pendVarName: ARRAY [0 .. 255] OF SymTab.Name; 142 pendVarT: ARRAY [0 .. 255] OF SymTab.TypeIndex; 143 (* Forward module-level variables referenced from a procedure body. *) 144 (* GOTO/labels: the label and goto names of the procedure being parsed, 145 reset per procedure and checked at its END. *) 146 nLab, nGot: CARDINAL; 147 labNm, gotNm: ARRAY [0 .. 255] OF SymTab.Name; 148 149 (* Generics (Increment 1): the last refining module seen — instance 150 name, generic name, and the actual type parameters. *) 151 refInst, refGen: SymTab.Name; 152 refN: CARDINAL; 153 refActual: ARRAY [0 .. 15] OF SymTab.TypeIndex; 154 refKind: ARRAY [0 .. 15] OF INTEGER; (* 0 = type, 1 = value, 2 = proc *) 155 refVal: ARRAY [0 .. 15] OF SymTab.Name; 156 refMod: ARRAY [0 .. 15] OF SymTab.Name; 157 isGen: BOOLEAN; 158 159 (* Generics (Increment 2): instantiation re-parse context. When the 160 driver re-parses a generic's source to instantiate it as `instName`, 161 instActive is TRUE, the module is renamed, and each type formal is 162 bound to the corresponding instActual entry. *) 163 instActive: BOOLEAN; 164 instName: SymTab.Name; 165 instActual: ARRAY [0 .. 15] OF SymTab.TypeIndex; 166 instKind: ARRAY [0 .. 15] OF INTEGER; 167 instVal: ARRAY [0 .. 15] OF SymTab.Name; 168 instMod: ARRAY [0 .. 15] OF SymTab.Name; 169 instN: CARDINAL; 170 instFk: CARDINAL; (* formal cursor while binding during re-parse *) 171 172 (* Identity of the last-parsed unit and refinement, for the driver's 173 generic registry and its re-parse decision. *) 174 unitName: SymTab.Name; 175 unitWasGen: BOOLEAN; 176 unitWasDef: BOOLEAN; 177 refSeen: BOOLEAN; 178 refIsDef: BOOLEAN; 179 180 181 PROCEDURE CopyNm (src: ARRAY OF CHAR; VAR dst: SymTab.Name); 182 VAR i: CARDINAL; 183 BEGIN 184 i := 0; 185 WHILE (i <= HIGH(dst)) AND (i <= HIGH(src)) AND (src[i] # CHR(0)) DO 186 dst[i] := src[i]; INC(i) 187 END; 188 IF i <= HIGH(dst) THEN dst[i] := CHR(0) END 189 END CopyNm; 190 191 PROCEDURE InInst () : BOOLEAN; 192 BEGIN RETURN instActive END InInst; 193 194 PROCEDURE InstNameGet (VAR nm: SymTab.Name); 195 BEGIN CopyNm(instName, nm) END InstNameGet; 196 197 PROCEDURE InstActualGet (i: CARDINAL) : SymTab.TypeIndex; 198 BEGIN 199 IF i >= instN THEN RETURN SymTab.InvalidType END; 200 RETURN instActual[i] 201 END InstActualGet; 202 203 PROCEDURE InstBegin (name: ARRAY OF CHAR); 204 BEGIN instActive := TRUE; CopyNm(name, instName); instN := 0; 205 instFk := 0 END InstBegin; 206 207 PROCEDURE InstActualKind (i: CARDINAL) : INTEGER; 208 BEGIN 209 IF i >= instN THEN RETURN 0 END; 210 RETURN instKind[i] 211 END InstActualKind; 212 213 PROCEDURE InstActualVal (i: CARDINAL; VAR v: SymTab.Name); 214 VAR k: CARDINAL; 215 BEGIN 216 v[0] := CHR(0); 217 IF i >= instN THEN RETURN END; 218 k := 0; 219 WHILE (k <= HIGH(v)) AND (instVal[i][k] # CHR(0)) DO 220 v[k] := instVal[i][k]; INC(k) 221 END; 222 v[k] := CHR(0) 223 END InstActualVal; 224 225 PROCEDURE InstActualMod (i: CARDINAL; VAR m: SymTab.Name); 226 VAR k: CARDINAL; 227 BEGIN 228 m[0] := CHR(0); 229 IF i >= instN THEN RETURN END; 230 k := 0; 231 WHILE (k <= HIGH(m)) AND (instMod[i][k] # CHR(0)) DO 232 m[k] := instMod[i][k]; INC(k) 233 END; 234 m[k] := CHR(0) 235 END InstActualMod; 236 237 PROCEDURE InstAddActual (kind: INTEGER; t: SymTab.TypeIndex; 238 val, m: ARRAY OF CHAR); 239 VAR k: CARDINAL; 240 BEGIN 241 IF instN > HIGH(instActual) THEN RETURN END; 242 instKind[instN] := kind; instActual[instN] := t; 243 k := 0; 244 WHILE (k <= HIGH(instVal[instN])) AND (val[k] # CHR(0)) DO 245 instVal[instN][k] := val[k]; INC(k) 246 END; 247 instVal[instN][k] := CHR(0); 248 k := 0; 249 WHILE (k <= HIGH(instMod[instN])) AND (m[k] # CHR(0)) DO 250 instMod[instN][k] := m[k]; INC(k) 251 END; 252 instMod[instN][k] := CHR(0); 253 INC(instN) 254 END InstAddActual; 255 256 PROCEDURE InstEnd; 257 BEGIN instActive := FALSE; instN := 0 END InstEnd; 258 259 PROCEDURE UnitNameGet (VAR nm: SymTab.Name); 260 BEGIN CopyNm(unitName, nm) END UnitNameGet; 261 262 PROCEDURE UnitIsGeneric () : BOOLEAN; 263 BEGIN RETURN unitWasGen END UnitIsGeneric; 264 265 PROCEDURE UnitIsDefModule () : BOOLEAN; 266 BEGIN RETURN unitWasDef END UnitIsDefModule; 267 268 PROCEDURE RefineSeen () : BOOLEAN; 269 BEGIN RETURN refSeen END RefineSeen; 270 271 PROCEDURE RefineIsDef () : BOOLEAN; 272 BEGIN RETURN refIsDef END RefineIsDef; 273 274 PROCEDURE RefineInst (VAR nm: SymTab.Name); 275 BEGIN CopyNm(refInst, nm) END RefineInst; 276 277 PROCEDURE RefineGen (VAR nm: SymTab.Name); 278 BEGIN CopyNm(refGen, nm) END RefineGen; 279 280 PROCEDURE RefineActualCount () : CARDINAL; 281 BEGIN RETURN refN END RefineActualCount; 282 283 PROCEDURE RefineActualGet (i: CARDINAL) : SymTab.TypeIndex; 284 BEGIN 285 IF i >= refN THEN RETURN SymTab.InvalidType END; 286 RETURN refActual[i] 287 END RefineActualGet; 288 289 PROCEDURE RefineActualKind (i: CARDINAL) : INTEGER; 290 BEGIN 291 IF i >= refN THEN RETURN 0 END; 292 RETURN refKind[i] 293 END RefineActualKind; 294 295 PROCEDURE RefineActualMod (i: CARDINAL; VAR m: SymTab.Name); 296 VAR k: CARDINAL; 297 BEGIN 298 m[0] := CHR(0); 299 IF i >= refN THEN RETURN END; 300 k := 0; 301 WHILE (k <= HIGH(m)) AND (refMod[i][k] # CHR(0)) DO 302 m[k] := refMod[i][k]; INC(k) 303 END; 304 m[k] := CHR(0) 305 END RefineActualMod; 306 307 PROCEDURE RefineActualVal (i: CARDINAL; VAR v: SymTab.Name); 308 VAR k: CARDINAL; 309 BEGIN 310 v[0] := CHR(0); 311 IF i >= refN THEN RETURN END; 312 k := 0; 313 WHILE (k <= HIGH(v)) AND (refVal[i][k] # CHR(0)) DO 314 v[k] := refVal[i][k]; INC(k) 315 END; 316 v[k] := CHR(0) 317 END RefineActualVal; 318 319 PROCEDURE NoteLabel (nm: ARRAY OF CHAR); 320 (* Record a statement label; duplicate is 200. *) 321 VAR i: CARDINAL; 322 BEGIN 323 i := 0; 324 WHILE i < nLab DO 325 IF SymTab.Equal(labNm[i], nm) THEN SemError(200); RETURN END; 326 INC(i) 327 END; 328 IF nLab <= HIGH(labNm) THEN 329 CopyNm(nm, labNm[nLab]); INC(nLab) 330 END 331 END NoteLabel; 332 333 PROCEDURE NoteGoto (nm: ARRAY OF CHAR); 334 VAR i: CARDINAL; 335 BEGIN 336 i := 0; 337 WHILE i < nGot DO 338 IF SymTab.Equal(gotNm[i], nm) THEN RETURN END; 339 INC(i) 340 END; 341 IF nGot <= HIGH(gotNm) THEN 342 CopyNm(nm, gotNm[nGot]); INC(nGot) 343 END 344 END NoteGoto; 345 346 PROCEDURE CheckGotos; 347 (* At a procedure's END: every GOTO must name a label in that procedure. *) 348 VAR i, j: CARDINAL; found: BOOLEAN; 349 BEGIN 350 i := 0; 351 WHILE i < nGot DO 352 found := FALSE; j := 0; 353 WHILE (j < nLab) AND NOT found DO 354 IF SymTab.Equal(labNm[j], gotNm[i]) THEN found := TRUE END; 355 INC(j) 356 END; 357 IF NOT found THEN SemError(201) END; 358 INC(i) 359 END 360 END CheckGotos; 361 362 PROCEDURE FlushPend; 363 (* Emit module-level globals whose forward type is now resolved. *) 364 VAR k: CARDINAL; 365 BEGIN 366 k := 0; 367 WHILE k < nPendVar DO 368 INC(k) 369 END; 370 nPendVar := 0 371 END FlushPend; 372 373 PROCEDURE AstAppend (kind: INTEGER; VAR head, tail: AST.Node; 374 item: AST.Node); 375 (* Appends `item` to a chunked sequence: each node holds up to 376 AST.MaxChild-1 items; child[MaxChild-1] continues into the next 377 chunk. Unbounded, so blocks/decl sequences are not capped at 8. *) 378 VAR n: AST.Node; 379 BEGIN 380 IF item = AST.NoNode THEN RETURN END; 381 IF head = AST.NoNode THEN 382 head := AST.MakeNode(kind); tail := head 383 END; 384 IF AST.NChild(tail) >= AST.MaxChild - 1 THEN 385 n := AST.MakeNode(kind); 386 AST.SetChild(tail, AST.MaxChild - 1, n); 387 tail := n 388 END; 389 AST.SetChild(tail, AST.NChild(tail), item) 390 END AstAppend; 391 392 PROCEDURE AstCallNode (callee: AST.Node) : AST.Node; 393 (* Builds NkCall(callee, actuals...) from astArgs/astNArgs. The actuals 394 are a chunked sequence (AstAppend): a call can have more than 395 MaxChild-1 arguments (the generic ArgList has 9), and SetChild would 396 silently drop the tail. NkBlock marks the continuation chunks. *) 397 VAR n, tail: AST.Node; j: CARDINAL; 398 BEGIN 399 n := AST.MakeNode(AST.NkCall); 400 AST.SetChild(n, 0, callee); 401 tail := n; 402 j := 0; 403 WHILE j < astNArgs DO 404 AstAppend(AST.NkBlock, n, tail, astArgs[j]); 405 INC(j) 406 END; 407 RETURN n 408 END AstCallNode; 409 410 411 412 PROCEDURE GetUnit (): AST.Node; 413 (* The most recently parsed unit's AST root (for the Lower comparison). *) 414 BEGIN 415 RETURN astUnit 416 END GetUnit; 417 418 PROCEDURE SetTwoPhase (b: BOOLEAN); 419 (* Driver switch for the two-phase parse probe (milestone 1). *) 420 BEGIN 421 twoPhaseParse := b 422 END SetTwoPhase; 423 424 PROCEDURE TokIs (kw: ARRAY OF CHAR): BOOLEAN; 425 (* The current lookahead token's source text equals kw. Compares text, 426 not token codes, so grammar renumbering cannot desync the skipper. *) 427 VAR tok: ARRAY [0 .. 63] OF CHAR; 428 BEGIN 429 M2S.GetName(M2S.nextPos, M2S.nextLen, tok); 430 RETURN SymTab.Equal(tok, kw) 431 END TokIs; 432 433 PROCEDURE Adv; 434 (* Advance one token: exactly the parser frame's Get for a grammar 435 without pragmas (its pragma branch is empty and the scanner never 436 returns a token above maxT, so the repeat loop runs once). A 437 separate name because the frame's Get is declared later in this 438 module: a bare Get here would bind the imported M2S.Get (which takes 439 a parameter) under single-pass compilers. *) 440 BEGIN 441 M2S.Get(sym); 442 INC(errDist) 443 END Adv; 444 445 PROCEDURE ConsCode (nm: ARRAY OF CHAR): INTEGER; 446 (* Constraint name -> code: 0 none, 1 ORDINAL, 2 INTEGER, 3 REAL. *) 447 BEGIN 448 IF SymTab.Equal(nm, "ORDINAL") THEN RETURN 1 449 ELSIF SymTab.Equal(nm, "INTEGER") THEN RETURN 2 450 ELSIF SymTab.Equal(nm, "REAL") THEN RETURN 3 451 ELSIF SymTab.Equal(nm, "POINTER") THEN RETURN 4 452 ELSIF SymTab.Equal(nm, "SCALAR") THEN RETURN 5 453 END; 454 RETURN 0 455 END ConsCode; 456 457 PROCEDURE ConsOk (cons: INTEGER; t: SymTab.TypeIndex): BOOLEAN; 458 (* TRUE when t satisfies the constraint code. *) 459 BEGIN 460 IF cons = 0 THEN RETURN TRUE 461 ELSIF cons = 1 THEN RETURN SymTab.IsOrdinal(t) 462 ELSIF cons = 2 THEN RETURN SymTab.ClassOf(t) = SymTab.ClInt 463 ELSIF cons = 3 THEN RETURN SymTab.ClassOf(t) = SymTab.ClReal 464 ELSIF cons = 4 THEN RETURN SymTab.ClassOf(t) = SymTab.ClPtr 465 ELSIF cons = 5 THEN 466 RETURN (SymTab.ClassOf(t) = SymTab.ClInt) 467 OR (SymTab.ClassOf(t) = SymTab.ClChar) 468 OR (SymTab.ClassOf(t) = SymTab.ClBool) 469 OR (SymTab.ClassOf(t) = SymTab.ClEnum) 470 OR (SymTab.ClassOf(t) = SymTab.ClUChar) 471 OR (SymTab.ClassOf(t) = SymTab.ClReal) 472 END; 473 RETURN TRUE 474 END ConsOk; 475 476 PROCEDURE OrdClass (t: SymTab.TypeIndex): BOOLEAN; 477 (* TRUE for scalar ordinal classes (int/char/bool/enum/uchar); a 478 conversion between two of these is representation-preserving, so its 479 folded value equals the operand's. *) 480 VAR c: INTEGER; 481 BEGIN 482 c := SymTab.ClassOf(t); 483 RETURN (c = SymTab.ClInt) OR (c = SymTab.ClChar) OR (c = SymTab.ClBool) 484 OR (c = SymTab.ClEnum) OR (c = SymTab.ClUChar) 485 END OrdClass; 486 487 PROCEDURE NoteSpan (pn: SymTab.Name; start: M2S.INT32); 488 (* Records an outermost body span for the re-parse pass (milestone 2). 489 Diagnostic only for now: nothing consumes the table yet. Declared 490 before its caller: V3 resolves single-pass (declaration before use), 491 with no forward tolerance for procedure calls. *) 492 BEGIN 493 IF nSpans > HIGH(spanName) THEN RETURN END; 494 CopyNm(pn, spanName[nSpans]); 495 spanStart[nSpans] := start; 496 spanIdx[nSpans] := SymTab.DeferBody(); 497 INC(nSpans) 498 END NoteSpan; 499 500 PROCEDURE Openers (): BOOLEAN; 501 (* TRUE when the current token opens a block that must be closed by an 502 END (BEGIN is excluded: a block's BEGIN shares the declaration END; 503 REPEAT..UNTIL and EXIT/RETURN need no END). *) 504 BEGIN 505 RETURN TokIs("MODULE") OR TokIs("PROCEDURE") OR TokIs("CLASS") 506 OR TokIs("RECORD") OR TokIs("IF") OR TokIs("CASE") 507 OR TokIs("WHILE") OR TokIs("FOR") OR TokIs("LOOP") 508 OR TokIs("WITH") 509 END Openers; 510 511 PROCEDURE DeferSkip (pn: SymTab.Name): BOOLEAN; 512 (* Phase 1 of the deferral: skip the body starting at the current token 513 (the first token after the heading's ';') up to the matching END, 514 verify the END's name, and LEAVE the scanner positioned exactly at 515 that END (so Block's trailing "END" ident consumes it for real), with 516 the span recorded for the re-parse pass. On any inconsistency, 517 restore the scanner and return FALSE so the caller parses normally. *) 518 VAR depth, guard: CARDINAL; 519 nm: SymTab.Name; 520 ok: BOOLEAN; 521 start, endPos: M2S.INT32; 522 BEGIN 523 deferredBody := FALSE; 524 start := M2S.nextPos; 525 M2S.PushPos; 526 depth := 0; guard := 0; ok := TRUE; 527 LOOP 528 IF sym = 0 THEN ok := FALSE; EXIT END; 529 IF TokIs("END") THEN 530 IF depth = 0 THEN EXIT END; 531 DEC(depth) 532 ELSIF Openers() THEN 533 INC(depth) 534 END; 535 Adv; 536 INC(guard); 537 IF guard > 1000000 THEN ok := FALSE; EXIT END 538 END; 539 IF ok THEN 540 (* sym is the matching END; check the name after it, then seek back 541 so Block sees END (its "END" ident then consumes it for real). *) 542 endPos := M2S.nextPos; 543 Adv; 544 M2S.GetName(M2S.nextPos, M2S.nextLen, nm); 545 IF (sym = 0) OR NOT SymTab.Equal(nm, pn) THEN ok := FALSE END; 546 IF ok THEN 547 M2S.SeekTo(endPos); Adv 548 END 549 END; 550 IF ok THEN 551 NoteSpan(pn, start); 552 spanTy[nSpans - 1] := Lower.CurScopeProc(); 553 spanNode[nSpans - 1] := curProcNode; 554 M2S.DropPos; (* keep the scanner at END; discard the snapshot *) 555 deferredBody := TRUE; 556 RETURN TRUE 557 ELSE 558 M2S.PopPos; 559 FileIO.WriteString(FileIO.StdOut, "twophase defer mismatch in "); 560 FileIO.WriteString(FileIO.StdOut, pn); 561 FileIO.WriteLn(FileIO.StdOut); 562 RETURN FALSE 563 END 564 END DeferSkip; 565 566 CHARACTERS 567 eol = CHR(13) . 568 lf = CHR(10) . 569 letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" . 570 digit = "0123456789" . 571 hexDigit = digit + "ABCDEFabcdef" . 572 noQuote1 = ANY - "'" - eol . 573 noQuote2 = ANY - '"' - eol . 574 575 IGNORE CHR(9) .. CHR(13) 576 577 COMMENTS FROM "(*" TO "*)" NESTED 578 COMMENTS FROM "//" TO lf 579 580 TOKENS 581 ident = letter { letter | digit | "_" } . 582 integer = digit { digit } 583 | digit { digit } CONTEXT("..") 584 | "0x" hexDigit { hexDigit } 585 | "0X" hexDigit { hexDigit } . 586 real = digit { digit } "." { digit } 587 [ ( "E" | "e" ) [ "+" | "-" ] digit { digit } ] . 588 string = "'" { noQuote1 } "'" 589 | '"' { noQuote2 } '"' . 590 charConst = digit { digit } ( "C" | "c" ) . 591 ustring = ( "U" | "u" ) ( "'" { noQuote1 } "'" | '"' { noQuote2 } '"' ) . 592 593 PRODUCTIONS 594 M2 595 = (. astCur := AST.NoNode; astStmt := AST.NoNode; astDecl := AST.NoNode; astImp := AST.NoNode; astImpTail := AST.NoNode; 596 astImp := AST.NoNode; 597 astImpTail := AST.NoNode; 598 nSpans := 0; 599 SymTab.DeferReset; .) 600 Unit "." . 601 (* Units: program modules compile fully; DEFINITION and 602 IMPLEMENTATION modules parse + check now but lower in step 4 603 (each ends with one 230); same for nested local modules. *) 604 (* Generics (Increment 1): formal and actual parameters. Formals are 605 TYPE parameters only; actuals are type identifiers. *) 606 GenericFormals 607 = "(" GenericFormal { ";" GenericFormal } ")" . 608 GenericFormal (. VAR nm: SymTab.Name; vt: SymTab.TypeIndex; 609 names: ARRAY [0 .. 15] OF SymTab.Name; 610 nn, k: CARDINAL; 611 mmod: SymTab.Name; 612 quid, qdep: CARDINAL; 613 qres: SymTab.TypeIndex; 614 qext: BOOLEAN; 615 cons: INTEGER; 616 cn: SymTab.Name; 617 isTypeFormal: BOOLEAN; .) 618 = (. nn := 0; .) 619 GetIdent (. k := 0; 620 WHILE (k <= HIGH(names[nn])) AND (nm[k] # CHR(0)) DO 621 names[nn][k] := nm[k]; INC(k) END; 622 names[nn][k] := CHR(0); INC(nn); .) 623 { "," GetIdent (. k := 0; 624 WHILE (k <= HIGH(names[nn])) AND (nm[k] # CHR(0)) DO 625 names[nn][k] := nm[k]; INC(k) END; 626 names[nn][k] := CHR(0); INC(nn); .) } 627 ":" (. vt := SymTab.InvalidType; isTypeFormal := FALSE; .) 628 ( "TYPE" (. isTypeFormal := TRUE; .) 629 [ "(" GetIdent ")" (. cons := ConsCode(cn); .) ] 630 | ProcType (. isTypeFormal := FALSE; .) 631 | TypeIdent ) (. k := 0; 632 WHILE k < nn DO 633 IF isTypeFormal THEN 634 IF instActive THEN 635 (* constraint: a type 636 formal needs a type 637 actual that satisfies 638 the declared constraint *) 639 IF InstActualKind(instFk) # 0 THEN 640 SemError(233) 641 ELSIF NOT ConsOk(cons, InstActualGet(instFk)) THEN 642 SemError(233) 643 ELSIF NOT SymTab.EnterTypeParamBound(names[k], InstActualGet(instFk)) THEN 644 SemError(200) END 645 ELSIF NOT SymTab.EnterTypeParam(names[k]) THEN 646 SemError(200) END 647 ELSIF SymTab.ClassOf(vt) = SymTab.ClProc THEN 648 (* procedure formal *) 649 IF instActive THEN 650 IF InstActualKind(instFk) # 2 THEN 651 SemError(233) END; 652 InstActualMod(instFk, mmod); 653 InstActualVal(instFk, nm); 654 IF NOT SymTab.AliasProc(names[k], mmod, nm) THEN 655 SemError(201) 656 ELSIF SymTab.QualProcInfo(mmod, nm, quid, qdep, qres, qext) THEN 657 Lower.AliasProc(names[k], quid, qres, qdep, qext) 658 END 659 ELSE 660 (* template: a callable 661 placeholder of the 662 formal's proc type *) 663 IF NOT SymTab.Enter(names[k], SymTab.KindVar) THEN 664 SemError(200) END; 665 SymTab.SetSymType(names[k], vt) 666 END 667 ELSE 668 (* constraint: a value 669 formal needs a value 670 actual *) 671 IF instActive AND (InstActualKind(instFk) # 1) THEN 672 SemError(233) END; 673 IF NOT SymTab.Enter(names[k], SymTab.KindConst) THEN 674 SemError(200) END; 675 SymTab.SetSymType(names[k], vt); 676 IF instActive THEN 677 InstActualVal(instFk, nm); 678 SymTab.SetSymVal(names[k], nm) 679 ELSE SymTab.SetSymVal(names[k], "0") 680 END 681 END; 682 INC(instFk); INC(k) 683 END; .) . 684 Actuals 685 = Actual { "," Actual } . 686 Actual (. VAR at: SymTab.TypeIndex; 687 nm: SymTab.Name; 688 s: ARRAY [0 .. 255] OF CHAR; 689 qv: QbeGen.QVal; 690 isCh, isV: BOOLEAN; 691 aKind: INTEGER; 692 amod: SymTab.Name; 693 nm2: SymTab.Name; 694 qu, qd: CARDINAL; 695 qr: SymTab.TypeIndex; 696 qe: BOOLEAN; 697 k: CARDINAL; .) 698 = (. isV := FALSE; at := SymTab.InvalidType; 699 nm[0] := CHR(0); nm2[0] := CHR(0); 700 aKind := 0; amod[0] := CHR(0); .) 701 ( integer (. LexString(s); QbeGen.NormInt(s, qv); 702 isV := TRUE; aKind := 1; at := SymTab.IntType(); 703 CopyNm(qv, nm); .) 704 | charConst (. LexString(s); QbeGen.NormLit(s, qv, isCh); 705 isV := TRUE; aKind := 1; at := SymTab.CharType(); 706 CopyNm(qv, nm); .) 707 | GetIdent [ "." GetIdent ] 708 (. isV := FALSE; at := SymTab.InvalidType; 709 aKind := 0; amod[0] := CHR(0); 710 IF nm2[0] # CHR(0) THEN 711 (* qualified actual Mod.Name: 712 a nested instance's type 713 (Mod.Type) or a procedure 714 (Mod.Proc); no import 715 needed *) 716 IF SymTab.QualProcInfo(nm, nm2, 717 qu, qd, qr, qe) THEN 718 aKind := 2 719 ELSE at := SymTab.QualType(nm, nm2); 720 IF at # SymTab.InvalidType THEN 721 aKind := 0 722 ELSE SemError(201); 723 aKind := 0; at := SymTab.InvalidType 724 END 725 END; 726 CopyNm(nm, amod); 727 CopyNm(nm2, nm) 728 ELSIF SymTab.Lookup(nm) 729 AND ((SymTab.SymKind(nm) = SymTab.KindType) 730 OR (SymTab.SymKind(nm) = SymTab.KindPredef)) THEN 731 at := SymTab.SymType(nm) 732 ELSIF SymTab.Lookup(nm) 733 AND (SymTab.SymKind(nm) = SymTab.KindProc) THEN 734 aKind := 2; at := SymTab.SymType(nm); 735 IF NOT SymTab.SymMod(nm, amod) THEN 736 amod[0] := CHR(0) END 737 ELSIF SymTab.Lookup(nm) 738 AND (SymTab.SymKind(nm) = SymTab.KindConst) THEN 739 isV := TRUE; aKind := 1; at := SymTab.SymType(nm); 740 IF NOT SymTab.GetSymVal(nm, s) THEN s[0] := CHR(0) END; 741 CopyNm(s, nm) 742 ELSE SemError(201) 743 END; .) ) 744 (. IF refN <= HIGH(refActual) THEN 745 IF aKind = 0 THEN 746 IF isV THEN refKind[refN] := 1 747 ELSE refKind[refN] := 0 END 748 ELSE refKind[refN] := aKind END; 749 refActual[refN] := at; 750 k := 0; 751 WHILE (k <= HIGH(refVal[refN])) AND (nm[k] # CHR(0)) DO 752 refVal[refN][k] := nm[k]; INC(k) END; 753 refVal[refN][k] := CHR(0); 754 k := 0; 755 WHILE (k <= HIGH(refMod[refN])) AND (amod[k] # CHR(0)) DO 756 refMod[refN][k] := amod[k]; INC(k) END; 757 refMod[refN][k] := CHR(0); 758 INC(refN) 759 END; .) . 760 Unit 761 = (. isGen := FALSE; 762 allowDefer := FALSE; 763 repassing := FALSE; .) 764 [ "GENERIC" (. isGen := TRUE; .) ] 765 ( DefUnit | ImplUnit | ProgModule ) . 766 (* Step 4.3: one session compiles DEFINITION, its IMPLEMENTATION 767 and one program (last) into one image. Units share the symbol 768 table; imports materialize exported names. *) 769 DefUnit (. VAR m1, m2, pn: SymTab.Name; 770 g: SymTab.Name; 771 astSeq, astTail, astProc: AST.Node; .) 772 = (. refN := 0; refSeen := FALSE; .) 773 "DEFINITION" "MODULE" 774 [ "FOR" string ] (* ISO foreign module: FOR "C" *) 775 GetIdent (. IF instActive THEN InstNameGet(m1) END; 776 IF instActive THEN 777 IF NOT SymTab.Reenter(m1, 778 SymTab.UnitDef) THEN 779 SemError(200) END 780 ELSIF NOT SymTab.BeginDef(m1) THEN 781 SemError(200) END; 782 QbeGen.SetModule(m1); 783 CopyNm(m1, unitName); 784 unitWasGen := isGen 785 AND NOT instActive; 786 unitWasDef := TRUE; .) 787 [ GenericFormals ] 788 ( ";" 789 { Import (. AstAppend(AST.NkDeclSeq, 790 astImp, astImpTail, astDecl); .) } 791 [ "EXPORT" [ "QUALIFIED" | "UNQUALIFIED" ] (. (* definition-module export 792 list: parsed, and the 793 names are already exported 794 by the module scope *) .) 795 GetIdent { "," GetIdent } ";" ] 796 (. astSeq := AST.NoNode; 797 astTail := AST.NoNode; .) 798 { ConstBlock (. AstAppend(AST.NkDeclSeq, 799 astSeq, astTail, astDecl); .) 800 | TypeBlock (. AstAppend(AST.NkDeclSeq, 801 astSeq, astTail, astDecl); .) 802 | VarBlock (. AstAppend(AST.NkDeclSeq, 803 astSeq, astTail, astDecl); .) 804 | ProcHeading ";" 805 (. (* a heading only: record it so 806 Lower can replay it *) 807 astProc := AST.MakeNode(AST.NkProcDecl); 808 AST.SetOp(astProc, 0); 809 AST.SetChild(astProc, 0, 810 AST.MakeLeaf(AST.NkIdent, pn)); 811 AstAppend(AST.NkDeclSeq, 812 astSeq, astTail, astProc); 813 Lower.NoteProcNode(astProc); 814 Lower.ScopeLeave; 815 SymTab.CloseProc; 816 QbeGen.AbortFunc; .) } 817 (. astUnit := AST.MakeNode(AST.NkUnit); 818 AST.SetChild(astUnit, 0, 819 AST.MakeLeaf(AST.NkIdent, m1)); 820 AST.SetChild(astUnit, 1, astSeq); 821 AST.SetChild(astUnit, 3, astImp); 822 astDecl := AST.NoNode; 823 astStmt := AST.NoNode; .) 824 "END" 825 GetIdent (. IF instActive THEN InstNameGet(m2) END; 826 IF NOT SymTab.Equal(m1, m2) THEN 827 SemError(202) END; 828 SymTab.EndUnit; .) 829 | "=" GetIdent [ "(" Actuals ")" ] ";" 830 (. CopyNm(m1, refInst); 831 CopyNm(g, refGen); 832 refSeen := TRUE; refIsDef := TRUE; 833 astUnit := AST.MakeNode(AST.NkUnit); 834 AST.SetChild(astUnit, 0, 835 AST.MakeLeaf(AST.NkIdent, m1)); 836 astDecl := AST.NoNode; 837 astStmt := AST.NoNode; .) 838 "END" 839 GetIdent (. IF NOT SymTab.Equal(m1, m2) THEN 840 SemError(202) END; 841 SymTab.EndUnit; .) ) . 842 ImplUnit (. VAR m1, m2: SymTab.Name; 843 g: SymTab.Name; 844 k: CARDINAL; 845 rp: CARDINAL; 846 rpOk: BOOLEAN; 847 rErrs: INTEGER; 848 rDecl, rStmt: AST.Node; 849 rnm: SymTab.Name; 850 rSym, rErr: CARDINAL; 851 fname: SymTab.Name; 852 unres: BOOLEAN; 853 astNode: AST.Node; .) 854 = (. refN := 0; refSeen := FALSE; .) 855 "IMPLEMENTATION" "MODULE" 856 [ "FOR" string ] (* ISO foreign module: FOR "C" *) 857 GetIdent (. IF instActive THEN InstNameGet(m1) END; 858 IF instActive THEN 859 IF NOT SymTab.Reenter(m1, 860 SymTab.UnitImpl) THEN 861 SemError(201) END 862 ELSIF NOT SymTab.BeginImpl(m1) THEN 863 SemError(201) END; 864 astStmt := AST.NoNode; 865 astDecl := AST.NoNode; 866 astImp := AST.NoNode; 867 astImpTail := AST.NoNode; 868 nPendVar := 0; 869 CopyNm(m1, unitName); 870 unitWasGen := isGen AND NOT instActive; 871 unitWasDef := FALSE; 872 QbeGen.SetModule(m1); .) 873 [ GenericFormals ] 874 ( ";" 875 { Import (. AstAppend(AST.NkDeclSeq, 876 astImp, astImpTail, astDecl); .) } 877 DeclSeq (. astStmt := AST.NoNode; .) 878 [ "BEGIN" (. FlushPend; 879 k := 0; 880 WHILE k < SymTab.FwdPending() DO 881 SymTab.FwdInfo(k, fname, unres); 882 IF unres THEN SemError(201) END; 883 INC(k) 884 END; 885 SymTab.FwdClear; 886 887 nLab := 0; nGot := 0; .) 888 [ StatSeq ] ] 889 (. IF twoPhaseParse THEN 890 rSym := sym; rErr := errDist; 891 rDecl := astDecl; rStmt := astStmt; 892 M2S.PushPos; 893 repassing := TRUE; 894 rp := 0; 895 WHILE rp < nSpans DO 896 k := 0; 897 WHILE (k <= HIGH(rnm)) 898 AND (spanName[rp][k] # CHR(0)) DO 899 rnm[k] := spanName[rp][k]; INC(k) 900 END; 901 rnm[k] := CHR(0); 902 M2S.SeekTo(spanStart[rp]); 903 Adv; 904 rpOk := SymTab.ReenterDeferred(spanIdx[rp]); 905 IF NOT rpOk THEN 906 FileIO.WriteString(FileIO.StdOut, 907 "twophase reenter failed"); 908 FileIO.WriteLn(FileIO.StdOut) 909 END; 910 Lower.ReenterScopeProc(spanTy[rp]); 911 QbeGen.BeginFunc(""); 912 Block(rnm); 913 AST.SetChild(spanNode[rp], 1, astStmt); 914 AST.SetChild(spanNode[rp], 2, astBlkDecls); 915 Lower.ScopeLeave; 916 SymTab.CloseProc; 917 QbeGen.EndFunc(SymTab.ProcRes(rnm)); 918 INC(rp) 919 END; 920 rErrs := M2S.errors; 921 repassing := FALSE; 922 M2S.PopPos; 923 sym := rSym; errDist := rErr; 924 M2S.errors := rErrs; 925 926 astDecl := rDecl; astStmt := rStmt 927 END; .) 928 "END" 929 GetIdent (. IF instActive THEN InstNameGet(m2) END; 930 FlushPend; 931 k := 0; 932 WHILE k < SymTab.FwdPending() DO 933 SymTab.FwdInfo(k, fname, unres); 934 IF unres THEN SemError(201) END; 935 INC(k) 936 END; 937 SymTab.FwdClear; 938 939 astNode := AST.MakeNode(AST.NkUnit); 940 AST.SetChild(astNode, 0, 941 AST.MakeLeaf(AST.NkIdent, m1)); 942 AST.SetChild(astNode, 1, astDecl); 943 AST.SetChild(astNode, 2, astStmt); 944 AST.SetChild(astNode, 3, astImp); 945 astUnit := astNode; 946 IF NOT SymTab.Equal(m1, m2) THEN 947 SemError(202) END; 948 CheckGotos; 949 SymTab.EndUnit; .) 950 | "=" GetIdent [ "(" Actuals ")" ] ";" 951 (. CopyNm(m1, refInst); 952 CopyNm(g, refGen); 953 refSeen := TRUE; refIsDef := FALSE; 954 astNode := AST.MakeNode(AST.NkUnit); 955 AST.SetChild(astNode, 0, 956 AST.MakeLeaf(AST.NkIdent, m1)); 957 astDecl := AST.NoNode; 958 astStmt := AST.NoNode; .) 959 { Import (. (* refinement unit import *) .) } 960 "END" 961 GetIdent (. IF NOT SymTab.Equal(m1, m2) THEN 962 SemError(202) END; 963 SymTab.EndUnit; .) ) . 964 ProgModule (. VAR m1, m2: SymTab.Name; 965 k: CARDINAL; 966 rp: CARDINAL; 967 rpOk: BOOLEAN; 968 rErrs: INTEGER; 969 rDecl, rStmt: AST.Node; 970 rnm: SymTab.Name; 971 rSym, rErr: CARDINAL; 972 fname: SymTab.Name; 973 unres: BOOLEAN; 974 astNode: AST.Node; .) 975 = "MODULE" 976 GetIdent (. IF NOT SymTab.BeginProg(m1) THEN 977 SemError(200) END; 978 astStmt := AST.NoNode; 979 astDecl := AST.NoNode; 980 astImp := AST.NoNode; 981 astImpTail := AST.NoNode; 982 nPendVar := 0; 983 QbeGen.SetModule(m1); .) 984 [ Priority ] 985 ";" 986 { Import (. AstAppend(AST.NkDeclSeq, 987 astImp, astImpTail, astDecl); .) } 988 DeclSeq (. astStmt := AST.NoNode; .) 989 [ "BEGIN" (. FlushPend; 990 k := 0; 991 WHILE k < SymTab.FwdPending() DO 992 SymTab.FwdInfo(k, fname, unres); 993 IF unres THEN SemError(201) END; 994 INC(k) 995 END; 996 SymTab.FwdClear; 997 998 nLab := 0; nGot := 0; .) 999 [ StatSeq ] ] 1000 (. IF twoPhaseParse THEN 1001 rSym := sym; rErr := errDist; 1002 rDecl := astDecl; rStmt := astStmt; 1003 M2S.PushPos; 1004 repassing := TRUE; 1005 rp := 0; 1006 WHILE rp < nSpans DO 1007 k := 0; 1008 WHILE (k <= HIGH(rnm)) 1009 AND (spanName[rp][k] # CHR(0)) DO 1010 rnm[k] := spanName[rp][k]; INC(k) 1011 END; 1012 rnm[k] := CHR(0); 1013 M2S.SeekTo(spanStart[rp]); 1014 Adv; 1015 rpOk := SymTab.ReenterDeferred(spanIdx[rp]); 1016 IF NOT rpOk THEN 1017 FileIO.WriteString(FileIO.StdOut, 1018 "twophase reenter failed"); 1019 FileIO.WriteLn(FileIO.StdOut) 1020 END; 1021 Lower.ReenterScopeProc(spanTy[rp]); 1022 QbeGen.BeginFunc(""); 1023 Block(rnm); 1024 AST.SetChild(spanNode[rp], 1, astStmt); 1025 AST.SetChild(spanNode[rp], 2, astBlkDecls); 1026 Lower.ScopeLeave; 1027 SymTab.CloseProc; 1028 QbeGen.EndFunc(SymTab.ProcRes(rnm)); 1029 INC(rp) 1030 END; 1031 rErrs := M2S.errors; 1032 repassing := FALSE; 1033 M2S.PopPos; 1034 sym := rSym; errDist := rErr; 1035 M2S.errors := rErrs; 1036 1037 astDecl := rDecl; astStmt := rStmt 1038 END; .) 1039 "END" 1040 GetIdent (. IF instActive THEN InstNameGet(m2) END; 1041 FlushPend; 1042 k := 0; 1043 WHILE k < SymTab.FwdPending() DO 1044 SymTab.FwdInfo(k, fname, unres); 1045 IF unres THEN SemError(201) END; 1046 INC(k) 1047 END; 1048 SymTab.FwdClear; 1049 1050 IF NOT SymTab.Equal(m1, m2) THEN 1051 SemError(202) END; 1052 astNode := AST.MakeNode(AST.NkUnit); 1053 AST.SetChild(astNode, 0, 1054 AST.MakeLeaf(AST.NkIdent, m1)); 1055 AST.SetChild(astNode, 1, astDecl); 1056 AST.SetChild(astNode, 2, astStmt); 1057 AST.SetChild(astNode, 3, astImp); 1058 astUnit := astNode; 1059 CheckGotos; 1060 SymTab.EndUnit; .) . 1061 DeclSeq (. VAR astSeq, astTail: AST.Node; .) 1062 = (. astSeq := AST.NoNode; 1063 astTail := AST.NoNode; .) 1064 { (. astDecl := AST.NoNode; .) 1065 ( ConstBlock | TypeBlock | VarBlock | ProcDecl ";" 1066 | NestedModule ";" | ClassItem ";" ) 1067 (. AstAppend(AST.NkDeclSeq, 1068 astSeq, astTail, astDecl); .) } 1069 (. astDecl := astSeq; .) . 1070 (* Local module, Wirth form. Declarations lower like top-level ones 1071 (same QBE module prefix); a BEGIN body becomes an init function 1072 that main calls; the EXPORT list is hoisted into the enclosing 1073 scope at END. *) 1074 NestedModule (. VAR m1, m2: SymTab.Name; 1075 expNames: ARRAY [0 .. 63] OF SymTab.Name; 1076 expCount, k: CARDINAL; 1077 astNode, nImp, nImpTail: 1078 AST.Node; .) 1079 = "MODULE" 1080 GetIdent (. IF NOT SymTab.Enter(m1, 1081 SymTab.KindModule) THEN 1082 SemError(200) END; 1083 SymTab.PushScope; 1084 expCount := 0; 1085 astNode := AST.MakeNode(AST.NkUnit); 1086 AST.SetChild(astNode, 0, 1087 AST.MakeLeaf(AST.NkIdent, m1)); 1088 astStmt := AST.NoNode; 1089 astDecl := AST.NoNode; 1090 nImp := AST.NoNode; 1091 nImpTail := AST.NoNode; .) 1092 [ Priority ] 1093 ";" 1094 { Import (. AstAppend(AST.NkDeclSeq, 1095 nImp, nImpTail, astDecl); .) } 1096 [ "EXPORT" [ "QUALIFIED" | "UNQUALIFIED" ] 1097 GetIdent (. INC(expCount); .) 1098 { "," GetIdent 1099 (. INC(expCount); .) } 1100 ";" ] 1101 DeclSeq (. astStmt := AST.NoNode; .) 1102 [ "BEGIN" (. astStmt := AST.NoNode; 1103 .) 1104 [ StatSeq ] ] 1105 "END" 1106 GetIdent (. AST.SetChild(astNode, 1, astDecl); 1107 AST.SetChild(astNode, 2, astStmt); 1108 AST.SetChild(astNode, 3, nImp); 1109 astDecl := astNode; 1110 IF NOT SymTab.Equal(m1, m2) THEN 1111 SemError(202) END; 1112 k := 0; 1113 WHILE k < expCount DO 1114 SymTab.ExportUp(expNames[k]); 1115 INC(k) 1116 END; 1117 SymTab.PopScope; .) . 1118 Priority 1119 = "[" integer "]" (. SemError(230); .) . 1120 (* Imports (4.3): FROM materializes the names (unqualified use); 1121 plain IMPORT only demands the module exists — qualified `L.x` 1122 materializes on first use (Design). *) 1123 (* Unknown modules stay unchecked stubs (legacy, so hand-written 1124 import lines don't fail); a known module's missing export is 1125 201. *) 1126 Import (. VAR n: SymTab.Name; 1127 astImport: AST.Node; .) 1128 = "FROM" 1129 GetIdent (. astImport := AST.MakeNode(AST.NkImport); 1130 AST.SetChild(astImport, 0, 1131 AST.MakeLeaf(AST.NkIdent, n)); .) 1132 "IMPORT" 1133 ImpList ";" (. astDecl := astImport; .) 1134 | "IMPORT" (. astImport := AST.MakeNode(AST.NkImport); .) 1135 ImpModList ";" (. astDecl := astImport; .) . 1136 ImpList 1137 (. VAR n: SymTab.Name; .) 1138 = ImpName 1139 { "," ImpName } . 1140 (* Pervasive built-ins imported from SYSTEM (e.g. TSIZE) are 1141 accepted and ignored: the built-in applies regardless. *) 1142 ImpName 1143 (. VAR n: SymTab.Name; .) 1144 = GetIdent (. AST.SetChild(node, AST.NChild(node), 1145 AST.MakeLeaf(AST.NkIdent, n)); 1146 IF SymTab.Equal(mod, "libc") THEN 1147 (* intrinsic C library: 1148 permissive external *) 1149 IF NOT SymTab.DeclareCProc(n) THEN 1150 SemError(201) END; 1151 Lower.NoteCProc(n) 1152 ELSIF SymTab.ModKnown(mod) THEN 1153 IF NOT SymTab.ImportFrom(mod, n) THEN 1154 SemError(201) 1155 ELSE Lower.NoteImportedProc(n) 1156 END 1157 END; .) 1158 | ( "TSIZE" | "SIZE" | "ADR" | "HIGH" | "LEN" 1159 | "CHR" | "ORD" | "ORDL" | "VAL" | "ABS" | "CAP" 1160 | "ODD" | "TRUNC" | "FLOAT" 1161 | "UCHR" | "CHR8" | "UORD" 1162 | "INC" | "DEC" 1163 | "SHIFT" | "ROTATE" | "CAST" | "MIN" | "MAX" 1164 | "INCL" | "EXCL" | "NEW" | "DISPOSE" | "LOC" ) . 1165 ImpModList (. VAR n: SymTab.Name; .) 1166 = GetIdent (. AST.SetChild(node, AST.NChild(node), 1167 AST.MakeLeaf(AST.NkIdent, n)); .) 1168 { "," GetIdent (. AST.SetChild(node, AST.NChild(node), 1169 AST.MakeLeaf(AST.NkIdent, n)); .) } . 1170 (* Opaque TYPE declarations (definition modules). The targetless 1171 alias resolves to InvalidType until step 4 completes it. *) 1172 (* Scalar-phase TYPEs: named types, integer subranges, enumerations. 1173 Opaque "TYPE T;" needs isDef (definition units); elsewhere 231. 1174 Composite forms (ARRAY/RECORD/SET/POINTER) arrive with step 3. *) 1175 TypeBlock (. VAR astSeq, astTail: AST.Node; .) 1176 = "TYPE" (. SymTab.BeginTypeBlock; 1177 astSeq := AST.NoNode; 1178 astTail := AST.NoNode; .) 1179 { (. astDecl := AST.NoNode; .) 1180 ( TypeItem ";" | ClassItem ";" ) 1181 (. AstAppend(AST.NkDeclSeq, 1182 astSeq, astTail, astDecl); .) } 1183 (. SymTab.EndTypeBlock; 1184 astDecl := astSeq; .) . 1185 TypeItem (. VAR n: SymTab.Name; 1186 t, op: SymTab.TypeIndex; 1187 astNode: AST.Node; .) 1188 = GetIdent (. op := SymTab.OpaqueBase(n); 1189 IF op = SymTab.InvalidType THEN 1190 IF NOT SymTab.Enter(n, 1191 SymTab.KindType) THEN 1192 SemError(200) END 1193 END; .) 1194 ( "=" Type (. astNode := AST.MakeNode(AST.NkTypeDecl); 1195 AST.SetChild(astNode, 0, 1196 AST.MakeLeaf(AST.NkIdent, n)); 1197 AST.SetTy(astNode, t); 1198 astDecl := astNode; 1199 IF op # SymTab.InvalidType THEN 1200 SymTab.SetTarget(op, t) 1201 ELSE SymTab.SetSymType(n, t) 1202 END; .) 1203 | (. IF op # SymTab.InvalidType THEN 1204 (* stays opaque *) 1205 ELSIF NOT isDef THEN 1206 SemError(231) 1207 ELSE SymTab.SetSymType(n, 1208 SymTab.NewAlias()) END; .) ) . 1209 Type 1210 = TypeIdent [ Subrange ] (* anchored subrange: T[lo..hi] *) 1211 | Subrange 1212 | Enum 1213 | ArrayType 1214 | SetType 1215 | RecordType 1216 | PointerType 1217 | ProcType . 1218 PointerType (. VAR base: SymTab.TypeIndex; .) 1219 = "POINTER" "TO" Type(. t := SymTab.NewPtr(base); .) . 1220 (* Procedure types (step 8.5): PROCEDURE (params): result. Values 1221 are code pointers; params are collected into the descriptor. *) 1222 ProcType (. VAR res, pt: SymTab.TypeIndex; 1223 isV: BOOLEAN; .) 1224 = "PROCEDURE" (. res := SymTab.InvalidType; 1225 t := SymTab.NewProcType(res); .) 1226 [ "(" [ ProcTypeSection { ";" ProcTypeSection } ] ")" ] 1227 [ ":" TypeIdent (. SymTab.SetProcTypeRes(t, res); .) ] . 1228 ProcTypeSection (. VAR pt: SymTab.TypeIndex; 1229 isV: BOOLEAN; 1230 cnt, k: CARDINAL; 1231 names: ARRAY [0 .. 15] OF SymTab.Name; .) 1232 = (. isV := FALSE; cnt := 0; .) 1233 [ "VAR" (. isV := TRUE; .) ] 1234 ( GetIdent (. INC(cnt); .) 1235 { "," GetIdent (. INC(cnt); .) } 1236 ( ":" Type (. k := 0; 1237 WHILE k < cnt DO 1238 SymTab.ProcTypeAdd(t, isV, pt); 1239 INC(k) 1240 END; .) 1241 | (. (* type-only parameter list: 1242 each name is a type (GNU 1243 shorthand used by the 1244 Coco/R scanner frame) *) 1245 k := 0; 1246 WHILE k < cnt DO 1247 IF SymTab.Lookup(names[k]) 1248 AND ((SymTab.SymKind(names[k]) = SymTab.KindType) 1249 OR (SymTab.SymKind(names[k]) = SymTab.KindPredef)) THEN 1250 pt := SymTab.SymType(names[k]) 1251 ELSE SemError(201); 1252 pt := SymTab.InvalidType 1253 END; 1254 SymTab.ProcTypeAdd(t, isV, pt); 1255 INC(k) 1256 END; .) ) 1257 | Type (. (* unnamed parameter (PIM): 1258 e.g. PROCEDURE (VAR ARRAY OF REAL) *) 1259 SymTab.ProcTypeAdd(t, isV, pt); .) ) . 1260 (* Arrays: "OF" without bounds is an open formal (allowed only 1261 where allowOpen); "[lo..hi, ...]" nests bounded levels inside 1262 out. Bounds are folded literals (int/char); anything else 230. 1263 Bare-type indices ("ARRAY Color OF") wait for enum ordinals. *) 1264 ArrayType 1265 (. VAR elem: SymTab.TypeIndex; 1266 ok: BOOLEAN; 1267 bnds, bndh: ARRAY [0 .. 7] OF INTEGER; 1268 nb, k: CARDINAL; 1269 idx: SymTab.TypeIndex; 1270 ilo, ihi: INTEGER; .) 1271 = "ARRAY" 1272 ( "OF" Type (. IF NOT allowOpen THEN 1273 SemError(230) END; 1274 t := SymTab.NewOpenArray(elem); .) 1275 | TypeIdent [ Subrange ] 1276 "OF" Type (. (* index-type array: the index 1277 type's ordinal bounds give the 1278 [lo..hi] pair *) 1279 IF SymTab.TypeBounds(idx, ilo, 1280 ihi) 1281 THEN t := SymTab.NewArrayB(elem, 1282 ilo, ihi) 1283 ELSIF SymTab.IsForwardType(idx) 1284 THEN 1285 (* forward index type: build 1286 with placeholder bounds, 1287 patched at EndTypeBlock *) 1288 t := SymTab.NewArrayB(elem, 1289 0, 0); 1290 SymTab.DeferArrayIdx(t, idx) 1291 ELSE SemError(230); 1292 t := SymTab.InvalidType 1293 END; .) 1294 | "[" (. SymTab.BoundBegin; ok := TRUE; .) 1295 BoundPair 1296 { "," BoundPair } 1297 "]" (. (* snapshot before the element 1298 type, which reuses the bound 1299 buffer for a nested ARRAY *) 1300 nb := SymTab.BoundCount(); 1301 k := 0; 1302 WHILE k < nb DO 1303 bnds[k] := SymTab.BoundLo(k); 1304 bndh[k] := SymTab.BoundHi(k); 1305 INC(k) 1306 END; .) 1307 "OF" Type 1308 (. IF ok THEN 1309 k := nb; 1310 WHILE k > 0 DO 1311 DEC(k); 1312 elem := SymTab.NewArrayB( 1313 elem, bnds[k], bndh[k]) 1314 END; 1315 t := elem 1316 ELSE t := SymTab.InvalidType 1317 END; .) ) . 1318 BoundPair (. VAR tlo, thi: SymTab.TypeIndex; 1319 qlo, qhi: QbeGen.QVal; 1320 lo, hi: INTEGER; 1321 cl, cl2: INTEGER; .) 1322 = Expr ".." Expr 1323 (. IF (tlo = SymTab.InvalidType) 1324 OR (thi = SymTab.InvalidType) THEN 1325 ok := FALSE 1326 ELSE cl := SymTab.ClassOf(tlo); 1327 cl2 := SymTab.ClassOf(thi); 1328 IF ((cl # SymTab.ClInt) 1329 AND (cl # SymTab.ClChar) 1330 AND (cl # SymTab.ClBool) 1331 AND (cl # SymTab.ClEnum)) 1332 OR ((cl2 # SymTab.ClInt) 1333 AND (cl2 # SymTab.ClChar) 1334 AND (cl2 # SymTab.ClBool) 1335 AND (cl2 # SymTab.ClEnum)) THEN 1336 SemError(230); ok := FALSE 1337 ELSIF NOT SymTab.ConstInt(qlo, lo) 1338 OR NOT SymTab.ConstInt(qhi, hi) 1339 OR (lo > hi) THEN 1340 SemError(230); ok := FALSE 1341 ELSIF NOT SymTab.BoundAdd(lo, hi) THEN 1342 SemError(230); ok := FALSE 1343 END; 1344 END; .) . 1345 (* Sets: multi-word masks over bases ≤ 256 values (bool, char, 1346 bounded subranges; enums wait for ordinals, INTEGER is 1347 unbounded). Literals are SET OF [0..255]; assignment and 1348 comparison across suitable bases are lenient (masks over min 1349 words + zero-check extras), out-of-span literals are 222. *) 1350 SetType (. VAR base: SymTab.TypeIndex; 1351 blo, bhi, bspan: INTEGER; 1352 bcls: INTEGER; .) 1353 = "SET" "OF" Type 1354 (. IF base = SymTab.InvalidType THEN 1355 t := SymTab.InvalidType 1356 ELSIF SymTab.Unresolved(base) THEN 1357 (* a forward type: defer the 1358 span check; the base 1359 resolves once the TYPE 1360 block completes *) 1361 t := SymTab.NewSet(base) 1362 ELSE bcls := 1363 SymTab.ClassOf(base); 1364 IF bcls = SymTab.ClBool THEN 1365 blo := 0; bspan := 2 1366 ELSIF bcls = SymTab.ClChar THEN 1367 blo := 0; bspan := 256 1368 ELSIF bcls = SymTab.ClEnum THEN 1369 blo := 0; 1370 bspan := VAL(INTEGER, 1371 SymTab.EnumCount(base)) 1372 ELSIF SymTab.SubBounds(base, 1373 blo, bhi) THEN 1374 bspan := bhi - blo + 1 1375 ELSE bspan := 0 END; 1376 IF (bspan <= 0) 1377 OR (bspan > 65536) THEN 1378 SemError(230); 1379 t := SymTab.InvalidType 1380 ELSE t := SymTab.NewSet(base) 1381 END 1382 END; .) . 1383 (* Records: flat blobs; array fields are pointers to static 1384 descriptors (locked amendment), nested records inline. Field 1385 offsets static and declaration-ordered. *) 1386 (* Field list: plain fields and (optionally) one variant part. The 1387 variant part is a `CASE ... END` item; because it starts with the 1388 CASE keyword it is unambiguously distinguishable from a field 1389 (which starts with an identifier). *) 1390 RecordType (. VAR t2: SymTab.TypeIndex; 1391 tagOk: BOOLEAN; .) 1392 = "RECORD" (. t := SymTab.NewRecord(); .) 1393 [ RecItem { ";" [ RecItem ] } ] 1394 "END" (. SymTab.LayoutRecord(t); .) . 1395 RecItem (. VAR tt: SymTab.TypeIndex; .) 1396 = RecField 1397 | CaseField (. SymTab.MarkVariant(rec); .) . 1398 (* A variant part: CASE tag : Type OF variants. The layout overlays 1399 every branch from the tag slot (see SymTab.ComputeOffsets). *) 1400 CaseField (. VAR tagT: SymTab.TypeIndex; 1401 tagN: SymTab.Name; .) 1402 = "CASE" (. SymTab.ResetFields(rec); .) 1403 GetIdent (. IF NOT SymTab.FieldPending(rec, 1404 tagN) THEN 1405 SemError(200) END; .) 1406 ":" Type (. IF (tagT # SymTab.InvalidType) 1407 AND NOT SymTab.IsOrdinal(tagT) THEN 1408 SemError(224) 1409 END; 1410 SymTab.FixPendingF(rec, tagT); 1411 SymTab.SetVariantTag(rec, tagN); .) 1412 "OF" 1413 RecFieldList 1414 { "|" (. SymTab.ResetFields(rec); .) 1415 RecFieldList } 1416 "END" . 1417 RecFieldList (. VAR lt, lq: SymTab.TypeIndex; 1418 lv1, lv2: QbeGen.QVal; .) 1419 = VarLabel [ ".." VarLabel ] ":" 1420 RecField { ";" [ RecField ] } . 1421 (* Variant case label: a constant (or a constant range). Values are 1422 not interpreted (the layout overlays regardless). *) 1423 VarLabel 1424 (. VAR lname: SymTab.Name; .) 1425 = ( ident (. LexName(lname); 1426 QbeGen.CopyOp("0", q); 1427 t := SymTab.IntType(); .) 1428 | integer (. LexString(lname); 1429 QbeGen.CopyOp("0", q); 1430 t := SymTab.IntType(); .) 1431 | charConst (. LexString(lname); 1432 QbeGen.CopyOp("0", q); 1433 t := SymTab.CharType(); .) ) . 1434 RecField (. VAR n: SymTab.Name; 1435 t2: SymTab.TypeIndex; .) 1436 = RecIdents ":" Type(. SymTab.FixPendingF(rec, t2); .) . 1437 RecIdents (. VAR n: SymTab.Name; .) 1438 = GetIdent (. IF NOT SymTab.FieldPending(rec, 1439 n) THEN 1440 SemError(200) END; .) 1441 { "," GetIdent (. IF NOT SymTab.FieldPending(rec, 1442 n) THEN 1443 SemError(200) END; .) } . 1444 TypeIdent (. VAR n, qid: SymTab.Name; 1445 k: INTEGER; 1446 dotted: BOOLEAN; .) 1447 = GetIdent (. dotted := FALSE; 1448 IF NOT SymTab.Lookup(n) THEN 1449 k := -1; 1450 t := SymTab.ForwardType(n); 1451 IF t = SymTab.InvalidType THEN 1452 SemError(201) 1453 END 1454 ELSE k := SymTab.SymKind(n); 1455 IF (k = SymTab.KindType) 1456 OR (k = SymTab.KindPredef) THEN 1457 t := SymTab.SymType(n) 1458 ELSE t := SymTab.InvalidType 1459 END 1460 END; .) 1461 [ "." GetIdent (. dotted := TRUE; 1462 IF k = SymTab.KindModule THEN 1463 t := SymTab.QualType(n, qid); 1464 IF t = SymTab.InvalidType THEN 1465 SemError(201) 1466 END 1467 ELSE SemError(221); 1468 t := SymTab.InvalidType 1469 END; .) ] 1470 (. IF NOT dotted THEN 1471 IF (k = SymTab.KindModule) 1472 OR ((k # SymTab.KindType) 1473 AND (k # SymTab.KindPredef) 1474 AND (k # SymTab.KindImport) 1475 AND (k # -1)) THEN 1476 SemError(221) 1477 END 1478 END; .) . 1479 Subrange (. VAR tlo, thi: SymTab.TypeIndex; 1480 qlo, qhi: QbeGen.QVal; 1481 lo, hi: INTEGER; .) 1482 = "[" Expr ".." Expr 1483 (. IF (tlo = SymTab.InvalidType) 1484 OR (thi = SymTab.InvalidType) THEN 1485 t := SymTab.InvalidType 1486 ELSIF NOT SymTab.IsOrdinal(tlo) 1487 OR NOT SymTab.IsOrdinal(thi) THEN 1488 SemError(230); 1489 t := SymTab.InvalidType 1490 ELSIF NOT SymTab.ConstInt(qlo, lo) 1491 OR NOT SymTab.ConstInt(qhi, hi) 1492 OR (lo > hi) THEN 1493 SemError(230); 1494 t := SymTab.InvalidType 1495 ELSE t := SymTab.NewSubR(lo, hi) 1496 END; .) 1497 "]" . 1498 Enum (. VAR n: SymTab.Name; 1499 ord: INTEGER; 1500 qv: QbeGen.QVal; .) 1501 = "(" (. t := SymTab.NewEnum(); 1502 ord := 0; .) 1503 GetIdent (. IF NOT SymTab.Enter(n, 1504 SymTab.KindConst) THEN 1505 SemError(200) END; 1506 SymTab.SetSymType(n, t); 1507 QbeGen.IntStr(ord, qv); 1508 SymTab.SetSymVal(n, qv); 1509 Lower.NoteVar(n, 1510 SymTab.KindConst, t); 1511 Lower.NoteConstVal(qv); 1512 INC(ord); .) 1513 { "," GetIdent (. IF NOT SymTab.Enter(n, 1514 SymTab.KindConst) THEN 1515 SemError(200) END; 1516 SymTab.SetSymType(n, t); 1517 QbeGen.IntStr(ord, qv); 1518 SymTab.SetSymVal(n, qv); 1519 Lower.NoteVar(n, 1520 SymTab.KindConst, t); 1521 Lower.NoteConstVal(qv); 1522 INC(ord); .) } 1523 ")" (. SymTab.SetEnumCount(t, 1524 VAL(CARDINAL, ord)); .) . 1525 (* Clarion-form classes (docs/OOP.txt): declaration + single 1526 inheritance + IMPLEMENTATION blocks. Scopes and member checks 1527 now; lowering (vtable, dispatch, THIS) later — one 230 per 1528 class/impl block. Methods end with ";" per the Table example 1529 (not "," as in the sketch). No underscores in identifiers. *) 1530 (* Single CLASS item in both loops: separating declaration from 1531 IMPLEMENTATION at the loop level needs 2-token lookahead 1532 (CLASS ident vs CLASS IMPLEMENTATION), which LL(1) cannot do. 1533 The second token decides after CLASS is consumed. A misplaced 1534 CLASS IMPLEMENTATION inside TYPE still parses (harmless: the 1535 whole unit ends 230 until lowering). *) 1536 ClassItem 1537 = "CLASS" ( "IMPLEMENTATION" ClassImplRest | ClassRest ) . 1538 ClassRest (. VAR cn, m2, pn: SymTab.Name; 1539 ct: SymTab.TypeIndex; .) 1540 = GetIdent (. IF NOT SymTab.Enter(cn, 1541 SymTab.KindType) THEN 1542 SemError(200) END; 1543 ct := SymTab.NewClass(); 1544 SymTab.SetSymType(cn, ct); 1545 SymTab.PushClassScope(ct); 1546 astCls := AST.MakeNode(AST.NkClassDecl); 1547 AST.SetChild(astCls, 0, 1548 AST.MakeLeaf(AST.NkIdent, cn)); 1549 astClsP := AST.NoNode; 1550 astClsPTail := AST.NoNode; 1551 astClsF := AST.NoNode; 1552 astClsFTail := AST.NoNode; 1553 astClsM := AST.NoNode; 1554 astClsMTail := AST.NoNode; .) 1555 [ Parents ] 1556 ";" 1557 { ClassField ";" } 1558 { MethodHeading ";" 1559 (. Lower.ScopeLeave; 1560 SymTab.CloseProc; 1561 QbeGen.AbortFunc; .) } 1562 "END" 1563 GetIdent (. IF NOT SymTab.Equal(cn, m2) THEN 1564 SemError(202) END; 1565 SymTab.LayoutClass(ct); 1566 SymTab.PopScope; 1567 AST.SetChild(astCls, 1, astClsP); 1568 AST.SetChild(astCls, 2, astClsF); 1569 AST.SetChild(astCls, 3, astClsM); 1570 astDecl := astCls; .) . 1571 Parents (. VAR p: SymTab.Name; .) 1572 = "(" Parent1 1573 { "," GetIdent

(. SemError(230); .) } 1574 ")" . 1575 Parent1 (. VAR p: SymTab.Name; 1576 pt: SymTab.TypeIndex; .) 1577 = GetIdent

(. IF NOT SymTab.Lookup(p) THEN 1578 SemError(201) 1579 ELSE pt := SymTab.SymType(p); 1580 IF SymTab.ClassOf(pt) # 1581 SymTab.ClClass THEN 1582 SemError(230) 1583 ELSE SymTab.SetParent(ct, pt) 1584 END 1585 END; 1586 AstAppend(AST.NkFieldDecl, 1587 astClsP, astClsPTail, 1588 AST.MakeLeaf(AST.NkIdent, p)); .) . 1589 ClassField (. VAR n, rhs: SymTab.Name; 1590 t: SymTab.TypeIndex; 1591 astNode: AST.Node; .) 1592 = GetIdent 1593 ( "=" GetIdent (. IF NOT SymTab.Enter(n, 1594 SymTab.KindConst) THEN 1595 SemError(200) END; 1596 astNode := AST.MakeNode(AST.NkConstDecl); 1597 AST.SetChild(astNode, 0, 1598 AST.MakeLeaf(AST.NkIdent, n)); 1599 AST.SetChild(astNode, 1, 1600 AST.MakeLeaf(AST.NkIdent, rhs)); 1601 AstAppend(AST.NkFieldDecl, 1602 astClsF, astClsFTail, astNode); 1603 IF SymTab.Lookup(rhs) THEN 1604 SymTab.SetSymType(n, 1605 SymTab.SymType(rhs)) 1606 END; .) 1607 | (. IF NOT SymTab.FieldPending(ct, 1608 n) THEN 1609 SemError(200) END; 1610 astNode := AST.MakeNode(AST.NkVarDecl); 1611 AST.SetChild(astNode, 0, 1612 AST.MakeLeaf(AST.NkIdent, n)); .) 1613 { "," GetIdent (. IF NOT SymTab.FieldPending(ct, 1614 n) THEN 1615 SemError(200) END; 1616 AST.SetChild(astNode, 1617 AST.NChild(astNode), 1618 AST.MakeLeaf(AST.NkIdent, n)); .) } 1619 ":" Type (. SymTab.FixPendingF(ct, t); 1620 AST.SetTy(astNode, t); 1621 AstAppend(AST.NkFieldDecl, 1622 astClsF, astClsFTail, astNode); .) ) . 1623 MethodHeading 1624 (. VAR wantVirt: BOOLEAN; .) 1625 = (. wantVirt := FALSE; .) 1626 [ "VIRTUAL" (. wantVirt := TRUE; .) ] 1627 ProcHeading (. IF wantVirt THEN 1628 SymTab.MarkVirtual END; 1629 astMethod := AST.MakeNode(AST.NkProcDecl); 1630 AST.SetChild(astMethod, 0, 1631 AST.MakeLeaf(AST.NkIdent, pn)); 1632 IF wantVirt THEN 1633 AST.SetOp(astMethod, 3) 1634 ELSE AST.SetOp(astMethod, 0) 1635 END; 1636 AstAppend(AST.NkFieldDecl, 1637 astClsM, astClsMTail, astMethod); .) . 1638 ClassImplRest (. VAR cn, m2: SymTab.Name; 1639 ct: SymTab.TypeIndex; .) 1640 = GetIdent (. IF NOT SymTab.Lookup(cn) THEN 1641 SemError(201); 1642 ct := SymTab.InvalidType 1643 ELSE ct := SymTab.SymType(cn); 1644 IF SymTab.ClassOf(ct) # 1645 SymTab.ClClass THEN 1646 SemError(230); 1647 ct := SymTab.InvalidType 1648 END 1649 END; 1650 astCls := AST.MakeNode(AST.NkClassDecl); 1651 AST.SetOp(astCls, 1); 1652 AST.SetChild(astCls, 0, 1653 AST.MakeLeaf(AST.NkIdent, cn)); 1654 astClsM := AST.NoNode; 1655 astClsMTail := AST.NoNode; 1656 astStmt := AST.NoNode; 1657 IF ct # 1658 SymTab.InvalidType THEN 1659 IF NOT SymTab.PushClassMembers( 1660 ct) THEN 1661 SemError(230) END; 1662 SymTab.PushImplClass(ct) 1663 END; .) 1664 ";" { MethodImpl ";" } 1665 (. astStmt := AST.NoNode; .) 1666 [ "BEGIN" (. astStmt := AST.MakeNode(AST.NkBlock); 1667 .) 1668 [ StatSeq ] ] 1669 "END" 1670 GetIdent (. IF NOT SymTab.Equal(cn, m2) THEN 1671 SemError(202) END; 1672 SymTab.PopImplClass; 1673 SymTab.PopScope; 1674 AST.SetChild(astCls, 1, AST.NoNode); 1675 AST.SetChild(astCls, 2, astStmt); 1676 AST.SetChild(astCls, 3, astClsM); 1677 astDecl := astCls; .) . 1678 MethodImpl (. VAR pn: SymTab.Name; 1679 thisQ: QbeGen.QVal; 1680 methRes: SymTab.TypeIndex; .) 1681 = MethodHeading ";" 1682 (. IF (ct # 1683 SymTab.InvalidType) 1684 AND NOT SymTab.MethodExists(ct, 1685 pn) THEN 1686 SemError(201) END; .) 1687 ( "FORWARD" (. AST.SetOp(astMethod, 1); 1688 SymTab.MarkFwd; 1689 QbeGen.AbortFunc; 1690 Lower.ScopeLeave; 1691 SymTab.CloseProc; .) 1692 | (. 1693 (* bind the receiver: bare 1694 field names resolve 1695 against THIS *) 1696 QbeGen.CopyOp("@", thisQ); 1697 QbeGen.PushWith(thisQ); .) 1698 Block (. AST.SetChild(astMethod, 1, astStmt); 1699 AST.SetChild(astMethod, 2, astBlkDecls); 1700 QbeGen.PopWith; 1701 methRes := SymTab.CurRes(); 1702 Lower.ScopeLeave; 1703 SymTab.CloseProc; 1704 QbeGen.EndFunc(methRes); .) ) . 1705 ConstBlock (. VAR astSeq, astTail: AST.Node; .) 1706 = "CONST" (. astSeq := AST.NoNode; 1707 astTail := AST.NoNode; .) 1708 { ConstDecl ";" (. AstAppend(AST.NkDeclSeq, 1709 astSeq, astTail, astDecl); .) } 1710 (. astDecl := astSeq; .) . 1711 ConstDecl (. VAR n: SymTab.Name; 1712 t: SymTab.TypeIndex; 1713 qv: QbeGen.QVal; 1714 cls: INTEGER; 1715 mk: ARRAY [0 .. 15] OF CARDINAL; 1716 mw: CARDINAL; 1717 mlo: INTEGER; 1718 astNode: AST.Node; .) 1719 = GetIdent (. IF NOT SymTab.Enter(n, 1720 SymTab.KindConst) THEN 1721 SemError(200) END; .) 1722 "=" 1723 Expr (. astNode := AST.MakeNode(AST.NkConstDecl); 1724 AST.SetChild(astNode, 0, 1725 AST.MakeLeaf(AST.NkIdent, n)); 1726 AST.SetChild(astNode, 1, astCur); 1727 AST.SetTy(astNode, t); 1728 astDecl := astNode; 1729 Lower.NoteVar(n, SymTab.KindConst, t); 1730 Lower.NoteConstVal(qv); 1731 SymTab.SetSymType(n, t); 1732 cls := SymTab.ClassOf(t); 1733 IF cls = SymTab.ClSet THEN 1734 (* a SET CONST needs static 1735 data: fold its mask now 1736 (the grammar sees the 1737 element values) and let 1738 Lower re-emit it *) 1739 IF Lower.SetConstMaskOf( 1740 AST.Child(astNode, 1), 1741 mk, mw, mlo) THEN 1742 Lower.NoteSetMask(n, mk, mw, 1743 mlo); 1744 SymTab.SetSymVal(n, qv) 1745 ELSE 1746 SemError(230) 1747 END 1748 ELSIF (cls = SymTab.ClArray) 1749 OR (cls = SymTab.ClRecord) 1750 OR (cls = SymTab.ClClass) 1751 OR (cls = SymTab.ClStr) 1752 OR (cls = SymTab.ClUStr) THEN 1753 (* an aggregate/string 1754 constant: qv is its 1755 descriptor address; no 1756 scalar data *) 1757 SymTab.SetSymVal(n, qv) 1758 ELSIF NOT QbeGen.IsImm(qv) THEN 1759 SemError(230) 1760 ELSE 1761 SymTab.SetSymVal(n, qv); 1762 END; .) . 1763 VarBlock (. VAR astSeq, astTail: AST.Node; .) 1764 = "VAR" (. astSeq := AST.NoNode; 1765 astTail := AST.NoNode; .) 1766 { VarDecl ";" (. AstAppend(AST.NkDeclSeq, 1767 astSeq, astTail, astDecl); .) } 1768 (. astDecl := astSeq; .) . 1769 VarDecl (. VAR nm: SymTab.Name; 1770 t: SymTab.TypeIndex; 1771 i: CARDINAL; 1772 cls: INTEGER; 1773 astNode, astTail: AST.Node; .) 1774 = VarIdents ":" 1775 Type (. astNode := AST.MakeNode(AST.NkVarDecl); 1776 astTail := astNode; 1777 i := 0; 1778 WHILE i < SymTab.PendCount() DO 1779 SymTab.PendName(i, nm); 1780 Lower.NoteVar(nm, SymTab.KindVar, t); 1781 (* chunked: a VAR list can 1782 exceed AST.MaxChild *) 1783 AstAppend(AST.NkBlock, 1784 astNode, astTail, 1785 AST.MakeLeaf(AST.NkIdent, nm)); 1786 INC(i) 1787 END; 1788 AST.SetTy(astNode, t); 1789 astDecl := astNode; 1790 cls := SymTab.ClassOf(t); 1791 IF (t # SymTab.InvalidType) 1792 AND NOT SymTab.IsUnresolved(t) 1793 AND (cls # SymTab.ClInt) 1794 AND (cls # SymTab.ClBool) 1795 AND (cls # SymTab.ClChar) 1796 AND (cls # SymTab.ClReal) 1797 AND (cls # SymTab.ClArray) 1798 AND (cls # SymTab.ClSet) 1799 AND (cls # SymTab.ClRecord) 1800 AND (cls # SymTab.ClPtr) 1801 AND (cls # SymTab.ClLong) 1802 AND (cls # SymTab.ClProc) 1803 AND (cls # SymTab.ClUChar) 1804 AND (cls # SymTab.ClUStr) 1805 AND (cls # SymTab.ClEnum) 1806 AND (cls # SymTab.ClClass) THEN 1807 SemError(230) END; 1808 IF QbeGen.LocFull() THEN 1809 SemError(233) END; 1810 i := 0; 1811 IF SymTab.IsUnresolved(t) 1812 AND NOT SymTab.InProc() THEN 1813 (* a forward-typed global: 1814 defer emission until the 1815 TYPE block completes *) 1816 AST.SetOp(astNode, 1); 1817 WHILE i < SymTab.PendCount() DO 1818 SymTab.PendName(i, nm); 1819 IF nPendVar <= 1820 HIGH(pendVarName) THEN 1821 pendVarName[nPendVar] := nm; 1822 pendVarT[nPendVar] := t; 1823 INC(nPendVar) 1824 END; 1825 INC(i) 1826 END 1827 ELSE 1828 WHILE i < SymTab.PendCount() DO 1829 SymTab.PendName(i, nm); 1830 INC(i) 1831 END 1832 END; 1833 (* a plain VAR list, not a 1834 heading: the signature 1835 result is discarded *) 1836 IF NOT SymTab.FixPending(t) THEN 1837 END; .) . 1838 VarIdents (. VAR n: SymTab.Name; .) 1839 = GetIdent (. IF NOT SymTab.EnterPending(n, 1840 SymTab.KindVar) THEN 1841 SemError(200) END; .) 1842 { "," 1843 GetIdent (. IF NOT SymTab.EnterPending(n, 1844 SymTab.KindVar) THEN 1845 SemError(200) END; .) } . 1846 ParIdents (. VAR n: SymTab.Name; .) 1847 = GetIdent (. IF NOT SymTab.EnterParam(n, isV) THEN 1848 SemError(200) END; .) 1849 { "," GetIdent (. IF NOT SymTab.EnterParam(n, isV) THEN 1850 SemError(200) END; .) } . 1851 (* Procedure headings enter scopes/params/result and buffer the 1852 QBE header; bodies lower to functions (4.1, module level only). 1853 FORWARD marks; the body heading re-enters (signature compare 1854 deferred). Nested procedures parse + check, lowering = 4.2. *) 1855 ProcHeading 1856 (. VAR t: SymTab.TypeIndex; 1857 mg: QbeGen.QVal; .) 1858 = "PROCEDURE" 1859 GetIdent (. IF methCls # 1860 SymTab.InvalidType THEN 1861 (* a method: resume the 1862 declared symbol (reuse 1863 its uid) *) 1864 IF NOT SymTab.ResumeMethod( 1865 methCls, pn) THEN 1866 SemError(200) END 1867 ELSIF NOT SymTab.EnterProc(pn) THEN 1868 IF NOT SymTab.ReenterProc(pn) THEN 1869 IF NOT SymTab.ResumeProc(pn) THEN 1870 SemError(200) END 1871 END 1872 END; 1873 Lower.ScopeEnter; 1874 Lower.NoteProc(pn, 1875 SymTab.ProcUid(pn), 1876 SymTab.InvalidType, 1877 SymTab.ProcDepthOf(pn), 1878 FALSE); 1879 QbeGen.BeginFunc(""); 1880 IF methCls # 1881 SymTab.InvalidType THEN 1882 (* hidden THIS receiver: 1883 a VAR param of the 1884 class type, pushed as 1885 the WITH base *) 1886 IF NOT SymTab.EnterThisParam( 1887 methCls) THEN 1888 SemError(200) END; 1889 IF NOT QbeGen.FuncParam( 1890 "THIS", TRUE, 1891 methCls) THEN 1892 SemError(233) END 1893 END; .) 1894 [ FormalParams ] 1895 [ ":" TypeIdent (. IF NOT SymTab.SetProcRes(t) THEN 1896 SemError(235) END; 1897 Lower.SetProcRes(t); .) ] . 1898 FormalParams 1899 = "(" [ ParamSection { ";" ParamSection } ] ")" . 1900 ParamSection (. VAR t: SymTab.TypeIndex; 1901 nm: SymTab.Name; 1902 i: CARDINAL; 1903 isV: BOOLEAN; .) 1904 = (. isV := FALSE; .) 1905 [ "VAR" (. isV := TRUE; .) ] 1906 ParIdents ":" Type (. i := 0; 1907 WHILE i < SymTab.PendCount() DO 1908 SymTab.PendName(i, nm); 1909 Lower.NoteParam(nm, t, isV); 1910 Lower.NoteVar(nm, SymTab.KindParam, t); 1911 (* value open arrays are 1912 passed as descriptor 1913 addresses (no copy): 1914 same representation as 1915 VAR formals *) 1916 IF NOT QbeGen.FuncParam(nm, 1917 isV 1918 OR SymTab.IsOpenArray(t), 1919 t) THEN 1920 SemError(233) END; 1921 INC(i) 1922 END; 1923 IF NOT SymTab.FixPending(t) THEN 1924 SemError(235) END; .) . 1925 (* Nested procedures lower like top-level ones (4.2): the 1926 static link gives them their parent's frame. Methods keep 1927 parse-now/230-later. *) 1928 ProcDecl (. VAR pn: SymTab.Name; 1929 astNode: AST.Node; .) 1930 = ProcHeading ";" 1931 (. astNode := AST.MakeNode(AST.NkProcDecl); 1932 AST.SetOp(astNode, 0); 1933 AST.SetChild(astNode, 0, 1934 AST.MakeLeaf(AST.NkIdent, pn)); 1935 Lower.NoteProcNode(astNode); .) 1936 ( "FORWARD" (. AST.SetOp(astNode, 1); 1937 astDecl := astNode; 1938 Lower.ScopeLeave; 1939 SymTab.MarkFwd; 1940 SymTab.CloseProc; 1941 QbeGen.AbortFunc; .) 1942 | "EXTERNAL" (. AST.SetOp(astNode, 2); 1943 astDecl := astNode; 1944 Lower.MarkProcExternal; 1945 Lower.ScopeLeave; 1946 SymTab.MarkExternal(""); 1947 SymTab.CloseProc; 1948 QbeGen.AbortFunc; .) 1949 | 1950 (. allowDefer := TRUE; deferredBody := FALSE; 1951 curProcNode := astNode; .) 1952 Block (. IF deferredBody THEN 1953 (* body skipped: close like 1954 FORWARD (no body node) *) 1955 astDecl := astNode; 1956 Lower.ScopeLeave; 1957 SymTab.CloseProc; 1958 QbeGen.AbortFunc 1959 ELSE 1960 AST.SetChild(astNode, 1, astStmt); 1961 AST.SetChild(astNode, 2, astBlkDecls); 1962 astDecl := astNode; 1963 Lower.ScopeLeave; 1964 SymTab.CloseProc; 1965 QbeGen.EndFunc( 1966 SymTab.ProcRes(pn)) 1967 END; .) ) . 1968 Block (. VAR m2: SymTab.Name; dfr: BOOLEAN; .) 1969 = (. dfr := FALSE; 1970 IF allowDefer AND twoPhaseParse 1971 AND NOT repassing THEN 1972 dfr := DeferSkip(pn) 1973 END; 1974 allowDefer := FALSE; 1975 .) 1976 DeclSeq (. astBlkDecls := astDecl; 1977 astStmt := AST.NoNode; 1978 nLab := 0; nGot := 0; .) 1979 [ "BEGIN" (. (* an empty body is still a 1980 body: mark it so Lower 1981 does not read it as a 1982 definition heading *) 1983 IF NOT dfr THEN 1984 IF astStmt = AST.NoNode THEN 1985 astStmt := 1986 AST.MakeNode(AST.NkBlock) 1987 END 1988 END; .) 1989 [ StatSeq ] ] 1990 "END" 1991 GetIdent (. IF NOT SymTab.Equal(pn, m2) THEN 1992 SemError(202) END; 1993 CheckGotos; .) . 1994 (* Two-phase, phase 2 (milestone 2c): re-parse every deferred module- 1995 level body once the unit's declarations are complete. Inlined at 1996 both call sites because a stand-alone epsilon production is 1997 "unreachable" to Coco/R (referenced only from actions). *) 1998 StatSeq (. VAR astSeq, astTail: AST.Node; .) 1999 = (. astSeq := AST.NoNode; 2000 astTail := AST.NoNode; .) 2001 Statement (. AstAppend(AST.NkBlock, 2002 astSeq, astTail, astStmt); .) 2003 { ";" [ Statement (. AstAppend(AST.NkBlock, 2004 astSeq, astTail, astStmt); .) ] } 2005 (. astStmt := astSeq; .) . 2006 (* Trailing/empty statements (`a; ; b`, Coco/R's generated `;;`) 2007 are accepted: the statement after ';' is optional. *) 2008 Statement (. VAR lx: QbeGen.QVal; lxnm: SymTab.Name; .) 2009 = (. astStmt := AST.NoNode; .) 2010 ( AssOrCall 2011 | IfStat 2012 | WhileStat 2013 | RepeatStat 2014 | LoopStat 2015 | ForStat 2016 | CaseStat 2017 | WithStat 2018 | ReturnStat 2019 | HaltStat 2020 | NewStat 2021 | DisposeStat 2022 | IncDecStat 2023 | InclExclStat 2024 | "EXIT" (. IF NOT QbeGen.TopLoop(lx) THEN 2025 SemError(230) END; 2026 astStmt := AST.MakeNode(AST.NkExit); .) 2027 | "GOTO" GetIdent (. NoteGoto(lxnm); 2028 astStmt := AST.MakeNode(AST.NkGoto); 2029 AST.SetChild(astStmt, 0, 2030 AST.MakeLeaf(AST.NkIdent, lxnm)); .) ) . 2031 (* INCL(set, elem) / EXCL(set, elem): PIM set-element builtins. *) 2032 InclExclStat (. VAR at, et2: SymTab.TypeIndex; 2033 dk: INTEGER; 2034 qd, qe: QbeGen.QVal; 2035 qn: SymTab.Name; 2036 sfx, isInc: BOOLEAN; 2037 astNode, astD: AST.Node; .) 2038 = ( "INCL" (. isInc := TRUE; .) 2039 | "EXCL" (. isInc := FALSE; .) ) 2040 "(" Design (. astD := astCur; .) "," 2041 Expr ")" 2042 (. astNode := AST.MakeNode(AST.NkCall); 2043 IF isInc THEN 2044 AST.SetChild(astNode, 0, 2045 AST.MakeLeaf(AST.NkIdent, "INCL")) 2046 ELSE AST.SetChild(astNode, 0, 2047 AST.MakeLeaf(AST.NkIdent, "EXCL")) 2048 END; 2049 IF astD # AST.NoNode THEN 2050 AST.SetChild(astNode, 1, astD) END; 2051 IF astCur # AST.NoNode THEN 2052 AST.SetChild(astNode, 2, astCur) END; 2053 astStmt := astNode; .) 2054 (. IF (at # SymTab.InvalidType) 2055 AND (SymTab.ClassOf(at) # SymTab.ClSet) THEN 2056 SemError(222) 2057 END; .) . 2058 (* INC(v [,step]) / DEC(v [,step]) as builtin statements over an 2059 integer designator. *) 2060 IncDecStat (. VAR dt, et2: SymTab.TypeIndex; 2061 dk: INTEGER; 2062 qd, qv, qn2, qstep: 2063 QbeGen.QVal; 2064 qn: SymTab.Name; 2065 sfx, isInc: BOOLEAN; 2066 astNode, astD, astStep: 2067 AST.Node; .) 2068 = (. isInc := TRUE; .) 2069 ( "INC" (. isInc := TRUE; .) 2070 | "DEC" (. isInc := FALSE; .) ) 2071 "(" (. astStep := AST.NoNode; .) 2072 Design (. astD := astCur; .) 2073 [ "," Expr (. astStep := astCur; .) ] 2074 ")" (. astNode := AST.MakeNode(AST.NkCall); 2075 IF isInc THEN 2076 AST.SetChild(astNode, 0, 2077 AST.MakeLeaf(AST.NkIdent, "INC")) 2078 ELSE AST.SetChild(astNode, 0, 2079 AST.MakeLeaf(AST.NkIdent, "DEC")) 2080 END; 2081 IF astD # AST.NoNode THEN 2082 AST.SetChild(astNode, 1, astD) END; 2083 IF astStep # AST.NoNode THEN 2084 AST.SetChild(astNode, 2, astStep) END; 2085 astStmt := astNode; .) (. IF dt = SymTab.InvalidType THEN 2086 ELSIF (dk # SymTab.KindVar) 2087 AND (dk # SymTab.KindParam) 2088 AND (dk # SymTab.KindField) THEN 2089 SemError(210) 2090 ELSIF NOT SymTab.IsIntFamily(dt) THEN 2091 SemError(211) 2092 END; .) . 2093 (* NEW/DISPOSE as builtin statements (no call syntax until step 4). 2094 Targets are pointer designators; DISPOSE nils afterwards (safer 2095 than Wirth-undefined; documented). DISPOSE is shallow. *) 2096 NewStat (. VAR dt: SymTab.TypeIndex; 2097 dk: INTEGER; 2098 qd, qm: QbeGen.QVal; 2099 qn: SymTab.Name; 2100 sfx: BOOLEAN; 2101 bt: SymTab.TypeIndex; 2102 astNode, astD: AST.Node; .) 2103 = "NEW" "(" Design (. astD := astCur; .) ")" 2104 (. astNode := AST.MakeNode(AST.NkCall); 2105 AST.SetChild(astNode, 0, 2106 AST.MakeLeaf(AST.NkIdent, "NEW")); 2107 IF astD # AST.NoNode THEN 2108 AST.SetChild(astNode, 1, astD) END; 2109 astStmt := astNode; .) 2110 (. IF dt = SymTab.InvalidType THEN 2111 ELSIF (dk # SymTab.KindVar) 2112 AND (dk # SymTab.KindParam) 2113 AND (dk # SymTab.KindField) THEN 2114 SemError(210) 2115 ELSIF SymTab.ClassOf(dt) # 2116 SymTab.ClPtr THEN 2117 SemError(219) 2118 END; .) . 2119 DisposeStat (. VAR dt: SymTab.TypeIndex; 2120 dk: INTEGER; 2121 qd, qv: QbeGen.QVal; 2122 qn: SymTab.Name; 2123 sfx: BOOLEAN; 2124 astNode, astD: AST.Node; .) 2125 = "DISPOSE" "(" Design (. astD := astCur; .) ")" 2126 (. astNode := AST.MakeNode(AST.NkCall); 2127 AST.SetChild(astNode, 0, 2128 AST.MakeLeaf(AST.NkIdent, "DISPOSE")); 2129 IF astD # AST.NoNode THEN 2130 AST.SetChild(astNode, 1, astD) END; 2131 astStmt := astNode; .) 2132 (. IF dt = SymTab.InvalidType THEN 2133 ELSIF (dk # SymTab.KindVar) 2134 AND (dk # SymTab.KindParam) 2135 AND (dk # SymTab.KindField) THEN 2136 SemError(210) 2137 ELSIF SymTab.ClassOf(dt) # 2138 SymTab.ClPtr THEN 2139 SemError(219) 2140 END; .) . 2141 (* WITH pushes each record's fields (inner wins) plus its base 2142 address; field designators resolve through both stacks. *) 2143 WithStat (. VAR nW: CARDINAL; 2144 astNode: AST.Node; .) 2145 = "WITH" (. nW := 0; 2146 astNode := AST.MakeNode(AST.NkWith); .) 2147 WithItem { "," WithItem } 2148 "DO" (. astStmt := AST.NoNode; .) 2149 [ StatSeq ] "END" (. AST.SetChild(astNode, 2150 AST.NChild(astNode), astStmt); 2151 astStmt := astNode; 2152 WHILE nW > 0 DO 2153 SymTab.PopScope; 2154 QbeGen.PopWith; 2155 DEC(nW) 2156 END; .) . 2157 WithItem 2158 (. VAR dt: SymTab.TypeIndex; 2159 dk: INTEGER; 2160 qd, qe: QbeGen.QVal; 2161 qn: SymTab.Name; 2162 sfx: BOOLEAN; .) 2163 = Design 2164 (. IF astCur # AST.NoNode THEN 2165 AST.SetChild(wnode, 2166 AST.NChild(wnode), astCur) END; 2167 IF dt = SymTab.InvalidType THEN 2168 ELSIF (SymTab.ClassOf(dt) # 2169 SymTab.ClRecord) 2170 AND (SymTab.ClassOf(dt) # 2171 SymTab.ClClass) THEN 2172 SemError(215) 2173 ELSIF SymTab.PushRecord(dt) THEN 2174 QbeGen.PushWith(qd); 2175 INC(nW) 2176 END; .) . 2177 (* Assignment or procedure-statement call (4.1, module level). 2178 Bare `P;` is a syntax error; function-as-statement is 233. *) 2179 AssOrCall (. VAR dt, et: SymTab.TypeIndex; 2180 dk: INTEGER; 2181 qd, qe, qt, ql: QbeGen.QVal; 2182 qn: SymTab.Name; 2183 ct2, res0: SymTab.TypeIndex; 2184 q2, mg0: QbeGen.QVal; 2185 isR, conv, wconv: BOOLEAN; 2186 called, sfx: BOOLEAN; 2187 astLhs, astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN; 2188 n: SymTab.Name; astLab, astNode: AST.Node; .) 2189 = GetIdent 2190 ( ":" (. NoteLabel(n); 2191 astNode := AST.MakeNode(AST.NkLabel); 2192 AST.SetChild(astNode, 0, 2193 AST.MakeLeaf(AST.NkIdent, n)); 2194 astLab := AST.MakeNode(AST.NkBlock); 2195 AST.SetChild(astLab, 0, astNode); .) 2196 Statement (. IF astStmt # AST.NoNode THEN 2197 AST.SetChild(astLab, 1, astStmt) END; 2198 astStmt := astLab; .) 2199 | DesignTail 2200 (. astLhs := astCur; astNArgs := 0; .) 2201 ( ":=" 2202 Expr (. astStmt := AST.MakeBin( 2203 AST.NkAssign, 0, astLhs, astCur); 2204 IF (dt # SymTab.InvalidType) 2205 AND (dk # SymTab.KindVar) 2206 AND (dk # SymTab.KindParam) 2207 AND (dk # SymTab.KindField) THEN 2208 SemError(210) 2209 ELSIF NOT SymTab.Assignable(et, 2210 dt) THEN 2211 SemError(210) 2212 ELSIF (dt # SymTab.InvalidType) 2213 AND (SymTab.ClassOf(dt) = 2214 SymTab.ClClass) THEN 2215 SemError(230) END; 2216 isR := (dt # 2217 SymTab.InvalidType) 2218 AND (SymTab.ClassOf(dt) 2219 = SymTab.ClReal); 2220 conv := isR 2221 AND SymTab.IsIntFamily(et); 2222 wconv := (dt # 2223 SymTab.InvalidType) 2224 AND SymTab.IsLongFamily(dt) 2225 AND SymTab.IsIntFamily(et); 2226 IF ((dk = SymTab.KindVar) 2227 OR (dk = SymTab.KindParam) 2228 OR (dk = SymTab.KindField)) 2229 AND (dt # SymTab.InvalidType) 2230 AND (et # SymTab.InvalidType) 2231 AND (SymTab.ClassOf(dt) # 2232 SymTab.ClClass) THEN 2233 END; .) 2234 | ArgList 2235 (. astRes := AstCallNode(astLhs); 2236 sfx := FALSE; .) 2237 ( { ResultComp } 2238 ":=" Expr (. astStmt := AST.MakeBin( 2239 AST.NkAssign, 0, astRes, astCur); 2240 IF NOT sfx THEN 2241 SemError(233) 2242 ELSIF (ct2 # SymTab.InvalidType) 2243 AND NOT SymTab.Assignable(et, ct2) THEN 2244 SemError(210) 2245 END; .) 2246 | (. IF ct2 # 2247 SymTab.InvalidType THEN 2248 SemError(233) END; 2249 astStmt := astRes; .) ) 2250 | (* bare `P;`: proper parameterless 2251 procedure call; anything else 2252 here is 233 (was a bare syntax 2253 error before 4.2) *) 2254 (. astStmt := AstCallNode(astLhs); 2255 IF (dk = SymTab.KindProc) 2256 AND NOT sfx THEN 2257 res0 := SymTab.ProcRes(qn); 2258 IF res0 # 2259 SymTab.InvalidType THEN 2260 SemError(233) 2261 ELSIF SymTab.ProcNPar(qn) # 2262 0 THEN 2263 SemError(233) 2264 END 2265 ELSE SemError(233) 2266 END; .) ) ) . 2267 (* Actual-parameter list shared by statement and expression calls. 2268 want selects CallEnd's result handling; t/q carry the call 2269 value (statement calls discard). Arity/type failures are 233; 2270 evaluation code still emits so the .ssa stays assembleable. *) 2271 ArgList (. VAR i, np: CARDINAL; 2275 vs: INTEGER; 2276 res: SymTab.TypeIndex; 2277 mg: QbeGen.QVal; 2278 ok, ind, isMeth, va, isConv: BOOLEAN; .) 2279 = "(" (. called := TRUE; 2280 ok := TRUE; 2281 ind := FALSE; 2282 isConv := FALSE; 2283 isMeth := methCls # 2284 SymTab.InvalidType; 2285 IF isMeth THEN 2286 res := SymTab.ClassMethodRes(methCls, pn) 2287 ELSIF SymTab.SymKind(pn) = SymTab.KindProc THEN 2288 res := SymTab.ProcRes(pn) 2289 ELSIF (SymTab.SymKind(pn) = SymTab.KindType) 2290 OR (SymTab.SymKind(pn) = SymTab.KindPredef) THEN 2291 (* ISO type conversion T(x): 2292 one value, result is T *) 2293 isConv := TRUE; 2294 res := SymTab.SymType(pn) 2295 ELSIF (pt # SymTab.InvalidType) 2296 AND (SymTab.ClassOf(pt) = SymTab.ClProc) THEN 2297 ind := TRUE; 2298 res := SymTab.ProcTypeRes(pt) 2299 ELSE SemError(233); 2300 ok := FALSE; 2301 res := SymTab.InvalidType 2302 END; 2303 i := 0; .) 2304 [ ActParam (. INC(i); .) 2305 { "," ActParam (. INC(i); .) } ] 2306 ")" (. IF ok THEN 2307 IF isConv THEN 2308 (* a conversion takes 2309 exactly one value *) 2310 IF i # 1 THEN 2311 SemError(233); ok := FALSE 2312 END 2313 ELSE 2314 IF isMeth THEN 2315 np := SymTab.ClassMethodNPar( 2316 methCls, pn) 2317 ELSIF ind THEN 2318 np := SymTab.ProcTypeNPar(pt) 2319 ELSE np := SymTab.ProcNPar(pn) 2320 END; 2321 va := (NOT isMeth) AND (NOT ind) 2322 AND (SymTab.SymKind(pn) = 2323 SymTab.KindProc) 2324 AND SymTab.Varargs(pn); 2325 IF (i # np) AND NOT va THEN 2326 SemError(233); ok := FALSE 2327 END 2328 END 2329 END; 2330 IF NOT ok THEN 2331 t := SymTab.InvalidType; 2332 QbeGen.CopyOp("0", q) 2333 ELSIF want THEN 2334 IF res = 2335 SymTab.InvalidType THEN 2336 IF NOT soft THEN SemError(233) END; 2337 t := SymTab.InvalidType; 2338 QbeGen.CopyOp("0", q) 2339 ELSE t := res; 2340 QbeGen.CopyOp("@", q) 2341 END 2342 ELSE 2343 IF res # 2344 SymTab.InvalidType THEN 2345 SemError(233) 2346 END; 2347 t := SymTab.InvalidType; 2348 QbeGen.CopyOp("0", q); 2349 END; .) . 2350 (* One actual: VAR formals take recorded designator addresses 2351 (233 otherwise); value formals take converted expressions. *) 2352 ActParam 2354 (. VAR at, ft: SymTab.TypeIndex; 2355 qe, qa, qt: QbeGen.QVal; 2356 isV, conv, va: BOOLEAN; 2357 cl: CHAR; 2358 savedN, aj: CARDINAL; 2359 savedArgs: ARRAY [0 .. 31] 2360 OF AST.Node; 2361 astActual: AST.Node; .) 2362 = (. (* Parsing the actual can clobber 2363 the enclosing call's argument 2364 list (Factor resets astNArgs), 2365 so save/restore it. *) 2366 savedN := astNArgs; aj := 0; 2367 WHILE aj <= HIGH(astArgs) DO 2368 savedArgs[aj] := astArgs[aj]; 2369 INC(aj) 2370 END; .) 2371 Expr (. QbeGen.CopyOp(qe, convQ); convT := at; 2372 astActual := astCur; 2373 astNArgs := savedN; aj := 0; 2374 WHILE aj <= HIGH(astArgs) DO 2375 astArgs[aj] := savedArgs[aj]; 2376 INC(aj) 2377 END; 2378 IF astNArgs <= HIGH(astArgs) THEN 2379 astArgs[astNArgs] := astCur; 2380 INC(astNArgs) 2381 END; 2382 va := (NOT ind) 2383 AND (methCls = 2384 SymTab.InvalidType) 2385 AND (SymTab.SymKind(pn) = 2386 SymTab.KindProc) 2387 AND SymTab.Varargs(pn); 2388 IF ind THEN 2389 ft := 2390 SymTab.ProcTypeParamType(pt, 2391 i); 2392 isV := 2393 SymTab.ProcTypeParamIsVar(pt, 2394 i) 2395 ELSIF methCls # 2396 SymTab.InvalidType THEN 2397 ft := 2398 SymTab.ClassMethodParamType( 2399 methCls, pn, i); 2400 isV := 2401 SymTab.ClassMethodParamIsVar( 2402 methCls, pn, i) 2403 ELSE 2404 ft := SymTab.ParamType(pn, i); 2405 isV := SymTab.ParamIsVar(pn, i) 2406 END; 2407 IF (at = SymTab.InvalidType) THEN 2408 ELSIF ft = SymTab.InvalidType THEN 2409 ELSIF isV THEN 2410 IF (SymTab.ClassOf(at) = SymTab.ClChar) 2411 AND (SymTab.ClassOf(ft) = SymTab.ClArray) 2412 AND (SymTab.ClassOf(SymTab.ArrayElem(ft)) = SymTab.ClChar) 2413 AND QbeGen.IsImm(qe) THEN 2414 ELSIF (AST.Kind(astActual) # 2415 AST.NkDesignator) 2416 AND (AST.Kind(astActual) # AST.NkStrLit) THEN 2417 SemError(233) 2418 ELSIF NOT SymTab.VarParamOk(at, ft) THEN 2419 SemError(233) 2420 END 2421 ELSE 2422 IF (SymTab.ClassOf(at) = SymTab.ClChar) 2423 AND (SymTab.ClassOf(ft) = SymTab.ClArray) 2424 AND (SymTab.ClassOf(SymTab.ArrayElem(ft)) = SymTab.ClChar) 2425 AND QbeGen.IsImm(qe) THEN 2426 ELSIF NOT SymTab.Assignable(at, ft) THEN 2427 SemError(233) 2428 END 2429 END; .) . 2430 IfStat (. VAR t: SymTab.TypeIndex; 2431 q: QbeGen.QVal; 2432 hasElse: BOOLEAN; 2433 astCond, astIf, astLast, 2434 astNode: AST.Node; .) 2435 = "IF" (. hasElse := FALSE; .) 2436 Expr (. astCond := astCur; astStmt := AST.NoNode; 2437 IF NOT SymTab.BoolCheck(t) THEN 2438 SemError(214) END; .) 2439 "THEN" [ StatSeq ] (. astNode := AST.MakeNode(AST.NkIf); 2440 AST.SetChild(astNode, 0, astCond); 2441 AST.SetChild(astNode, 1, astStmt); 2442 astIf := astNode; 2443 astLast := astNode; .) 2444 { "ELSIF" 2445 Expr (. astCond := astCur; astStmt := AST.NoNode; 2446 IF NOT SymTab.BoolCheck(t) THEN 2447 SemError(214) END; .) 2448 "THEN" [ StatSeq ] (. astNode := AST.MakeNode(AST.NkIf); 2449 AST.SetChild(astNode, 0, astCond); 2450 AST.SetChild(astNode, 1, astStmt); 2451 AST.SetChild(astLast, 2, astNode); 2452 astLast := astNode; .) } 2453 [ "ELSE" (. hasElse := TRUE; 2454 astStmt := AST.NoNode; .) 2455 [ StatSeq ] (. AST.SetChild(astLast, 2, astStmt); .) ] 2456 "END" (. astStmt := astIf; .) . 2457 WhileStat (. VAR t: SymTab.TypeIndex; 2458 q: QbeGen.QVal; 2459 astCond, astNode: AST.Node; .) 2460 = "WHILE" (. astStmt := AST.NoNode; .) 2461 Expr (. astCond := astCur; 2462 IF NOT SymTab.BoolCheck(t) THEN 2463 SemError(214) END; .) 2464 "DO" [ StatSeq ] (. astNode := AST.MakeNode(AST.NkWhile); 2465 AST.SetChild(astNode, 0, astCond); 2466 AST.SetChild(astNode, 1, astStmt); 2467 astStmt := astNode; .) 2468 "END" . 2469 RepeatStat (. VAR t: SymTab.TypeIndex; 2470 q: QbeGen.QVal; 2471 astCond, astBody, astNode: 2472 AST.Node; .) 2473 = "REPEAT" (. astStmt := AST.NoNode; .) 2474 [ StatSeq ] (. astBody := astStmt; .) 2475 "UNTIL" Expr (. astCond := astCur; 2476 astNode := AST.MakeNode(AST.NkRepeat); 2477 AST.SetChild(astNode, 0, astBody); 2478 AST.SetChild(astNode, 1, astCond); 2479 astStmt := astNode; 2480 IF NOT SymTab.BoolCheck(t) THEN 2481 SemError(214) END; .) . 2482 LoopStat (. VAR lEnd: QbeGen.QVal; astNode: AST.Node; .) 2483 = "LOOP" (. astStmt := AST.NoNode; 2484 QbeGen.NewLabel(lEnd); 2485 QbeGen.PushLoop(lEnd); .) 2486 [ StatSeq ] 2487 "END" (. astNode := AST.MakeNode(AST.NkLoop); 2488 AST.SetChild(astNode, 0, astStmt); 2489 astStmt := astNode; 2490 QbeGen.PopLoop; .) . 2491 (* FOR with static-sign BY (literal, non-zero; 220 otherwise). 2492 Runtime direction would need a compare-select; the literal 2493 sign picks cslew/csegew at "DO" time. *) 2494 ForStat (. VAR lv: SymTab.Name; 2495 tlo, thi, tby: 2496 SymTab.TypeIndex; 2497 qlo, qhi, qby, qt, qk, qb: 2498 QbeGen.QVal; 2499 lTop, lBody, lEnd: 2500 QbeGen.QVal; 2501 by: INTEGER; 2502 ok: BOOLEAN; 2503 astVar, astLo, astHi, astBy, 2504 astNode: AST.Node; .) 2505 = "FOR" (. by := 1; .) 2506 GetIdent (. astVar := AST.MakeLeaf(AST.NkIdent, lv); 2507 astStmt := AST.NoNode; 2508 astBy := AST.NoNode; 2509 ok := SymTab.Lookup(lv); 2510 IF NOT ok THEN 2511 SemError(201) 2512 ELSIF (SymTab.SymKind(lv) # 2513 SymTab.KindVar) 2514 AND (SymTab.SymKind(lv) # 2515 SymTab.KindParam) THEN 2516 SemError(220); ok := FALSE 2517 ELSIF NOT SymTab.IsIntFamily( 2518 SymTab.SymType(lv)) THEN 2519 SemError(220); ok := FALSE 2520 END; .) 2521 ":=" Expr (. astLo := astCur; 2522 IF NOT SymTab.IsIntFamily(tlo) THEN 2523 SemError(220); ok := FALSE 2524 END; .) 2525 "TO" Expr (. astHi := astCur; 2526 IF NOT SymTab.IsIntFamily(thi) THEN 2527 SemError(220); ok := FALSE 2528 END; .) 2529 [ "BY" Expr (. astBy := astCur; 2530 IF (tby # 2531 SymTab.InvalidType) 2532 AND NOT SymTab.IsIntFamily(tby) THEN 2533 SemError(220); ok := FALSE 2534 END; 2535 IF NOT SymTab.ConstInt(qby, by) THEN 2536 SemError(230); by := 1 2537 ELSIF by = 0 THEN 2538 SemError(220); by := 1 2539 END; .) ] 2540 "DO" 2541 [ StatSeq ] 2542 "END" (. astNode := AST.MakeNode(AST.NkFor); 2543 AST.SetChild(astNode, 0, astVar); 2544 AST.SetChild(astNode, 1, astLo); 2545 AST.SetChild(astNode, 2, astHi); 2546 AST.SetChild(astNode, 3, astBy); 2547 AST.SetChild(astNode, 4, astStmt); 2548 astStmt := astNode; 2549 .) . 2550 CaseStat (. VAR tsel: SymTab.TypeIndex; 2551 qsel, lEnd: QbeGen.QVal; 2552 arm, astNode, astArms, 2553 astArmsTail: AST.Node; .) 2554 = "CASE" Expr (. astNode := AST.MakeNode(AST.NkCase); 2555 AST.SetChild(astNode, 0, astCur); 2556 astArms := AST.NoNode; 2557 astArmsTail := AST.NoNode; 2558 .) 2559 "OF" CaseAlt 2560 { "|" CaseAlt } 2561 [ "ELSE" (. astStmt := AST.NoNode; .) 2562 [ StatSeq ] (. arm := AST.MakeNode(AST.NkCaseArm); 2563 AST.SetOp(arm, 1); 2564 AST.SetChild(arm, 0, astStmt); 2565 AstAppend(AST.NkBlock, 2566 astArms, astArmsTail, arm); .) ] 2567 "END" (. AST.SetChild(astNode, 1, astArms); 2568 astStmt := astNode; 2569 .) . 2570 (* Compare-chain lowering: each alternative ends its match-tests 2571 with "jmp lAfter", so the no-match fallthrough skips the body: 2572 "cmp; jnz(lBody,lF); lF: ... ; jmp lAfter; lBody: S; jmp lEnd; 2573 lAfter:". Falls into the next alternative, ELSE, or END. *) 2574 CaseAlt 2576 (. VAR arm: AST.Node; .) 2577 = (. arm := AST.MakeNode(AST.NkCaseArm); .) 2578 CaseLabel 2579 { "," CaseLabel } 2580 ":" (. astStmt := AST.NoNode; .) 2581 [ StatSeq ] (. AST.SetChild(arm, AST.NChild(arm), 2582 astStmt); 2583 AstAppend(AST.NkBlock, 2584 arms, armsTail, arm); 2585 .) . 2586 CaseLabel 2588 (. VAR t2, t3: SymTab.TypeIndex; 2589 q2, q3, qc, qd, qe: 2590 QbeGen.QVal; 2591 astLab: AST.Node; 2592 lNext: QbeGen.QVal; .) 2593 = Expr (. astLab := astCur; 2594 IF (t2 # 2595 SymTab.InvalidType) 2596 AND (tsel # 2597 SymTab.InvalidType) 2598 AND ((SymTab.ClassOf(t2) = 2599 SymTab.ClSet) 2600 OR (SymTab.ClassOf(tsel) = 2601 SymTab.ClSet)) THEN 2602 SemError(230) 2603 ELSIF (t2 # 2604 SymTab.InvalidType) 2605 AND (tsel # 2606 SymTab.InvalidType) 2607 AND NOT SymTab.EqCheck(t2, 2608 tsel) THEN 2609 SemError(213) END; 2610 IF NOT QbeGen.IsImm(q2) THEN 2611 SemError(230) 2612 END; .) 2613 [ ".." Expr (. astLab := AST.MakeBin( 2614 AST.NkSubrange, 0, astLab, astCur); 2615 IF (t3 # 2616 SymTab.InvalidType) 2617 AND (tsel # 2618 SymTab.InvalidType) 2619 AND NOT SymTab.EqCheck(t3, 2620 tsel) THEN 2621 SemError(213) END; 2622 IF NOT QbeGen.IsImm(q3) THEN 2623 SemError(230) 2624 END; .) ] 2625 (. AST.SetChild(arm, 2626 AST.NChild(arm), astLab); .) . 2627 ReturnStat (. VAR t: SymTab.TypeIndex; 2628 q, qt: QbeGen.QVal; 2629 res: SymTab.TypeIndex; 2630 hadE, conv: BOOLEAN; 2631 astVal, astNode: AST.Node; .) 2632 = "RETURN" (. hadE := FALSE; astStmt := AST.NoNode; .) 2633 [ Expr (. hadE := TRUE; astVal := astCur; .) ] 2634 (. astNode := AST.MakeNode(AST.NkReturn); 2635 IF hadE THEN 2636 AST.SetChild(astNode, 0, astVal) 2637 END; 2638 astStmt := astNode; 2639 conv := FALSE; 2640 IF NOT SymTab.InProc() THEN 2641 SemError(232) 2642 ELSE res := SymTab.CurRes(); 2643 IF NOT hadE THEN 2644 IF res # 2645 SymTab.InvalidType THEN 2646 SemError(232) 2647 END 2648 ELSIF (res = 2649 SymTab.InvalidType) 2650 OR (t # 2651 SymTab.InvalidType) 2652 AND NOT SymTab.Assignable(t, 2653 res) THEN 2654 SemError(232) 2655 END 2656 END; .) . 2657 HaltStat (. VAR t: SymTab.TypeIndex; 2658 q: QbeGen.QVal; 2659 astVal, astNode: AST.Node; .) 2660 = "HALT" (. astVal := AST.NoNode; .) 2661 [ "(" Expr (. astVal := astCur; .) ")" ] 2662 (. astNode := AST.MakeNode(AST.NkHalt); 2663 IF astVal # AST.NoNode THEN 2664 AST.SetChild(astNode, 0, astVal) 2665 END; 2666 astStmt := astNode; 2667 .) . 2668 (* Designator: scalar loads, array addresses, and index suffixes. 2669 Each index descends one level (bounds-checked, trap on breach); 2670 nested levels reload the inner descriptor address. q ends as the 2671 value (scalars), the descriptor address (plain arrays), or the 2672 element address (indexed); sfx marks the indexed form. *) 2673 Design 2675 (. VAR n: SymTab.Name; .) 2676 = GetIdent DesignTail . 2677 (* The part of Design after the identifier: resolve it and walk the 2678 selectors. Split out so a statement can decide between a label 2679 (`ident :`) and a designator (`ident := ...`) with one token. *) 2680 DesignTail 2682 (. VAR fn, mal: SymTab.Name; 2683 cls: INTEGER; 2684 ic: SymTab.TypeIndex; 2685 curT, it, eT, bt: 2686 SymTab.TypeIndex; 2687 iq, ql, qlo, qhi, qe: 2688 QbeGen.QVal; 2689 lo, hi: INTEGER; 2690 fo: INTEGER; 2691 isOpen: BOOLEAN; 2692 qb, cv: QbeGen.QVal; 2693 r: BOOLEAN; 2694 astDes, astSel: AST.Node; .) 2695 = (. methCls := SymTab.InvalidType; 2696 QbeGen.CopyOp(n, qn); 2697 sfx := FALSE; 2698 IF NOT SymTab.Lookup(n) THEN 2699 (* a bare method name inside 2700 a CLASS IMPLEMENTATION 2701 is a sibling call on 2702 THIS *) 2703 ic := SymTab.CurImplClass(); 2704 IF (ic # 2705 SymTab.InvalidType) 2706 AND SymTab.MethodExists(ic, n) THEN 2707 sfx := FALSE; 2708 QbeGen.CopyOp("@", q); 2709 methCls := ic; 2710 k := SymTab.KindProc; 2711 t := SymTab.InvalidType 2712 ELSIF SymTab.InProc() THEN 2713 (* not declared anywhere 2714 in scope: with bodies 2715 parsed at unit end this 2716 is a genuine 201 (a 2717 nested-local forward is 2718 no longer tolerated). *) 2719 SemError(201); 2720 t := SymTab.InvalidType; 2721 k := -1; 2722 QbeGen.CopyOp("0", q) 2723 ELSE 2724 SemError(201); 2725 t := 2726 SymTab.InvalidType; 2727 k := -1; 2728 QbeGen.CopyOp("0", q) 2729 END 2730 ELSE 2731 t := SymTab.SymType(n); 2732 k := SymTab.SymKind(n); 2733 IF k = SymTab.KindConst THEN 2734 IF SymTab.Equal(n, 2735 "TRUE") THEN 2736 t := SymTab.BoolType(); 2737 QbeGen.CopyOp("1", q) 2738 ELSIF SymTab.Equal(n, 2739 "FALSE") THEN 2740 t := SymTab.BoolType(); 2741 QbeGen.CopyOp("0", q) 2742 ELSIF SymTab.Equal(n, 2743 "NIL") THEN 2744 QbeGen.CopyOp("0", q) 2745 ELSE 2746 cls := 2747 SymTab.ClassOf(t); 2748 IF (t # 2749 SymTab.InvalidType) 2750 AND ((cls = SymTab.ClInt) 2751 OR (cls 2752 = SymTab.ClChar) 2753 OR (cls 2754 = SymTab.ClEnum) 2755 OR (cls 2756 = SymTab.ClReal) 2757 OR (cls 2758 = SymTab.ClLong) 2759 OR (cls 2760 = SymTab.ClNil) 2761 OR (cls = SymTab.ClBool)) THEN 2762 IF cls = SymTab.ClNil THEN 2763 QbeGen.CopyOp("0", q) 2764 ELSIF ((cls 2765 = SymTab.ClInt) 2766 OR (cls 2767 = SymTab.ClChar) 2768 OR (cls 2769 = SymTab.ClEnum) 2770 OR (cls 2771 = SymTab.ClLong) 2772 OR (cls = SymTab.ClBool)) 2773 AND SymTab.GetSymVal(n, cv) 2774 AND QbeGen.IsImm(cv) THEN 2775 QbeGen.CopyOp(cv, q) 2776 ELSE 2777 QbeGen.LoadVar(n, 2778 cls = SymTab.ClReal, 2779 q) 2780 END 2781 ELSIF (cls = SymTab.ClArray) 2782 OR (cls = SymTab.ClRecord) 2783 OR (cls = SymTab.ClClass) 2784 OR (cls = SymTab.ClStr) 2785 OR (cls = SymTab.ClUStr) 2786 OR (cls = SymTab.ClSet) THEN 2787 (* aggregate constant: 2788 its value IS the 2789 descriptor address *) 2790 IF SymTab.GetSymVal(n, cv) THEN 2791 QbeGen.CopyOp(cv, q) 2792 ELSE 2793 QbeGen.CopyOp("0", q) 2794 END 2795 ELSE 2796 IF t # 2797 SymTab.InvalidType THEN 2798 SemError(230) 2799 END; 2800 QbeGen.CopyOp("0", q) 2801 END 2802 END 2803 ELSIF (k = SymTab.KindVar) 2804 OR (k = SymTab.KindParam) THEN 2805 cls := SymTab.ClassOf(t); 2806 IF (cls # SymTab.ClInt) 2807 AND (cls # SymTab.ClBool) 2808 AND (cls # SymTab.ClChar) 2809 AND (cls # SymTab.ClUChar) 2810 AND (cls # SymTab.ClEnum) 2811 AND (cls # SymTab.ClReal) 2812 AND (cls # SymTab.ClPtr) 2813 AND (cls # SymTab.ClProc) 2814 AND (cls # SymTab.ClLong) 2815 AND (cls # SymTab.ClArray) 2816 AND (cls # SymTab.ClSet) 2817 AND (cls # SymTab.ClRecord) 2818 AND (cls # SymTab.ClUStr) 2819 AND (cls # SymTab.ClClass) THEN 2820 SemError(230); 2821 QbeGen.CopyOp("0", q) 2822 ELSE QbeGen.CopyOp("@", q) 2823 END 2824 ELSE QbeGen.CopyOp("0", q); 2825 IF k = SymTab.KindImport THEN 2826 SemError(230) 2827 ELSIF k = 2828 SymTab.KindProc THEN 2829 (* bare procedure name: 2830 a following ArgList 2831 makes it a call; 2832 otherwise Fact 2833 reports 230 *) 2834 ELSE 2835 IF k = SymTab.KindField THEN 2836 IF QbeGen.TopWith(qb) THEN 2837 sfx := TRUE 2838 ELSE SemError(230); 2839 QbeGen.CopyOp("0", q) 2840 END 2841 END 2842 END 2843 END 2844 END; .) 2845 (. astDes := AST.MakeNode(AST.NkDesignator); 2846 AST.SetChild(astDes, AST.NChild(astDes), AST.MakeLeaf(AST.NkIdent, n)); .) 2847 { "[" Expr 2848 (. AST.SetChild(astDes, AST.NChild(astDes), 2849 AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN 2850 ELSIF SymTab.ClassOf(t) # 2851 SymTab.ClArray THEN 2852 SemError(217); 2853 t := SymTab.InvalidType 2854 ELSIF NOT SymTab.IsIntFamily(it) 2855 AND (SymTab.ClassOf(it) # 2856 SymTab.ClChar) 2857 AND (SymTab.ClassOf(it) # 2858 SymTab.ClEnum) 2859 AND (SymTab.ClassOf(it) # 2860 SymTab.ClBool) THEN 2861 SemError(218); 2862 t := SymTab.InvalidType 2863 ELSE 2864 eT := SymTab.ArrayElem(t); 2865 t := eT; sfx := TRUE 2866 END; .) 2867 { "," Expr 2868 (. AST.SetChild(astDes, AST.NChild(astDes), 2869 AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN 2870 ELSIF SymTab.ClassOf(t) # 2871 SymTab.ClArray THEN 2872 SemError(217); 2873 t := SymTab.InvalidType 2874 ELSIF NOT SymTab.IsIntFamily(it) 2875 AND (SymTab.ClassOf(it) # 2876 SymTab.ClChar) 2877 AND (SymTab.ClassOf(it) # 2878 SymTab.ClEnum) 2879 AND (SymTab.ClassOf(it) # 2880 SymTab.ClBool) THEN 2881 SemError(218); 2882 t := SymTab.InvalidType 2883 ELSE 2884 eT := SymTab.ArrayElem(t); 2885 t := eT; sfx := TRUE 2886 END; .) } 2887 "]" 2888 | "." GetIdent 2889 (. astSel := AST.MakeNode(AST.NkSelector); 2890 AST.SetOp(astSel, AST.SelField); 2891 AST.SetChild(astSel, 0, AST.MakeLeaf(AST.NkIdent, fn)); 2892 AST.SetChild(astDes, AST.NChild(astDes), astSel); IF k = SymTab.KindModule THEN 2893 (* qualified L.x: materialize 2894 the export, then load it *) 2895 IF NOT SymTab.MaterializeAlias(n, 2896 fn, mal) THEN 2897 SemError(201); 2898 t := SymTab.InvalidType; 2899 QbeGen.CopyOp("0", q) 2900 ELSE 2901 QbeGen.CopyOp(mal, qn); 2902 t := SymTab.SymType(mal); 2903 k := SymTab.SymKind(mal); 2904 sfx := FALSE; 2905 IF k = SymTab.KindProc THEN 2906 (* call: ArgList supplies 2907 the value *) 2908 QbeGen.CopyOp("0", q) 2909 END 2910 END 2911 ELSIF t = SymTab.InvalidType THEN 2912 ELSIF (SymTab.ClassOf(t) # 2913 SymTab.ClRecord) 2914 AND (SymTab.ClassOf(t) # 2915 SymTab.ClClass) THEN 2916 SemError(215); 2917 t := SymTab.InvalidType 2918 ELSIF (SymTab.ClassOf(t) = 2919 SymTab.ClClass) 2920 AND SymTab.MethodExists(t, fn) THEN 2921 (* obj.Method: bind the 2922 method and pass obj as 2923 the hidden receiver; q 2924 already holds the 2925 object's address *) 2926 QbeGen.CopyOp(fn, n); 2927 QbeGen.CopyOp(fn, qn); 2928 methCls := t; 2929 k := SymTab.KindProc; 2930 t := SymTab.InvalidType 2931 ELSIF NOT SymTab.FieldExists(t, 2932 fn) THEN 2933 SemError(216); 2934 t := SymTab.InvalidType 2935 ELSE 2936 t := SymTab.FieldType(t, fn); 2937 sfx := TRUE 2938 END; .) 2939 | "^" 2940 (. astSel := AST.MakeNode(AST.NkSelector); 2941 AST.SetOp(astSel, AST.SelDeref); 2942 AST.SetChild(astDes, AST.NChild(astDes), astSel); IF t = SymTab.InvalidType THEN 2943 ELSIF SymTab.ClassOf(t) # 2944 SymTab.ClPtr THEN 2945 SemError(219); 2946 t := SymTab.InvalidType 2947 ELSE 2948 bt := SymTab.PtrBase(t); 2949 IF bt = SymTab.InvalidType THEN 2950 ELSE 2951 t := bt; 2952 sfx := TRUE 2953 END 2954 END; .) } (. astCur := astDes; .) . 2955 (* Result suffix (ISO component after a function call): `F()^`, 2956 `F()[i]`, `F().field`. The call result is in t/q with sfx FALSE 2957 (a value, or a descriptor address for aggregates); each component 2958 descends one level exactly like the Design components. *) 2959 ResultComp (. VAR it, eT, bt: SymTab.TypeIndex; 2963 iq, ql, qlo, qhi, qe, qb: 2964 QbeGen.QVal; 2965 lo, hi, fo: INTEGER; 2966 isOpen: BOOLEAN; 2967 fname: SymTab.Name; 2968 astWrap, astSel: AST.Node; .) 2969 = "[" Expr 2970 (. isM := FALSE; 2971 IF AST.Kind(node) # AST.NkDesignator THEN 2972 astWrap := AST.MakeNode( 2973 AST.NkDesignator); 2974 AST.SetChild(astWrap, 0, node); 2975 node := astWrap 2976 END; 2977 AST.SetChild(node, AST.NChild(node), 2978 AST.MakeUn(AST.NkSelector, 2979 AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN 2980 ELSIF SymTab.ClassOf(t) # 2981 SymTab.ClArray THEN 2982 SemError(217); 2983 t := SymTab.InvalidType 2984 ELSIF NOT SymTab.IsIntFamily(it) 2985 AND (SymTab.ClassOf(it) # SymTab.ClChar) 2986 AND (SymTab.ClassOf(it) # SymTab.ClEnum) 2987 AND (SymTab.ClassOf(it) # SymTab.ClBool) THEN 2988 SemError(218); 2989 t := SymTab.InvalidType 2990 ELSE 2991 eT := SymTab.ArrayElem(t); 2992 t := eT; sfx := TRUE 2993 END; .) 2994 "]" 2995 | "." GetIdent 2996 (. isM := FALSE; 2997 IF AST.Kind(node) # AST.NkDesignator THEN 2998 astWrap := AST.MakeNode( 2999 AST.NkDesignator); 3000 AST.SetChild(astWrap, 0, node); 3001 node := astWrap 3002 END; 3003 AST.SetChild(node, AST.NChild(node), 3004 AST.MakeUn(AST.NkSelector, 3005 AST.SelField, 3006 AST.MakeLeaf(AST.NkIdent, 3007 fname))); IF t = SymTab.InvalidType THEN 3008 ELSIF (SymTab.ClassOf(t) # 3009 SymTab.ClRecord) 3010 AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN 3011 SemError(215); 3012 t := SymTab.InvalidType 3013 ELSIF (SymTab.ClassOf(t) = 3014 SymTab.ClClass) 3015 AND SymTab.MethodExists(t, fname) THEN 3016 (* a method on the call result: 3017 a following ArgList makes 3018 the call *) 3019 mname := fname; 3020 methCls := t; isM := TRUE; 3021 t := SymTab.InvalidType 3022 ELSIF NOT SymTab.FieldExists(t, 3023 fname) THEN 3024 SemError(216); 3025 t := SymTab.InvalidType 3026 ELSE 3027 t := SymTab.FieldType(t, fname); 3028 sfx := TRUE 3029 END; .) 3030 | "^" (. isM := FALSE; 3031 IF AST.Kind(node) # AST.NkDesignator THEN 3032 astWrap := AST.MakeNode( 3033 AST.NkDesignator); 3034 AST.SetChild(astWrap, 0, node); 3035 node := astWrap 3036 END; 3037 astSel := AST.MakeNode(AST.NkSelector); 3038 AST.SetOp(astSel, AST.SelDeref); 3039 AST.SetChild(node, 3040 AST.NChild(node), astSel); IF t = SymTab.InvalidType THEN 3041 ELSIF SymTab.ClassOf(t) # 3042 SymTab.ClPtr THEN 3043 SemError(219); 3044 t := SymTab.InvalidType 3045 ELSE 3046 bt := SymTab.PtrBase(t); 3047 IF bt # SymTab.InvalidType THEN 3048 t := bt; sfx := TRUE 3049 END 3050 END; .) . 3051 Expr 3052 (. VAR t2: SymTab.TypeIndex; 3053 op: INTEGER; 3054 q2, qt, wl: QbeGen.QVal; 3055 astA, astB: AST.Node; 3056 astOp: INTEGER; 3057 astMade: BOOLEAN; 3058 isR: BOOLEAN; .) 3059 = SimExpr (. astA := astCur; astMade := FALSE; .) 3060 [ Rel SimExpr 3061 (. astB := astCur; astMade := TRUE; 3062 astOp := AST.OpEq; 3063 IF op = SymTab.OpNeq1 THEN astOp := AST.OpNe 3064 ELSIF op = SymTab.OpNeq2 THEN astOp := AST.OpNe 3065 ELSIF op = SymTab.OpLt THEN astOp := AST.OpLt 3066 ELSIF op = SymTab.OpLe THEN astOp := AST.OpLe 3067 ELSIF op = SymTab.OpGt THEN astOp := AST.OpGt 3068 ELSIF op = SymTab.OpGe THEN astOp := AST.OpGe 3069 ELSIF op = SymTab.OpIn THEN astOp := AST.OpIn 3070 END; 3071 IF op = SymTab.OpIn THEN 3072 IF SymTab.InCheck(t, t2) THEN 3073 IF (t = SymTab.InvalidType) 3074 OR (t2 = SymTab.InvalidType) THEN 3075 t := SymTab.BoolType(); QbeGen.CopyOp("0", q) 3076 ELSE 3077 t := SymTab.BoolType(); QbeGen.CopyOp("@", q) 3078 END 3079 ELSE SemError(222); t := SymTab.InvalidType; 3080 QbeGen.CopyOp("0", q) 3081 END 3082 ELSIF SymTab.RelCheck(t, t2, op) THEN 3083 IF (t = SymTab.InvalidType) 3084 OR (t2 = SymTab.InvalidType) THEN 3085 t := SymTab.BoolType(); QbeGen.CopyOp("0", q) 3086 ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr) 3087 OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN 3088 IF (op # SymTab.OpEq) AND (op # SymTab.OpNeq1) 3089 AND (op # SymTab.OpNeq2) THEN 3090 SemError(213); t := SymTab.InvalidType; 3091 QbeGen.CopyOp("0", q) 3092 ELSE 3093 t := SymTab.BoolType(); QbeGen.CopyOp("@", q) 3094 END 3095 ELSIF (SymTab.ClassOf(t) = SymTab.ClSet) 3096 OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN 3097 t := SymTab.BoolType(); QbeGen.CopyOp("@", q) 3098 ELSIF SymTab.StrCompat(t, t2) THEN 3099 QbeGen.StrEq(op, q, q2, qt); 3100 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q) 3101 ELSIF SymTab.IsLongFamily(t) 3102 OR SymTab.IsLongFamily(t2) THEN 3103 t := SymTab.BoolType(); QbeGen.CopyOp("@", q) 3104 ELSE 3105 t := SymTab.BoolType(); 3106 QbeGen.CopyOp("@", q) 3107 END 3108 ELSE SemError(213); t := SymTab.InvalidType; 3109 QbeGen.CopyOp("0", q) 3110 END; 3111 astCur := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB); .) ] 3112 (. IF NOT astMade THEN astCur := astA END; .) 3113 (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) . 3114 Rel 3115 = "=" (. op := SymTab.OpEq; .) 3116 | "#" (. op := SymTab.OpNeq1; .) 3117 | "<" (. op := SymTab.OpLt; .) 3118 | "<=" (. op := SymTab.OpLe; .) 3119 | ">" (. op := SymTab.OpGt; .) 3120 | ">=" (. op := SymTab.OpGe; .) 3121 | "IN" (. op := SymTab.OpIn; .) . 3122 SimExpr 3123 (. VAR t2, res2, lt, rt: 3124 SymTab.TypeIndex; 3125 op: INTEGER; 3126 q2, qt, wq, qf, q2a, q2b: 3127 QbeGen.QVal; 3128 neg, isR, isL, folded: 3129 BOOLEAN; 3130 fok: BOOLEAN; 3131 lw, rw, mw: CARDINAL; 3132 lTrue, lNext, lDone, qr, qs: QbeGen.QVal; 3133 astA, astB: AST.Node; 3134 astSign, astOp: INTEGER; .) 3135 = (. neg := FALSE; astSign := 0; .) 3136 [ "+" (. neg := TRUE; astSign := 1; .) 3137 | "-" (. neg := TRUE; astSign := -1; .) ] 3138 Term (. astA := astCur; 3139 IF neg AND QbeGen.IsImm(q) THEN 3140 QbeGen.NegFold(q, q) 3141 END; 3142 IF astSign < 0 THEN 3143 astCur := AST.MakeUn( 3144 AST.NkUnary, AST.OpSub, astA); 3145 astA := astCur 3146 END; .) 3147 { AddOp 3148 Term (. astB := astCur; .) 3149 (. astOp := AST.OpAdd; 3150 IF op = SymTab.OpSub THEN astOp := AST.OpSub 3151 ELSIF op = SymTab.OpOr THEN astOp := AST.OpOr END; 3152 astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB); 3153 astCur := astA; 3154 IF op = SymTab.OpOr THEN 3155 (* short-circuit: if q is true the RHS is skipped *) 3156 IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN 3157 t := SymTab.BoolType() 3158 ELSE SemError(212); t := SymTab.InvalidType END; 3159 IF t # SymTab.InvalidType THEN 3160 QbeGen.CopyOp("@", q) 3161 ELSE QbeGen.CopyOp("0", q) 3162 END 3163 ELSIF (op = SymTab.OpAdd) 3164 AND (SymTab.UStrCompat(t, t2) 3165 OR ((SymTab.ClassOf(t) = SymTab.ClUChar) 3166 AND (SymTab.ClassOf(t2) = SymTab.ClUStr)) 3167 OR ((SymTab.ClassOf(t) = SymTab.ClUStr) 3168 AND (SymTab.ClassOf(t2) = SymTab.ClUChar)) 3169 OR ((SymTab.ClassOf(t) = SymTab.ClUChar) 3170 AND (SymTab.ClassOf(t2) = SymTab.ClUChar))) THEN 3171 (* UString concatenation: a UCHAR operand becomes a 3172 1-codepoint UString; the result is a descriptor in the 3173 shim's concat buffer. Work on copies so neither 3174 operand is clobbered. *) 3175 t := SymTab.NewUStr(); 3176 QbeGen.CopyOp("@", q) 3177 ELSIF (op = SymTab.OpAdd) 3178 AND (SymTab.StrCompat(t, t2) 3179 OR (SymTab.IsStrType(t) 3180 AND (SymTab.ClassOf(t2) = SymTab.ClChar)) 3181 OR ((SymTab.ClassOf(t) = SymTab.ClChar) 3182 AND SymTab.IsStrType(t2))) THEN 3183 (* string concatenation; a CHAR operand becomes a 3184 1-character string literal. When both operands are 3185 constants, fold to a single string literal so a 3186 constructor element stays compile-time. *) 3187 QbeGen.StrFold(q, q2, SymTab.ClassOf(t), SymTab.ClassOf(t2), 3188 qt, fok); 3189 IF fok THEN QbeGen.CopyOp(qt, q) 3190 ELSE QbeGen.CopyOp("@", q) 3191 END; 3192 t := SymTab.NewStr() 3193 ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType) 3194 AND (SymTab.ClassOf(t) = SymTab.ClSet) 3195 AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN 3196 lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2); 3197 mw := lw; 3198 IF rw > mw THEN mw := rw END; 3199 t := SymTab.NewSet( 3200 SymTab.NewSubR(0, 3201 VAL(INTEGER, mw) * 32 - 1)); 3202 QbeGen.CopyOp("@", q) 3203 ELSE 3204 IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN 3205 lt := t; rt := t2; t := res2 3206 ELSE SemError(211); t := SymTab.InvalidType END; 3207 IF t # SymTab.InvalidType THEN 3208 isL := SymTab.IsLongFamily(t); 3209 isR := SymTab.ClassOf(t) = SymTab.ClReal; 3210 folded := FALSE; 3211 IF (NOT isL) AND (NOT isR) 3212 AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN 3213 IF op = SymTab.OpAdd THEN 3214 folded := QbeGen.Fold2(0, q, q2, qf) 3215 ELSE 3216 folded := QbeGen.Fold2(1, q, q2, qf) 3217 END 3218 END; 3219 IF folded THEN QbeGen.CopyOp(qf, q) 3220 ELSE 3221 QbeGen.CopyOp("@", q) 3222 END 3223 ELSE QbeGen.CopyOp("0", q) 3224 END 3225 END; .) } 3226 (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) . 3227 AddOp 3228 = "+" (. op := SymTab.OpAdd; .) 3229 | "-" (. op := SymTab.OpSub; .) 3230 | "OR" (. op := SymTab.OpOr; .) . 3231 Term 3232 (. VAR t2, res2, lt, rt: 3233 SymTab.TypeIndex; 3234 op: INTEGER; 3235 q2, qt, wq, qf: 3236 QbeGen.QVal; 3237 isR, isL, folded: BOOLEAN; 3238 lw, rw, mw: CARDINAL; 3239 lNext, lFalse, lDone, qr, qs: QbeGen.QVal; 3240 astA, astB: AST.Node; 3241 astOp: INTEGER; .) 3242 = Fact (. astA := astCur; .) { MulOp 3243 Fact (. astB := astCur; .) 3244 (. astOp := AST.OpMul; 3245 IF op = SymTab.OpSlash THEN astOp := AST.OpDiv 3246 ELSIF op = SymTab.OpDiv THEN astOp := AST.OpDiv 3247 ELSIF op = SymTab.OpMod THEN astOp := AST.OpMod 3248 ELSIF op = SymTab.OpAnd THEN astOp := AST.OpAnd END; 3249 astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB); 3250 astCur := astA; 3251 IF op = SymTab.OpAnd THEN 3252 (* short-circuit: if q is false the RHS is skipped *) 3253 IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN 3254 t := SymTab.BoolType() 3255 ELSE SemError(212); t := SymTab.InvalidType END; 3256 IF t # SymTab.InvalidType THEN QbeGen.CopyOp("@", q) 3257 ELSE QbeGen.CopyOp("0", q) 3258 END 3259 ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType) 3260 AND (SymTab.ClassOf(t) = SymTab.ClSet) 3261 AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN 3262 lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2); 3263 mw := lw; 3264 IF rw > mw THEN mw := rw END; 3265 t := SymTab.NewSet( 3266 SymTab.NewSubR(0, 3267 VAL(INTEGER, mw) * 32 - 1)); 3268 QbeGen.CopyOp("@", q) 3269 ELSE 3270 IF SymTab.ArithCheck(t, t2, 3271 (op = SymTab.OpDiv) OR (op = SymTab.OpMod), 3272 res2) THEN 3273 lt := t; rt := t2; t := res2 3274 ELSE SemError(211); t := SymTab.InvalidType END; 3275 IF t # SymTab.InvalidType THEN 3276 isL := SymTab.IsLongFamily(t); 3277 isR := SymTab.ClassOf(t) = SymTab.ClReal; 3278 folded := FALSE; 3279 IF (NOT isL) AND (NOT isR) 3280 AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN 3281 IF op = SymTab.OpTimes THEN 3282 folded := QbeGen.Fold2(2, q, q2, qf) 3283 ELSIF op = SymTab.OpDiv THEN 3284 folded := QbeGen.Fold2(3, q, q2, qf) 3285 ELSIF op = SymTab.OpMod THEN 3286 folded := QbeGen.Fold2(4, q, q2, qf) 3287 END 3288 END; 3289 IF folded THEN QbeGen.CopyOp(qf, q) 3290 ELSE 3291 QbeGen.CopyOp("@", q) 3292 END 3293 ELSE QbeGen.CopyOp("0", q) 3294 END 3295 END; .) } 3296 (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) . 3297 MulOp 3298 = "*" (. op := SymTab.OpTimes; .) 3299 | "/" (. op := SymTab.OpSlash; .) 3300 | "DIV" (. op := SymTab.OpDiv; .) 3301 | "MOD" (. op := SymTab.OpMod; .) 3302 | ( "AND" | "&" ) (. op := SymTab.OpAnd; .) . 3303 Fact 3304 (. VAR s: ARRAY [0 .. 255] OF CHAR; 3305 et, dt, t2, st, ct2, et2: 3306 SymTab.TypeIndex; 3307 dk: INTEGER; 3308 qd, q2, sq, qa, qm0, qr, qt: 3309 QbeGen.QVal; 3310 qn, vn: SymTab.Name; 3311 vt: SymTab.TypeIndex; 3312 c1, c2: INTEGER; 3313 lo, hi: INTEGER; 3314 isMax: BOOLEAN; 3315 called, isHigh, sfx, isCh, 3316 isU, uok, isStr: BOOLEAN; 3317 ucp: INTEGER; astIsLit: BOOLEAN; 3318 astD: AST.Node; 3319 astCall: BOOLEAN; 3320 astNode, astNot: AST.Node; 3321 j: CARDINAL; 3322 astArg2: AST.Node; 3323 astBrace: AST.Node; 3324 astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN; 3325 isConvF: BOOLEAN; .) 3326 = (. astIsLit := FALSE; .) 3327 ( integer (. LexString(s); 3328 QbeGen.NormInt(s, q); astIsLit := TRUE; astCur := AST.MakeLeaf(AST.NkIntLit, s); 3329 t := SymTab.IntType(); .) 3330 | charConst (. LexString(s); 3331 QbeGen.NormLit(s, q, isCh); 3332 astIsLit := TRUE; 3333 astCur := AST.MakeLeaf( 3334 AST.NkCharLit, s); 3335 t := SymTab.CharType(); .) 3336 | real (. LexString(s); 3337 QbeGen.NormReal(s, q); 3338 astIsLit := TRUE; 3339 astCur := AST.MakeLeaf( 3340 AST.NkRealLit, s); 3341 t := SymTab.RealType(); .) 3342 | string (. LexString(s); 3343 astIsLit := TRUE; 3344 astCur := AST.MakeLeaf( 3345 AST.NkStrLit, s); 3346 IF SymTab.StrLen(s) = 3 THEN 3347 t := SymTab.CharType(); 3348 QbeGen.IntStr( 3349 QbeGen.CharVal(s), q) 3350 ELSE t := SymTab.NewStr(); 3351 QbeGen.DeclStr(s, q); 3352 (* a literal's value IS its 3353 static descriptor address *) 3354 END; .) 3355 | ustring (. LexString(s); 3356 astIsLit := TRUE; 3357 astCur := AST.MakeLeaf( 3358 AST.NkStrLit, s); 3359 QbeGen.DeclUStr(s, q, isU, ucp, 3360 uok); 3361 IF NOT uok THEN 3362 SemError(234); 3363 t := SymTab.InvalidType 3364 ELSIF isU THEN 3365 t := SymTab.UCharType(); 3366 QbeGen.IntStr(ucp, q) 3367 ELSE 3368 t := SymTab.NewUStr(); 3369 END; .) 3370 | Design (. astD := astCur; astCall := FALSE; astBrace := AST.NoNode; 3371 astNArgs := 0; called := FALSE; 3372 t := dt; 3373 IF dk = SymTab.KindConst THEN 3374 QbeGen.CopyOp(qd, q) 3375 ELSE QbeGen.CopyOp("@", q) 3376 END; .) 3377 [ TypedBraceLit (. t := dt; astCall := TRUE; 3378 astBrace := astCur; .) ] 3379 [ ArgList 3380 (. astCall := TRUE; 3381 IF (SymTab.SymKind(qn) = SymTab.KindType) 3382 OR (SymTab.SymKind(qn) = SymTab.KindPredef) THEN 3383 (* T(x): emit as the VAL builtin so Lower's 3384 conversion rules apply unchanged *) 3385 astNode := AST.MakeNode(AST.NkCall); 3386 AST.SetChild(astNode, 0, 3387 AST.MakeLeaf(AST.NkIdent, "VAL")); 3388 AST.SetChild(astNode, 1, 3389 AST.MakeLeaf(AST.NkIdent, qn)); 3390 IF astNArgs = 1 THEN 3391 AST.SetChild(astNode, 2, astArgs[0]) 3392 END; 3393 isConvF := TRUE 3394 ELSE astNode := AstCallNode(astD) 3395 END; 3396 astRes := astNode; 3397 t := ct2; 3398 QbeGen.CopyOp(q2, q); 3399 IF isConvF AND QbeGen.IsImm(convQ) 3400 AND OrdClass(convT) AND OrdClass(ct2) THEN 3401 QbeGen.CopyOp(convQ, q) 3402 END; 3403 sfx := FALSE; .) 3404 { ResultComp 3405 [ (. astNArgs := 0; .) 3406 ArgList 3407 (. astNode := AstCallNode(astRes); 3408 astRes := astNode; 3409 t := ct2; 3410 QbeGen.CopyOp(q2, q); 3411 sfx := FALSE; .) ] } 3412 (. IF sfx THEN 3413 IF t = SymTab.InvalidType THEN 3414 QbeGen.CopyOp("0", q) 3415 ELSIF (SymTab.ClassOf(t) # 3416 SymTab.ClRecord) 3417 AND (SymTab.ClassOf(t) # SymTab.ClSet) 3418 AND (SymTab.ClassOf(t) # SymTab.ClArray) 3419 AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN 3420 QbeGen.CopyOp("@", q) 3421 END 3422 END; .) ] 3423 (. IF called THEN 3424 astCur := astRes 3425 ELSIF astCall THEN 3426 astCur := astBrace 3427 ELSE astCur := astD 3428 END; 3429 astIsLit := TRUE; 3430 IF NOT called 3431 AND (dk = SymTab.KindProc) THEN 3432 (* bare zero-arg function 3433 call (parentheses may be 3434 omitted); a proper or 3435 parameterised proc here 3436 is 230 *) 3437 IF (SymTab.ProcNPar(qn) = 0) 3438 AND (SymTab.ProcRes(qn) # SymTab.InvalidType) THEN 3439 t := SymTab.ProcRes(qn); 3440 QbeGen.CopyOp("@", q); 3441 astCur := AST.MakeNode(AST.NkCall); 3442 AST.SetChild(astCur, 0, astD) 3443 ELSE 3444 t := SymTab.ProcTypeOf(qn); 3445 QbeGen.CopyOp("@", q) 3446 END 3447 END; .) 3448 | ( "HIGH" (. isHigh := TRUE; .) 3449 | ( "LEN" | "LENGTH" ) (. isHigh := FALSE; .) ) 3450 "(" ( Design (. isStr := FALSE; 3451 isU := FALSE; .) 3452 | string (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s); 3453 isStr := TRUE; 3454 isU := FALSE; 3455 IF SymTab.StrLen(s) = 3 THEN 3456 dt := SymTab.CharType(); 3457 QbeGen.IntStr(QbeGen.CharVal(s), 3458 qd) 3459 ELSE 3460 dt := SymTab.NewStr(); 3461 QbeGen.DeclStr(s, qd); 3462 END; 3463 dk := -1; 3464 qn[0] := CHR(0); .) 3465 | ustring (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s); 3466 QbeGen.DeclUStr(s, qd, isU, ucp, 3467 uok); 3468 isStr := FALSE; 3469 IF NOT uok THEN 3470 SemError(234); 3471 dt := SymTab.InvalidType 3472 ELSIF isU THEN 3473 (* one codepoint: a UCHAR; 3474 LEN is 1, HIGH is 0 *) 3475 dt := SymTab.UCharType(); 3476 QbeGen.IntStr(ucp, qd) 3477 ELSE 3478 dt := SymTab.NewUStr(); 3479 END; 3480 dk := -1; 3481 qn[0] := CHR(0); .) ) 3482 ")" 3483 (. astNode := AST.MakeNode(AST.NkCall); 3484 IF isHigh THEN AST.SetChild(astNode, 0, 3485 AST.MakeLeaf(AST.NkIdent, "HIGH")) 3486 ELSE AST.SetChild(astNode, 0, 3487 AST.MakeLeaf(AST.NkIdent, "LEN")) END; 3488 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3489 astCur := astNode; astIsLit := TRUE; 3490 IF (dt # SymTab.InvalidType) 3491 AND (SymTab.ClassOf(dt) = SymTab.ClUStr) THEN 3492 (* UString: the count is 3493 the descriptor header *) 3494 t := SymTab.IntType(); 3495 QbeGen.CopyOp("@", q) 3496 ELSIF (dt # SymTab.InvalidType) 3497 AND (SymTab.ClassOf(dt) = SymTab.ClUChar) THEN 3498 (* single UCHAR codepoint *) 3499 IF isHigh THEN 3500 QbeGen.CopyOp("0", qr) 3501 ELSE 3502 QbeGen.CopyOp("1", qr) 3503 END; 3504 t := SymTab.IntType(); 3505 QbeGen.CopyOp(qr, q) 3506 ELSIF isStr THEN 3507 (* fold: content length at 3508 compile time *) 3509 IF SymTab.StrLen(s) = 3 THEN 3510 c1 := 1 3511 ELSE 3512 c1 := 3513 SymTab.StrLen(s) - 2 3514 END; 3515 IF isHigh THEN 3516 DEC(c1) 3517 END; 3518 QbeGen.IntStr(c1, qr); 3519 t := SymTab.IntType(); 3520 QbeGen.CopyOp(qr, q) 3521 ELSIF dt = SymTab.InvalidType THEN 3522 t := SymTab.InvalidType; 3523 QbeGen.CopyOp("0", q) 3524 ELSIF SymTab.ClassOf(dt) # 3525 SymTab.ClArray THEN 3526 SemError(217); 3527 t := SymTab.InvalidType; 3528 QbeGen.CopyOp("0", q) 3529 ELSE 3530 IF SymTab.IsOpenArray(dt) THEN 3531 t := SymTab.IntType(); 3532 QbeGen.CopyOp("@", q) 3533 ELSE 3534 IF isHigh THEN 3535 QbeGen.IntStr( 3536 SymTab.ArrayHi(dt), qr) 3537 ELSE 3538 QbeGen.IntStr(VAL( 3539 INTEGER, 3540 SymTab.ArrayLen(dt)), 3541 qr) 3542 END; 3543 t := SymTab.IntType(); 3544 QbeGen.CopyOp(qr, q) 3545 END 3546 END; .) 3547 | ( "SIZE" | "TSIZE" ) "(" Design ")" 3548 (. astNode := AST.MakeNode(AST.NkCall); 3549 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "SIZE")); 3550 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3551 astCur := astNode; astIsLit := TRUE; .) 3552 (. IF dt = SymTab.InvalidType THEN 3553 t := SymTab.InvalidType; 3554 QbeGen.CopyOp("0", q) 3555 ELSE 3556 QbeGen.IntStr(VAL(INTEGER, 3557 SymTab.ObjectSize(dt)), q); 3558 t := SymTab.IntType() 3559 END; .) 3560 | ( "SHIFT" (. isMax := FALSE; .) 3561 | "ROTATE" (. isMax := TRUE; .) ) 3562 "(" Expr (. astArg2 := astCur; .) "," Expr ")" 3563 (. astNode := AST.MakeNode(AST.NkCall); 3564 IF isMax THEN AST.SetChild(astNode, 0, 3565 AST.MakeLeaf(AST.NkIdent, "ROTATE")) 3566 ELSE AST.SetChild(astNode, 0, 3567 AST.MakeLeaf(AST.NkIdent, "SHIFT")) END; 3568 IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END; 3569 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END; 3570 astCur := astNode; astIsLit := TRUE; 3571 (* set shift/rotate: isMax 3572 doubles as "rotate" *) 3573 IF (et # SymTab.InvalidType) 3574 AND (SymTab.ClassOf(et) = 3575 SymTab.ClSet) THEN 3576 t := et; 3577 QbeGen.CopyOp("@", q) 3578 ELSE SemError(230); 3579 t := SymTab.InvalidType; 3580 QbeGen.CopyOp("0", q) 3581 END; .) 3582 | ( "MIN" (. isMax := FALSE; .) 3583 | "MAX" (. isMax := TRUE; .) ) 3584 "(" Design ")" 3585 (. astNode := AST.MakeNode(AST.NkCall); 3586 IF isMax THEN AST.SetChild(astNode, 0, 3587 AST.MakeLeaf(AST.NkIdent, "MAX")) 3588 ELSE AST.SetChild(astNode, 0, 3589 AST.MakeLeaf(AST.NkIdent, "MIN")) END; 3590 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3591 astCur := astNode; astIsLit := TRUE; 3592 IF (dt # SymTab.InvalidType) 3593 AND (SymTab.ClassOf(dt) = SymTab.ClReal) THEN 3594 (* REAL/LONGREAL: the 3595 implementation bounds *) 3596 IF isMax THEN 3597 QbeGen.NormReal( 3598 "3.402823e38", q) 3599 ELSE QbeGen.NormReal( 3600 "-3.402823e38", q) 3601 END; 3602 t := SymTab.RealType() 3603 ELSIF (dt # 3604 SymTab.InvalidType) 3605 AND (SymTab.ClassOf(dt) = 3606 SymTab.ClLong) THEN 3607 IF isMax THEN 3608 QbeGen.CopyOp( 3609 "9223372036854775807", q) 3610 ELSE QbeGen.CopyOp( 3611 "-9223372036854775808", q) 3612 END; 3613 t := SymTab.LongType() 3614 ELSIF SymTab.TypeBounds(dt, lo, 3615 hi) THEN 3616 IF isMax THEN 3617 QbeGen.IntStr(hi, q) 3618 ELSE QbeGen.IntStr(lo, q) 3619 END; 3620 t := SymTab.IntType() 3621 ELSE SemError(230); 3622 t := SymTab.InvalidType; 3623 QbeGen.CopyOp("0", q) 3624 END; .) 3625 | "ADR" "(" Design ")" 3626 (. astNode := AST.MakeNode(AST.NkCall); 3627 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ADR")); 3628 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3629 astCur := astNode; astIsLit := TRUE; .) 3630 (. IF dt = SymTab.InvalidType THEN 3631 t := SymTab.InvalidType; 3632 QbeGen.CopyOp("0", q) 3633 ELSE 3634 IF sfx 3635 OR (dk = SymTab.KindVar) 3636 OR (dk = SymTab.KindParam) THEN 3637 QbeGen.CopyOp("@", q) 3638 ELSE SemError(230); 3639 QbeGen.CopyOp("0", q) 3640 END; 3641 t := SymTab.AddrType() 3642 END; .) 3643 | "CHR" "(" Expr ")" 3644 (. astNode := AST.MakeNode(AST.NkCall); 3645 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR")); 3646 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3647 astCur := astNode; astIsLit := TRUE; .) 3648 (. IF (et # SymTab.InvalidType) 3649 AND NOT SymTab.IsIntFamily(et) THEN 3650 SemError(211) END; 3651 t := SymTab.CharType(); .) 3652 | ( "ORD" | "ORDL" ) "(" Expr ")" 3653 (. astNode := AST.MakeNode(AST.NkCall); 3654 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ORD")); 3655 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3656 astCur := astNode; astIsLit := TRUE; .) 3657 (. IF et # SymTab.InvalidType THEN 3658 IF (SymTab.ClassOf(et) # 3659 SymTab.ClChar) 3660 AND (SymTab.ClassOf(et) # 3661 SymTab.ClBool) 3662 AND (SymTab.ClassOf(et) # 3663 SymTab.ClEnum) 3664 AND NOT SymTab.IsIntFamily(et) THEN 3665 SemError(211) END 3666 END; 3667 t := SymTab.IntType(); .) 3668 | "CAP" "(" Expr ")" 3669 (. astNode := AST.MakeNode(AST.NkCall); 3670 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CAP")); 3671 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3672 astCur := astNode; astIsLit := TRUE; .) 3673 (. IF QbeGen.IsImm(q) 3674 AND SymTab.ConstInt(q, lo) THEN 3675 IF (lo >= VAL(INTEGER, ORD("a"))) AND (lo <= VAL(INTEGER, ORD("z"))) THEN lo := lo - 32 END; 3676 QbeGen.IntStr(lo, q) 3677 ELSE QbeGen.CopyOp("@", q) 3678 END; 3679 t := SymTab.CharType(); .) 3680 | "UCHR" "(" Expr ")" 3681 (. astNode := AST.MakeNode(AST.NkCall); 3682 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UCHR")); 3683 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3684 astCur := astNode; astIsLit := TRUE; .) 3685 (. (* UCHR: the UCHAR constructor. 3686 CHAR -> UCHAR (identity); 3687 INTEGER familly -> UCHAR 3688 (codepoint value). *) 3689 IF (et # SymTab.InvalidType) 3690 AND (SymTab.ClassOf(et) # SymTab.ClChar) 3691 AND NOT SymTab.IsIntFamily(et) THEN 3692 SemError(211) END; 3693 t := SymTab.UCharType(); .) 3694 | "CHR8" "(" Expr ")" 3695 (. astNode := AST.MakeNode(AST.NkCall); 3696 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR8")); 3697 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3698 astCur := astNode; astIsLit := TRUE; .) 3699 (. IF (et # SymTab.InvalidType) 3700 AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN 3701 SemError(211) END; 3702 t := SymTab.CharType(); .) 3703 | "UORD" "(" Expr ")" 3704 (. astNode := AST.MakeNode(AST.NkCall); 3705 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UORD")); 3706 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3707 astCur := astNode; astIsLit := TRUE; .) 3708 (. (* UORD(u): the codepoint as a 3709 32-bit ordinal (INTEGER), 3710 cf. ORD for CHAR. *) 3711 IF (et # SymTab.InvalidType) 3712 AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN 3713 SemError(211) END; 3714 t := SymTab.IntType(); .) 3715 | "ABS" "(" Expr ")" 3716 (. astNode := AST.MakeNode(AST.NkCall); 3717 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ABS")); 3718 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3719 astCur := astNode; astIsLit := TRUE; .) 3720 (. IF (et # SymTab.InvalidType) 3721 AND NOT SymTab.IsIntFamily(et) 3722 AND (SymTab.ClassOf(et) # 3723 SymTab.ClReal) THEN 3724 SemError(211) 3725 ELSIF QbeGen.IsImm(q) 3726 AND SymTab.ConstInt(q, lo) THEN 3727 IF lo < 0 THEN lo := -lo END; 3728 QbeGen.IntStr(lo, q) 3729 ELSE QbeGen.CopyOp("@", q) 3730 END; 3731 t := et; .) 3732 | "ODD" "(" Expr ")" 3733 (. astNode := AST.MakeNode(AST.NkCall); 3734 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ODD")); 3735 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END; 3736 astCur := astNode; astIsLit := TRUE; .) 3737 (. IF (et # SymTab.InvalidType) 3738 AND NOT SymTab.IsIntFamily(et) THEN 3739 SemError(211) END; 3740 t := SymTab.BoolType(); 3741 IF QbeGen.IsImm(q) 3742 AND SymTab.ConstInt(q, lo) THEN 3743 IF (lo MOD 2) # 0 THEN 3744 QbeGen.CopyOp("1", q) 3745 ELSE QbeGen.CopyOp("0", q) 3746 END 3747 ELSE QbeGen.CopyOp("@", q) 3748 END; .) 3749 | "TRUNC" "(" Expr ")" 3750 (. (* TRUNC(x): real -> INTEGER, as the VAL builtin *) 3751 astNode := AST.MakeNode(AST.NkCall); 3752 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL")); 3753 AST.SetChild(astNode, 1, AST.MakeLeaf(AST.NkIdent, "INTEGER")); 3754 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END; 3755 astCur := astNode; astIsLit := TRUE; .) 3756 (. t := SymTab.IntType(); 3757 QbeGen.CopyOp("@", q); .) 3758 | "FLOAT" "(" Expr ")" 3759 (. (* FLOAT(i): integer -> REAL, as the VAL builtin *) 3760 astNode := AST.MakeNode(AST.NkCall); 3761 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL")); 3762 AST.SetChild(astNode, 1, AST.MakeLeaf(AST.NkIdent, "REAL")); 3763 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END; 3764 astCur := astNode; astIsLit := TRUE; .) 3765 (. t := SymTab.RealType(); 3766 IF QbeGen.IsImm(q) AND SymTab.ConstInt(q, lo) THEN QbeGen.NormReal(q, qa); QbeGen.CopyOp(qa, q) 3767 ELSE QbeGen.CopyOp("@", q) END; .) 3768 | "VAL" "(" GetIdent (. astArg2 := AST.MakeLeaf(AST.NkIdent, vn); .) "," Expr ")" 3769 (. astNode := AST.MakeNode(AST.NkCall); 3770 AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL")); 3771 IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END; 3772 IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END; 3773 astCur := astNode; astIsLit := TRUE; .) 3774 (. IF NOT SymTab.Lookup(vn) THEN 3775 SemError(201); 3776 t := SymTab.InvalidType 3777 ELSE vt := SymTab.SymType(vn); 3778 IF vt = SymTab.InvalidType THEN 3779 t := SymTab.InvalidType 3780 ELSIF et = 3781 SymTab.InvalidType THEN 3782 t := vt 3783 ELSE 3784 c1 := SymTab.ClassOf(et); 3785 c2 := SymTab.ClassOf(vt); 3786 IF (c1 = SymTab.ClInt) 3787 AND (c2 = SymTab.ClLong) THEN 3788 IF NOT QbeGen.IsImm(q) THEN QbeGen.WidenLong(q, qa); QbeGen.CopyOp(qa, q) END; 3789 t := vt 3790 ELSIF (c1 = SymTab.ClLong) 3791 AND (c2 = SymTab.ClInt) THEN 3792 IF NOT (QbeGen.IsImm(q) AND SymTab.ConstInt(q, lo)) THEN QbeGen.NarrowLong(q, qa); QbeGen.CopyOp(qa, q) END; 3793 t := vt 3794 ELSIF (c1 = SymTab.ClInt) 3795 AND (c2 = SymTab.ClReal) THEN 3796 IF QbeGen.IsImm(q) AND SymTab.ConstInt(q, lo) THEN QbeGen.NormReal(q, qa) ELSE QbeGen.ConvIR(q, qa) END; 3797 QbeGen.CopyOp(qa, q); 3798 t := vt 3799 ELSIF (c1 = SymTab.ClLong) 3800 AND (c2 = SymTab.ClReal) THEN 3801 IF QbeGen.IsImm(q) AND SymTab.ConstInt(q, lo) THEN QbeGen.NormReal(q, qa) ELSE QbeGen.ConvLR(q, qa) END; 3802 QbeGen.CopyOp(qa, q); 3803 t := vt 3804 ELSIF (c1 = SymTab.ClReal) 3805 AND (c2 = SymTab.ClInt) THEN 3806 QbeGen.ConvRI(q, qa); 3807 QbeGen.CopyOp(qa, q); 3808 t := vt 3809 ELSIF (c1 = SymTab.ClReal) 3810 AND (c2 = SymTab.ClLong) THEN 3811 QbeGen.ConvRL(q, qa); 3812 QbeGen.CopyOp(qa, q); 3813 t := vt 3814 ELSIF (c1 = SymTab.ClLong) 3815 AND (c2 = SymTab.ClLong) THEN 3816 t := vt 3817 ELSIF ((c1 = SymTab.ClInt) 3818 OR (c1 = 3819 SymTab.ClChar) 3820 OR (c1 = 3821 SymTab.ClBool) 3822 OR (c1 = 3823 SymTab.ClEnum)) 3824 AND ((c2 = SymTab.ClInt) 3825 OR (c2 = 3826 SymTab.ClChar) 3827 OR (c2 = 3828 SymTab.ClBool) 3829 OR (c2 = 3830 SymTab.ClEnum)) THEN 3831 t := vt 3832 ELSIF (c1 = SymTab.ClPtr) 3833 AND (c2 = SymTab.ClPtr) THEN 3834 t := vt 3835 ELSIF ((c1 = SymTab.ClProc) 3836 AND (c2 = SymTab.ClProc)) 3837 OR ((c1 = SymTab.ClProc) AND (c2 = SymTab.ClPtr)) 3838 OR ((c1 = SymTab.ClPtr) AND (c2 = SymTab.ClProc)) THEN 3839 t := vt 3840 ELSIF (c1 = SymTab.ClReal) 3841 AND (c2 = SymTab.ClReal) THEN 3842 t := vt 3843 ELSE SemError(230); 3844 t := SymTab.InvalidType 3845 END 3846 END 3847 END; .) 3848 | "(" Expr ")" (. t := et; astIsLit := TRUE; .) 3849 | SetLit (. astIsLit := TRUE; t := st; 3850 QbeGen.CopyOp(sq, q); .) 3851 | ( "NOT" | "~" ) Fact (. astNot := astCur; 3852 IF SymTab.BoolCheck(t2) THEN 3853 t := SymTab.BoolType() 3854 ELSE SemError(212); 3855 t := SymTab.InvalidType END; 3856 IF t # SymTab.InvalidType THEN 3857 QbeGen.CopyOp("@", q) 3858 ELSE QbeGen.CopyOp("0", q) 3859 END; 3860 astIsLit := TRUE; 3861 astCur := AST.MakeUn( 3862 AST.NkUnary, AST.OpNot, astNot); .) 3863 ) 3864 (. IF NOT astIsLit THEN astCur := AST.NoNode END; .) 3865 (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) . 3866 (* Set literals are SET OF [0..255] (8 words); elements validated 3867 0..255 statically when foldable (222 otherwise), runtime trap 3868 for computed elements. Ranges always lower via SetRange. *) 3869 SetLit 3870 (. VAR astNode: AST.Node; .) 3871 = "{" (. t := SymTab.NewSet( 3872 SymTab.NewSubR(0, 255)); 3873 astNode := AST.MakeNode(AST.NkSetLit); 3874 QbeGen.NewSetTemp(8, q); 3875 QbeGen.SetZero(q, 8); .) 3876 [ SetElem { "," SetElem } ] 3877 "}" (. astCur := astNode; .) . 3878 (* Typed brace constructor: TypeName{ elems } — BITSET{0} (a set) 3879 or ArrayName{...} (an array constructor, GNU Modula-2). The 3880 declared type sets the width (set) or element type (array). *) 3881 TypedBraceLit 3882 (. VAR nw: CARDINAL; 3883 astNode, astTail: AST.Node; 3884 savedCls: INTEGER; .) 3885 = "{" (. savedCls := braceCls; 3886 astNode := AST.MakeNode(AST.NkBraceLit); 3887 AST.SetTy(astNode, vt); 3888 astTail := astNode; 3889 IF vt = SymTab.InvalidType THEN 3890 braceCls := -1 3891 ELSE braceCls := 3892 SymTab.ClassOf(vt) 3893 END; 3894 IF braceCls = SymTab.ClSet THEN 3895 IF vt = SymTab.InvalidType THEN 3896 nw := 8 3897 ELSE nw := SymTab.SetWords(vt); 3898 IF nw = 0 THEN nw := 8 END 3899 END; 3900 QbeGen.NewSetTemp(nw, q); 3901 QbeGen.SetZero(q, nw) 3902 ELSIF (braceCls = 3903 SymTab.ClArray) 3904 OR (braceCls = 3905 SymTab.ClRecord) 3906 OR (braceCls = 3907 SymTab.ClClass) THEN 3908 QbeGen.CtorBegin(vt) 3909 ELSE 3910 IF vt # SymTab.InvalidType THEN 3911 SemError(230) END; 3912 braceCls := -1 3913 END; .) 3914 [ BraceElem 3915 { "," BraceElem } ] 3916 "}" (. IF (braceCls = SymTab.ClArray) 3917 OR (braceCls = 3918 SymTab.ClRecord) 3919 OR (braceCls = 3920 SymTab.ClClass) THEN 3921 QbeGen.CtorEnd(q) 3922 ELSIF braceCls # SymTab.ClSet THEN 3923 QbeGen.CopyOp("0", q) 3924 END; 3925 braceCls := savedCls; .) 3926 (. astCur := astNode; .) . 3927 BraceElem 3929 (. VAR et, et2: SymTab.TypeIndex; 3930 qe, q2: QbeGen.QVal; 3931 v, v2, reps, k: INTEGER; 3932 elem: SymTab.TypeIndex; 3933 lo: INTEGER; 3934 span: CARDINAL; 3935 cl, cl2: INTEGER; 3936 hasR, hasB: BOOLEAN; 3937 astEl: AST.Node; .) 3938 = (. hasR := FALSE; hasB := FALSE; 3939 reps := 1; .) 3940 Expr (. astEl := astCur; .) 3941 [ ".." Expr (. astEl := AST.MakeBin( 3942 AST.NkSubrange, 0, astEl, astCur); 3943 hasR := TRUE; .) ] 3944 [ "BY" Expr (. hasB := TRUE; .) ] 3945 (. IF braceCls = SymTab.ClSet THEN 3946 IF hasB THEN SemError(230) END; 3947 lo := SymTab.SetBaseLo(vt); 3948 span := SymTab.SetCount(vt); 3949 IF (et = SymTab.InvalidType) 3950 OR (hasR AND (et2 = 3951 SymTab.InvalidType)) THEN 3952 ELSE cl := 3953 SymTab.ClassOf(et); 3954 IF hasR THEN 3955 cl2 := 3956 SymTab.ClassOf(et2) 3957 ELSE cl2 := SymTab.ClInt 3958 END; 3959 IF NOT SymTab.SetElemClassOk(cl) 3960 OR (hasR AND NOT 3961 SymTab.SetElemClassOk(cl2)) 3962 THEN 3963 SemError(222) 3964 ELSIF hasR 3965 AND SymTab.ConstInt(qe, v) 3966 AND SymTab.ConstInt(q2, 3967 v2) 3968 AND ((v < lo) 3969 OR (v2 < lo) 3970 OR (v >= lo + 3971 VAL(INTEGER, span)) 3972 OR (v2 >= lo + 3973 VAL(INTEGER, span)) 3974 OR (v > v2)) THEN 3975 SemError(222) 3976 ELSIF hasR THEN 3977 QbeGen.SetRange(sq, qe, q2, 3978 lo, span) 3979 ELSIF SymTab.ConstInt(qe, 3980 v) 3981 AND ((v < lo) 3982 OR (v >= lo + 3983 VAL(INTEGER, 3984 span))) THEN 3985 SemError(222) 3986 ELSE QbeGen.SetBit(sq, qe, 3987 lo, span) 3988 END 3989 END 3990 ELSIF (braceCls = SymTab.ClArray) 3991 OR (braceCls = 3992 SymTab.ClRecord) 3993 OR (braceCls = 3994 SymTab.ClClass) THEN 3995 IF hasR THEN SemError(230) END; 3996 reps := 1; 3997 IF hasB THEN 3998 IF SymTab.ConstInt(q2, v2) 3999 AND (v2 >= 1) THEN 4000 reps := v2 4001 ELSE SemError(230) 4002 END 4003 END; 4004 k := 0; 4005 WHILE k < reps DO 4006 QbeGen.CtorElem(qe); 4007 INC(k) 4008 END 4009 END; .) 4010 (. (* the BY form repeats the 4011 element; keep the AST in 4012 step with CtorElem *) 4013 k := 0; 4014 WHILE k < reps DO 4015 AstAppend(AST.NkBlock, 4016 node, tail, astEl); 4017 INC(k) 4018 END; .) . 4019 SetElem (. VAR et, et2: SymTab.TypeIndex; 4020 qe, q2: QbeGen.QVal; 4021 v, v2: INTEGER; 4022 lo: INTEGER; 4023 span: CARDINAL; 4024 cl, cl2: INTEGER; 4025 hasR: BOOLEAN; 4026 astEl: AST.Node; .) 4027 = (. hasR := FALSE; .) 4028 Expr (. astEl := astCur; .) 4029 [ ".." Expr (. astEl := AST.MakeBin( 4030 AST.NkSubrange, 0, astEl, astCur); 4031 hasR := TRUE; .) ] 4032 (. lo := SymTab.SetBaseLo(st); 4033 span := SymTab.SetCount(st); 4034 IF (et = SymTab.InvalidType) 4035 OR (hasR AND (et2 = 4036 SymTab.InvalidType)) THEN 4037 ELSE cl := 4038 SymTab.ClassOf(et); 4039 IF hasR THEN 4040 cl2 := 4041 SymTab.ClassOf(et2) 4042 ELSE cl2 := SymTab.ClInt 4043 END; 4044 IF NOT SymTab.SetElemClassOk(cl) 4045 OR (hasR AND NOT 4046 SymTab.SetElemClassOk(cl2)) 4047 THEN 4048 SemError(222) 4049 ELSIF hasR 4050 AND SymTab.ConstInt(qe, v) 4051 AND SymTab.ConstInt(q2, 4052 v2) 4053 AND ((v < lo) 4054 OR (v2 < lo) 4055 OR (v >= lo + 4056 VAL(INTEGER, span)) 4057 OR (v2 >= lo + 4058 VAL(INTEGER, span)) 4059 OR (v > v2)) THEN 4060 SemError(222) 4061 ELSIF hasR THEN 4062 QbeGen.SetRange(sq, qe, q2, 4063 lo, span) 4064 ELSIF SymTab.ConstInt(qe, 4065 v) 4066 AND ((v < lo) 4067 OR (v >= lo + 4068 VAL(INTEGER, 4069 span))) THEN 4070 SemError(222) 4071 ELSE QbeGen.SetBit(sq, qe, 4072 lo, span) 4073 END 4074 END; .) 4075 (. AST.SetChild(node, 4076 AST.NChild(node), astEl); .) . 4077 GetIdent 4078 = ident (. LexName(n); .) . 4079 4080 END M2. 0 errors Statistics: nr of terminals: 112 (limit 400) nr of non-terminals: 90 (limit 210) nr of pragmas: 0 (limit 388) nr of symbolnodes: 202 (limit 500) nr of graphnodes: 1284 (limit 1500) nr of conditionsets: 12 (limit 100) nr of charactersets: 16 (limit 250)