Kaynağa Gözat

language: fold CAP/ABS/ODD over immediates (CONST); BOOLEAN consts

A CONST initialiser calling a builtin (CAP(VAL(CHAR,65)), testcap2) was
rejected: CAP/ABS/ODD set the runtime sentinel "@", so ConstDecl's IsImm
check failed.  Fold them in the grammar's Fact when the operand is an
immediate (CAP uppercases a CHAR, ABS takes the magnitude, ODD yields
0/1); this only feeds the const-ness check, Lower re-lowers from the AST
so runtime code is unchanged.

Also add ClBool to the grammar's Design class list: a BOOLEAN CONST
other than TRUE/FALSE (e.g. ODD(9)) was rejected at the designator
(Lower already handled ClBool).

Corpus 387 -> 389, 0 crashes.  Suite 226/226 (t_constbuiltin).
Fixpoint OK, 3,826,628 bytes.
Eric Streit 12 saat önce
ebeveyn
işleme
96a153b8e1

+ 2 - 2
README.md

@@ -47,8 +47,8 @@ docs/              STATUS.md, plan.md, plan-*.md, analysis_*.md, summary_*.md
 
 ## Status (2026-10-18)
 
-- Suite **225/225**; self-hosting **fixpoint OK** (byte-identical
-  stage2/stage3, 3,823,438 bytes); corpus **387/612 compile-OK,
+- Suite **226/226**; self-hosting **fixpoint OK** (byte-identical
+  stage2/stage3, 3,826,628 bytes); corpus **389/612 compile-OK,
   0 crashes** (`tools/v3-corpus`).
 - Active branch **`resolve-check`** (holds the AST/`Lower`/parse
   refactors and generics).

+ 1 - 0
compiler/run_tests.sh

@@ -96,6 +96,7 @@ expect_run t_enumidx.mod 42
 expect_run t_setenum.mod 42
 expect_run t_fwdset.mod 42
 expect_run t_setconst.mod 42
+expect_run t_constbuiltin.mod 42
 expect_run t_unicode.mod 31
 expect_run t_charbounds.mod 3
 expect_run t_record.mod 160

+ 23 - 5
compiler/src/M2.atg

@@ -2745,7 +2745,8 @@ PRODUCTIONS
                                                     OR (cls
                                                         = SymTab.ClLong)
                                                     OR (cls
-                                                        = SymTab.ClNil)) THEN
+                                                        = SymTab.ClNil)
+                                                     OR (cls = SymTab.ClBool)) THEN
                                                    IF cls = SymTab.ClNil THEN
                                                      QbeGen.CopyOp("0", q)
                                                    ELSIF ((cls
@@ -2755,7 +2756,8 @@ PRODUCTIONS
                                                      OR (cls
                                                        = SymTab.ClEnum)
                                                      OR (cls
-                                                       = SymTab.ClLong))
+                                                       = SymTab.ClLong)
+                                                      OR (cls = SymTab.ClBool))
   AND SymTab.GetSymVal(n, cv)
   AND QbeGen.IsImm(cv) THEN
                                                      QbeGen.CopyOp(cv, q)
@@ -3656,8 +3658,13 @@ PRODUCTIONS
    AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CAP"));
    IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
    astCur := astNode; astIsLit := TRUE; .)
-                                         (. QbeGen.CopyOp("@", q);
-                                           t := SymTab.CharType(); .)
+                                         (. IF QbeGen.IsImm(q)
+  AND SymTab.ConstInt(q, lo) THEN
+     IF (lo >= VAL(INTEGER, ORD("a"))) AND (lo <= VAL(INTEGER, ORD("z"))) THEN lo := lo - 32 END;
+     QbeGen.IntStr(lo, q)
+   ELSE QbeGen.CopyOp("@", q)
+   END;
+   t := SymTab.CharType(); .)
     | "UCHR" "(" Expr<et, q> ")"
     (. astNode := AST.MakeNode(AST.NkCall);
    AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UCHR"));
@@ -3703,6 +3710,10 @@ PRODUCTIONS
  AND (SymTab.ClassOf(et) #
                                                 SymTab.ClReal) THEN
                                              SemError(211)
+                                            ELSIF QbeGen.IsImm(q)
+  AND SymTab.ConstInt(q, lo) THEN
+                                              IF lo < 0 THEN lo := -lo END;
+                                              QbeGen.IntStr(lo, q)
                                             ELSE QbeGen.CopyOp("@", q)
                                            END;
                                            t := et; .)
@@ -3715,7 +3726,14 @@ PRODUCTIONS
  AND NOT SymTab.IsIntFamily(et) THEN
                                              SemError(211) END;
                                            t := SymTab.BoolType();
-                                           QbeGen.CopyOp("@", q); .)
+                                           IF QbeGen.IsImm(q)
+  AND SymTab.ConstInt(q, lo) THEN
+                                             IF (lo MOD 2) # 0 THEN
+                                               QbeGen.CopyOp("1", q)
+                                             ELSE QbeGen.CopyOp("0", q)
+                                             END
+                                           ELSE QbeGen.CopyOp("@", q)
+                                           END; .)
     | "TRUNC" "(" Expr<et, q> ")"
     (. (* TRUNC(x): real -> INTEGER, as the VAL builtin *)
    astNode := AST.MakeNode(AST.NkCall);

+ 1308 - 1290
compiler/src/M2.lst

@@ -2764,1302 +2764,1320 @@ Listing:
  2745                                                      OR (cls
  2746                                                          = SymTab.ClLong)
  2747                                                      OR (cls
- 2748                                                          = SymTab.ClNil)) THEN
- 2749                                                     IF cls = SymTab.ClNil THEN
- 2750                                                       QbeGen.CopyOp("0", q)
- 2751                                                     ELSIF ((cls
- 2752                                                         = SymTab.ClInt)
- 2753                                                       OR (cls
- 2754                                                         = SymTab.ClChar)
- 2755                                                       OR (cls
- 2756                                                         = SymTab.ClEnum)
- 2757                                                       OR (cls
- 2758                                                         = SymTab.ClLong))
- 2759    AND SymTab.GetSymVal(n, cv)
- 2760    AND QbeGen.IsImm(cv) THEN
- 2761                                                       QbeGen.CopyOp(cv, q)
- 2762                                                     ELSE
- 2763                                                       QbeGen.LoadVar(n,
- 2764                                                         cls = SymTab.ClReal,
- 2765                                                         q)
- 2766                                                     END
- 2767                                                   ELSIF (cls = SymTab.ClArray)
- 2768                                                      OR (cls = SymTab.ClRecord)
- 2769                                                      OR (cls = SymTab.ClClass)
- 2770                                                      OR (cls = SymTab.ClStr)
- 2771                                                      OR (cls = SymTab.ClUStr)
- 2772                                                      OR (cls = SymTab.ClSet) THEN
- 2773                                                     (* aggregate constant:
- 2774                                                        its value IS the
- 2775                                                        descriptor address *)
- 2776                                                     IF SymTab.GetSymVal(n, cv) THEN
- 2777                                                       QbeGen.CopyOp(cv, q)
- 2778                                                     ELSE
- 2779                                                       QbeGen.CopyOp("0", q)
- 2780                                                     END
- 2781                                                   ELSE
- 2782                                                     IF t #
- 2783                                                        SymTab.InvalidType THEN
- 2784                                                       SemError(230)
- 2785                                                     END;
- 2786                                                     QbeGen.CopyOp("0", q)
- 2787                                                   END
- 2788                                                 END
- 2789                                               ELSIF (k = SymTab.KindVar)
- 2790                                                  OR (k = SymTab.KindParam) THEN
- 2791                                                 cls := SymTab.ClassOf(t);
- 2792                                                 IF (cls # SymTab.ClInt)
- 2793                                                    AND (cls # SymTab.ClBool)
- 2794                                                    AND (cls # SymTab.ClChar)
- 2795                                                    AND (cls # SymTab.ClUChar)
- 2796                                                    AND (cls # SymTab.ClEnum)
- 2797                                                    AND (cls # SymTab.ClReal)
- 2798                                                    AND (cls # SymTab.ClPtr)
- 2799                                                    AND (cls # SymTab.ClProc)
- 2800                                                    AND (cls # SymTab.ClLong)
- 2801                                                    AND (cls # SymTab.ClArray)
- 2802                                                    AND (cls # SymTab.ClSet)
- 2803                                                    AND (cls # SymTab.ClRecord)
- 2804                                                    AND (cls # SymTab.ClUStr)
- 2805                                                    AND (cls # SymTab.ClClass) THEN
- 2806                                                   SemError(230);
- 2807                                                   QbeGen.CopyOp("0", q)
- 2808                                                 ELSE QbeGen.CopyOp("@", q)
- 2809                                                 END
- 2810                                               ELSE QbeGen.CopyOp("0", q);
- 2811                                                 IF k = SymTab.KindImport THEN
- 2812                                                   SemError(230)
- 2813                                                 ELSIF k =
- 2814                                                    SymTab.KindProc THEN
- 2815                                                   (* bare procedure name:
- 2816                                                      a following ArgList
- 2817                                                      makes it a call;
- 2818                                                      otherwise Fact
- 2819                                                      reports 230 *)
- 2820                                                 ELSE
- 2821                                                    IF k = SymTab.KindField THEN
- 2822                                                      IF QbeGen.TopWith(qb) THEN
- 2823                                                        sfx := TRUE
- 2824                                                      ELSE SemError(230);
- 2825                                                        QbeGen.CopyOp("0", q)
- 2826                                                      END
- 2827                                                    END
- 2828                                                 END
- 2829                                               END
- 2830                                             END; .)
- 2831        (. astDes := AST.MakeNode(AST.NkDesignator);
- 2832           AST.SetChild(astDes, AST.NChild(astDes), AST.MakeLeaf(AST.NkIdent, n)); .)
- 2833        { "[" Expr<it, iq>
- 2834                                          (. AST.SetChild(astDes, AST.NChild(astDes),
- 2835               AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
- 2836                                             ELSIF SymTab.ClassOf(t) #
- 2837                                                   SymTab.ClArray THEN
- 2838                                               SemError(217);
- 2839                                               t := SymTab.InvalidType
- 2840                                             ELSIF NOT SymTab.IsIntFamily(it)
- 2841   AND (SymTab.ClassOf(it) #
- 2842                                                   SymTab.ClChar)
+ 2748                                                          = SymTab.ClNil)
+ 2749                                                       OR (cls = SymTab.ClBool)) THEN
+ 2750                                                     IF cls = SymTab.ClNil THEN
+ 2751                                                       QbeGen.CopyOp("0", q)
+ 2752                                                     ELSIF ((cls
+ 2753                                                         = SymTab.ClInt)
+ 2754                                                       OR (cls
+ 2755                                                         = SymTab.ClChar)
+ 2756                                                       OR (cls
+ 2757                                                         = SymTab.ClEnum)
+ 2758                                                       OR (cls
+ 2759                                                         = SymTab.ClLong)
+ 2760                                                        OR (cls = SymTab.ClBool))
+ 2761    AND SymTab.GetSymVal(n, cv)
+ 2762    AND QbeGen.IsImm(cv) THEN
+ 2763                                                       QbeGen.CopyOp(cv, q)
+ 2764                                                     ELSE
+ 2765                                                       QbeGen.LoadVar(n,
+ 2766                                                         cls = SymTab.ClReal,
+ 2767                                                         q)
+ 2768                                                     END
+ 2769                                                   ELSIF (cls = SymTab.ClArray)
+ 2770                                                      OR (cls = SymTab.ClRecord)
+ 2771                                                      OR (cls = SymTab.ClClass)
+ 2772                                                      OR (cls = SymTab.ClStr)
+ 2773                                                      OR (cls = SymTab.ClUStr)
+ 2774                                                      OR (cls = SymTab.ClSet) THEN
+ 2775                                                     (* aggregate constant:
+ 2776                                                        its value IS the
+ 2777                                                        descriptor address *)
+ 2778                                                     IF SymTab.GetSymVal(n, cv) THEN
+ 2779                                                       QbeGen.CopyOp(cv, q)
+ 2780                                                     ELSE
+ 2781                                                       QbeGen.CopyOp("0", q)
+ 2782                                                     END
+ 2783                                                   ELSE
+ 2784                                                     IF t #
+ 2785                                                        SymTab.InvalidType THEN
+ 2786                                                       SemError(230)
+ 2787                                                     END;
+ 2788                                                     QbeGen.CopyOp("0", q)
+ 2789                                                   END
+ 2790                                                 END
+ 2791                                               ELSIF (k = SymTab.KindVar)
+ 2792                                                  OR (k = SymTab.KindParam) THEN
+ 2793                                                 cls := SymTab.ClassOf(t);
+ 2794                                                 IF (cls # SymTab.ClInt)
+ 2795                                                    AND (cls # SymTab.ClBool)
+ 2796                                                    AND (cls # SymTab.ClChar)
+ 2797                                                    AND (cls # SymTab.ClUChar)
+ 2798                                                    AND (cls # SymTab.ClEnum)
+ 2799                                                    AND (cls # SymTab.ClReal)
+ 2800                                                    AND (cls # SymTab.ClPtr)
+ 2801                                                    AND (cls # SymTab.ClProc)
+ 2802                                                    AND (cls # SymTab.ClLong)
+ 2803                                                    AND (cls # SymTab.ClArray)
+ 2804                                                    AND (cls # SymTab.ClSet)
+ 2805                                                    AND (cls # SymTab.ClRecord)
+ 2806                                                    AND (cls # SymTab.ClUStr)
+ 2807                                                    AND (cls # SymTab.ClClass) THEN
+ 2808                                                   SemError(230);
+ 2809                                                   QbeGen.CopyOp("0", q)
+ 2810                                                 ELSE QbeGen.CopyOp("@", q)
+ 2811                                                 END
+ 2812                                               ELSE QbeGen.CopyOp("0", q);
+ 2813                                                 IF k = SymTab.KindImport THEN
+ 2814                                                   SemError(230)
+ 2815                                                 ELSIF k =
+ 2816                                                    SymTab.KindProc THEN
+ 2817                                                   (* bare procedure name:
+ 2818                                                      a following ArgList
+ 2819                                                      makes it a call;
+ 2820                                                      otherwise Fact
+ 2821                                                      reports 230 *)
+ 2822                                                 ELSE
+ 2823                                                    IF k = SymTab.KindField THEN
+ 2824                                                      IF QbeGen.TopWith(qb) THEN
+ 2825                                                        sfx := TRUE
+ 2826                                                      ELSE SemError(230);
+ 2827                                                        QbeGen.CopyOp("0", q)
+ 2828                                                      END
+ 2829                                                    END
+ 2830                                                 END
+ 2831                                               END
+ 2832                                             END; .)
+ 2833        (. astDes := AST.MakeNode(AST.NkDesignator);
+ 2834           AST.SetChild(astDes, AST.NChild(astDes), AST.MakeLeaf(AST.NkIdent, n)); .)
+ 2835        { "[" Expr<it, iq>
+ 2836                                          (. AST.SetChild(astDes, AST.NChild(astDes),
+ 2837               AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
+ 2838                                             ELSIF SymTab.ClassOf(t) #
+ 2839                                                   SymTab.ClArray THEN
+ 2840                                               SemError(217);
+ 2841                                               t := SymTab.InvalidType
+ 2842                                             ELSIF NOT SymTab.IsIntFamily(it)
  2843   AND (SymTab.ClassOf(it) #
- 2844                                                   SymTab.ClEnum)
+ 2844                                                   SymTab.ClChar)
  2845   AND (SymTab.ClassOf(it) #
- 2846                                                   SymTab.ClBool) THEN
- 2847                                               SemError(218);
- 2848                                               t := SymTab.InvalidType
- 2849                                              ELSE
- 2850                                                eT := SymTab.ArrayElem(t);
- 2851                                                t := eT; sfx := TRUE
- 2852                                              END; .)
- 2853          { "," Expr<it, iq>
- 2854                                          (. AST.SetChild(astDes, AST.NChild(astDes),
- 2855               AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
- 2856                                             ELSIF SymTab.ClassOf(t) #
- 2857                                                   SymTab.ClArray THEN
- 2858                                               SemError(217);
- 2859                                               t := SymTab.InvalidType
- 2860                                             ELSIF NOT SymTab.IsIntFamily(it)
- 2861   AND (SymTab.ClassOf(it) #
- 2862                                                   SymTab.ClChar)
+ 2846                                                   SymTab.ClEnum)
+ 2847   AND (SymTab.ClassOf(it) #
+ 2848                                                   SymTab.ClBool) THEN
+ 2849                                               SemError(218);
+ 2850                                               t := SymTab.InvalidType
+ 2851                                              ELSE
+ 2852                                                eT := SymTab.ArrayElem(t);
+ 2853                                                t := eT; sfx := TRUE
+ 2854                                              END; .)
+ 2855          { "," Expr<it, iq>
+ 2856                                          (. AST.SetChild(astDes, AST.NChild(astDes),
+ 2857               AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
+ 2858                                             ELSIF SymTab.ClassOf(t) #
+ 2859                                                   SymTab.ClArray THEN
+ 2860                                               SemError(217);
+ 2861                                               t := SymTab.InvalidType
+ 2862                                             ELSIF NOT SymTab.IsIntFamily(it)
  2863   AND (SymTab.ClassOf(it) #
- 2864                                                   SymTab.ClEnum)
+ 2864                                                   SymTab.ClChar)
  2865   AND (SymTab.ClassOf(it) #
- 2866                                                   SymTab.ClBool) THEN
- 2867                                               SemError(218);
- 2868                                               t := SymTab.InvalidType
- 2869                                              ELSE
- 2870                                                eT := SymTab.ArrayElem(t);
- 2871                                                t := eT; sfx := TRUE
- 2872                                              END; .) }
- 2873          "]"
- 2874        | "." GetIdent<fn>
- 2875                                          (. astSel := AST.MakeNode(AST.NkSelector);
- 2876               AST.SetOp(astSel, AST.SelField);
- 2877               AST.SetChild(astSel, 0, AST.MakeLeaf(AST.NkIdent, fn));
- 2878               AST.SetChild(astDes, AST.NChild(astDes), astSel); IF k = SymTab.KindModule THEN
- 2879                                               (* qualified L.x: materialize
- 2880                                                  the export, then load it *)
- 2881                                               IF NOT SymTab.MaterializeAlias(n,
- 2882                                                    fn, mal) THEN
- 2883                                                 SemError(201);
- 2884                                                 t := SymTab.InvalidType;
- 2885                                                 QbeGen.CopyOp("0", q)
- 2886                                               ELSE
- 2887                                                 QbeGen.CopyOp(mal, qn);
- 2888                                                 t := SymTab.SymType(mal);
- 2889                                                 k := SymTab.SymKind(mal);
- 2890                                                 sfx := FALSE;
- 2891                                                 IF k = SymTab.KindProc THEN
- 2892                                                   (* call: ArgList supplies
- 2893                                                      the value *)
- 2894                                                   QbeGen.CopyOp("0", q)
- 2895                                                  END
- 2896                                               END
- 2897                                             ELSIF t = SymTab.InvalidType THEN
- 2898                                             ELSIF (SymTab.ClassOf(t) #
- 2899                                                    SymTab.ClRecord)
- 2900   AND (SymTab.ClassOf(t) #
- 2901                                                   SymTab.ClClass) THEN
- 2902                                               SemError(215);
- 2903                                               t := SymTab.InvalidType
- 2904                                             ELSIF (SymTab.ClassOf(t) =
- 2905                                                    SymTab.ClClass)
- 2906    AND SymTab.MethodExists(t, fn) THEN
- 2907                                               (* obj.Method: bind the
- 2908                                                  method and pass obj as
- 2909                                                  the hidden receiver; q
- 2910                                                  already holds the
- 2911                                                  object's address *)
- 2912                                               QbeGen.CopyOp(fn, n);
- 2913                                               QbeGen.CopyOp(fn, qn);
- 2914                                               methCls := t;
- 2915                                               k := SymTab.KindProc;
- 2916                                               t := SymTab.InvalidType
- 2917                                             ELSIF NOT SymTab.FieldExists(t,
- 2918                                                      fn) THEN
- 2919                                               SemError(216);
- 2920                                               t := SymTab.InvalidType
- 2921                                              ELSE
- 2922                                                t := SymTab.FieldType(t, fn);
- 2923                                                sfx := TRUE
- 2924                                              END; .)
- 2925        | "^"
- 2926                                          (. astSel := AST.MakeNode(AST.NkSelector);
- 2927               AST.SetOp(astSel, AST.SelDeref);
- 2928               AST.SetChild(astDes, AST.NChild(astDes), astSel); IF t = SymTab.InvalidType THEN
- 2929                                             ELSIF SymTab.ClassOf(t) #
- 2930                                                   SymTab.ClPtr THEN
- 2931                                               SemError(219);
- 2932                                               t := SymTab.InvalidType
- 2933                                             ELSE
- 2934                                               bt := SymTab.PtrBase(t);
- 2935                                               IF bt = SymTab.InvalidType THEN
- 2936                                               ELSE
- 2937                                                  t := bt;
- 2938                                                  sfx := TRUE
- 2939                                                END
- 2940                                             END; .) } (. astCur := astDes; .) .
- 2941    (* Result suffix (ISO component after a function call): `F()^`,
- 2942       `F()[i]`, `F().field`.  The call result is in t/q with sfx FALSE
- 2943       (a value, or a descriptor address for aggregates); each component
- 2944       descends one level exactly like the Design components. *)
- 2945    ResultComp<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
- 2946               VAR sfx: BOOLEAN; VAR node: AST.Node;
- 2947               VAR mname: SymTab.Name; VAR methCls: SymTab.TypeIndex;
- 2948               VAR isM: BOOLEAN>          (. VAR it, eT, bt: SymTab.TypeIndex;
- 2949                                               iq, ql, qlo, qhi, qe, qb:
- 2950                                                 QbeGen.QVal;
- 2951                                               lo, hi, fo: INTEGER;
- 2952                                               isOpen: BOOLEAN;
- 2953                                               fname: SymTab.Name;
- 2954                                               astWrap, astSel: AST.Node; .)
- 2955      = "[" Expr<it, iq>
- 2956                                          (. isM := FALSE;
- 2957                                             IF AST.Kind(node) # AST.NkDesignator THEN
- 2958                                               astWrap := AST.MakeNode(
- 2959                                                 AST.NkDesignator);
- 2960                                               AST.SetChild(astWrap, 0, node);
- 2961                                               node := astWrap
- 2962                                             END;
- 2963                                             AST.SetChild(node, AST.NChild(node),
- 2964                                               AST.MakeUn(AST.NkSelector,
- 2965                                                 AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
- 2966                                             ELSIF SymTab.ClassOf(t) #
- 2967                                                   SymTab.ClArray THEN
- 2968                                               SemError(217);
- 2969                                               t := SymTab.InvalidType
- 2970                                             ELSIF NOT SymTab.IsIntFamily(it)
- 2971    AND (SymTab.ClassOf(it) # SymTab.ClChar)
- 2972    AND (SymTab.ClassOf(it) # SymTab.ClEnum)
- 2973    AND (SymTab.ClassOf(it) # SymTab.ClBool) THEN
- 2974                                               SemError(218);
- 2975                                               t := SymTab.InvalidType
- 2976                                              ELSE
- 2977                                                eT := SymTab.ArrayElem(t);
- 2978                                                t := eT; sfx := TRUE
- 2979                                              END; .)
- 2980        "]"
- 2981      | "." GetIdent<fname>
- 2982                                          (. isM := FALSE;
- 2983                                             IF AST.Kind(node) # AST.NkDesignator THEN
- 2984                                               astWrap := AST.MakeNode(
- 2985                                                 AST.NkDesignator);
- 2986                                               AST.SetChild(astWrap, 0, node);
- 2987                                               node := astWrap
- 2988                                             END;
- 2989                                             AST.SetChild(node, AST.NChild(node),
- 2990                                               AST.MakeUn(AST.NkSelector,
- 2991                                                 AST.SelField,
- 2992                                                 AST.MakeLeaf(AST.NkIdent,
- 2993                                                   fname))); IF t = SymTab.InvalidType THEN
- 2994                                             ELSIF (SymTab.ClassOf(t) #
- 2995                                                    SymTab.ClRecord)
- 2996    AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN
- 2997                                               SemError(215);
- 2998                                               t := SymTab.InvalidType
- 2999                                              ELSIF (SymTab.ClassOf(t) =
- 3000                                                     SymTab.ClClass)
- 3001    AND SymTab.MethodExists(t, fname) THEN
- 3002                                                (* a method on the call result:
- 3003                                                   a following ArgList makes
- 3004                                                   the call *)
- 3005                                                mname := fname;
- 3006                                                methCls := t; isM := TRUE;
- 3007                                                t := SymTab.InvalidType
- 3008                                             ELSIF NOT SymTab.FieldExists(t,
- 3009                                                      fname) THEN
- 3010                                               SemError(216);
- 3011                                               t := SymTab.InvalidType
- 3012                                              ELSE
- 3013                                                t := SymTab.FieldType(t, fname);
- 3014                                                sfx := TRUE
- 3015                                              END; .)
- 3016      | "^"                               (. isM := FALSE;
- 3017                                             IF AST.Kind(node) # AST.NkDesignator THEN
- 3018                                               astWrap := AST.MakeNode(
- 3019                                                 AST.NkDesignator);
- 3020                                               AST.SetChild(astWrap, 0, node);
- 3021                                               node := astWrap
- 3022                                             END;
- 3023                                             astSel := AST.MakeNode(AST.NkSelector);
- 3024                                             AST.SetOp(astSel, AST.SelDeref);
- 3025                                             AST.SetChild(node,
- 3026                                               AST.NChild(node), astSel); IF t = SymTab.InvalidType THEN
- 3027                                             ELSIF SymTab.ClassOf(t) #
- 3028                                                   SymTab.ClPtr THEN
- 3029                                               SemError(219);
- 3030                                               t := SymTab.InvalidType
- 3031                                             ELSE
- 3032                                               bt := SymTab.PtrBase(t);
- 3033                                               IF bt # SymTab.InvalidType THEN
- 3034                                                  t := bt; sfx := TRUE
- 3035                                               END
- 3036                                             END; .) .
- 3037    Expr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 3038                                          (. VAR t2: SymTab.TypeIndex;
- 3039                                               op: INTEGER;
- 3040                                               q2, qt, wl: QbeGen.QVal;
- 3041                                                astA, astB: AST.Node;
- 3042                                                astOp: INTEGER;
- 3043                                                astMade: BOOLEAN;
- 3044                                               isR: BOOLEAN; .)
- 3045      = SimExpr<t, q>                     (. astA := astCur; astMade := FALSE; .)
- 3046        [ Rel<op> SimExpr<t2, q2>
- 3047          (. astB := astCur; astMade := TRUE;
- 3048              astOp := AST.OpEq;
- 3049              IF op = SymTab.OpNeq1 THEN astOp := AST.OpNe
- 3050              ELSIF op = SymTab.OpNeq2 THEN astOp := AST.OpNe
- 3051              ELSIF op = SymTab.OpLt THEN astOp := AST.OpLt
- 3052              ELSIF op = SymTab.OpLe THEN astOp := AST.OpLe
- 3053              ELSIF op = SymTab.OpGt THEN astOp := AST.OpGt
- 3054              ELSIF op = SymTab.OpGe THEN astOp := AST.OpGe
- 3055              ELSIF op = SymTab.OpIn THEN astOp := AST.OpIn
- 3056              END;
- 3057              IF op = SymTab.OpIn THEN
- 3058               IF SymTab.InCheck(t, t2) THEN
- 3059                 IF (t = SymTab.InvalidType)
- 3060                    OR (t2 = SymTab.InvalidType) THEN
- 3061                   t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
- 3062                 ELSE
- 3063                    t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
- 3064                 END
- 3065               ELSE SemError(222); t := SymTab.InvalidType;
- 3066                 QbeGen.CopyOp("0", q)
- 3067               END
- 3068             ELSIF SymTab.RelCheck(t, t2, op) THEN
- 3069               IF (t = SymTab.InvalidType)
- 3070                  OR (t2 = SymTab.InvalidType) THEN
- 3071                 t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
- 3072               ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
- 3073                  OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN
- 3074                 IF (op # SymTab.OpEq) AND (op # SymTab.OpNeq1)
- 3075   AND (op # SymTab.OpNeq2) THEN
- 3076                   SemError(213); t := SymTab.InvalidType;
- 3077                   QbeGen.CopyOp("0", q)
- 3078                  ELSE
- 3079                    t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
- 3080                  END
- 3081                ELSIF (SymTab.ClassOf(t) = SymTab.ClSet)
- 3082                   OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 3083                  t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
- 3084               ELSIF SymTab.StrCompat(t, t2) THEN
- 3085                 QbeGen.StrEq(op, q, q2, qt);
- 3086                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
- 3087               ELSIF SymTab.IsLongFamily(t)
- 3088                  OR SymTab.IsLongFamily(t2) THEN
- 3089                  t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
- 3090                ELSE
- 3091                  t := SymTab.BoolType();
- 3092                  QbeGen.CopyOp("@", q)
- 3093                END
- 3094             ELSE SemError(213); t := SymTab.InvalidType;
- 3095                QbeGen.CopyOp("0", q)
- 3096              END;
- 3097              astCur := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB); .) ]
- 3098         (. IF NOT astMade THEN astCur := astA END; .)
- 3099             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
- 3100    Rel<VAR op: INTEGER>
- 3101      = "="                               (. op := SymTab.OpEq; .)
- 3102      | "#"                               (. op := SymTab.OpNeq1; .)
- 3103      | "<"                               (. op := SymTab.OpLt; .)
- 3104      | "<="                              (. op := SymTab.OpLe; .)
- 3105      | ">"                               (. op := SymTab.OpGt; .)
- 3106      | ">="                              (. op := SymTab.OpGe; .)
- 3107      | "IN"                              (. op := SymTab.OpIn; .) .
- 3108    SimExpr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 3109                                          (. VAR t2, res2, lt, rt:
- 3110                                                 SymTab.TypeIndex;
- 3111                                               op: INTEGER;
- 3112                                               q2, qt, wq, qf, q2a, q2b:
- 3113                                                 QbeGen.QVal;
- 3114                                               neg, isR, isL, folded:
- 3115                                                 BOOLEAN;
- 3116                                               fok: BOOLEAN;
- 3117                                               lw, rw, mw: CARDINAL;
- 3118                                               lTrue, lNext, lDone, qr, qs: QbeGen.QVal;
- 3119                                                astA, astB: AST.Node;
- 3120                                                astSign, astOp: INTEGER; .)
- 3121      =                                   (. neg := FALSE; astSign := 0; .)
- 3122        [ "+"                         (. neg := TRUE; astSign := 1; .)
- 3123        | "-"                         (. neg := TRUE; astSign := -1; .) ]
- 3124        Term<t, q> (. astA := astCur;
- 3125                                            IF neg AND QbeGen.IsImm(q) THEN
- 3126                                              QbeGen.NegFold(q, q)
- 3127                                            END;
- 3128                                           IF astSign < 0 THEN
- 3129                                             astCur := AST.MakeUn(
- 3130                                               AST.NkUnary, AST.OpSub, astA);
- 3131                                             astA := astCur
- 3132                                           END; .)
- 3133         { AddOp<op>
- 3134           Term<t2, q2> (. astB := astCur; .)
- 3135          (. astOp := AST.OpAdd;
- 3136             IF op = SymTab.OpSub THEN astOp := AST.OpSub
- 3137             ELSIF op = SymTab.OpOr THEN astOp := AST.OpOr END;
- 3138             astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB);
- 3139             astCur := astA;
- 3140             IF op = SymTab.OpOr THEN
- 3141               (* short-circuit: if q is true the RHS is skipped *)
- 3142               IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
- 3143                 t := SymTab.BoolType()
- 3144               ELSE SemError(212); t := SymTab.InvalidType END;
- 3145                IF t # SymTab.InvalidType THEN
- 3146                  QbeGen.CopyOp("@", q)
- 3147                ELSE QbeGen.CopyOp("0", q)
- 3148                END
- 3149             ELSIF (op = SymTab.OpAdd)
- 3150               AND (SymTab.UStrCompat(t, t2)
- 3151                 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
- 3152                   AND (SymTab.ClassOf(t2) = SymTab.ClUStr))
- 3153                 OR ((SymTab.ClassOf(t) = SymTab.ClUStr)
- 3154                   AND (SymTab.ClassOf(t2) = SymTab.ClUChar))
- 3155                 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
- 3156                   AND (SymTab.ClassOf(t2) = SymTab.ClUChar))) THEN
- 3157               (* UString concatenation: a UCHAR operand becomes a
- 3158                  1-codepoint UString; the result is a descriptor in the
- 3159                  shim's concat buffer.  Work on copies so neither
- 3160                  operand is clobbered. *)
- 3161                t := SymTab.NewUStr();
- 3162                QbeGen.CopyOp("@", q)
- 3163             ELSIF (op = SymTab.OpAdd)
- 3164               AND (SymTab.StrCompat(t, t2)
- 3165                 OR (SymTab.IsStrType(t)
- 3166                   AND (SymTab.ClassOf(t2) = SymTab.ClChar))
- 3167                 OR ((SymTab.ClassOf(t) = SymTab.ClChar)
- 3168                   AND SymTab.IsStrType(t2))) THEN
- 3169               (* string concatenation; a CHAR operand becomes a
- 3170                  1-character string literal.  When both operands are
- 3171                  constants, fold to a single string literal so a
- 3172                  constructor element stays compile-time. *)
- 3173                QbeGen.StrFold(q, q2, SymTab.ClassOf(t), SymTab.ClassOf(t2),
- 3174                  qt, fok);
- 3175                IF fok THEN QbeGen.CopyOp(qt, q)
- 3176                ELSE QbeGen.CopyOp("@", q)
- 3177                END;
- 3178                t := SymTab.NewStr()
- 3179             ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
- 3180   AND (SymTab.ClassOf(t) = SymTab.ClSet)
- 3181   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 3182                lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
- 3183                mw := lw;
- 3184                IF rw > mw THEN mw := rw END;
- 3185                t := SymTab.NewSet(
- 3186                       SymTab.NewSubR(0,
- 3187                         VAL(INTEGER, mw) * 32 - 1));
- 3188                QbeGen.CopyOp("@", q)
- 3189             ELSE
- 3190               IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
- 3191                 lt := t; rt := t2; t := res2
- 3192               ELSE SemError(211); t := SymTab.InvalidType END;
- 3193               IF t # SymTab.InvalidType THEN
- 3194                 isL := SymTab.IsLongFamily(t);
- 3195                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 3196                 folded := FALSE;
- 3197                 IF (NOT isL) AND (NOT isR)
- 3198    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
- 3199                   IF op = SymTab.OpAdd THEN
- 3200                     folded := QbeGen.Fold2(0, q, q2, qf)
- 3201                   ELSE
- 3202                     folded := QbeGen.Fold2(1, q, q2, qf)
- 3203                   END
- 3204                 END;
- 3205                 IF folded THEN QbeGen.CopyOp(qf, q)
- 3206                  ELSE
- 3207                  QbeGen.CopyOp("@", q)
- 3208                  END
- 3209               ELSE QbeGen.CopyOp("0", q)
- 3210               END
- 3211             END; .) }
- 3212             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
- 3213    AddOp<VAR op: INTEGER>
- 3214      = "+"                               (. op := SymTab.OpAdd; .)
- 3215      | "-"                               (. op := SymTab.OpSub; .)
- 3216      | "OR"                              (. op := SymTab.OpOr; .) .
- 3217    Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 3218                                          (. VAR t2, res2, lt, rt:
- 3219                                                 SymTab.TypeIndex;
- 3220                                               op: INTEGER;
- 3221                                               q2, qt, wq, qf:
- 3222                                                 QbeGen.QVal;
- 3223                                               isR, isL, folded: BOOLEAN;
- 3224                                               lw, rw, mw: CARDINAL;
- 3225                                               lNext, lFalse, lDone, qr, qs: QbeGen.QVal;
- 3226                                                astA, astB: AST.Node;
- 3227                                                astOp: INTEGER; .)
- 3228      = Fact<t, q> (. astA := astCur; .) { MulOp<op>
- 3229          Fact<t2, q2> (. astB := astCur; .)
- 3230        (. astOp := AST.OpMul;
- 3231           IF op = SymTab.OpSlash THEN astOp := AST.OpDiv
- 3232           ELSIF op = SymTab.OpDiv THEN astOp := AST.OpDiv
- 3233           ELSIF op = SymTab.OpMod THEN astOp := AST.OpMod
- 3234           ELSIF op = SymTab.OpAnd THEN astOp := AST.OpAnd END;
- 3235           astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB);
- 3236           astCur := astA;
- 3237           IF op = SymTab.OpAnd THEN
- 3238             (* short-circuit: if q is false the RHS is skipped *)
- 3239             IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
- 3240               t := SymTab.BoolType()
- 3241             ELSE SemError(212); t := SymTab.InvalidType END;
- 3242              IF t # SymTab.InvalidType THEN QbeGen.CopyOp("@", q)
- 3243              ELSE QbeGen.CopyOp("0", q)
- 3244              END
- 3245           ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
- 3246   AND (SymTab.ClassOf(t) = SymTab.ClSet)
- 3247   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 3248              lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
- 3249              mw := lw;
- 3250              IF rw > mw THEN mw := rw END;
- 3251              t := SymTab.NewSet(
- 3252                     SymTab.NewSubR(0,
- 3253                       VAL(INTEGER, mw) * 32 - 1));
- 3254              QbeGen.CopyOp("@", q)
- 3255           ELSE
- 3256             IF SymTab.ArithCheck(t, t2,
- 3257                  (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
- 3258                  res2) THEN
- 3259               lt := t; rt := t2; t := res2
- 3260             ELSE SemError(211); t := SymTab.InvalidType END;
- 3261             IF t # SymTab.InvalidType THEN
- 3262               isL := SymTab.IsLongFamily(t);
- 3263               isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 3264               folded := FALSE;
- 3265               IF (NOT isL) AND (NOT isR)
- 3266    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
- 3267                 IF op = SymTab.OpTimes THEN
- 3268                   folded := QbeGen.Fold2(2, q, q2, qf)
- 3269                 ELSIF op = SymTab.OpDiv THEN
- 3270                   folded := QbeGen.Fold2(3, q, q2, qf)
- 3271                 ELSIF op = SymTab.OpMod THEN
- 3272                   folded := QbeGen.Fold2(4, q, q2, qf)
- 3273                 END
- 3274               END;
- 3275               IF folded THEN QbeGen.CopyOp(qf, q)
- 3276                ELSE
- 3277                QbeGen.CopyOp("@", q)
- 3278                END
- 3279             ELSE QbeGen.CopyOp("0", q)
- 3280             END
- 3281           END; .) }
- 3282             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
- 3283    MulOp<VAR op: INTEGER>
- 3284      = "*"                               (. op := SymTab.OpTimes; .)
- 3285      | "/"                               (. op := SymTab.OpSlash; .)
- 3286      | "DIV"                             (. op := SymTab.OpDiv; .)
- 3287      | "MOD"                             (. op := SymTab.OpMod; .)
- 3288      | ( "AND" | "&" )                   (. op := SymTab.OpAnd; .) .
- 3289    Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 3290                                          (. VAR s: ARRAY [0 .. 255] OF CHAR;
- 3291                                               et, dt, t2, st, ct2, et2:
- 3292                                                 SymTab.TypeIndex;
- 3293                                               dk: INTEGER;
- 3294                                               qd, q2, sq, qa, qm0, qr, qt:
- 3295                                                 QbeGen.QVal;
- 3296                                               qn, vn: SymTab.Name;
- 3297                                               vt: SymTab.TypeIndex;
- 3298                                               c1, c2: INTEGER;
- 3299                                               lo, hi: INTEGER;
- 3300                                               isMax: BOOLEAN;
- 3301                                               called, isHigh, sfx, isCh,
- 3302                                               isU, uok, isStr: BOOLEAN;
- 3303                                               ucp: INTEGER; astIsLit: BOOLEAN;
- 3304                                                astD: AST.Node;
- 3305                                                astCall: BOOLEAN;
- 3306                                                astNode, astNot: AST.Node;
- 3307                                                j: CARDINAL;
- 3308                                                astArg2: AST.Node;
- 3309                                                astBrace: AST.Node;
- 3310                                                astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN;
- 3311                                                isConvF: BOOLEAN; .)
- 3312      = (. astIsLit := FALSE; .)
- 3313      ( integer                           (. LexString(s);
- 3314                                             QbeGen.NormInt(s, q); astIsLit := TRUE; astCur := AST.MakeLeaf(AST.NkIntLit, s);
- 3315                                             t := SymTab.IntType(); .)
- 3316      | charConst                         (. LexString(s);
- 3317                                             QbeGen.NormLit(s, q, isCh);
- 3318                                             astIsLit := TRUE;
- 3319                                             astCur := AST.MakeLeaf(
- 3320                                               AST.NkCharLit, s);
- 3321                                             t := SymTab.CharType(); .)
- 3322      | real                              (. LexString(s);
- 3323                                             QbeGen.NormReal(s, q);
- 3324                                             astIsLit := TRUE;
- 3325                                             astCur := AST.MakeLeaf(
- 3326                                               AST.NkRealLit, s);
- 3327                                             t := SymTab.RealType(); .)
- 3328      | string                            (. LexString(s);
- 3329                                             astIsLit := TRUE;
- 3330                                             astCur := AST.MakeLeaf(
- 3331                                               AST.NkStrLit, s);
- 3332                                             IF SymTab.StrLen(s) = 3 THEN
- 3333                                               t := SymTab.CharType();
- 3334                                               QbeGen.IntStr(
- 3335                                                 QbeGen.CharVal(s), q)
- 3336                                             ELSE t := SymTab.NewStr();
- 3337                                               QbeGen.DeclStr(s, q);
- 3338                                               (* a literal's value IS its
- 3339                                                  static descriptor address *)
- 3340                                             END; .)
- 3341      | ustring                           (. LexString(s);
- 3342                                             astIsLit := TRUE;
- 3343                                             astCur := AST.MakeLeaf(
- 3344                                               AST.NkStrLit, s);
- 3345                                             QbeGen.DeclUStr(s, q, isU, ucp,
- 3346                                               uok);
- 3347                                             IF NOT uok THEN
- 3348                                               SemError(234);
- 3349                                               t := SymTab.InvalidType
- 3350                                             ELSIF isU THEN
- 3351                                               t := SymTab.UCharType();
- 3352                                               QbeGen.IntStr(ucp, q)
- 3353                                             ELSE
- 3354                                               t := SymTab.NewUStr();
- 3355                                             END; .)
- 3356      | Design<dt, dk, qd, qn, sfx>       (. astD := astCur; astCall := FALSE; astBrace := AST.NoNode;
- 3357                                             astNArgs := 0; called := FALSE;
- 3358                                             t := dt;
- 3359                                             IF dk = SymTab.KindConst THEN
- 3360                                               QbeGen.CopyOp(qd, q)
- 3361                                             ELSE QbeGen.CopyOp("@", q)
- 3362                                             END; .)
- 3363        [ TypedBraceLit<dt, q>            (. t := dt; astCall := TRUE;
- 3364                                               astBrace := astCur; .) ]
- 3365        [ ArgList<qn, dt, qd, TRUE, FALSE, methCls, ct2, q2, called>
- 3366                                          (. astCall := TRUE;
- 3367                                             IF (SymTab.SymKind(qn) = SymTab.KindType)
- 3368    OR (SymTab.SymKind(qn) = SymTab.KindPredef) THEN
- 3369                                             (* T(x): emit as the VAL builtin so Lower's
- 3370                                                conversion rules apply unchanged *)
- 3371                                             astNode := AST.MakeNode(AST.NkCall);
- 3372                                             AST.SetChild(astNode, 0,
- 3373                                               AST.MakeLeaf(AST.NkIdent, "VAL"));
- 3374                                             AST.SetChild(astNode, 1,
- 3375                                               AST.MakeLeaf(AST.NkIdent, qn));
- 3376                                             IF astNArgs = 1 THEN
- 3377                                               AST.SetChild(astNode, 2, astArgs[0])
- 3378                                             END;
- 3379                                             isConvF := TRUE
- 3380                                             ELSE astNode := AstCallNode(astD)
- 3381                                             END;
- 3382                                             astRes := astNode;
- 3383                                             t := ct2;
- 3384                                             QbeGen.CopyOp(q2, q);
- 3385                                             IF isConvF AND QbeGen.IsImm(convQ)
- 3386                                                AND OrdClass(convT) AND OrdClass(ct2) THEN
- 3387                                               QbeGen.CopyOp(convQ, q)
- 3388                                             END;
- 3389                                             sfx := FALSE; .)
- 3390          { ResultComp<t, q, sfx, astRes, mname, methCls, isM>
- 3391            [ (. astNArgs := 0; .)
- 3392              ArgList<mname, t, q, TRUE, FALSE, methCls, ct2, q2, called>
- 3393                                          (. astNode := AstCallNode(astRes);
- 3394                                             astRes := astNode;
- 3395                                             t := ct2;
- 3396                                             QbeGen.CopyOp(q2, q);
- 3397                                             sfx := FALSE; .) ] }
- 3398                                          (. IF sfx THEN
- 3399                                               IF t = SymTab.InvalidType THEN
- 3400                                                 QbeGen.CopyOp("0", q)
- 3401                                               ELSIF (SymTab.ClassOf(t) #
- 3402                                                      SymTab.ClRecord)
- 3403    AND (SymTab.ClassOf(t) # SymTab.ClSet)
- 3404    AND (SymTab.ClassOf(t) # SymTab.ClArray)
- 3405    AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN
- 3406                                                  QbeGen.CopyOp("@", q)
- 3407                                               END
- 3408                                             END; .) ]
- 3409                                          (. IF called THEN
- 3410                                               astCur := astRes
- 3411                                             ELSIF astCall THEN
- 3412                                               astCur := astBrace
- 3413                                             ELSE astCur := astD
- 3414                                             END;
- 3415                                              astIsLit := TRUE;
- 3416                                              IF NOT called
- 3417   AND (dk = SymTab.KindProc) THEN
- 3418                                               (* bare zero-arg function
- 3419                                                  call (parentheses may be
- 3420                                                  omitted); a proper or
- 3421                                                  parameterised proc here
- 3422                                                  is 230 *)
- 3423                                                IF (SymTab.ProcNPar(qn) = 0)
- 3424   AND (SymTab.ProcRes(qn) # SymTab.InvalidType) THEN
- 3425                                                  t := SymTab.ProcRes(qn);
- 3426                                                  QbeGen.CopyOp("@", q);
- 3427                                                  astCur := AST.MakeNode(AST.NkCall);
- 3428                                                  AST.SetChild(astCur, 0, astD)
- 3429                                                ELSE
- 3430                                                  t := SymTab.ProcTypeOf(qn);
- 3431                                                  QbeGen.CopyOp("@", q)
- 3432                                                END
- 3433                                             END; .)
- 3434      | ( "HIGH"                          (. isHigh := TRUE; .)
- 3435        | ( "LEN" | "LENGTH" )            (. isHigh := FALSE; .) )
- 3436        "(" ( Design<dt, dk, qd, qn, sfx> (. isStr := FALSE;
- 3437                                              isU := FALSE; .)
- 3438            | string                       (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s);
- 3439                                              isStr := TRUE;
- 3440                                              isU := FALSE;
- 3441                                              IF SymTab.StrLen(s) = 3 THEN
- 3442                                                dt := SymTab.CharType();
- 3443                                                QbeGen.IntStr(QbeGen.CharVal(s),
- 3444                                                  qd)
- 3445                                              ELSE
- 3446                                                dt := SymTab.NewStr();
- 3447                                                QbeGen.DeclStr(s, qd);
- 3448                                              END;
- 3449                                              dk := -1;
- 3450                                              qn[0] := CHR(0); .)
- 3451            | ustring                      (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s);
- 3452                                              QbeGen.DeclUStr(s, qd, isU, ucp,
- 3453                                                uok);
- 3454                                              isStr := FALSE;
- 3455                                              IF NOT uok THEN
- 3456                                                SemError(234);
- 3457                                                dt := SymTab.InvalidType
- 3458                                              ELSIF isU THEN
- 3459                                                (* one codepoint: a UCHAR;
- 3460                                                   LEN is 1, HIGH is 0 *)
- 3461                                                dt := SymTab.UCharType();
- 3462                                                QbeGen.IntStr(ucp, qd)
- 3463                                              ELSE
- 3464                                                dt := SymTab.NewUStr();
- 3465                                              END;
- 3466                                              dk := -1;
- 3467                                              qn[0] := CHR(0); .) )
- 3468        ")"
- 3469                                          (. astNode := AST.MakeNode(AST.NkCall);
- 3470     IF isHigh THEN AST.SetChild(astNode, 0,
- 3471       AST.MakeLeaf(AST.NkIdent, "HIGH"))
- 3472     ELSE AST.SetChild(astNode, 0,
- 3473       AST.MakeLeaf(AST.NkIdent, "LEN")) END;
- 3474     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3475     astCur := astNode; astIsLit := TRUE;
- 3476                                             IF (dt # SymTab.InvalidType)
- 3477    AND (SymTab.ClassOf(dt) = SymTab.ClUStr) THEN
- 3478                                               (* UString: the count is
- 3479                                                  the descriptor header *)
- 3480                                                t := SymTab.IntType();
- 3481                                                QbeGen.CopyOp("@", q)
- 3482                                             ELSIF (dt # SymTab.InvalidType)
- 3483    AND (SymTab.ClassOf(dt) = SymTab.ClUChar) THEN
- 3484                                               (* single UCHAR codepoint *)
- 3485                                               IF isHigh THEN
- 3486                                                 QbeGen.CopyOp("0", qr)
- 3487                                               ELSE
- 3488                                                 QbeGen.CopyOp("1", qr)
- 3489                                               END;
- 3490                                               t := SymTab.IntType();
- 3491                                               QbeGen.CopyOp(qr, q)
- 3492                                             ELSIF isStr THEN
- 3493                                               (* fold: content length at
- 3494                                                  compile time *)
- 3495                                               IF SymTab.StrLen(s) = 3 THEN
- 3496                                                 c1 := 1
- 3497                                               ELSE
- 3498                                                 c1 :=
- 3499                                                   SymTab.StrLen(s) - 2
- 3500                                               END;
- 3501                                               IF isHigh THEN
- 3502                                                 DEC(c1)
- 3503                                               END;
- 3504                                               QbeGen.IntStr(c1, qr);
- 3505                                               t := SymTab.IntType();
- 3506                                               QbeGen.CopyOp(qr, q)
- 3507                                             ELSIF dt = SymTab.InvalidType THEN
- 3508                                               t := SymTab.InvalidType;
- 3509                                               QbeGen.CopyOp("0", q)
- 3510                                             ELSIF SymTab.ClassOf(dt) #
- 3511                                                   SymTab.ClArray THEN
- 3512                                               SemError(217);
- 3513                                               t := SymTab.InvalidType;
- 3514                                               QbeGen.CopyOp("0", q)
- 3515                                             ELSE
- 3516                                                IF SymTab.IsOpenArray(dt) THEN
- 3517                                                  t := SymTab.IntType();
- 3518                                                  QbeGen.CopyOp("@", q)
- 3519                                                ELSE
- 3520                                                  IF isHigh THEN
- 3521                                                    QbeGen.IntStr(
- 3522                                                      SymTab.ArrayHi(dt), qr)
- 3523                                                  ELSE
- 3524                                                    QbeGen.IntStr(VAL(
- 3525                                                      INTEGER,
- 3526                                                      SymTab.ArrayLen(dt)),
- 3527                                                      qr)
- 3528                                                  END;
- 3529                                                  t := SymTab.IntType();
- 3530                                                  QbeGen.CopyOp(qr, q)
- 3531                                                END
- 3532                                              END; .)
- 3533      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
- 3534      (. astNode := AST.MakeNode(AST.NkCall);
- 3535     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "SIZE"));
- 3536     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3537     astCur := astNode; astIsLit := TRUE; .)
- 3538                                          (. IF dt = SymTab.InvalidType THEN
- 3539                                               t := SymTab.InvalidType;
- 3540                                               QbeGen.CopyOp("0", q)
- 3541                                             ELSE
- 3542                                               QbeGen.IntStr(VAL(INTEGER,
- 3543                                                 SymTab.ObjectSize(dt)), q);
- 3544                                               t := SymTab.IntType()
- 3545                                             END; .)
- 3546      | ( "SHIFT"                         (. isMax := FALSE; .)
- 3547        | "ROTATE"                        (. isMax := TRUE; .) )
- 3548        "(" Expr<et, q> (. astArg2 := astCur; .) "," Expr<et2, q2> ")"
- 3549                                          (. astNode := AST.MakeNode(AST.NkCall);
- 3550     IF isMax THEN AST.SetChild(astNode, 0,
- 3551       AST.MakeLeaf(AST.NkIdent, "ROTATE"))
- 3552     ELSE AST.SetChild(astNode, 0,
- 3553       AST.MakeLeaf(AST.NkIdent, "SHIFT")) END;
- 3554     IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END;
- 3555     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
- 3556     astCur := astNode; astIsLit := TRUE;
- 3557                                             (* set shift/rotate: isMax
- 3558                                                doubles as "rotate" *)
- 3559                                             IF (et # SymTab.InvalidType)
- 3560                                                AND (SymTab.ClassOf(et) =
- 3561                                                   SymTab.ClSet) THEN
- 3562                                                t := et;
- 3563                                                QbeGen.CopyOp("@", q)
- 3564                                             ELSE SemError(230);
- 3565                                               t := SymTab.InvalidType;
- 3566                                               QbeGen.CopyOp("0", q)
- 3567                                             END; .)
- 3568      | ( "MIN"                           (. isMax := FALSE; .)
- 3569        | "MAX"                           (. isMax := TRUE; .) )
- 3570        "(" Design<dt, dk, qd, qn, sfx> ")"
- 3571                                          (. astNode := AST.MakeNode(AST.NkCall);
- 3572     IF isMax THEN AST.SetChild(astNode, 0,
- 3573       AST.MakeLeaf(AST.NkIdent, "MAX"))
- 3574     ELSE AST.SetChild(astNode, 0,
- 3575       AST.MakeLeaf(AST.NkIdent, "MIN")) END;
- 3576     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3577     astCur := astNode; astIsLit := TRUE;
- 3578                                             IF (dt # SymTab.InvalidType)
- 3579   AND (SymTab.ClassOf(dt) = SymTab.ClReal) THEN
- 3580                                               (* REAL/LONGREAL: the
- 3581                                                  implementation bounds *)
- 3582                                               IF isMax THEN
- 3583                                                 QbeGen.NormReal(
- 3584                                                   "3.402823e38", q)
- 3585                                               ELSE QbeGen.NormReal(
- 3586                                                   "-3.402823e38", q)
- 3587                                               END;
- 3588                                               t := SymTab.RealType()
- 3589                                             ELSIF (dt #
- 3590                                                SymTab.InvalidType)
- 3591   AND (SymTab.ClassOf(dt) =
- 3592                                                   SymTab.ClLong) THEN
- 3593                                               IF isMax THEN
- 3594                                                 QbeGen.CopyOp(
- 3595                                                   "9223372036854775807", q)
- 3596                                               ELSE QbeGen.CopyOp(
- 3597                                                   "-9223372036854775808", q)
- 3598                                               END;
- 3599                                               t := SymTab.LongType()
- 3600                                             ELSIF SymTab.TypeBounds(dt, lo,
- 3601                                                      hi) THEN
- 3602                                               IF isMax THEN
- 3603                                                 QbeGen.IntStr(hi, q)
- 3604                                               ELSE QbeGen.IntStr(lo, q)
- 3605                                               END;
- 3606                                               t := SymTab.IntType()
- 3607                                             ELSE SemError(230);
- 3608                                               t := SymTab.InvalidType;
- 3609                                               QbeGen.CopyOp("0", q)
- 3610                                             END; .)
- 3611      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
- 3612      (. astNode := AST.MakeNode(AST.NkCall);
- 3613     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ADR"));
- 3614     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3615     astCur := astNode; astIsLit := TRUE; .)
- 3616                                          (. IF dt = SymTab.InvalidType THEN
- 3617                                               t := SymTab.InvalidType;
- 3618                                               QbeGen.CopyOp("0", q)
- 3619                                             ELSE
- 3620                                                IF sfx
- 3621                                                   OR (dk = SymTab.KindVar)
- 3622                                                   OR (dk = SymTab.KindParam) THEN
- 3623                                                  QbeGen.CopyOp("@", q)
- 3624                                                ELSE SemError(230);
- 3625                                                  QbeGen.CopyOp("0", q)
- 3626                                                END;
- 3627                                               t := SymTab.AddrType()
- 3628                                             END; .)
- 3629      | "CHR" "(" Expr<et, q> ")"
- 3630      (. astNode := AST.MakeNode(AST.NkCall);
- 3631     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR"));
- 3632     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3633     astCur := astNode; astIsLit := TRUE; .)
- 3634                                          (. IF (et # SymTab.InvalidType)
- 3635   AND NOT SymTab.IsIntFamily(et) THEN
- 3636                                               SemError(211) END;
- 3637                                             t := SymTab.CharType(); .)
- 3638      | ( "ORD" | "ORDL" ) "(" Expr<et, q> ")"
- 3639      (. astNode := AST.MakeNode(AST.NkCall);
- 3640     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ORD"));
- 3641     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3642     astCur := astNode; astIsLit := TRUE; .)
- 3643                                          (. IF et # SymTab.InvalidType THEN
- 3644                                               IF (SymTab.ClassOf(et) #
- 3645                                                   SymTab.ClChar)
- 3646   AND (SymTab.ClassOf(et) #
- 3647                                                     SymTab.ClBool)
+ 2866                                                   SymTab.ClEnum)
+ 2867   AND (SymTab.ClassOf(it) #
+ 2868                                                   SymTab.ClBool) THEN
+ 2869                                               SemError(218);
+ 2870                                               t := SymTab.InvalidType
+ 2871                                              ELSE
+ 2872                                                eT := SymTab.ArrayElem(t);
+ 2873                                                t := eT; sfx := TRUE
+ 2874                                              END; .) }
+ 2875          "]"
+ 2876        | "." GetIdent<fn>
+ 2877                                          (. astSel := AST.MakeNode(AST.NkSelector);
+ 2878               AST.SetOp(astSel, AST.SelField);
+ 2879               AST.SetChild(astSel, 0, AST.MakeLeaf(AST.NkIdent, fn));
+ 2880               AST.SetChild(astDes, AST.NChild(astDes), astSel); IF k = SymTab.KindModule THEN
+ 2881                                               (* qualified L.x: materialize
+ 2882                                                  the export, then load it *)
+ 2883                                               IF NOT SymTab.MaterializeAlias(n,
+ 2884                                                    fn, mal) THEN
+ 2885                                                 SemError(201);
+ 2886                                                 t := SymTab.InvalidType;
+ 2887                                                 QbeGen.CopyOp("0", q)
+ 2888                                               ELSE
+ 2889                                                 QbeGen.CopyOp(mal, qn);
+ 2890                                                 t := SymTab.SymType(mal);
+ 2891                                                 k := SymTab.SymKind(mal);
+ 2892                                                 sfx := FALSE;
+ 2893                                                 IF k = SymTab.KindProc THEN
+ 2894                                                   (* call: ArgList supplies
+ 2895                                                      the value *)
+ 2896                                                   QbeGen.CopyOp("0", q)
+ 2897                                                  END
+ 2898                                               END
+ 2899                                             ELSIF t = SymTab.InvalidType THEN
+ 2900                                             ELSIF (SymTab.ClassOf(t) #
+ 2901                                                    SymTab.ClRecord)
+ 2902   AND (SymTab.ClassOf(t) #
+ 2903                                                   SymTab.ClClass) THEN
+ 2904                                               SemError(215);
+ 2905                                               t := SymTab.InvalidType
+ 2906                                             ELSIF (SymTab.ClassOf(t) =
+ 2907                                                    SymTab.ClClass)
+ 2908    AND SymTab.MethodExists(t, fn) THEN
+ 2909                                               (* obj.Method: bind the
+ 2910                                                  method and pass obj as
+ 2911                                                  the hidden receiver; q
+ 2912                                                  already holds the
+ 2913                                                  object's address *)
+ 2914                                               QbeGen.CopyOp(fn, n);
+ 2915                                               QbeGen.CopyOp(fn, qn);
+ 2916                                               methCls := t;
+ 2917                                               k := SymTab.KindProc;
+ 2918                                               t := SymTab.InvalidType
+ 2919                                             ELSIF NOT SymTab.FieldExists(t,
+ 2920                                                      fn) THEN
+ 2921                                               SemError(216);
+ 2922                                               t := SymTab.InvalidType
+ 2923                                              ELSE
+ 2924                                                t := SymTab.FieldType(t, fn);
+ 2925                                                sfx := TRUE
+ 2926                                              END; .)
+ 2927        | "^"
+ 2928                                          (. astSel := AST.MakeNode(AST.NkSelector);
+ 2929               AST.SetOp(astSel, AST.SelDeref);
+ 2930               AST.SetChild(astDes, AST.NChild(astDes), astSel); IF t = SymTab.InvalidType THEN
+ 2931                                             ELSIF SymTab.ClassOf(t) #
+ 2932                                                   SymTab.ClPtr THEN
+ 2933                                               SemError(219);
+ 2934                                               t := SymTab.InvalidType
+ 2935                                             ELSE
+ 2936                                               bt := SymTab.PtrBase(t);
+ 2937                                               IF bt = SymTab.InvalidType THEN
+ 2938                                               ELSE
+ 2939                                                  t := bt;
+ 2940                                                  sfx := TRUE
+ 2941                                                END
+ 2942                                             END; .) } (. astCur := astDes; .) .
+ 2943    (* Result suffix (ISO component after a function call): `F()^`,
+ 2944       `F()[i]`, `F().field`.  The call result is in t/q with sfx FALSE
+ 2945       (a value, or a descriptor address for aggregates); each component
+ 2946       descends one level exactly like the Design components. *)
+ 2947    ResultComp<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
+ 2948               VAR sfx: BOOLEAN; VAR node: AST.Node;
+ 2949               VAR mname: SymTab.Name; VAR methCls: SymTab.TypeIndex;
+ 2950               VAR isM: BOOLEAN>          (. VAR it, eT, bt: SymTab.TypeIndex;
+ 2951                                               iq, ql, qlo, qhi, qe, qb:
+ 2952                                                 QbeGen.QVal;
+ 2953                                               lo, hi, fo: INTEGER;
+ 2954                                               isOpen: BOOLEAN;
+ 2955                                               fname: SymTab.Name;
+ 2956                                               astWrap, astSel: AST.Node; .)
+ 2957      = "[" Expr<it, iq>
+ 2958                                          (. isM := FALSE;
+ 2959                                             IF AST.Kind(node) # AST.NkDesignator THEN
+ 2960                                               astWrap := AST.MakeNode(
+ 2961                                                 AST.NkDesignator);
+ 2962                                               AST.SetChild(astWrap, 0, node);
+ 2963                                               node := astWrap
+ 2964                                             END;
+ 2965                                             AST.SetChild(node, AST.NChild(node),
+ 2966                                               AST.MakeUn(AST.NkSelector,
+ 2967                                                 AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
+ 2968                                             ELSIF SymTab.ClassOf(t) #
+ 2969                                                   SymTab.ClArray THEN
+ 2970                                               SemError(217);
+ 2971                                               t := SymTab.InvalidType
+ 2972                                             ELSIF NOT SymTab.IsIntFamily(it)
+ 2973    AND (SymTab.ClassOf(it) # SymTab.ClChar)
+ 2974    AND (SymTab.ClassOf(it) # SymTab.ClEnum)
+ 2975    AND (SymTab.ClassOf(it) # SymTab.ClBool) THEN
+ 2976                                               SemError(218);
+ 2977                                               t := SymTab.InvalidType
+ 2978                                              ELSE
+ 2979                                                eT := SymTab.ArrayElem(t);
+ 2980                                                t := eT; sfx := TRUE
+ 2981                                              END; .)
+ 2982        "]"
+ 2983      | "." GetIdent<fname>
+ 2984                                          (. isM := FALSE;
+ 2985                                             IF AST.Kind(node) # AST.NkDesignator THEN
+ 2986                                               astWrap := AST.MakeNode(
+ 2987                                                 AST.NkDesignator);
+ 2988                                               AST.SetChild(astWrap, 0, node);
+ 2989                                               node := astWrap
+ 2990                                             END;
+ 2991                                             AST.SetChild(node, AST.NChild(node),
+ 2992                                               AST.MakeUn(AST.NkSelector,
+ 2993                                                 AST.SelField,
+ 2994                                                 AST.MakeLeaf(AST.NkIdent,
+ 2995                                                   fname))); IF t = SymTab.InvalidType THEN
+ 2996                                             ELSIF (SymTab.ClassOf(t) #
+ 2997                                                    SymTab.ClRecord)
+ 2998    AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN
+ 2999                                               SemError(215);
+ 3000                                               t := SymTab.InvalidType
+ 3001                                              ELSIF (SymTab.ClassOf(t) =
+ 3002                                                     SymTab.ClClass)
+ 3003    AND SymTab.MethodExists(t, fname) THEN
+ 3004                                                (* a method on the call result:
+ 3005                                                   a following ArgList makes
+ 3006                                                   the call *)
+ 3007                                                mname := fname;
+ 3008                                                methCls := t; isM := TRUE;
+ 3009                                                t := SymTab.InvalidType
+ 3010                                             ELSIF NOT SymTab.FieldExists(t,
+ 3011                                                      fname) THEN
+ 3012                                               SemError(216);
+ 3013                                               t := SymTab.InvalidType
+ 3014                                              ELSE
+ 3015                                                t := SymTab.FieldType(t, fname);
+ 3016                                                sfx := TRUE
+ 3017                                              END; .)
+ 3018      | "^"                               (. isM := FALSE;
+ 3019                                             IF AST.Kind(node) # AST.NkDesignator THEN
+ 3020                                               astWrap := AST.MakeNode(
+ 3021                                                 AST.NkDesignator);
+ 3022                                               AST.SetChild(astWrap, 0, node);
+ 3023                                               node := astWrap
+ 3024                                             END;
+ 3025                                             astSel := AST.MakeNode(AST.NkSelector);
+ 3026                                             AST.SetOp(astSel, AST.SelDeref);
+ 3027                                             AST.SetChild(node,
+ 3028                                               AST.NChild(node), astSel); IF t = SymTab.InvalidType THEN
+ 3029                                             ELSIF SymTab.ClassOf(t) #
+ 3030                                                   SymTab.ClPtr THEN
+ 3031                                               SemError(219);
+ 3032                                               t := SymTab.InvalidType
+ 3033                                             ELSE
+ 3034                                               bt := SymTab.PtrBase(t);
+ 3035                                               IF bt # SymTab.InvalidType THEN
+ 3036                                                  t := bt; sfx := TRUE
+ 3037                                               END
+ 3038                                             END; .) .
+ 3039    Expr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 3040                                          (. VAR t2: SymTab.TypeIndex;
+ 3041                                               op: INTEGER;
+ 3042                                               q2, qt, wl: QbeGen.QVal;
+ 3043                                                astA, astB: AST.Node;
+ 3044                                                astOp: INTEGER;
+ 3045                                                astMade: BOOLEAN;
+ 3046                                               isR: BOOLEAN; .)
+ 3047      = SimExpr<t, q>                     (. astA := astCur; astMade := FALSE; .)
+ 3048        [ Rel<op> SimExpr<t2, q2>
+ 3049          (. astB := astCur; astMade := TRUE;
+ 3050              astOp := AST.OpEq;
+ 3051              IF op = SymTab.OpNeq1 THEN astOp := AST.OpNe
+ 3052              ELSIF op = SymTab.OpNeq2 THEN astOp := AST.OpNe
+ 3053              ELSIF op = SymTab.OpLt THEN astOp := AST.OpLt
+ 3054              ELSIF op = SymTab.OpLe THEN astOp := AST.OpLe
+ 3055              ELSIF op = SymTab.OpGt THEN astOp := AST.OpGt
+ 3056              ELSIF op = SymTab.OpGe THEN astOp := AST.OpGe
+ 3057              ELSIF op = SymTab.OpIn THEN astOp := AST.OpIn
+ 3058              END;
+ 3059              IF op = SymTab.OpIn THEN
+ 3060               IF SymTab.InCheck(t, t2) THEN
+ 3061                 IF (t = SymTab.InvalidType)
+ 3062                    OR (t2 = SymTab.InvalidType) THEN
+ 3063                   t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
+ 3064                 ELSE
+ 3065                    t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
+ 3066                 END
+ 3067               ELSE SemError(222); t := SymTab.InvalidType;
+ 3068                 QbeGen.CopyOp("0", q)
+ 3069               END
+ 3070             ELSIF SymTab.RelCheck(t, t2, op) THEN
+ 3071               IF (t = SymTab.InvalidType)
+ 3072                  OR (t2 = SymTab.InvalidType) THEN
+ 3073                 t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
+ 3074               ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
+ 3075                  OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN
+ 3076                 IF (op # SymTab.OpEq) AND (op # SymTab.OpNeq1)
+ 3077   AND (op # SymTab.OpNeq2) THEN
+ 3078                   SemError(213); t := SymTab.InvalidType;
+ 3079                   QbeGen.CopyOp("0", q)
+ 3080                  ELSE
+ 3081                    t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
+ 3082                  END
+ 3083                ELSIF (SymTab.ClassOf(t) = SymTab.ClSet)
+ 3084                   OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 3085                  t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
+ 3086               ELSIF SymTab.StrCompat(t, t2) THEN
+ 3087                 QbeGen.StrEq(op, q, q2, qt);
+ 3088                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
+ 3089               ELSIF SymTab.IsLongFamily(t)
+ 3090                  OR SymTab.IsLongFamily(t2) THEN
+ 3091                  t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
+ 3092                ELSE
+ 3093                  t := SymTab.BoolType();
+ 3094                  QbeGen.CopyOp("@", q)
+ 3095                END
+ 3096             ELSE SemError(213); t := SymTab.InvalidType;
+ 3097                QbeGen.CopyOp("0", q)
+ 3098              END;
+ 3099              astCur := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB); .) ]
+ 3100         (. IF NOT astMade THEN astCur := astA END; .)
+ 3101             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
+ 3102    Rel<VAR op: INTEGER>
+ 3103      = "="                               (. op := SymTab.OpEq; .)
+ 3104      | "#"                               (. op := SymTab.OpNeq1; .)
+ 3105      | "<"                               (. op := SymTab.OpLt; .)
+ 3106      | "<="                              (. op := SymTab.OpLe; .)
+ 3107      | ">"                               (. op := SymTab.OpGt; .)
+ 3108      | ">="                              (. op := SymTab.OpGe; .)
+ 3109      | "IN"                              (. op := SymTab.OpIn; .) .
+ 3110    SimExpr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 3111                                          (. VAR t2, res2, lt, rt:
+ 3112                                                 SymTab.TypeIndex;
+ 3113                                               op: INTEGER;
+ 3114                                               q2, qt, wq, qf, q2a, q2b:
+ 3115                                                 QbeGen.QVal;
+ 3116                                               neg, isR, isL, folded:
+ 3117                                                 BOOLEAN;
+ 3118                                               fok: BOOLEAN;
+ 3119                                               lw, rw, mw: CARDINAL;
+ 3120                                               lTrue, lNext, lDone, qr, qs: QbeGen.QVal;
+ 3121                                                astA, astB: AST.Node;
+ 3122                                                astSign, astOp: INTEGER; .)
+ 3123      =                                   (. neg := FALSE; astSign := 0; .)
+ 3124        [ "+"                         (. neg := TRUE; astSign := 1; .)
+ 3125        | "-"                         (. neg := TRUE; astSign := -1; .) ]
+ 3126        Term<t, q> (. astA := astCur;
+ 3127                                            IF neg AND QbeGen.IsImm(q) THEN
+ 3128                                              QbeGen.NegFold(q, q)
+ 3129                                            END;
+ 3130                                           IF astSign < 0 THEN
+ 3131                                             astCur := AST.MakeUn(
+ 3132                                               AST.NkUnary, AST.OpSub, astA);
+ 3133                                             astA := astCur
+ 3134                                           END; .)
+ 3135         { AddOp<op>
+ 3136           Term<t2, q2> (. astB := astCur; .)
+ 3137          (. astOp := AST.OpAdd;
+ 3138             IF op = SymTab.OpSub THEN astOp := AST.OpSub
+ 3139             ELSIF op = SymTab.OpOr THEN astOp := AST.OpOr END;
+ 3140             astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB);
+ 3141             astCur := astA;
+ 3142             IF op = SymTab.OpOr THEN
+ 3143               (* short-circuit: if q is true the RHS is skipped *)
+ 3144               IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
+ 3145                 t := SymTab.BoolType()
+ 3146               ELSE SemError(212); t := SymTab.InvalidType END;
+ 3147                IF t # SymTab.InvalidType THEN
+ 3148                  QbeGen.CopyOp("@", q)
+ 3149                ELSE QbeGen.CopyOp("0", q)
+ 3150                END
+ 3151             ELSIF (op = SymTab.OpAdd)
+ 3152               AND (SymTab.UStrCompat(t, t2)
+ 3153                 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
+ 3154                   AND (SymTab.ClassOf(t2) = SymTab.ClUStr))
+ 3155                 OR ((SymTab.ClassOf(t) = SymTab.ClUStr)
+ 3156                   AND (SymTab.ClassOf(t2) = SymTab.ClUChar))
+ 3157                 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
+ 3158                   AND (SymTab.ClassOf(t2) = SymTab.ClUChar))) THEN
+ 3159               (* UString concatenation: a UCHAR operand becomes a
+ 3160                  1-codepoint UString; the result is a descriptor in the
+ 3161                  shim's concat buffer.  Work on copies so neither
+ 3162                  operand is clobbered. *)
+ 3163                t := SymTab.NewUStr();
+ 3164                QbeGen.CopyOp("@", q)
+ 3165             ELSIF (op = SymTab.OpAdd)
+ 3166               AND (SymTab.StrCompat(t, t2)
+ 3167                 OR (SymTab.IsStrType(t)
+ 3168                   AND (SymTab.ClassOf(t2) = SymTab.ClChar))
+ 3169                 OR ((SymTab.ClassOf(t) = SymTab.ClChar)
+ 3170                   AND SymTab.IsStrType(t2))) THEN
+ 3171               (* string concatenation; a CHAR operand becomes a
+ 3172                  1-character string literal.  When both operands are
+ 3173                  constants, fold to a single string literal so a
+ 3174                  constructor element stays compile-time. *)
+ 3175                QbeGen.StrFold(q, q2, SymTab.ClassOf(t), SymTab.ClassOf(t2),
+ 3176                  qt, fok);
+ 3177                IF fok THEN QbeGen.CopyOp(qt, q)
+ 3178                ELSE QbeGen.CopyOp("@", q)
+ 3179                END;
+ 3180                t := SymTab.NewStr()
+ 3181             ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
+ 3182   AND (SymTab.ClassOf(t) = SymTab.ClSet)
+ 3183   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 3184                lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
+ 3185                mw := lw;
+ 3186                IF rw > mw THEN mw := rw END;
+ 3187                t := SymTab.NewSet(
+ 3188                       SymTab.NewSubR(0,
+ 3189                         VAL(INTEGER, mw) * 32 - 1));
+ 3190                QbeGen.CopyOp("@", q)
+ 3191             ELSE
+ 3192               IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
+ 3193                 lt := t; rt := t2; t := res2
+ 3194               ELSE SemError(211); t := SymTab.InvalidType END;
+ 3195               IF t # SymTab.InvalidType THEN
+ 3196                 isL := SymTab.IsLongFamily(t);
+ 3197                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 3198                 folded := FALSE;
+ 3199                 IF (NOT isL) AND (NOT isR)
+ 3200    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
+ 3201                   IF op = SymTab.OpAdd THEN
+ 3202                     folded := QbeGen.Fold2(0, q, q2, qf)
+ 3203                   ELSE
+ 3204                     folded := QbeGen.Fold2(1, q, q2, qf)
+ 3205                   END
+ 3206                 END;
+ 3207                 IF folded THEN QbeGen.CopyOp(qf, q)
+ 3208                  ELSE
+ 3209                  QbeGen.CopyOp("@", q)
+ 3210                  END
+ 3211               ELSE QbeGen.CopyOp("0", q)
+ 3212               END
+ 3213             END; .) }
+ 3214             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
+ 3215    AddOp<VAR op: INTEGER>
+ 3216      = "+"                               (. op := SymTab.OpAdd; .)
+ 3217      | "-"                               (. op := SymTab.OpSub; .)
+ 3218      | "OR"                              (. op := SymTab.OpOr; .) .
+ 3219    Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 3220                                          (. VAR t2, res2, lt, rt:
+ 3221                                                 SymTab.TypeIndex;
+ 3222                                               op: INTEGER;
+ 3223                                               q2, qt, wq, qf:
+ 3224                                                 QbeGen.QVal;
+ 3225                                               isR, isL, folded: BOOLEAN;
+ 3226                                               lw, rw, mw: CARDINAL;
+ 3227                                               lNext, lFalse, lDone, qr, qs: QbeGen.QVal;
+ 3228                                                astA, astB: AST.Node;
+ 3229                                                astOp: INTEGER; .)
+ 3230      = Fact<t, q> (. astA := astCur; .) { MulOp<op>
+ 3231          Fact<t2, q2> (. astB := astCur; .)
+ 3232        (. astOp := AST.OpMul;
+ 3233           IF op = SymTab.OpSlash THEN astOp := AST.OpDiv
+ 3234           ELSIF op = SymTab.OpDiv THEN astOp := AST.OpDiv
+ 3235           ELSIF op = SymTab.OpMod THEN astOp := AST.OpMod
+ 3236           ELSIF op = SymTab.OpAnd THEN astOp := AST.OpAnd END;
+ 3237           astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB);
+ 3238           astCur := astA;
+ 3239           IF op = SymTab.OpAnd THEN
+ 3240             (* short-circuit: if q is false the RHS is skipped *)
+ 3241             IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
+ 3242               t := SymTab.BoolType()
+ 3243             ELSE SemError(212); t := SymTab.InvalidType END;
+ 3244              IF t # SymTab.InvalidType THEN QbeGen.CopyOp("@", q)
+ 3245              ELSE QbeGen.CopyOp("0", q)
+ 3246              END
+ 3247           ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
+ 3248   AND (SymTab.ClassOf(t) = SymTab.ClSet)
+ 3249   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 3250              lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
+ 3251              mw := lw;
+ 3252              IF rw > mw THEN mw := rw END;
+ 3253              t := SymTab.NewSet(
+ 3254                     SymTab.NewSubR(0,
+ 3255                       VAL(INTEGER, mw) * 32 - 1));
+ 3256              QbeGen.CopyOp("@", q)
+ 3257           ELSE
+ 3258             IF SymTab.ArithCheck(t, t2,
+ 3259                  (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
+ 3260                  res2) THEN
+ 3261               lt := t; rt := t2; t := res2
+ 3262             ELSE SemError(211); t := SymTab.InvalidType END;
+ 3263             IF t # SymTab.InvalidType THEN
+ 3264               isL := SymTab.IsLongFamily(t);
+ 3265               isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 3266               folded := FALSE;
+ 3267               IF (NOT isL) AND (NOT isR)
+ 3268    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
+ 3269                 IF op = SymTab.OpTimes THEN
+ 3270                   folded := QbeGen.Fold2(2, q, q2, qf)
+ 3271                 ELSIF op = SymTab.OpDiv THEN
+ 3272                   folded := QbeGen.Fold2(3, q, q2, qf)
+ 3273                 ELSIF op = SymTab.OpMod THEN
+ 3274                   folded := QbeGen.Fold2(4, q, q2, qf)
+ 3275                 END
+ 3276               END;
+ 3277               IF folded THEN QbeGen.CopyOp(qf, q)
+ 3278                ELSE
+ 3279                QbeGen.CopyOp("@", q)
+ 3280                END
+ 3281             ELSE QbeGen.CopyOp("0", q)
+ 3282             END
+ 3283           END; .) }
+ 3284             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
+ 3285    MulOp<VAR op: INTEGER>
+ 3286      = "*"                               (. op := SymTab.OpTimes; .)
+ 3287      | "/"                               (. op := SymTab.OpSlash; .)
+ 3288      | "DIV"                             (. op := SymTab.OpDiv; .)
+ 3289      | "MOD"                             (. op := SymTab.OpMod; .)
+ 3290      | ( "AND" | "&" )                   (. op := SymTab.OpAnd; .) .
+ 3291    Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 3292                                          (. VAR s: ARRAY [0 .. 255] OF CHAR;
+ 3293                                               et, dt, t2, st, ct2, et2:
+ 3294                                                 SymTab.TypeIndex;
+ 3295                                               dk: INTEGER;
+ 3296                                               qd, q2, sq, qa, qm0, qr, qt:
+ 3297                                                 QbeGen.QVal;
+ 3298                                               qn, vn: SymTab.Name;
+ 3299                                               vt: SymTab.TypeIndex;
+ 3300                                               c1, c2: INTEGER;
+ 3301                                               lo, hi: INTEGER;
+ 3302                                               isMax: BOOLEAN;
+ 3303                                               called, isHigh, sfx, isCh,
+ 3304                                               isU, uok, isStr: BOOLEAN;
+ 3305                                               ucp: INTEGER; astIsLit: BOOLEAN;
+ 3306                                                astD: AST.Node;
+ 3307                                                astCall: BOOLEAN;
+ 3308                                                astNode, astNot: AST.Node;
+ 3309                                                j: CARDINAL;
+ 3310                                                astArg2: AST.Node;
+ 3311                                                astBrace: AST.Node;
+ 3312                                                astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN;
+ 3313                                                isConvF: BOOLEAN; .)
+ 3314      = (. astIsLit := FALSE; .)
+ 3315      ( integer                           (. LexString(s);
+ 3316                                             QbeGen.NormInt(s, q); astIsLit := TRUE; astCur := AST.MakeLeaf(AST.NkIntLit, s);
+ 3317                                             t := SymTab.IntType(); .)
+ 3318      | charConst                         (. LexString(s);
+ 3319                                             QbeGen.NormLit(s, q, isCh);
+ 3320                                             astIsLit := TRUE;
+ 3321                                             astCur := AST.MakeLeaf(
+ 3322                                               AST.NkCharLit, s);
+ 3323                                             t := SymTab.CharType(); .)
+ 3324      | real                              (. LexString(s);
+ 3325                                             QbeGen.NormReal(s, q);
+ 3326                                             astIsLit := TRUE;
+ 3327                                             astCur := AST.MakeLeaf(
+ 3328                                               AST.NkRealLit, s);
+ 3329                                             t := SymTab.RealType(); .)
+ 3330      | string                            (. LexString(s);
+ 3331                                             astIsLit := TRUE;
+ 3332                                             astCur := AST.MakeLeaf(
+ 3333                                               AST.NkStrLit, s);
+ 3334                                             IF SymTab.StrLen(s) = 3 THEN
+ 3335                                               t := SymTab.CharType();
+ 3336                                               QbeGen.IntStr(
+ 3337                                                 QbeGen.CharVal(s), q)
+ 3338                                             ELSE t := SymTab.NewStr();
+ 3339                                               QbeGen.DeclStr(s, q);
+ 3340                                               (* a literal's value IS its
+ 3341                                                  static descriptor address *)
+ 3342                                             END; .)
+ 3343      | ustring                           (. LexString(s);
+ 3344                                             astIsLit := TRUE;
+ 3345                                             astCur := AST.MakeLeaf(
+ 3346                                               AST.NkStrLit, s);
+ 3347                                             QbeGen.DeclUStr(s, q, isU, ucp,
+ 3348                                               uok);
+ 3349                                             IF NOT uok THEN
+ 3350                                               SemError(234);
+ 3351                                               t := SymTab.InvalidType
+ 3352                                             ELSIF isU THEN
+ 3353                                               t := SymTab.UCharType();
+ 3354                                               QbeGen.IntStr(ucp, q)
+ 3355                                             ELSE
+ 3356                                               t := SymTab.NewUStr();
+ 3357                                             END; .)
+ 3358      | Design<dt, dk, qd, qn, sfx>       (. astD := astCur; astCall := FALSE; astBrace := AST.NoNode;
+ 3359                                             astNArgs := 0; called := FALSE;
+ 3360                                             t := dt;
+ 3361                                             IF dk = SymTab.KindConst THEN
+ 3362                                               QbeGen.CopyOp(qd, q)
+ 3363                                             ELSE QbeGen.CopyOp("@", q)
+ 3364                                             END; .)
+ 3365        [ TypedBraceLit<dt, q>            (. t := dt; astCall := TRUE;
+ 3366                                               astBrace := astCur; .) ]
+ 3367        [ ArgList<qn, dt, qd, TRUE, FALSE, methCls, ct2, q2, called>
+ 3368                                          (. astCall := TRUE;
+ 3369                                             IF (SymTab.SymKind(qn) = SymTab.KindType)
+ 3370    OR (SymTab.SymKind(qn) = SymTab.KindPredef) THEN
+ 3371                                             (* T(x): emit as the VAL builtin so Lower's
+ 3372                                                conversion rules apply unchanged *)
+ 3373                                             astNode := AST.MakeNode(AST.NkCall);
+ 3374                                             AST.SetChild(astNode, 0,
+ 3375                                               AST.MakeLeaf(AST.NkIdent, "VAL"));
+ 3376                                             AST.SetChild(astNode, 1,
+ 3377                                               AST.MakeLeaf(AST.NkIdent, qn));
+ 3378                                             IF astNArgs = 1 THEN
+ 3379                                               AST.SetChild(astNode, 2, astArgs[0])
+ 3380                                             END;
+ 3381                                             isConvF := TRUE
+ 3382                                             ELSE astNode := AstCallNode(astD)
+ 3383                                             END;
+ 3384                                             astRes := astNode;
+ 3385                                             t := ct2;
+ 3386                                             QbeGen.CopyOp(q2, q);
+ 3387                                             IF isConvF AND QbeGen.IsImm(convQ)
+ 3388                                                AND OrdClass(convT) AND OrdClass(ct2) THEN
+ 3389                                               QbeGen.CopyOp(convQ, q)
+ 3390                                             END;
+ 3391                                             sfx := FALSE; .)
+ 3392          { ResultComp<t, q, sfx, astRes, mname, methCls, isM>
+ 3393            [ (. astNArgs := 0; .)
+ 3394              ArgList<mname, t, q, TRUE, FALSE, methCls, ct2, q2, called>
+ 3395                                          (. astNode := AstCallNode(astRes);
+ 3396                                             astRes := astNode;
+ 3397                                             t := ct2;
+ 3398                                             QbeGen.CopyOp(q2, q);
+ 3399                                             sfx := FALSE; .) ] }
+ 3400                                          (. IF sfx THEN
+ 3401                                               IF t = SymTab.InvalidType THEN
+ 3402                                                 QbeGen.CopyOp("0", q)
+ 3403                                               ELSIF (SymTab.ClassOf(t) #
+ 3404                                                      SymTab.ClRecord)
+ 3405    AND (SymTab.ClassOf(t) # SymTab.ClSet)
+ 3406    AND (SymTab.ClassOf(t) # SymTab.ClArray)
+ 3407    AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN
+ 3408                                                  QbeGen.CopyOp("@", q)
+ 3409                                               END
+ 3410                                             END; .) ]
+ 3411                                          (. IF called THEN
+ 3412                                               astCur := astRes
+ 3413                                             ELSIF astCall THEN
+ 3414                                               astCur := astBrace
+ 3415                                             ELSE astCur := astD
+ 3416                                             END;
+ 3417                                              astIsLit := TRUE;
+ 3418                                              IF NOT called
+ 3419   AND (dk = SymTab.KindProc) THEN
+ 3420                                               (* bare zero-arg function
+ 3421                                                  call (parentheses may be
+ 3422                                                  omitted); a proper or
+ 3423                                                  parameterised proc here
+ 3424                                                  is 230 *)
+ 3425                                                IF (SymTab.ProcNPar(qn) = 0)
+ 3426   AND (SymTab.ProcRes(qn) # SymTab.InvalidType) THEN
+ 3427                                                  t := SymTab.ProcRes(qn);
+ 3428                                                  QbeGen.CopyOp("@", q);
+ 3429                                                  astCur := AST.MakeNode(AST.NkCall);
+ 3430                                                  AST.SetChild(astCur, 0, astD)
+ 3431                                                ELSE
+ 3432                                                  t := SymTab.ProcTypeOf(qn);
+ 3433                                                  QbeGen.CopyOp("@", q)
+ 3434                                                END
+ 3435                                             END; .)
+ 3436      | ( "HIGH"                          (. isHigh := TRUE; .)
+ 3437        | ( "LEN" | "LENGTH" )            (. isHigh := FALSE; .) )
+ 3438        "(" ( Design<dt, dk, qd, qn, sfx> (. isStr := FALSE;
+ 3439                                              isU := FALSE; .)
+ 3440            | string                       (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s);
+ 3441                                              isStr := TRUE;
+ 3442                                              isU := FALSE;
+ 3443                                              IF SymTab.StrLen(s) = 3 THEN
+ 3444                                                dt := SymTab.CharType();
+ 3445                                                QbeGen.IntStr(QbeGen.CharVal(s),
+ 3446                                                  qd)
+ 3447                                              ELSE
+ 3448                                                dt := SymTab.NewStr();
+ 3449                                                QbeGen.DeclStr(s, qd);
+ 3450                                              END;
+ 3451                                              dk := -1;
+ 3452                                              qn[0] := CHR(0); .)
+ 3453            | ustring                      (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s);
+ 3454                                              QbeGen.DeclUStr(s, qd, isU, ucp,
+ 3455                                                uok);
+ 3456                                              isStr := FALSE;
+ 3457                                              IF NOT uok THEN
+ 3458                                                SemError(234);
+ 3459                                                dt := SymTab.InvalidType
+ 3460                                              ELSIF isU THEN
+ 3461                                                (* one codepoint: a UCHAR;
+ 3462                                                   LEN is 1, HIGH is 0 *)
+ 3463                                                dt := SymTab.UCharType();
+ 3464                                                QbeGen.IntStr(ucp, qd)
+ 3465                                              ELSE
+ 3466                                                dt := SymTab.NewUStr();
+ 3467                                              END;
+ 3468                                              dk := -1;
+ 3469                                              qn[0] := CHR(0); .) )
+ 3470        ")"
+ 3471                                          (. astNode := AST.MakeNode(AST.NkCall);
+ 3472     IF isHigh THEN AST.SetChild(astNode, 0,
+ 3473       AST.MakeLeaf(AST.NkIdent, "HIGH"))
+ 3474     ELSE AST.SetChild(astNode, 0,
+ 3475       AST.MakeLeaf(AST.NkIdent, "LEN")) END;
+ 3476     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3477     astCur := astNode; astIsLit := TRUE;
+ 3478                                             IF (dt # SymTab.InvalidType)
+ 3479    AND (SymTab.ClassOf(dt) = SymTab.ClUStr) THEN
+ 3480                                               (* UString: the count is
+ 3481                                                  the descriptor header *)
+ 3482                                                t := SymTab.IntType();
+ 3483                                                QbeGen.CopyOp("@", q)
+ 3484                                             ELSIF (dt # SymTab.InvalidType)
+ 3485    AND (SymTab.ClassOf(dt) = SymTab.ClUChar) THEN
+ 3486                                               (* single UCHAR codepoint *)
+ 3487                                               IF isHigh THEN
+ 3488                                                 QbeGen.CopyOp("0", qr)
+ 3489                                               ELSE
+ 3490                                                 QbeGen.CopyOp("1", qr)
+ 3491                                               END;
+ 3492                                               t := SymTab.IntType();
+ 3493                                               QbeGen.CopyOp(qr, q)
+ 3494                                             ELSIF isStr THEN
+ 3495                                               (* fold: content length at
+ 3496                                                  compile time *)
+ 3497                                               IF SymTab.StrLen(s) = 3 THEN
+ 3498                                                 c1 := 1
+ 3499                                               ELSE
+ 3500                                                 c1 :=
+ 3501                                                   SymTab.StrLen(s) - 2
+ 3502                                               END;
+ 3503                                               IF isHigh THEN
+ 3504                                                 DEC(c1)
+ 3505                                               END;
+ 3506                                               QbeGen.IntStr(c1, qr);
+ 3507                                               t := SymTab.IntType();
+ 3508                                               QbeGen.CopyOp(qr, q)
+ 3509                                             ELSIF dt = SymTab.InvalidType THEN
+ 3510                                               t := SymTab.InvalidType;
+ 3511                                               QbeGen.CopyOp("0", q)
+ 3512                                             ELSIF SymTab.ClassOf(dt) #
+ 3513                                                   SymTab.ClArray THEN
+ 3514                                               SemError(217);
+ 3515                                               t := SymTab.InvalidType;
+ 3516                                               QbeGen.CopyOp("0", q)
+ 3517                                             ELSE
+ 3518                                                IF SymTab.IsOpenArray(dt) THEN
+ 3519                                                  t := SymTab.IntType();
+ 3520                                                  QbeGen.CopyOp("@", q)
+ 3521                                                ELSE
+ 3522                                                  IF isHigh THEN
+ 3523                                                    QbeGen.IntStr(
+ 3524                                                      SymTab.ArrayHi(dt), qr)
+ 3525                                                  ELSE
+ 3526                                                    QbeGen.IntStr(VAL(
+ 3527                                                      INTEGER,
+ 3528                                                      SymTab.ArrayLen(dt)),
+ 3529                                                      qr)
+ 3530                                                  END;
+ 3531                                                  t := SymTab.IntType();
+ 3532                                                  QbeGen.CopyOp(qr, q)
+ 3533                                                END
+ 3534                                              END; .)
+ 3535      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
+ 3536      (. astNode := AST.MakeNode(AST.NkCall);
+ 3537     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "SIZE"));
+ 3538     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3539     astCur := astNode; astIsLit := TRUE; .)
+ 3540                                          (. IF dt = SymTab.InvalidType THEN
+ 3541                                               t := SymTab.InvalidType;
+ 3542                                               QbeGen.CopyOp("0", q)
+ 3543                                             ELSE
+ 3544                                               QbeGen.IntStr(VAL(INTEGER,
+ 3545                                                 SymTab.ObjectSize(dt)), q);
+ 3546                                               t := SymTab.IntType()
+ 3547                                             END; .)
+ 3548      | ( "SHIFT"                         (. isMax := FALSE; .)
+ 3549        | "ROTATE"                        (. isMax := TRUE; .) )
+ 3550        "(" Expr<et, q> (. astArg2 := astCur; .) "," Expr<et2, q2> ")"
+ 3551                                          (. astNode := AST.MakeNode(AST.NkCall);
+ 3552     IF isMax THEN AST.SetChild(astNode, 0,
+ 3553       AST.MakeLeaf(AST.NkIdent, "ROTATE"))
+ 3554     ELSE AST.SetChild(astNode, 0,
+ 3555       AST.MakeLeaf(AST.NkIdent, "SHIFT")) END;
+ 3556     IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END;
+ 3557     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
+ 3558     astCur := astNode; astIsLit := TRUE;
+ 3559                                             (* set shift/rotate: isMax
+ 3560                                                doubles as "rotate" *)
+ 3561                                             IF (et # SymTab.InvalidType)
+ 3562                                                AND (SymTab.ClassOf(et) =
+ 3563                                                   SymTab.ClSet) THEN
+ 3564                                                t := et;
+ 3565                                                QbeGen.CopyOp("@", q)
+ 3566                                             ELSE SemError(230);
+ 3567                                               t := SymTab.InvalidType;
+ 3568                                               QbeGen.CopyOp("0", q)
+ 3569                                             END; .)
+ 3570      | ( "MIN"                           (. isMax := FALSE; .)
+ 3571        | "MAX"                           (. isMax := TRUE; .) )
+ 3572        "(" Design<dt, dk, qd, qn, sfx> ")"
+ 3573                                          (. astNode := AST.MakeNode(AST.NkCall);
+ 3574     IF isMax THEN AST.SetChild(astNode, 0,
+ 3575       AST.MakeLeaf(AST.NkIdent, "MAX"))
+ 3576     ELSE AST.SetChild(astNode, 0,
+ 3577       AST.MakeLeaf(AST.NkIdent, "MIN")) END;
+ 3578     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3579     astCur := astNode; astIsLit := TRUE;
+ 3580                                             IF (dt # SymTab.InvalidType)
+ 3581   AND (SymTab.ClassOf(dt) = SymTab.ClReal) THEN
+ 3582                                               (* REAL/LONGREAL: the
+ 3583                                                  implementation bounds *)
+ 3584                                               IF isMax THEN
+ 3585                                                 QbeGen.NormReal(
+ 3586                                                   "3.402823e38", q)
+ 3587                                               ELSE QbeGen.NormReal(
+ 3588                                                   "-3.402823e38", q)
+ 3589                                               END;
+ 3590                                               t := SymTab.RealType()
+ 3591                                             ELSIF (dt #
+ 3592                                                SymTab.InvalidType)
+ 3593   AND (SymTab.ClassOf(dt) =
+ 3594                                                   SymTab.ClLong) THEN
+ 3595                                               IF isMax THEN
+ 3596                                                 QbeGen.CopyOp(
+ 3597                                                   "9223372036854775807", q)
+ 3598                                               ELSE QbeGen.CopyOp(
+ 3599                                                   "-9223372036854775808", q)
+ 3600                                               END;
+ 3601                                               t := SymTab.LongType()
+ 3602                                             ELSIF SymTab.TypeBounds(dt, lo,
+ 3603                                                      hi) THEN
+ 3604                                               IF isMax THEN
+ 3605                                                 QbeGen.IntStr(hi, q)
+ 3606                                               ELSE QbeGen.IntStr(lo, q)
+ 3607                                               END;
+ 3608                                               t := SymTab.IntType()
+ 3609                                             ELSE SemError(230);
+ 3610                                               t := SymTab.InvalidType;
+ 3611                                               QbeGen.CopyOp("0", q)
+ 3612                                             END; .)
+ 3613      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
+ 3614      (. astNode := AST.MakeNode(AST.NkCall);
+ 3615     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ADR"));
+ 3616     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3617     astCur := astNode; astIsLit := TRUE; .)
+ 3618                                          (. IF dt = SymTab.InvalidType THEN
+ 3619                                               t := SymTab.InvalidType;
+ 3620                                               QbeGen.CopyOp("0", q)
+ 3621                                             ELSE
+ 3622                                                IF sfx
+ 3623                                                   OR (dk = SymTab.KindVar)
+ 3624                                                   OR (dk = SymTab.KindParam) THEN
+ 3625                                                  QbeGen.CopyOp("@", q)
+ 3626                                                ELSE SemError(230);
+ 3627                                                  QbeGen.CopyOp("0", q)
+ 3628                                                END;
+ 3629                                               t := SymTab.AddrType()
+ 3630                                             END; .)
+ 3631      | "CHR" "(" Expr<et, q> ")"
+ 3632      (. astNode := AST.MakeNode(AST.NkCall);
+ 3633     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR"));
+ 3634     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3635     astCur := astNode; astIsLit := TRUE; .)
+ 3636                                          (. IF (et # SymTab.InvalidType)
+ 3637   AND NOT SymTab.IsIntFamily(et) THEN
+ 3638                                               SemError(211) END;
+ 3639                                             t := SymTab.CharType(); .)
+ 3640      | ( "ORD" | "ORDL" ) "(" Expr<et, q> ")"
+ 3641      (. astNode := AST.MakeNode(AST.NkCall);
+ 3642     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ORD"));
+ 3643     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3644     astCur := astNode; astIsLit := TRUE; .)
+ 3645                                          (. IF et # SymTab.InvalidType THEN
+ 3646                                               IF (SymTab.ClassOf(et) #
+ 3647                                                   SymTab.ClChar)
  3648   AND (SymTab.ClassOf(et) #
- 3649                                                     SymTab.ClEnum)
- 3650   AND NOT SymTab.IsIntFamily(et) THEN
- 3651                                                 SemError(211) END
- 3652                                             END;
- 3653                                             t := SymTab.IntType(); .)
- 3654      | "CAP" "(" Expr<et, q> ")"
- 3655      (. astNode := AST.MakeNode(AST.NkCall);
- 3656     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CAP"));
- 3657     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3658     astCur := astNode; astIsLit := TRUE; .)
- 3659                                           (. QbeGen.CopyOp("@", q);
- 3660                                             t := SymTab.CharType(); .)
- 3661      | "UCHR" "(" Expr<et, q> ")"
- 3662      (. astNode := AST.MakeNode(AST.NkCall);
- 3663     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UCHR"));
- 3664     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3665     astCur := astNode; astIsLit := TRUE; .)
- 3666                                          (. (* UCHR: the UCHAR constructor.
- 3667                                                CHAR -> UCHAR (identity);
- 3668                                                INTEGER familly -> UCHAR
- 3669                                                (codepoint value). *)
- 3670                                             IF (et # SymTab.InvalidType)
- 3671    AND (SymTab.ClassOf(et) # SymTab.ClChar)
- 3672    AND NOT SymTab.IsIntFamily(et) THEN
- 3673                                               SemError(211) END;
- 3674                                             t := SymTab.UCharType(); .)
- 3675      | "CHR8" "(" Expr<et, q> ")"
- 3676      (. astNode := AST.MakeNode(AST.NkCall);
- 3677     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR8"));
- 3678     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3679     astCur := astNode; astIsLit := TRUE; .)
- 3680                                          (. IF (et # SymTab.InvalidType)
- 3681    AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
- 3682                                               SemError(211) END;
- 3683                                             t := SymTab.CharType(); .)
- 3684      | "UORD" "(" Expr<et, q> ")"
- 3685      (. astNode := AST.MakeNode(AST.NkCall);
- 3686     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UORD"));
- 3687     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3688     astCur := astNode; astIsLit := TRUE; .)
- 3689                                          (. (* UORD(u): the codepoint as a
- 3690                                                32-bit ordinal (INTEGER),
- 3691                                                cf. ORD for CHAR. *)
- 3692                                             IF (et # SymTab.InvalidType)
- 3693    AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
- 3694                                               SemError(211) END;
- 3695                                             t := SymTab.IntType(); .)
- 3696      | "ABS" "(" Expr<et, q> ")"
- 3697      (. astNode := AST.MakeNode(AST.NkCall);
- 3698     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ABS"));
- 3699     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3700     astCur := astNode; astIsLit := TRUE; .)
- 3701                                          (. IF (et # SymTab.InvalidType)
- 3702   AND NOT SymTab.IsIntFamily(et)
- 3703   AND (SymTab.ClassOf(et) #
- 3704                                                  SymTab.ClReal) THEN
- 3705                                               SemError(211)
- 3706                                              ELSE QbeGen.CopyOp("@", q)
- 3707                                             END;
- 3708                                             t := et; .)
- 3709      | "ODD" "(" Expr<et, q> ")"
- 3710      (. astNode := AST.MakeNode(AST.NkCall);
- 3711     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ODD"));
- 3712     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3713     astCur := astNode; astIsLit := TRUE; .)
- 3714                                          (. IF (et # SymTab.InvalidType)
- 3715   AND NOT SymTab.IsIntFamily(et) THEN
- 3716                                               SemError(211) END;
- 3717                                             t := SymTab.BoolType();
- 3718                                             QbeGen.CopyOp("@", q); .)
- 3719      | "TRUNC" "(" Expr<et, q> ")"
- 3720      (. (* TRUNC(x): real -> INTEGER, as the VAL builtin *)
- 3721     astNode := AST.MakeNode(AST.NkCall);
- 3722     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
- 3723     AST.SetChild(astNode, 1, AST.MakeLeaf(AST.NkIdent, "INTEGER"));
- 3724     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
- 3725     astCur := astNode; astIsLit := TRUE; .)
- 3726                                          (. t := SymTab.IntType();
- 3727                                             QbeGen.CopyOp("@", q); .)
- 3728      | "FLOAT" "(" Expr<et, q> ")"
- 3729      (. (* FLOAT(i): integer -> REAL, as the VAL builtin *)
- 3730     astNode := AST.MakeNode(AST.NkCall);
- 3731     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
- 3732     AST.SetChild(astNode, 1, AST.MakeLeaf(AST.NkIdent, "REAL"));
- 3733     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
- 3734     astCur := astNode; astIsLit := TRUE; .)
- 3735                                          (. t := SymTab.RealType();
- 3736                                             QbeGen.CopyOp("@", q); .)
- 3737      | "VAL" "(" GetIdent<vn> (. astArg2 := AST.MakeLeaf(AST.NkIdent, vn); .) "," Expr<et, q> ")"
- 3738      (. astNode := AST.MakeNode(AST.NkCall);
- 3739     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
- 3740     IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END;
- 3741     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
- 3742     astCur := astNode; astIsLit := TRUE; .)
- 3743                                          (. IF NOT SymTab.Lookup(vn) THEN
- 3744                                               SemError(201);
- 3745                                               t := SymTab.InvalidType
- 3746                                             ELSE vt := SymTab.SymType(vn);
- 3747                                               IF vt = SymTab.InvalidType THEN
- 3748                                                 t := SymTab.InvalidType
- 3749                                               ELSIF et =
- 3750                                                  SymTab.InvalidType THEN
- 3751                                                 t := vt
- 3752                                               ELSE
- 3753                                                 c1 := SymTab.ClassOf(et);
- 3754                                                 c2 := SymTab.ClassOf(vt);
- 3755                                                 IF (c1 = SymTab.ClInt)
- 3756    AND (c2 = SymTab.ClLong) THEN
- 3757                                                   QbeGen.WidenLong(q, qa);
- 3758                                                   QbeGen.CopyOp(qa, q);
- 3759                                                   t := vt
- 3760                                                 ELSIF (c1 = SymTab.ClLong)
- 3761    AND (c2 = SymTab.ClInt) THEN
- 3762                                                   QbeGen.NarrowLong(q, qa);
- 3763                                                   QbeGen.CopyOp(qa, q);
- 3764                                                   t := vt
- 3765                                                 ELSIF (c1 = SymTab.ClInt)
- 3766    AND (c2 = SymTab.ClReal) THEN
- 3767                                                   QbeGen.ConvIR(q, qa);
- 3768                                                   QbeGen.CopyOp(qa, q);
- 3769                                                   t := vt
- 3770                                                 ELSIF (c1 = SymTab.ClLong)
- 3771    AND (c2 = SymTab.ClReal) THEN
- 3772                                                   QbeGen.ConvLR(q, qa);
- 3773                                                   QbeGen.CopyOp(qa, q);
- 3774                                                   t := vt
- 3775                                                 ELSIF (c1 = SymTab.ClReal)
- 3776    AND (c2 = SymTab.ClInt) THEN
- 3777                                                   QbeGen.ConvRI(q, qa);
- 3778                                                   QbeGen.CopyOp(qa, q);
- 3779                                                   t := vt
- 3780                                                 ELSIF (c1 = SymTab.ClReal)
- 3781    AND (c2 = SymTab.ClLong) THEN
- 3782                                                   QbeGen.ConvRL(q, qa);
- 3783                                                   QbeGen.CopyOp(qa, q);
- 3784                                                   t := vt
- 3785                                                 ELSIF ((c1 = SymTab.ClInt)
- 3786                                                     OR (c1 =
- 3787                                                        SymTab.ClChar)
- 3788                                                     OR (c1 =
- 3789                                                        SymTab.ClBool)
- 3790                                                     OR (c1 =
- 3791                                                        SymTab.ClEnum))
- 3792   AND ((c2 = SymTab.ClInt)
- 3793                                                     OR (c2 =
- 3794                                                        SymTab.ClChar)
- 3795                                                     OR (c2 =
- 3796                                                        SymTab.ClBool)
- 3797                                                     OR (c2 =
- 3798                                                        SymTab.ClEnum)) THEN
- 3799                                                   t := vt
- 3800                                                 ELSIF (c1 = SymTab.ClPtr)
- 3801   AND (c2 = SymTab.ClPtr) THEN
+ 3649                                                     SymTab.ClBool)
+ 3650   AND (SymTab.ClassOf(et) #
+ 3651                                                     SymTab.ClEnum)
+ 3652   AND NOT SymTab.IsIntFamily(et) THEN
+ 3653                                                 SemError(211) END
+ 3654                                             END;
+ 3655                                             t := SymTab.IntType(); .)
+ 3656      | "CAP" "(" Expr<et, q> ")"
+ 3657      (. astNode := AST.MakeNode(AST.NkCall);
+ 3658     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CAP"));
+ 3659     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3660     astCur := astNode; astIsLit := TRUE; .)
+ 3661                                           (. IF QbeGen.IsImm(q)
+ 3662    AND SymTab.ConstInt(q, lo) THEN
+ 3663       IF (lo >= VAL(INTEGER, ORD("a"))) AND (lo <= VAL(INTEGER, ORD("z"))) THEN lo := lo - 32 END;
+ 3664       QbeGen.IntStr(lo, q)
+ 3665     ELSE QbeGen.CopyOp("@", q)
+ 3666     END;
+ 3667     t := SymTab.CharType(); .)
+ 3668      | "UCHR" "(" Expr<et, q> ")"
+ 3669      (. astNode := AST.MakeNode(AST.NkCall);
+ 3670     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UCHR"));
+ 3671     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3672     astCur := astNode; astIsLit := TRUE; .)
+ 3673                                          (. (* UCHR: the UCHAR constructor.
+ 3674                                                CHAR -> UCHAR (identity);
+ 3675                                                INTEGER familly -> UCHAR
+ 3676                                                (codepoint value). *)
+ 3677                                             IF (et # SymTab.InvalidType)
+ 3678    AND (SymTab.ClassOf(et) # SymTab.ClChar)
+ 3679    AND NOT SymTab.IsIntFamily(et) THEN
+ 3680                                               SemError(211) END;
+ 3681                                             t := SymTab.UCharType(); .)
+ 3682      | "CHR8" "(" Expr<et, q> ")"
+ 3683      (. astNode := AST.MakeNode(AST.NkCall);
+ 3684     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR8"));
+ 3685     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3686     astCur := astNode; astIsLit := TRUE; .)
+ 3687                                          (. IF (et # SymTab.InvalidType)
+ 3688    AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
+ 3689                                               SemError(211) END;
+ 3690                                             t := SymTab.CharType(); .)
+ 3691      | "UORD" "(" Expr<et, q> ")"
+ 3692      (. astNode := AST.MakeNode(AST.NkCall);
+ 3693     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UORD"));
+ 3694     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3695     astCur := astNode; astIsLit := TRUE; .)
+ 3696                                          (. (* UORD(u): the codepoint as a
+ 3697                                                32-bit ordinal (INTEGER),
+ 3698                                                cf. ORD for CHAR. *)
+ 3699                                             IF (et # SymTab.InvalidType)
+ 3700    AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
+ 3701                                               SemError(211) END;
+ 3702                                             t := SymTab.IntType(); .)
+ 3703      | "ABS" "(" Expr<et, q> ")"
+ 3704      (. astNode := AST.MakeNode(AST.NkCall);
+ 3705     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ABS"));
+ 3706     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3707     astCur := astNode; astIsLit := TRUE; .)
+ 3708                                          (. IF (et # SymTab.InvalidType)
+ 3709   AND NOT SymTab.IsIntFamily(et)
+ 3710   AND (SymTab.ClassOf(et) #
+ 3711                                                  SymTab.ClReal) THEN
+ 3712                                               SemError(211)
+ 3713                                              ELSIF QbeGen.IsImm(q)
+ 3714    AND SymTab.ConstInt(q, lo) THEN
+ 3715                                                IF lo < 0 THEN lo := -lo END;
+ 3716                                                QbeGen.IntStr(lo, q)
+ 3717                                              ELSE QbeGen.CopyOp("@", q)
+ 3718                                             END;
+ 3719                                             t := et; .)
+ 3720      | "ODD" "(" Expr<et, q> ")"
+ 3721      (. astNode := AST.MakeNode(AST.NkCall);
+ 3722     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ODD"));
+ 3723     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3724     astCur := astNode; astIsLit := TRUE; .)
+ 3725                                          (. IF (et # SymTab.InvalidType)
+ 3726   AND NOT SymTab.IsIntFamily(et) THEN
+ 3727                                               SemError(211) END;
+ 3728                                             t := SymTab.BoolType();
+ 3729                                             IF QbeGen.IsImm(q)
+ 3730    AND SymTab.ConstInt(q, lo) THEN
+ 3731                                               IF (lo MOD 2) # 0 THEN
+ 3732                                                 QbeGen.CopyOp("1", q)
+ 3733                                               ELSE QbeGen.CopyOp("0", q)
+ 3734                                               END
+ 3735                                             ELSE QbeGen.CopyOp("@", q)
+ 3736                                             END; .)
+ 3737      | "TRUNC" "(" Expr<et, q> ")"
+ 3738      (. (* TRUNC(x): real -> INTEGER, as the VAL builtin *)
+ 3739     astNode := AST.MakeNode(AST.NkCall);
+ 3740     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
+ 3741     AST.SetChild(astNode, 1, AST.MakeLeaf(AST.NkIdent, "INTEGER"));
+ 3742     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
+ 3743     astCur := astNode; astIsLit := TRUE; .)
+ 3744                                          (. t := SymTab.IntType();
+ 3745                                             QbeGen.CopyOp("@", q); .)
+ 3746      | "FLOAT" "(" Expr<et, q> ")"
+ 3747      (. (* FLOAT(i): integer -> REAL, as the VAL builtin *)
+ 3748     astNode := AST.MakeNode(AST.NkCall);
+ 3749     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
+ 3750     AST.SetChild(astNode, 1, AST.MakeLeaf(AST.NkIdent, "REAL"));
+ 3751     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
+ 3752     astCur := astNode; astIsLit := TRUE; .)
+ 3753                                          (. t := SymTab.RealType();
+ 3754                                             QbeGen.CopyOp("@", q); .)
+ 3755      | "VAL" "(" GetIdent<vn> (. astArg2 := AST.MakeLeaf(AST.NkIdent, vn); .) "," Expr<et, q> ")"
+ 3756      (. astNode := AST.MakeNode(AST.NkCall);
+ 3757     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
+ 3758     IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END;
+ 3759     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
+ 3760     astCur := astNode; astIsLit := TRUE; .)
+ 3761                                          (. IF NOT SymTab.Lookup(vn) THEN
+ 3762                                               SemError(201);
+ 3763                                               t := SymTab.InvalidType
+ 3764                                             ELSE vt := SymTab.SymType(vn);
+ 3765                                               IF vt = SymTab.InvalidType THEN
+ 3766                                                 t := SymTab.InvalidType
+ 3767                                               ELSIF et =
+ 3768                                                  SymTab.InvalidType THEN
+ 3769                                                 t := vt
+ 3770                                               ELSE
+ 3771                                                 c1 := SymTab.ClassOf(et);
+ 3772                                                 c2 := SymTab.ClassOf(vt);
+ 3773                                                 IF (c1 = SymTab.ClInt)
+ 3774    AND (c2 = SymTab.ClLong) THEN
+ 3775                                                   QbeGen.WidenLong(q, qa);
+ 3776                                                   QbeGen.CopyOp(qa, q);
+ 3777                                                   t := vt
+ 3778                                                 ELSIF (c1 = SymTab.ClLong)
+ 3779    AND (c2 = SymTab.ClInt) THEN
+ 3780                                                   QbeGen.NarrowLong(q, qa);
+ 3781                                                   QbeGen.CopyOp(qa, q);
+ 3782                                                   t := vt
+ 3783                                                 ELSIF (c1 = SymTab.ClInt)
+ 3784    AND (c2 = SymTab.ClReal) THEN
+ 3785                                                   QbeGen.ConvIR(q, qa);
+ 3786                                                   QbeGen.CopyOp(qa, q);
+ 3787                                                   t := vt
+ 3788                                                 ELSIF (c1 = SymTab.ClLong)
+ 3789    AND (c2 = SymTab.ClReal) THEN
+ 3790                                                   QbeGen.ConvLR(q, qa);
+ 3791                                                   QbeGen.CopyOp(qa, q);
+ 3792                                                   t := vt
+ 3793                                                 ELSIF (c1 = SymTab.ClReal)
+ 3794    AND (c2 = SymTab.ClInt) THEN
+ 3795                                                   QbeGen.ConvRI(q, qa);
+ 3796                                                   QbeGen.CopyOp(qa, q);
+ 3797                                                   t := vt
+ 3798                                                 ELSIF (c1 = SymTab.ClReal)
+ 3799    AND (c2 = SymTab.ClLong) THEN
+ 3800                                                   QbeGen.ConvRL(q, qa);
+ 3801                                                   QbeGen.CopyOp(qa, q);
  3802                                                   t := vt
- 3803                                                 ELSIF (c1 = SymTab.ClReal)
- 3804   AND (c2 = SymTab.ClReal) THEN
- 3805                                                   t := vt
- 3806                                                 ELSE SemError(230);
- 3807                                                   t := SymTab.InvalidType
- 3808                                                 END
- 3809                                               END
- 3810                                             END; .)
- 3811      | "(" Expr<et, q> ")"               (. t := et; astIsLit := TRUE; .)
- 3812      | SetLit<st, sq>                    (. astIsLit := TRUE; t := st;
- 3813                                             QbeGen.CopyOp(sq, q); .)
- 3814      | ( "NOT" | "~" ) Fact<t2, q2>      (. astNot := astCur;
- 3815                                             IF SymTab.BoolCheck(t2) THEN
- 3816                                               t := SymTab.BoolType()
- 3817                                             ELSE SemError(212);
- 3818                                               t := SymTab.InvalidType END;
- 3819                                             IF t # SymTab.InvalidType THEN
- 3820                                                QbeGen.CopyOp("@", q)
- 3821                                             ELSE QbeGen.CopyOp("0", q)
- 3822                                             END;
- 3823                                             astIsLit := TRUE;
- 3824                                             astCur := AST.MakeUn(
- 3825                                               AST.NkUnary, AST.OpNot, astNot); .)
- 3826      )
- 3827      (. IF NOT astIsLit THEN astCur := AST.NoNode END; .)
- 3828             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
- 3829    (* Set literals are SET OF [0..255] (8 words); elements validated
- 3830       0..255 statically when foldable (222 otherwise), runtime trap
- 3831       for computed elements. Ranges always lower via SetRange. *)
- 3832    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 3833                                          (. VAR astNode: AST.Node; .)
- 3834      = "{"                               (. t := SymTab.NewSet(
- 3835                                               SymTab.NewSubR(0, 255));
- 3836                                             astNode := AST.MakeNode(AST.NkSetLit);
- 3837                                             QbeGen.NewSetTemp(8, q);
- 3838                                             QbeGen.SetZero(q, 8); .)
- 3839        [ SetElem<t, q, astNode> { "," SetElem<t, q, astNode> } ]
- 3840        "}"                               (. astCur := astNode; .) .
- 3841    (* Typed brace constructor: TypeName{ elems } — BITSET{0} (a set)
- 3842       or ArrayName{...} (an array constructor, GNU Modula-2).  The
- 3843       declared type sets the width (set) or element type (array). *)
- 3844    TypedBraceLit<vt: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 3845                                          (. VAR nw: CARDINAL;
- 3846                                               astNode, astTail: AST.Node;
- 3847                                               savedCls: INTEGER; .)
- 3848      = "{"                               (. savedCls := braceCls;
- 3849                                             astNode := AST.MakeNode(AST.NkBraceLit);
- 3850                                             AST.SetTy(astNode, vt);
- 3851                                             astTail := astNode;
- 3852                                             IF vt = SymTab.InvalidType THEN
- 3853                                               braceCls := -1
- 3854                                             ELSE braceCls :=
- 3855                                                    SymTab.ClassOf(vt)
- 3856                                             END;
- 3857                                             IF braceCls = SymTab.ClSet THEN
- 3858                                               IF vt = SymTab.InvalidType THEN
- 3859                                                 nw := 8
- 3860                                               ELSE nw := SymTab.SetWords(vt);
- 3861                                                 IF nw = 0 THEN nw := 8 END
- 3862                                               END;
- 3863                                               QbeGen.NewSetTemp(nw, q);
- 3864                                               QbeGen.SetZero(q, nw)
- 3865                                             ELSIF (braceCls =
- 3866                                                    SymTab.ClArray)
- 3867                                                OR (braceCls =
- 3868                                                    SymTab.ClRecord)
- 3869                                                OR (braceCls =
- 3870                                                    SymTab.ClClass) THEN
- 3871                                               QbeGen.CtorBegin(vt)
- 3872                                             ELSE
- 3873                                               IF vt # SymTab.InvalidType THEN
- 3874                                                 SemError(230) END;
- 3875                                               braceCls := -1
- 3876                                             END; .)
- 3877        [ BraceElem<vt, q, astNode, astTail>
- 3878          { "," BraceElem<vt, q, astNode, astTail> } ]
- 3879        "}"                               (. IF (braceCls = SymTab.ClArray)
- 3880                                                OR (braceCls =
- 3881                                                   SymTab.ClRecord)
- 3882                                                OR (braceCls =
- 3883                                                   SymTab.ClClass) THEN
- 3884                                               QbeGen.CtorEnd(q)
- 3885                                             ELSIF braceCls # SymTab.ClSet THEN
- 3886                                               QbeGen.CopyOp("0", q)
- 3887                                             END;
- 3888                                             braceCls := savedCls; .)
- 3889                                          (. astCur := astNode; .) .
- 3890    BraceElem<vt: SymTab.TypeIndex; VAR sq: QbeGen.QVal;
- 3891              VAR node, tail: AST.Node>
- 3892                                          (. VAR et, et2: SymTab.TypeIndex;
- 3893                                               qe, q2: QbeGen.QVal;
- 3894                                               v, v2, reps, k: INTEGER;
- 3895                                               elem: SymTab.TypeIndex;
- 3896                                               lo: INTEGER;
- 3897                                               span: CARDINAL;
- 3898                                               cl, cl2: INTEGER;
- 3899                                               hasR, hasB: BOOLEAN;
- 3900                                               astEl: AST.Node; .)
- 3901      =                                   (. hasR := FALSE; hasB := FALSE;
- 3902                                             reps := 1; .)
- 3903        Expr<et, qe> (. astEl := astCur; .)
- 3904        [ ".." Expr<et2, q2>              (. astEl := AST.MakeBin(
- 3905                                               AST.NkSubrange, 0, astEl, astCur);
- 3906                                             hasR := TRUE; .) ]
- 3907        [ "BY" Expr<et2, q2>              (. hasB := TRUE; .) ]
- 3908                                          (. IF braceCls = SymTab.ClSet THEN
- 3909                                               IF hasB THEN SemError(230) END;
- 3910                                               lo := SymTab.SetBaseLo(vt);
- 3911                                               span := SymTab.SetCount(vt);
- 3912                                               IF (et = SymTab.InvalidType)
- 3913                                                  OR (hasR AND (et2 =
- 3914                                                     SymTab.InvalidType)) THEN
- 3915                                               ELSE cl :=
- 3916                                                      SymTab.ClassOf(et);
- 3917                                                 IF hasR THEN
- 3918                                                   cl2 :=
- 3919                                                     SymTab.ClassOf(et2)
- 3920                                                 ELSE cl2 := SymTab.ClInt
- 3921                                                 END;
- 3922                                                 IF NOT SymTab.SetElemClassOk(cl)
- 3923                                                    OR (hasR AND NOT
- 3924                                                       SymTab.SetElemClassOk(cl2))
- 3925                                                 THEN
- 3926                                                   SemError(222)
- 3927                                                 ELSIF hasR
- 3928   AND SymTab.ConstInt(qe, v)
- 3929   AND SymTab.ConstInt(q2,
- 3930                                                       v2)
- 3931   AND ((v < lo)
- 3932                                                       OR (v2 < lo)
- 3933                                                       OR (v >= lo +
- 3934                                                          VAL(INTEGER, span))
- 3935                                                       OR (v2 >= lo +
- 3936                                                          VAL(INTEGER, span))
- 3937                                                       OR (v > v2)) THEN
- 3938                                                   SemError(222)
- 3939                                                  ELSIF hasR THEN
- 3940                                                    QbeGen.SetRange(sq, qe, q2,
- 3941                                                      lo, span)
- 3942                                                  ELSIF SymTab.ConstInt(qe,
- 3943                                                          v)
- 3944   AND ((v < lo)
- 3945                                                        OR (v >= lo +
- 3946                                                           VAL(INTEGER,
- 3947                                                             span))) THEN
- 3948                                                    SemError(222)
- 3949                                                  ELSE QbeGen.SetBit(sq, qe,
- 3950                                                    lo, span)
- 3951                                                 END
- 3952                                               END
- 3953                                             ELSIF (braceCls = SymTab.ClArray)
- 3954                                                OR (braceCls =
- 3955                                                   SymTab.ClRecord)
- 3956                                                OR (braceCls =
- 3957                                                   SymTab.ClClass) THEN
- 3958                                               IF hasR THEN SemError(230) END;
- 3959                                               reps := 1;
- 3960                                               IF hasB THEN
- 3961                                                 IF SymTab.ConstInt(q2, v2)
- 3962   AND (v2 >= 1) THEN
- 3963                                                   reps := v2
- 3964                                                 ELSE SemError(230)
- 3965                                                 END
- 3966                                               END;
- 3967                                               k := 0;
- 3968                                               WHILE k < reps DO
- 3969                                                 QbeGen.CtorElem(qe);
- 3970                                                 INC(k)
- 3971                                               END
- 3972                                             END; .)
- 3973                                          (. (* the BY form repeats the
- 3974                                               element; keep the AST in
- 3975                                               step with CtorElem *)
- 3976                                             k := 0;
- 3977                                             WHILE k < reps DO
- 3978                                               AstAppend(AST.NkBlock,
- 3979                                                 node, tail, astEl);
- 3980                                               INC(k)
- 3981                                             END; .) .
- 3982    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal; node: AST.Node>         (. VAR et, et2: SymTab.TypeIndex;
- 3983                                               qe, q2: QbeGen.QVal;
- 3984                                               v, v2: INTEGER;
- 3985                                               lo: INTEGER;
- 3986                                               span: CARDINAL;
- 3987                                               cl, cl2: INTEGER;
- 3988                                               hasR: BOOLEAN;
- 3989                                               astEl: AST.Node; .)
- 3990      =                                   (. hasR := FALSE; .)
- 3991        Expr<et, qe> (. astEl := astCur; .)
- 3992        [ ".." Expr<et2, q2>              (. astEl := AST.MakeBin(
- 3993                                               AST.NkSubrange, 0, astEl, astCur);
- 3994                                             hasR := TRUE; .) ]
- 3995                                          (. lo := SymTab.SetBaseLo(st);
- 3996                                             span := SymTab.SetCount(st);
- 3997                                             IF (et = SymTab.InvalidType)
- 3998                                                OR (hasR AND (et2 =
- 3999                                                   SymTab.InvalidType)) THEN
- 4000                                             ELSE cl :=
- 4001                                                    SymTab.ClassOf(et);
- 4002                                               IF hasR THEN
- 4003                                                 cl2 :=
- 4004                                                   SymTab.ClassOf(et2)
- 4005                                               ELSE cl2 := SymTab.ClInt
- 4006                                               END;
- 4007                                               IF NOT SymTab.SetElemClassOk(cl)
- 4008                                                  OR (hasR AND NOT
- 4009                                                     SymTab.SetElemClassOk(cl2))
- 4010                                               THEN
- 4011                                                 SemError(222)
- 4012                                               ELSIF hasR
- 4013   AND SymTab.ConstInt(qe, v)
- 4014   AND SymTab.ConstInt(q2,
- 4015                                                     v2)
- 4016   AND ((v < lo)
- 4017                                                     OR (v2 < lo)
- 4018                                                     OR (v >= lo +
- 4019                                                        VAL(INTEGER, span))
- 4020                                                     OR (v2 >= lo +
- 4021                                                        VAL(INTEGER, span))
- 4022                                                     OR (v > v2)) THEN
- 4023                                                 SemError(222)
- 4024                                                ELSIF hasR THEN
- 4025                                                  QbeGen.SetRange(sq, qe, q2,
- 4026                                                    lo, span)
- 4027                                                ELSIF SymTab.ConstInt(qe,
- 4028                                                        v)
- 4029   AND ((v < lo)
- 4030                                                      OR (v >= lo +
- 4031                                                         VAL(INTEGER,
- 4032                                                           span))) THEN
- 4033                                                  SemError(222)
- 4034                                                ELSE QbeGen.SetBit(sq, qe,
- 4035                                                  lo, span)
- 4036                                               END
- 4037                                             END; .)
- 4038                                          (. AST.SetChild(node,
- 4039                                               AST.NChild(node), astEl); .) .
- 4040    GetIdent<VAR n: SymTab.Name>
- 4041      = ident                             (. LexName(n); .) .
- 4042  
- 4043  END M2.
+ 3803                                                 ELSIF ((c1 = SymTab.ClInt)
+ 3804                                                     OR (c1 =
+ 3805                                                        SymTab.ClChar)
+ 3806                                                     OR (c1 =
+ 3807                                                        SymTab.ClBool)
+ 3808                                                     OR (c1 =
+ 3809                                                        SymTab.ClEnum))
+ 3810   AND ((c2 = SymTab.ClInt)
+ 3811                                                     OR (c2 =
+ 3812                                                        SymTab.ClChar)
+ 3813                                                     OR (c2 =
+ 3814                                                        SymTab.ClBool)
+ 3815                                                     OR (c2 =
+ 3816                                                        SymTab.ClEnum)) THEN
+ 3817                                                   t := vt
+ 3818                                                 ELSIF (c1 = SymTab.ClPtr)
+ 3819   AND (c2 = SymTab.ClPtr) THEN
+ 3820                                                   t := vt
+ 3821                                                 ELSIF (c1 = SymTab.ClReal)
+ 3822   AND (c2 = SymTab.ClReal) THEN
+ 3823                                                   t := vt
+ 3824                                                 ELSE SemError(230);
+ 3825                                                   t := SymTab.InvalidType
+ 3826                                                 END
+ 3827                                               END
+ 3828                                             END; .)
+ 3829      | "(" Expr<et, q> ")"               (. t := et; astIsLit := TRUE; .)
+ 3830      | SetLit<st, sq>                    (. astIsLit := TRUE; t := st;
+ 3831                                             QbeGen.CopyOp(sq, q); .)
+ 3832      | ( "NOT" | "~" ) Fact<t2, q2>      (. astNot := astCur;
+ 3833                                             IF SymTab.BoolCheck(t2) THEN
+ 3834                                               t := SymTab.BoolType()
+ 3835                                             ELSE SemError(212);
+ 3836                                               t := SymTab.InvalidType END;
+ 3837                                             IF t # SymTab.InvalidType THEN
+ 3838                                                QbeGen.CopyOp("@", q)
+ 3839                                             ELSE QbeGen.CopyOp("0", q)
+ 3840                                             END;
+ 3841                                             astIsLit := TRUE;
+ 3842                                             astCur := AST.MakeUn(
+ 3843                                               AST.NkUnary, AST.OpNot, astNot); .)
+ 3844      )
+ 3845      (. IF NOT astIsLit THEN astCur := AST.NoNode END; .)
+ 3846             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
+ 3847    (* Set literals are SET OF [0..255] (8 words); elements validated
+ 3848       0..255 statically when foldable (222 otherwise), runtime trap
+ 3849       for computed elements. Ranges always lower via SetRange. *)
+ 3850    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 3851                                          (. VAR astNode: AST.Node; .)
+ 3852      = "{"                               (. t := SymTab.NewSet(
+ 3853                                               SymTab.NewSubR(0, 255));
+ 3854                                             astNode := AST.MakeNode(AST.NkSetLit);
+ 3855                                             QbeGen.NewSetTemp(8, q);
+ 3856                                             QbeGen.SetZero(q, 8); .)
+ 3857        [ SetElem<t, q, astNode> { "," SetElem<t, q, astNode> } ]
+ 3858        "}"                               (. astCur := astNode; .) .
+ 3859    (* Typed brace constructor: TypeName{ elems } — BITSET{0} (a set)
+ 3860       or ArrayName{...} (an array constructor, GNU Modula-2).  The
+ 3861       declared type sets the width (set) or element type (array). *)
+ 3862    TypedBraceLit<vt: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 3863                                          (. VAR nw: CARDINAL;
+ 3864                                               astNode, astTail: AST.Node;
+ 3865                                               savedCls: INTEGER; .)
+ 3866      = "{"                               (. savedCls := braceCls;
+ 3867                                             astNode := AST.MakeNode(AST.NkBraceLit);
+ 3868                                             AST.SetTy(astNode, vt);
+ 3869                                             astTail := astNode;
+ 3870                                             IF vt = SymTab.InvalidType THEN
+ 3871                                               braceCls := -1
+ 3872                                             ELSE braceCls :=
+ 3873                                                    SymTab.ClassOf(vt)
+ 3874                                             END;
+ 3875                                             IF braceCls = SymTab.ClSet THEN
+ 3876                                               IF vt = SymTab.InvalidType THEN
+ 3877                                                 nw := 8
+ 3878                                               ELSE nw := SymTab.SetWords(vt);
+ 3879                                                 IF nw = 0 THEN nw := 8 END
+ 3880                                               END;
+ 3881                                               QbeGen.NewSetTemp(nw, q);
+ 3882                                               QbeGen.SetZero(q, nw)
+ 3883                                             ELSIF (braceCls =
+ 3884                                                    SymTab.ClArray)
+ 3885                                                OR (braceCls =
+ 3886                                                    SymTab.ClRecord)
+ 3887                                                OR (braceCls =
+ 3888                                                    SymTab.ClClass) THEN
+ 3889                                               QbeGen.CtorBegin(vt)
+ 3890                                             ELSE
+ 3891                                               IF vt # SymTab.InvalidType THEN
+ 3892                                                 SemError(230) END;
+ 3893                                               braceCls := -1
+ 3894                                             END; .)
+ 3895        [ BraceElem<vt, q, astNode, astTail>
+ 3896          { "," BraceElem<vt, q, astNode, astTail> } ]
+ 3897        "}"                               (. IF (braceCls = SymTab.ClArray)
+ 3898                                                OR (braceCls =
+ 3899                                                   SymTab.ClRecord)
+ 3900                                                OR (braceCls =
+ 3901                                                   SymTab.ClClass) THEN
+ 3902                                               QbeGen.CtorEnd(q)
+ 3903                                             ELSIF braceCls # SymTab.ClSet THEN
+ 3904                                               QbeGen.CopyOp("0", q)
+ 3905                                             END;
+ 3906                                             braceCls := savedCls; .)
+ 3907                                          (. astCur := astNode; .) .
+ 3908    BraceElem<vt: SymTab.TypeIndex; VAR sq: QbeGen.QVal;
+ 3909              VAR node, tail: AST.Node>
+ 3910                                          (. VAR et, et2: SymTab.TypeIndex;
+ 3911                                               qe, q2: QbeGen.QVal;
+ 3912                                               v, v2, reps, k: INTEGER;
+ 3913                                               elem: SymTab.TypeIndex;
+ 3914                                               lo: INTEGER;
+ 3915                                               span: CARDINAL;
+ 3916                                               cl, cl2: INTEGER;
+ 3917                                               hasR, hasB: BOOLEAN;
+ 3918                                               astEl: AST.Node; .)
+ 3919      =                                   (. hasR := FALSE; hasB := FALSE;
+ 3920                                             reps := 1; .)
+ 3921        Expr<et, qe> (. astEl := astCur; .)
+ 3922        [ ".." Expr<et2, q2>              (. astEl := AST.MakeBin(
+ 3923                                               AST.NkSubrange, 0, astEl, astCur);
+ 3924                                             hasR := TRUE; .) ]
+ 3925        [ "BY" Expr<et2, q2>              (. hasB := TRUE; .) ]
+ 3926                                          (. IF braceCls = SymTab.ClSet THEN
+ 3927                                               IF hasB THEN SemError(230) END;
+ 3928                                               lo := SymTab.SetBaseLo(vt);
+ 3929                                               span := SymTab.SetCount(vt);
+ 3930                                               IF (et = SymTab.InvalidType)
+ 3931                                                  OR (hasR AND (et2 =
+ 3932                                                     SymTab.InvalidType)) THEN
+ 3933                                               ELSE cl :=
+ 3934                                                      SymTab.ClassOf(et);
+ 3935                                                 IF hasR THEN
+ 3936                                                   cl2 :=
+ 3937                                                     SymTab.ClassOf(et2)
+ 3938                                                 ELSE cl2 := SymTab.ClInt
+ 3939                                                 END;
+ 3940                                                 IF NOT SymTab.SetElemClassOk(cl)
+ 3941                                                    OR (hasR AND NOT
+ 3942                                                       SymTab.SetElemClassOk(cl2))
+ 3943                                                 THEN
+ 3944                                                   SemError(222)
+ 3945                                                 ELSIF hasR
+ 3946   AND SymTab.ConstInt(qe, v)
+ 3947   AND SymTab.ConstInt(q2,
+ 3948                                                       v2)
+ 3949   AND ((v < lo)
+ 3950                                                       OR (v2 < lo)
+ 3951                                                       OR (v >= lo +
+ 3952                                                          VAL(INTEGER, span))
+ 3953                                                       OR (v2 >= lo +
+ 3954                                                          VAL(INTEGER, span))
+ 3955                                                       OR (v > v2)) THEN
+ 3956                                                   SemError(222)
+ 3957                                                  ELSIF hasR THEN
+ 3958                                                    QbeGen.SetRange(sq, qe, q2,
+ 3959                                                      lo, span)
+ 3960                                                  ELSIF SymTab.ConstInt(qe,
+ 3961                                                          v)
+ 3962   AND ((v < lo)
+ 3963                                                        OR (v >= lo +
+ 3964                                                           VAL(INTEGER,
+ 3965                                                             span))) THEN
+ 3966                                                    SemError(222)
+ 3967                                                  ELSE QbeGen.SetBit(sq, qe,
+ 3968                                                    lo, span)
+ 3969                                                 END
+ 3970                                               END
+ 3971                                             ELSIF (braceCls = SymTab.ClArray)
+ 3972                                                OR (braceCls =
+ 3973                                                   SymTab.ClRecord)
+ 3974                                                OR (braceCls =
+ 3975                                                   SymTab.ClClass) THEN
+ 3976                                               IF hasR THEN SemError(230) END;
+ 3977                                               reps := 1;
+ 3978                                               IF hasB THEN
+ 3979                                                 IF SymTab.ConstInt(q2, v2)
+ 3980   AND (v2 >= 1) THEN
+ 3981                                                   reps := v2
+ 3982                                                 ELSE SemError(230)
+ 3983                                                 END
+ 3984                                               END;
+ 3985                                               k := 0;
+ 3986                                               WHILE k < reps DO
+ 3987                                                 QbeGen.CtorElem(qe);
+ 3988                                                 INC(k)
+ 3989                                               END
+ 3990                                             END; .)
+ 3991                                          (. (* the BY form repeats the
+ 3992                                               element; keep the AST in
+ 3993                                               step with CtorElem *)
+ 3994                                             k := 0;
+ 3995                                             WHILE k < reps DO
+ 3996                                               AstAppend(AST.NkBlock,
+ 3997                                                 node, tail, astEl);
+ 3998                                               INC(k)
+ 3999                                             END; .) .
+ 4000    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal; node: AST.Node>         (. VAR et, et2: SymTab.TypeIndex;
+ 4001                                               qe, q2: QbeGen.QVal;
+ 4002                                               v, v2: INTEGER;
+ 4003                                               lo: INTEGER;
+ 4004                                               span: CARDINAL;
+ 4005                                               cl, cl2: INTEGER;
+ 4006                                               hasR: BOOLEAN;
+ 4007                                               astEl: AST.Node; .)
+ 4008      =                                   (. hasR := FALSE; .)
+ 4009        Expr<et, qe> (. astEl := astCur; .)
+ 4010        [ ".." Expr<et2, q2>              (. astEl := AST.MakeBin(
+ 4011                                               AST.NkSubrange, 0, astEl, astCur);
+ 4012                                             hasR := TRUE; .) ]
+ 4013                                          (. lo := SymTab.SetBaseLo(st);
+ 4014                                             span := SymTab.SetCount(st);
+ 4015                                             IF (et = SymTab.InvalidType)
+ 4016                                                OR (hasR AND (et2 =
+ 4017                                                   SymTab.InvalidType)) THEN
+ 4018                                             ELSE cl :=
+ 4019                                                    SymTab.ClassOf(et);
+ 4020                                               IF hasR THEN
+ 4021                                                 cl2 :=
+ 4022                                                   SymTab.ClassOf(et2)
+ 4023                                               ELSE cl2 := SymTab.ClInt
+ 4024                                               END;
+ 4025                                               IF NOT SymTab.SetElemClassOk(cl)
+ 4026                                                  OR (hasR AND NOT
+ 4027                                                     SymTab.SetElemClassOk(cl2))
+ 4028                                               THEN
+ 4029                                                 SemError(222)
+ 4030                                               ELSIF hasR
+ 4031   AND SymTab.ConstInt(qe, v)
+ 4032   AND SymTab.ConstInt(q2,
+ 4033                                                     v2)
+ 4034   AND ((v < lo)
+ 4035                                                     OR (v2 < lo)
+ 4036                                                     OR (v >= lo +
+ 4037                                                        VAL(INTEGER, span))
+ 4038                                                     OR (v2 >= lo +
+ 4039                                                        VAL(INTEGER, span))
+ 4040                                                     OR (v > v2)) THEN
+ 4041                                                 SemError(222)
+ 4042                                                ELSIF hasR THEN
+ 4043                                                  QbeGen.SetRange(sq, qe, q2,
+ 4044                                                    lo, span)
+ 4045                                                ELSIF SymTab.ConstInt(qe,
+ 4046                                                        v)
+ 4047   AND ((v < lo)
+ 4048                                                      OR (v >= lo +
+ 4049                                                         VAL(INTEGER,
+ 4050                                                           span))) THEN
+ 4051                                                  SemError(222)
+ 4052                                                ELSE QbeGen.SetBit(sq, qe,
+ 4053                                                  lo, span)
+ 4054                                               END
+ 4055                                             END; .)
+ 4056                                          (. AST.SetChild(node,
+ 4057                                               AST.NChild(node), astEl); .) .
+ 4058    GetIdent<VAR n: SymTab.Name>
+ 4059      = ident                             (. LexName(n); .) .
+ 4060  
+ 4061  END M2.
 
     0 errors
 

+ 17 - 0
compiler/tests/t_constbuiltin.mod

@@ -0,0 +1,17 @@
+MODULE TConstBuiltin;
+// CONST initialisers that call builtins over immediates: CAP, ABS, ODD
+// and MIN/MAX of a set type all fold to a scalar constant.  Exit 42.
+TYPE CS = SET OF [3..20];
+CONST A  = CAP('a');
+      B  = ABS(-7);
+      C  = ODD(9);
+      D  = ODD(4);
+      Z  = CAP(VAL(CHAR, 97));
+      Lo = MIN(CS);
+      Hi = MAX(CS);
+VAR ExitCode : INTEGER;
+BEGIN
+  IF (A = 'A') AND (Z = 'A') AND (B = 7) AND C AND NOT D
+     AND (Lo = 3) AND (Hi = 20)
+  THEN ExitCode := 42 ELSE ExitCode := 1 END
+END TConstBuiltin.

+ 1 - 1
docs/INDEX.md

@@ -28,7 +28,7 @@ bisecting *why* a decision was made, not for reading end-to-end).
 - `summary_corpus-sweep-2026-10-18.md` — corpus sweep (builtins, bool/enum
   bounds, set-of-enum, forward set); set-constant + folding findings.
 - `summary_set-constants-2026-10-18.md` — SET CONST landed (static
-  masks, folded unions).
+  masks, folded unions) + builtin CONST folding (CAP/ABS/ODD, BOOLEAN consts).
 - `summary_dlist-showcase-2026-10-16.md` — showcase23 + limitation fixes.
 - `summary_generics-limitations-fixed-2026-10-16.md` — the two
   template/proc-param limitations, fixed.

+ 11 - 11
docs/STATUS.md

@@ -4,10 +4,10 @@ This answers "where are we now?".
 
 ## Numbers
 
-- Suite **225/225** (`compiler/run_tests.sh`).
+- Suite **226/226** (`compiler/run_tests.sh`).
 - Self-hosting **FIXPOINT OK** — stage2 and stage3 images are
-  byte-identical (3,823,438 bytes).
-- Corpus **387 / 612** sources compile with 0 errors, **0 crashes**
+  byte-identical (3,826,628 bytes).
+- Corpus **389 / 612** sources compile with 0 errors, **0 crashes**
   (`tools/v3-corpus/corpus.sh` over the gm2 testsuite); the rest are
   genuine language gaps or unresolved imports.
 - Branch **`resolve-check`**; tree clean.
@@ -57,7 +57,9 @@ parameters, constraints, nested generics, generic classes.
   corpus 365 → 381.
 - **SET CONST** (static masks): a set constant (`CharSet{"0".."9"}`,
   a union of set constants) is folded to a mask at parse and re-emitted
-  as a pooled `data $setN` descriptor: corpus 382 → 387.
+  as a pooled `data $setN` descriptor.  **Builtin `CONST` folding**
+  (`CAP`/`ABS`/`ODD` over immediates) and `BOOLEAN` `CONST`s also
+  landed: corpus 382 → 389.
 - Clean `M2` exit codes (0 ok / 1 errors / 2 usage-IO).
 - Bug fixes: `PopPos` wiping repass diagnostics; global record data
   size (`w 0` → `l 0` for pointer/`LONGINT`/proc fields); template
@@ -67,12 +69,10 @@ parameters, constraints, nested generics, generic classes.
 
 ## What remains
 
-1. **Corpus language gaps** — `SET CONST` landed (2026-10-18); the top
-   remaining buckets are `not supported yet`, `undeclared identifier`,
-   `invalid call`.  Next recorded item: **builtin calls in `CONST`**
-   (`CAP(VAL(CHAR,65))`, `MIN`/`MAX` of sets) — fold builtins over
-   immediates.  Separate genuine gaps from missing stdlib imports
-   (`LIB`).  See `docs/analysis_gaps.md`.
+1. **Corpus language gaps** — `SET CONST` and builtin `CONST` folding
+   landed (2026-10-18); the top remaining buckets are `not supported
+   yet`, `undeclared identifier`, `invalid call`.  Separate genuine gaps
+   from missing stdlib imports (`LIB`).  See `docs/analysis_gaps.md`.
 2. **The size-sensitive V3 miscompile** — the long-standing "removing
    `ASTDUMP` from `M2.atg` breaks the fixpoint" has never been
    root-caused.  A real correctness landmine.
@@ -87,7 +87,7 @@ parameters, constraints, nested generics, generic classes.
 ```sh
 cd compiler
 ./build.sh          # M2.atg -> scanner/parser/driver -> ./M2
-./run_tests.sh      # 225/225
+./run_tests.sh      # 226/226
 cd ..
 ./bootstrap/fixpoint.sh   # FIXPOINT OK (byte-identical stage2/stage3)
 ```

+ 10 - 9
docs/analysis_gaps.md

@@ -186,12 +186,13 @@ one-liners** (deliberately left as `230`, no silent miscompile):
    suite tests `t_setconst`/`t_bad_setconst`.  `setconst3` still fails
    on its *forward* `CONST` reference in a `VAR` bound (separate gap).
 2. **Builtin calls in `CONST`** (`CONST A = CAP(VAL(CHAR,
-   65))`, `testcap2.mod`; `MIN`/`MAX` of sets, `minmaxreal3`,
-   `testlongint`).  `VAL` over ordinals already leaves the operand's
-   immediate in place, but `CAP`/`ABS`/`ODD`/… set the runtime sentinel
-   `"@"`, so `ConstDecl`'s `IsImm` check rejects them.  A principled fix
-   is to fold these builtins when their operand is an immediate.
-   **Still open.**
-
-Both bounded once the static-mask / fold helpers exist.  The
-static-mask helper now exists (§9.1).
+   65))`, `testcap2.mod`; `MIN`/`MAX` of sets).  **DONE (2026-10-18).**
+   `CAP`/`ABS`/`ODD` now fold over an immediate operand in the grammar's
+   `Fact` (so `ConstDecl`'s `IsImm` check accepts them); `MIN`/`MAX` of a
+   set already folded via `TypeBounds`.  A `BOOLEAN` `CONST` other than
+   `TRUE`/`FALSE` was also rejected at the designator — the grammar's
+   `Design` class list was missing `ClBool`.  Corpus **387 -> 389**;
+   suite test `t_constbuiltin`.  `constcast` (REAL<->CARDINAL `CONST`
+   conversions) and `minmaxreal3` (SYSTEM `REAL64`) remain.
+
+Both recorded features are now closed.

+ 30 - 16
docs/summary_set-constants-2026-10-18.md

@@ -1,14 +1,16 @@
-# Session summary — SET CONST (static masks) 2026-10-18
+# Session summary — SET CONST + builtin CONST folding 2026-10-18
 
-Branch **`resolve-check`**.  Suite **225/225**; fixpoint **OK
-(3,823,438 bytes)**; corpus **387/612 compile-OK, 0 crashes**.
+Branch **`resolve-check`**.  Suite **226/226**; fixpoint **OK
+(3,826,628 bytes)**; corpus **389/612 compile-OK, 0 crashes**.
 
-Tag: `v3-set-constants`.
+Tags: `v3-set-constants`, `v3-const-builtin-fold`.
 
 ## What this session did
 
-Landed **set constants** — the first of the two features recorded in
-`docs/analysis_gaps.md` §9 — from the previous corpus sweep.
+Landed the two features recorded in `docs/analysis_gaps.md` §9 by the
+previous corpus sweep: **set constants** (static masks) and **builtin
+calls in `CONST` initialisers**.  Corpus **382 → 389** (+7 files, 0
+crashes).
 
 ```mod
 CONST Digits = CharSet{"0".."9"};          (* char range *)
@@ -17,9 +19,8 @@ CONST Digits = CharSet{"0".."9"};          (* char range *)
       Warm   = CS{Red, Blue};              (* enum base *)
 ```
 
-Corpus **382 → 387** (+5 files: `setconst`, `setconst2`, and 3 more),
-0 crashes.  New suite tests `t_setconst` (run, exit 42) and
-`t_bad_setconst` (reject, 230).
+New suite tests: `t_setconst` (run), `t_bad_setconst` (reject),
+`t_constbuiltin` (run).
 
 ## Why it was reverted before, and the fix
 
@@ -52,30 +53,43 @@ Bound: masks are folded up to **16 words (512 bits)**; a wider `SET
 CONST` stays a `230` (`MaxCFoldW`).  The corpus set constants are
 ≤ 8 words.
 
+## Builtin CONST folding
+
+`CAP`/`ABS`/`ODD` set the runtime sentinel `"@"`, so a `CONST` such as
+`A = CAP(VAL(CHAR, 65))` (`testcap2`) was a `230`.  They now fold over
+an immediate operand in the grammar (`Fact`): `CAP` uppercases a CHAR,
+`ABS` takes the magnitude, `ODD` yields `0`/`1`.  This only feeds the
+`ConstDecl` `IsImm` check (Lower re-lowers from the AST, so runtime code
+is unchanged).
+
+`MIN`/`MAX` of a set type already folded via `TypeBounds`.  A
+`BOOLEAN` `CONST` other than `TRUE`/`FALSE` was also rejected at the
+designator — the grammar's `Design` class list was missing `ClBool`
+(Lower already had it); added.  Corpus **387 → 389**.
+
 ## Not fixed (recorded)
 
 - **`setconst3.mod`** still fails: its `VAR mem: ARRAY [0..CARDINAL(
   addressLines)]` names a `CONST` declared *after* the `VAR` (a forward
   CONST reference), which is a separate gap.  Its `SET CONST` itself now
   parses.
-- **Builtin calls in `CONST`** (`CAP(VAL(CHAR,65))`, `MIN`/`MAX` of
-  sets) — still the second recorded feature; fold builtins over
-  immediates.
+- `constcast.mod` (`REAL`↔`CARDINAL` `CONST` conversions) and
+  `minmaxreal3.mod` (SYSTEM `REAL64`) remain.
 
 ## Files
 
 `compiler/src/Lower.{def,mod}` (evaluator + `PoolSet` call),
 `compiler/src/QbeGen.{def,mod}` (`PoolSet`/`FlushSets`/pool state),
-`compiler/src/M2.atg` (`ConstDecl`, `Design`),
+`compiler/src/M2.atg` (`ConstDecl`, `Design`, `CAP`/`ABS`/`ODD` folds),
 `compiler/tests/t_setconst.mod`, `compiler/tests/t_bad_setconst.mod`,
-`compiler/run_tests.sh`.
+`compiler/tests/t_constbuiltin.mod`, `compiler/run_tests.sh`.
 
 ## Resume
 
 ```sh
 cd .../m2compiler-V3
 git checkout resolve-check
-cd compiler && ./build.sh && ./run_tests.sh   # 225/225
+cd compiler && ./build.sh && ./run_tests.sh   # 226/226
 cd .. && TMP="$PWD/.scratch/fixpoint" ./bootstrap/fixpoint.sh
-M2FLAGS="" ./.scratch/corpusx.sh              # 387 OK, 0 crash
+M2FLAGS="" ./.scratch/corpusx.sh              # 389 OK, 0 crash
 ```