FILE: M2GImpl.mesa
Modula-2 Code-Generator Part 1
Last Edited by: Gutknecht, September 20, 1985 11:33:54 pm PDT
Satterthwaite December 12, 1985 10:43:28 am PST

DIRECTORY
M2D: TYPE USING [WordSize, StrForm, ObjPtr, HeaderPtr, ConstPtr, TypPtr, VarPtr, FieldPtr, ProcPtr, EnumPtr, ModulePtr, StrPtr, RangePtr, SetPtr, PointerPtr, ArrayPtr, ProcTypPtr, PDPtr, CDPtr, ParPtr, mainmod, undftyp, notyp, inttyp, cardtyp, realtyp, dbltyp, booltyp, chartyp, wordtyp, bitstyp, addrtyp, lrltyp, SET, UNION, INTERSECTION, SETDIFF, SYMMDIFF, SUBSET],
M2G: TYPE USING [ItemPtr, Item, LabelRange, LabelTabPtr],
M2I: TYPE USING [Relation, inv, pc, Reloc, PutOI, PutOB, PutODB, PutOQB, PutRR, PutQR, PutLR, PutLRB, PutLRRB, PutJBB, PutRJB, PutExch, PutLod, PutAdd, PutSub, PutBJ, PutFJ, PutROp, PutSOp, FixByte, FixLong, FixJmp, FixLink, MergedLinks],
M2S: TYPE USING [Symbol, Mark];
M2GImpl : CEDAR PROGRAM
IMPORTS M2D, M2I, M2S
EXPORTS M2G =
BEGIN OPEN M2G;
DFC: CARDINAL = 61B; LIQB: CARDINAL = 62B; J5: CARDINAL = 66B; CALL: CARDINAL = 70B; RX: CARDINAL = 102B; BC: CARDINAL = 103B; ADD: CARDINAL = 104B; SUB: CARDINAL = 105B; DUP: CARDINAL = 110B; DIS: CARDINAL = 111B; EXDIS: CARDINAL = 113B; SFC: CARDINAL = 114B; RETN: CARDINAL = 116B; J1: CARDINAL = 126B; SJ: CARDINAL = 127B; LC: CARDINAL = 130B; LR: CARDINAL = 140B; SR: CARDINAL = 160B; QOR: CARDINAL = 200B; QAND: CARDINAL = 201B; QRX: CARDINAL = 202B; QADD: CARDINAL = 204B; QSUB: CARDINAL = 205B; ALS: CARDINAL = 210B; AS: CARDINAL = 213B; CST: CARDINAL = 214B; RET: CARDINAL = 216B; LIB: CARDINAL = 222B; ADDB: CARDINAL = 224B; J2: CARDINAL = 226B; RB: CARDINAL = 230B; RSB: CARDINAL = 232B; WSB: CARDINAL = 233B; LRI: CARDINAL = 240B; SRI: CARDINAL = 260B; ROR: CARDINAL = 300B; RAND: CARDINAL = 301B; RADD: CARDINAL = 304B; RSUB: CARDINAL = 305B; RXOR: CARDINAL = 310B; RFU: CARDINAL = 312B; LFC: CARDINAL = 321B; LIDB: CARDINAL = 322B; LIPC: CARDINAL = 323B; J3: CARDINAL = 326B; JDB: CARDINAL = 327B; RRI: CARDINAL = 332B; WRI: CARDINAL = 333B; RJLB: CARDINAL = 342B; RJLEB: CARDINAL = 343B; RJGEB: CARDINAL = 346B; RJGB: CARDINAL = 347B; JEBB: CARDINAL = 360B; SHL: CARDINAL = 370B; SHR: CARDINAL = 371B; FSDB: CARDINAL = 373B;
Trap: CARDINAL = 0; Move: CARDINAL = 1; Mult: CARDINAL = 2; Div: CARDINAL = 3; Mod: CARDINAL = 4; RealAdd: CARDINAL = 5; RealSub: CARDINAL = 6; RealMult: CARDINAL = 7; RealDiv: CARDINAL = 8; Alloc: CARDINAL = 9; Dealloc: CARDINAL = 10; MakeBit: CARDINAL = 11; MakeBits: CARDINAL = 12;
utilities
exp: CARDINAL ← 0;
err: PROC [n: CARDINAL] = { M2S.Mark [n] };
clog: PROC [x: CARDINAL] RETURNS [CARDINAL] =
{ exp ← 0;
IF x > 0 THEN
WHILE x MOD 2 = 0 DO x ← x/2; exp ← exp + 1 ENDLOOP;
RETURN [x] };
SRTest: PROC [x: ItemPtr] =
{ WITH x^.typ SELECT FROM
range: M2D.RangePtr => x^.typ ← range^.BaseTyp;
ENDCASE };
statements
PutStore: PROC [x, y: ItemPtr] =
{ IF x^.mode = regMd THEN
IF y^.mode = opnMd THEN M2I.PutROp [y^.opr, x^.reg, y^.opt, y^.reg, y^.opt2, y^.reg2]
ELSE { LoadStk [y]; M2I.PutLR [SR+x^.reg] }
ELSE { LoadStk [y];
IF x^.mode = ladrMd THEN M2I.PutLRB [SRI+x^.reg, x^.off]
ELSE IF x^.mode = sadrMd THEN M2I.PutOB [WSB, x^.off]
ELSE IF x^.mode # stkMd THEN err [300] }};
GenItem: PUBLIC PROC [x: ItemPtr, y: M2D.ObjPtr, Scope: M2D.HeaderPtr] =
{ IF y # NIL THEN { x^.typ ← y^.typ;
WITH y SELECT FROM
const: M2D.ConstPtr => {
   x^.mode ← conMd;
   x^.val.D0 ← const^.conval.D0; x^.val.D1 ← const^.conval.D1;
   x^.val.D2 ← const^.conval.D2; x^.val.D3 ← const^.conval.D3 };
typ: M2D.TypPtr => { x^.mode ← typMd };
var: M2D.VarPtr => { x^.mode ← varMd; x^.obj ← y };
field: M2D.FieldPtr => {
   IF (x^.contxt^.lev # 0) AND (Scope^.cell < 16) THEN
    { x^.mode ← ladrMd; x^.reg ← Scope^.cell }
   ELSE { M2I.PutLRB [LRI+x^.contxt^.LNK+1, Scope^.cell];
    x^.mode ← sadrMd };
   x^.off ← field^.offset };
proc: M2D.ProcPtr => {
   x^.mode ← (IF proc^.bd^.form = Block THEN procMd ELSE codMd);
   x^.obj ← y; x^.typ ← M2D.undftyp };
mod: M2D.ModulePtr => { x^.mode ← stkMd; err [107] }
ENDCASE }
ELSE { err [50]; x^.typ ← M2D.undftyp; x^.mode ← stkMd }};
GenIndex: PUBLIC PROC [x, y: ItemPtr] =
{ SRTest [y]; -- (x^.mode = ladrMd) OR (x^.mode = sadrMd)
WITH x^.typ SELECT FROM
array: M2D.ArrayPtr => {
eltyp: M2D.StrPtr = array^.ElemTyp;
IF array^.dyn THEN { LoadStk [y];
IF (y^.typ # M2D.cardtyp) AND (y^.typ # M2D.inttyp) THEN err [109];
IF rngchk THEN
{ var: M2D.VarPtr = NARROW [x^.obj];
M2I.PutLR [LR+var^.cell+1]; M2I.PutOI [BC] };
IF x^.mode = sadrMd THEN x^.mode ← sinxMd ELSE x^.mode ← linxMd }
ELSE
{ range: M2D.RangePtr = NARROW [array^.IndexTyp];
inxtyp: M2D.StrPtr ← range^.BaseTyp;
m: INTEGER = range^.min; n: INTEGER = range^.max;
IF y^.mode = conMd THEN { sz: CARDINAL; i: INTEGER ← y^.val.I;
IF inxtyp # y^.typ THEN
IF (i < 0) OR (inxtyp = M2D.cardtyp) AND (y^.typ # M2D.inttyp) OR (inxtyp = M2D.inttyp) AND (y^.typ # M2D.cardtyp) THEN err [109];
IF (m <= i) AND (i <= n) THEN i ← i - m ELSE { err [108]; i ← 0 };
sz ← eltyp^.size * i;
IF eltyp^.form = Char THEN {};
IF x^.off + sz < 256 THEN x^.off ← x^.off + sz
ELSE { M2I.PutLod [x^.off + sz];
IF x^.mode = sadrMd THEN x^.mode ← sinxMd ELSE x^.mode ← linxMd }}
ELSE { LoadStk [y];
IF (inxtyp # y^.typ) AND ((inxtyp # M2D.cardtyp) OR (y^.typ # M2D.inttyp)) AND ((inxtyp # M2D.inttyp) OR (y^.typ # M2D.cardtyp)) THEN { err [109] };
IF m # 0 THEN M2I.PutSub [m];
IF rngchk THEN { M2I.PutLod [n+1-m]; M2I.PutOI [BC] };
IF eltyp^.size # 1 THEN
IF clog [eltyp^.size] = 1 THEN M2I.PutODB [SHL, 32*64+exp]
ELSE { M2I.PutLod [eltyp^.size]; M2I.PutOQB [CALL, Mult] };
IF x^.mode = sadrMd THEN x^.mode ← sinxMd ELSE x^.mode ← linxMd }};
x^.typ ← eltyp };
ENDCASE => err [109] };
GenField: PUBLIC PROC [x: ItemPtr, f: M2D.ObjPtr] =
{ -- x^.typ^.form = Record --
WITH f SELECT FROM
field: M2D.FieldPtr => {
LoadAdr [x];
IF x^.off + field^.offset < 256 THEN x^.off ← x^.off + field^.offset
ELSE { M2I.PutLod [x^.off + field^.offset];
IF x^.mode = sadrMd THEN M2I.PutOI [ADD]
ELSE { M2I.PutQR [QADD, 0, 0, x^.reg]; x^.mode ← sadrMd };
x^.off ← 0 };
x^.typ ← f^.typ };
const: M2D.ConstPtr => {
x^.mode ← conMd; x^.typ ← f^.typ;
x^.val.D0 ← const^.conval.D0; x^.val.D1 ← const^.conval.D1;
x^.val.D2 ← const^.conval.D2; x^.val.D3 ← const^.conval.D3 };
ENDCASE => { err [110];
x^.typ ← M2D.undftyp; x^.mode ← sadrMd; x^.off ← 0 }};
GenDeRef: PUBLIC PROC [x: ItemPtr] =
{ WITH x^.typ SELECT FROM
pointer: M2D.PointerPtr => { Load [x]; x^.typ ← pointer^.BaseTyp };
ENDCASE =>
IF x^.typ = M2D.addrtyp THEN { Load [x]; x^.typ ← M2D.wordtyp }
ELSE err [111];
IF x^.mode = regMd THEN x^.mode ← ladrMd ELSE x^.mode ← sadrMd;
x^.off ← 0 };
GenSingSet: PUBLIC PROC [x, e: ItemPtr] =
{ -- x^.typ^.form = Set
set: M2D.SetPtr = NARROW [x^.typ];
s: M2D.StrPtr ← set^.BaseTyp;
x^.mode ← stkMd; SRTest [e];
IF s^.form = Range THEN
{ range: M2D.RangePtr = NARROW [s]; s ← range^.BaseTyp };
IF e^.typ = s THEN
IF e^.mode = conMd THEN
{ x^.mode ← conMd; x^.val.S ← ALL [FALSE];
IF e^.val.C < M2D.WordSize THEN x^.val.S [e^.val.C] ← TRUE
ELSE err [202] }
ELSE { LoadStk [e]; M2I.PutOQB [CALL, MakeBit] }
ELSE err [116] };
GenSet: PUBLIC PROC [x, e1, e2: ItemPtr] =
{ -- x^.typ^.form = Set
set: M2D.SetPtr = NARROW [x^.typ];
s: M2D.StrPtr ← set^.BaseTyp;
x^.mode ← stkMd; SRTest [e1]; SRTest [e2];
IF s^.form = Range THEN
{ range: M2D.RangePtr = NARROW [s]; s ← range^.BaseTyp };
IF (e1^.typ = s) AND (e2^.typ = s) THEN
IF (e1^.mode = conMd) AND (e2^.mode = conMd) THEN
{ x^.mode ← conMd; x^.val.S ← ALL [FALSE];
IF (e1^.val.C <= e2^.val.C) AND (e2^.val.C < M2D.WordSize) THEN
{ i: CARDINAL ← e1^.val.C;
DO x^.val.S [i] ← TRUE;
IF i = e2^.val.C THEN EXIT;
i ← i + 1
ENDLOOP }
ELSE err [202] }
ELSE { LoadStk [e1]; LoadStk [e2]; M2I.PutOQB [CALL, MakeBits];
LoadStk [x]; M2I.PutRR [ROR, 1, 1, 1, 0, 13, 14, 13] }
ELSE err [116] };
MoveDyn: PROC [x, y: ItemPtr] =
{ var: M2D.VarPtr = NARROW [x^.obj];
xarray: M2D.ArrayPtr = NARROW [x^.typ];
LoadStk [y]; M2I.PutLR [LR+var^.cell+1];
IF xarray^.ElemTyp^.size # 1 THEN
{ M2I.PutLod [xarray^.ElemTyp^.size]; M2I.PutOQB [CALL, Mult] };
M2I.PutOQB [CALL, Move] };
PrepAss: PUBLIC PROC [x: ItemPtr] =
{ IF (x^.mode = conMd) OR (x^.mode = procMd) THEN err [142];
IF (x^.typ^.form = Array) OR (x^.typ^.form = Record) THEN LoadAdrStk [x]
ELSE
{ IF x^.mode = varMd THEN
{ var: M2D.VarPtr = NARROW [x^.obj];
IF (x^.contxt^.lev = var^.lev) AND (var^.lev # 0) AND (var^.cell < 16) AND NOT var^.varpar THEN { x^.opt ← 0; x^.reg ← var^.cell; x^.mode ← regMd }
ELSE LoadAdr [x] }
ELSE IF x^.mode = linxMd THEN
{ M2I.PutQR [QADD, 0, 0, x^.reg]; x^.mode ← sadrMd; x^.off ← 0 }
ELSE IF x^.mode = sinxMd THEN
{ M2I.PutOI [ADD]; x^.mode ← sadrMd; x^.off ← 0 }}};
GenAssign: PUBLIC PROC [x, y: ItemPtr] =
{ f: M2D.StrForm ← x^.typ^.form; g: M2D.StrForm ← y^.typ^.form;
xp, yp: M2D.ParPtr; s, vsz: INTEGER;
SRTest [y];
IF f = Range THEN
{ range: M2D.RangePtr = NARROW [x^.typ];
IF rngchk THEN
IF y^.mode = conMd THEN
{ IF (y^.val.I < range^.min) OR (y^.val.I > range^.max) THEN err [138] }
ELSE { IF x^.mode # stkMd THEN LoadStk [x];
IF range^.min = 0 THEN { M2I.PutLod [range^.max+1]; M2I.PutOI [BC] }
ELSE { M2I.PutOI [DUP]; M2I.PutSub [range^.min] };
M2I.PutLod [range^.max+1-range^.min]; M2I.PutOI [BC]; M2I.PutOI [DIS] };
x^.typ ← range^.BaseTyp };
SELECT f FROM
Undef  => IF (x^.typ = M2D.wordtyp) AND (y^.typ^.size = 1) THEN PutStore [x, y]
    ELSE err [133];
Bool  => IF y^.mode = jmpMd THEN { [] ← GenCFJ [y];
    M2I.PutOI [LC+1]; M2I.PutODB [JDB, 4];
    M2I.FixLink [y^.Fjmp, M2I.pc]; M2I.PutOI [LC+0];
    PutStore [x, y] }
      ELSE IF g = Bool THEN PutStore [x, y]
      ELSE err [133];
  Char  => IF g = Char THEN PutStore [x, y] ELSE err [133];
  Card  => IF (g = Card) OR (g = Double) THEN PutStore [x, y]
      ELSE IF g = Int THEN
       { IF y^.mode = conMd THEN { IF y^.val.I < 0 THEN err [132] }
       ELSE LoadStk [y]; -- emit check
       PutStore [x, y] }
      ELSE err [133];
  Int  => IF (g = Int) OR (g = Double) THEN
       IF (y^.mode = opnMd) AND (x^.mode = regMd) THEN
        M2I.PutRR [y^.opr, x^.opt, y^.opt, y^.opt2, 0, x^.reg, y^.reg, y^.reg2]
       ELSE PutStore [x, y]
      ELSE IF g = Card THEN
       { IF y^.mode = conMd THEN { IF y^.val.C > MaxInt THEN err [208] }
       ELSE LoadStk [y]; -- emit check --
       PutStore [x, y] }
      ELSE err [133];
  Double => IF (g = Double) OR (g = Int) OR (g = Card) OR
      (x^.typ = M2D.addrtyp) AND (g = Pointer) THEN PutStore [x, y]
      ELSE err [133];
  Real  => IF (g = Real) OR (g = LongReal) THEN PutStore [x, y]
      ELSE err [133];
  LongReal => IF (g = Real) OR (g = LongReal) THEN PutStore [x, y]
      ELSE err [133];
  Enum  => IF x^.typ = y^.typ THEN PutStore [x, y]
      ELSE err [133];
  Range  => {};
  Pointer, Opaque => IF (x^.typ = y^.typ) OR (y^.typ = M2D.addrtyp) THEN
       PutStore [x, y]
      ELSE err [133];
  Set  => IF x^.typ = y^.typ THEN PutStore [x, y]
      ELSE err [133];
  Array  => { xarray: M2D.ArrayPtr = NARROW [x^.typ];
      IF xarray^.dyn THEN { var: M2D.VarPtr = NARROW [x^.obj];
       IF y^.typ^.form = Array THEN
        { yarray: M2D.ArrayPtr = NARROW [y^.typ];
        IF (yarray^.ElemTyp = xarray^.ElemTyp) OR
         (xarray^.ElemTyp = M2D.wordtyp) AND
         (yarray^.ElemTyp^.size = 1) THEN MoveDyn [x, y]
        ELSE err [133] }
       ELSE IF (xarray^.ElemTyp = M2D.chartyp) AND (g = String) THEN
        MoveDyn [x, y]
       ELSE err [133] }
      ELSE IF x^.typ = y^.typ THEN { LoadStk [y];
       M2I.PutLod [x^.typ^.size]; M2I.PutOQB [CALL, Move] }
      ELSE IF (xarray^.ElemTyp = M2D.chartyp) THEN
       IF g = String THEN
       { range: M2D.RangePtr = NARROW [xarray^.IndexTyp];
       LoadStk [y];
       s ← y^.val.D1; -- check length --
       vsz ← range^.max - range^.min + 1;
       IF s < vsz THEN s ← s + 1 ELSE IF s > vsz THEN err [146];
       M2I.PutLod [s]; M2I.PutOQB [CALL, Move] }
       ELSE IF g = Char THEN err [200]
       ELSE err [133]
      ELSE err [133] };
  Record => IF x^.typ = y^.typ THEN { LoadStk [y];
       IF x^.mode = sadrMd THEN
       { M2I.PutLod [x^.typ^.size]; M2I.PutOQB [CALL, Move] }}
      ELSE err [133];
  ProcTyp => IF y^.mode = procMd THEN
       { -- procedure to proc. variable; check compatibility
       xproc: M2D.ProcTypPtr = NARROW [x^.typ];
       yproc: M2D.ProcPtr = NARROW [y^.obj];
       ypd: M2D.PDPtr = NARROW [yproc^.bd];
       IF ypd^.lev # 1 THEN err [127]
       ELSE IF xproc^.resTyp # y^.obj^.typ THEN err [128]
       ELSE { xp ← xproc^.firstPar; yp ← yproc^.firstParam;
        WHILE xp # NIL DO
        IF yp # NIL THEN
        { IF (xp^.varpar) # (yp^.varpar) THEN err [129]
        ELSE IF xp^.typ # yp^.typ THEN
        IF (xp^.typ^.form # Array) OR
         (yp^.typ^.form # Array) THEN err [129]
        ELSE
        { xarray: M2D.ArrayPtr = NARROW [xp^.typ];
        yarray: M2D.ArrayPtr = NARROW [yp^.typ];
        IF NOT xarray^.dyn OR NOT yarray^.dyn OR
        (xarray^.ElemTyp # yarray^.ElemTyp) THEN err [129] };
        yp ← yp^.next }
        ELSE err [130];
        xp ← xp^.next
        ENDLOOP;
        IF yp # NIL THEN err [131];
        M2I.PutODB [LIPC, ypd^.num]; y^.mode ← stkMd;
        PutStore [x, y] }}
      ELSE IF x^.typ = y^.typ THEN PutStore [x, y]
  ENDCASE };
LoadDyn: PROC [x: ItemPtr] =
{ var: M2D.VarPtr = NARROW[x^.obj];
dl: CARDINAL ← x^.contxt^.lev - var^.lev;
pd: M2D.PDPtr;
(var^.lev # 0) AND (var^.cell < 16)
IF dl = 0 THEN { M2I.PutLR [LR+var^.cell]; M2I.PutLR [LR+var^.cell+1] }
ELSE { SL: CARDINAL = x^.contxt^.LNK;
pd ← x^.contxt;
IF dl >= 2 THEN
{ M2I.PutLRB [LRI+SL, 0]; pd ← pd^.pAnc; dl ← dl - 2;
WHILE dl # 0 DO M2I.PutOB [RB, 0]; pd ← pd^.pAnc; dl ← dl - 1 ENDLOOP }
ELSE M2I.PutLR [LR+SL];
M2I.PutOB [RSB, IF var^.cell # 0 THEN var^.cell ELSE SL];
M2I.PutExch; M2I.PutOB [RB, var^.cell+1];
pd^.impRegs [var^.cell] ← TRUE; pd^.impRegs [var^.cell+1] ← TRUE };
x^.mode ← stkMd };
GenParam: PUBLIC PROC [ap: ItemPtr, f: M2D.ParPtr] =
{ fp: ItemPtr = NEW [Item];
IF f^.typ^.form = Array THEN
{ farray: M2D.ArrayPtr = NARROW [f^.typ];
IF farray^.dyn THEN
IF ap^.typ^.form = Array THEN
{ aarray: M2D.ArrayPtr = NARROW [ap^.typ];
IF (farray^.ElemTyp = aarray^.ElemTyp) OR (farray^.ElemTyp = M2D.wordtyp) AND (aarray^.ElemTyp^.size = 1) THEN
IF aarray^.dyn THEN LoadDyn [ap]
ELSE { range: M2D.RangePtr = NARROW [aarray^.IndexTyp];
LoadStk [ap]; M2I.PutLod [range^.max+1-range^.min] }
ELSE err [133] }
ELSE IF (farray^.ElemTyp = M2D.chartyp) THEN
IF ap^.typ^.form = String THEN { LoadStk [ap]; M2I.PutLod [ap^.val.D1] }
ELSE IF ap^.typ^.form = Char THEN { LoadStk [ap]; M2I.PutLod [1] }
ELSE err [133]
ELSE err [133]
ELSE IF f^.typ = ap^.typ THEN LoadStk [ap]
ELSE IF farray^.ElemTyp = M2D.chartyp THEN
IF ap^.typ^.form = String THEN LoadStk [ap]
ELSE IF ap^.typ^.form = Char THEN err [200]
ELSE err [133]
ELSE err [133] }
ELSE IF f^.typ^.form = Record THEN
IF f^.typ = ap^.typ THEN LoadStk [ap]
ELSE err [133]
ELSE IF f^.varpar THEN
{ IF (ap^.typ = f^.typ) OR (f^.typ = M2D.wordtyp) AND (ap^.typ^.size = 1) OR (f^.typ = M2D.addrtyp) AND (ap^.typ^.form = Pointer) THEN
{ LoadAdrStk [ap]; ap^.mode ← stkMd }
ELSE err [137] }
ELSE { fp^.mode ← stkMd; fp^.typ ← f^.typ; GenAssign [fp, ap] }};
MoveRegs: PROC [x: ItemPtr, op: CARDINAL] =
{ empty: M2D.SET = ALL [FALSE];
rset: M2D.SET = x^.expRegs; pd: M2D.PDPtr = x^.contxt;
i: CARDINAL;
IF rset # empty THEN
{ SL: CARDINAL = pd^.LNK; FRX: CARDINAL = SL+1;
IF rset [0] THEN M2I.PutLRRB [op, SL, 0, FRX];
i ← 1;
DO IF rset [i] THEN M2I.PutLRRB [op, i, i, FRX];
IF i = M2D.WordSize-1 THEN EXIT;
i ← i + 1
ENDLOOP;
pd^.needsBUP ← TRUE }};
PrepCall: PUBLIC PROC [x: ItemPtr] RETURNS [fpar: M2D.ParPtr] =
{ IF x^.mode = procMd OR x^.mode = codMd THEN
{ proc: M2D.ProcPtr = NARROW [x^.obj]; fpar ← proc^.firstParam }
ELSE IF x^.typ^.form = ProcTyp THEN
{ proctyp: M2D.ProcTypPtr = NARROW [x^.typ]; fpar ← proctyp^.firstPar }
ELSE { err [136]; fpar ← NIL; x^.typ ← M2D.undftyp }};
GenCall: PUBLIC PROC [x: ItemPtr] =
{ i, dl, len: CARDINAL;
IF x^.mode = procMd THEN
{ pd: M2D.PDPtr = NARROW [NARROW [x^.obj, M2D.ProcPtr]^.bd];
IF pd^.mod = 0 THEN -- internal call
IF x^.contxt^.lev = 0 THEN M2I.PutODB [LFC, pd^.pc - M2I.pc]
ELSE
{ IF pd^.lev > 1 THEN -- provide SL
{ SL: CARDINAL = x^.contxt^.LNK; FRX: CARDINAL = SL+1;
IF x^.contxt^.lev >= pd^.lev THEN
{ dl ← x^.contxt^.lev - pd^.lev;
IF dl >= 1 THEN { M2I.PutLRB [LRI+SL, 0]; dl ← dl - 1;
WHILE dl # 0 DO M2I.PutOB [RB, 0]; dl ← dl - 1 ENDLOOP }
ELSE M2I.PutLR [LR+SL] }
ELSE -- nested proc call
{ x^.expRegs ← M2D.UNION [x^.expRegs, pd^.impRegs];
x^.contxt^.needsBUP ← TRUE; M2I.PutLR [LR+FRX] }};
MoveRegs [x, WRI]; M2I.PutODB [LFC, pd^.pc - M2I.pc]; MoveRegs [x, RRI] }
ELSE IF x^.contxt^.lev = 0 THEN M2I.PutOQB [DFC, pd^.mod*256 + pd^.num]
ELSE { MoveRegs [x, WRI];
M2I.Reloc; M2I.PutOQB [DFC, pd^.mod*256 + pd^.num]; MoveRegs [x, RRI] };
x^.typ ← x^.obj^.typ }
ELSE IF x^.mode = codMd THEN
{ cd: M2D.CDPtr = NARROW [NARROW [x^.obj, M2D.ProcPtr]^.bd];
len ← cd^.length; i ← 0;
WHILE i < len DO M2I.FixByte [cd^.cod[i]]; i ← i + 1 ENDLOOP;
x^.typ ← x^.obj^.typ }
ELSE IF x^.typ^.form = ProcTyp THEN
{ proctyp: M2D.ProcTypPtr = NARROW [x^.typ];
LoadStk [x]; M2I.PutOI [SFC];
x^.typ ← proctyp^.resTyp };
x^.mode ← stkMd };
InitMods: PROC [obj: M2D.ObjPtr] =
{ WHILE obj # NIL DO
IF obj^.class = Module THEN
{ module: M2D.ModulePtr = NARROW [obj];
InitMods [module^.firstObj]; M2I.PutODB [LFC, module^.pc - M2I.pc] };
obj ← obj^.next
ENDLOOP };
InitFRXVars: PROC [obj: M2D.ObjPtr, FRX, A, a: CARDINAL] RETURNS [CARDINAL] =
{ WHILE obj # NIL DO
WITH obj SELECT FROM
var: M2D.VarPtr => {
IF (obj^.typ^.form = Array) OR (obj^.typ^.form = Record) THEN
{ sz: CARDINAL = obj^.typ^.size; a ← a + sz;
IF a # A THEN
{ M2I.PutOI [DUP]; M2I.PutLRB [SRI+FRX, var^.cell]; M2I.PutAdd [sz] }
ELSE M2I.PutLRB [SRI+FRX, var^.cell] }};
module: M2D.ModulePtr =>
a ← InitFRXVars [module^.firstObj, FRX, A, a];
ENDCASE;
obj ← obj^.next
ENDLOOP;
RETURN [a] };
GenEnterM: PUBLIC PROC [mod: M2D.ModulePtr] =
{ IF mod^.prio > 0 THEN {}};
GenInitM: PUBLIC PROC [mod: M2D.ModulePtr, modno: CARDINAL] RETURNS [loc: CARDINAL ] = { -- main module --
s, a, A: CARDINAL;
FRX: CARDINAL = mod^.pAnc^.LNK+1;
M2I.Reloc; M2I.PutOQB [LIQB, 0]; M2I.PutOB [ALS, 0]; -- adr [literals]
M2I.Reloc; M2I.PutOQB [LIQB, 1]; -- to global FRX
M2I.PutLRRB [WRI, 0, 0, 1]; -- init adr [literals] in mem
M2I.PutOI [LC+1]; M2I.PutOI [LC+0];
M2I.PutOB [CST, 1]; M2I.PutJBB [JEBB, 5, 0]; -- check init flag
M2I.PutOB [RET, 127]; M2I.PutOB [AS, 126];
a ← 0; A ← mod^.pAnc^.adr; loc ← M2I.pc;
IF a # A THEN
{ M2I.PutOI [J1]; M2I.PutOB [J2, 0] }; -- ld offset mem var space
[] ← InitFRXVars [mod^.firstObj, FRX, mod^.pAnc^.adr, 0];
s ← 1; -- init imports --
WHILE s < modno DO s ← s + 1 ENDLOOP;
InitMods [mod^.firstObj] };
GenEnterP: PUBLIC PROC [proc: M2D.ProcPtr] RETURNS [loc1, loc2: CARDINAL] =
{ pd: M2D.PDPtr = NARROW [proc^.bd];
IF pd^.lev = 1 THEN { M2I.Reloc; M2I.PutOQB [LIQB, 1] };
M2I.PutOB [ALS, 128 - pd^.LNK];
alloc FRX
loc1 ← M2I.pc; M2I.PutODB [J3, 0]; M2I.PutOQB [J5, 0];
gen SL in FRX
loc2 ← M2I.pc; M2I.PutODB [J3, 0];
IF pd^.mAnc^.prio # 0 THEN {}};
GenInitP: PUBLIC PROC [proc: M2D.ProcPtr] RETURNS [loc1, loc2, cell: CARDINAL]=
{ a, A, r: CARDINAL; obj: M2D.ObjPtr; par: M2D.ParPtr;
pd: M2D.PDPtr = NARROW [proc^.bd];
InitPar: PROC [reg, sz: CARDINAL] =
{ a ← a + sz;
IF a # A THEN { M2I.PutOI [DUP]; M2I.PutOI [DUP];
M2I.PutLR [LR+reg]; M2I.PutLod [sz]; M2I.PutOQB [CALL, Move];
M2I.PutLR [SR+reg]; M2I.PutAdd [sz] }
ELSE { M2I.PutOI [DUP];
M2I.PutLR [LR+reg]; M2I.PutLod [sz]; M2I.PutOQB [CALL, Move];
M2I.PutLR [SR+reg] }};
InitVars: PROC [obj: M2D.ObjPtr] =
{ DO
IF obj = NIL THEN EXIT;
WITH obj SELECT FROM
var: M2D.VarPtr => {
IF var^.cell >= 16 THEN EXIT;
IF (obj^.typ^.form = Array) OR (obj^.typ^.form = Record) THEN
{ sz: CARDINAL ← obj^.typ^.size; a ← a + sz;
IF a # A THEN { M2I.PutOI [DUP]; M2I.PutAdd [sz] }}
ELSE M2I.PutOI [DUP] };
module: M2D.ModulePtr => InitVars [module^.firstObj];
ENDCASE;
obj ← obj^.next
ENDLOOP;
[] ← InitFRXVars [obj, pd^.LNK+1, A, a] };
a ← 0; A ← pd^.adr; loc1 ← M2I.pc;
IF a # A THEN { M2I.PutOI [J1]; M2I.PutOB [J2, 0] }; -- ld data offset
par ← proc^.firstParam; obj ← pd^.firstLocal;
WHILE par # NIL DO
IF (obj^.typ^.form = Array) OR (obj^.typ^.form = Record) THEN
{ var: M2D.VarPtr = NARROW [obj];
IF NOT var^.varpar THEN
IF obj^.typ^.form = Array THEN
{ array: M2D.ArrayPtr = NARROW [obj^.typ];
IF array^.dyn THEN
{ M2I.PutLR [LR+var^.cell+1]; M2I.PutOQB [CALL, Alloc];
M2I.PutOI [DUP]; M2I.PutLR [LR+var^.cell];
M2I.PutLR [LR+var^.cell+1]; M2I.PutOQB [CALL, Move];
M2I.PutLR [SR+var^.cell] }
ELSE InitPar [var^.cell, obj^.typ^.size] }
ELSE InitPar [var^.cell, obj^.typ^.size] };
par ← par^.next; obj ← obj^.next
ENDLOOP;
InitVars [obj];
provide cells for WITH bases
loc2 ← M2I.pc; cell ← pd^.cell; r ← pd^.cell;
WHILE r < 15 DO M2I.PutOI [J1]; r ← r + 1 ENDLOOP;
InitMods [obj] };
GenReturn: PUBLIC PROC [x: ItemPtr, ancestor: M2D.ObjPtr, loc: CARDINAL] RETURNS [Loc: CARDINAL] =
{ res: ItemPtr = NEW [Item];
DeallocDyn: PROC [par: M2D.ParPtr] =
{ reg: CARDINAL ← 0;
WHILE par # NIL DO
IF par^.typ^.form = Array THEN
{ array: M2D.ArrayPtr = NARROW [par^.typ];
IF array^.dyn THEN
{ IF NOT par^.varpar THEN
{ M2I.PutLR [LR+reg]; M2I.PutOQB [CALL, Dealloc] };
reg ← reg + 2 }
ELSE reg ← reg + 1 }
ELSE reg ← reg + 1;
par ← par^.next
ENDLOOP };
Loc ← loc;
IF x^.typ = NIL THEN
{ IF ancestor^.typ # M2D.notyp THEN err [139];
IF ancestor^.class = Proc THEN
{ proc: M2D.ProcPtr = NARROW [ancestor];
pd: M2D.PDPtr = NARROW [proc^.bd];
IF pd^.mAnc^.prio > 0 THEN {};
DeallocDyn [proc^.firstParam];
Dealloc FRX
Loc ← M2I.pc; M2I.PutODB [J3, loc]; M2I.PutODB [J3, 0];
M2I.PutOB [RET, 127] }
ELSE IF ancestor = M2D.mainmod THEN M2I.PutOB [RET, 127]
ELSE M2I.PutOI [RETN] }
ELSE IF ancestor^.class = Proc THEN
{ proc: M2D.ProcPtr = NARROW [ancestor];
pd: M2D.PDPtr = NARROW [proc^.bd];
IF pd^.mAnc^.prio > 0 THEN {};
IF x^.mode < opnMd THEN LoadStk [x];
DeallocDyn [proc^.firstParam];
Dealloc FRX
Loc ← M2I.pc; M2I.PutODB [J3, loc]; M2I.PutODB [J3, 0];
res^.mode ← regMd; res^.opt ← 0; res^.reg ← 0; res^.typ ← ancestor^.typ;
GenAssign [res, x];
M2I.PutOB [RET, 0] }
ELSE err [300] };
GenTrap: PUBLIC PROC [n: CARDINAL] = { M2I.PutOB [LIB, n]; M2I.PutOQB [CALL, Trap] };
GenCase1: PUBLIC PROC [x: ItemPtr] RETURNS [L0: CARDINAL] =
{ f: M2D.StrForm = x^.typ^.form;
IF (f <= Int) OR (f = Enum) OR (f = Range) THEN
{ LoadStk [x]; L0 ← M2I.pc;
M2I.PutOQB [LIQB, 0]; -- low limit --
M2I.PutRJB [RJGEB, 1, 0, 1, 0, 13, 6];
M2I.PutODB [JDB, 0]; -- else jump --
M2I.PutOQB [LIQB, 0]; -- high limit --
M2I.PutRJB [RJLEB, 1, 0, 1, 0, 13, 6];
M2I.PutODB [JDB, 0]; -- else jump --
M2I.PutODB [JDB, 0] }
ELSE { err [140]; L0 ← M2I.pc }};
GenCase2: PUBLIC PROC [l2: CARDINAL] RETURNS [L2: CARDINAL] =
{ L2 ← M2I.pc; M2I.PutODB [JDB, l2] };
GenCase3: PUBLIC PROC [L0, L1, L2, n: CARDINAL, tab: LabelTabPtr] =
{ i: CARDINAL; j: INTEGER;
IF n > 0 THEN
{ M2I.FixLong [L0+1, tab[0].low]; M2I.FixLong [L0+12, tab[n-1].high] };
M2I.FixJmp [L0+8, L1]; M2I.FixJmp [L0+19, L1]; M2I.FixJmp [L0+22, M2I.pc];
M2I.PutSub [tab[0].low]; M2I.PutOI [DUP]; M2I.PutOI [DUP];
M2I.PutOI [ADD]; M2I.PutOI [ADD]; M2I.PutOB [ADDB, 1];
M2I.PutOI [SJ];
i ← 0; j ← tab[0].low;
WHILE i < n DO
WHILE j < tab[i].low DO
M2I.PutODB [JDB, L1 - M2I.pc]; j ← j + 1 -- ELSE --
ENDLOOP;
WHILE j <= tab[i].high DO
M2I.PutODB [JDB, tab[i].label - M2I.pc]; j ← j + 1
ENDLOOP;
i ← i + 1
ENDLOOP;
M2I.FixLink [L2, M2I.pc] };
GenFor1: PUBLIC PROC [v, e1: ItemPtr] =
{ f: M2D.StrForm;
SRTest [v]; f ← v^.typ^.form;
IF (f <= Int) OR (f = Enum) THEN { SRTest [e1]; GenAssign [v, e1] }
ELSE err [142] };
GenFor2: PUBLIC PROC [v, e2: ItemPtr] =
{ SRTest [v]; SRTest [e2];
IF (v^.typ = e2^.typ) OR (v^.typ = M2D.inttyp) AND (e2^.typ = M2D.cardtyp) AND (e2^.mode = conMd) AND (e2^.val.C < MaxInt) THEN LoadStk [e2]
ELSE err [117] };
GenFor3: PUBLIC PROC [v, e2, e3: ItemPtr] RETURNS [L0, L1: CARDINAL] =
{ L0 ← M2I.pc; Load [v];
IF e3^.val.I > 0 THEN
IF v^.mode = stkMd THEN M2I.PutRJB [RJGEB, 0, 1, 1, 0, 12, 6]
ELSE IF (v^.mode = regMd) AND (v^.opt = 0) THEN
M2I.PutRJB [RJGEB, 0, 0, 0, 0, v^.reg, 6]
ELSE err [141]
ELSE IF e3^.val.I < 0 THEN
IF v^.mode = stkMd THEN M2I.PutRJB [RJLEB, 0, 1, 1, 0, 12, 6]
ELSE IF (v^.mode = regMd) AND (v^.opt = 0) THEN
M2I.PutRJB [RJLEB, 0, 0, 0, 0, v^.reg, 6]
ELSE err [141]
ELSE err [141];
L1 ← M2I.pc; M2I.PutODB [JDB, 0] };
GenFor4: PUBLIC PROC [v, e3: ItemPtr, L0, L1: CARDINAL] =
{ w: ItemPtr = NEW [Item];
SRTest [v]; w^ ← v^; PrepAss [v]; Load [w];
GenOp [plus, w, e3]; GenAssign [v, w];
GenBJ [L0]; M2I.FixJmp [L1, M2I.pc] };
GenWith: PUBLIC PROC [v, x: ItemPtr] = { PutStore [v, x] };
expressions
MaxCard: CARDINAL = 177777B;
MaxInt: INTEGER = 77777B;
MinInt: INTEGER = - MaxInt;
MaxReal: REAL = 1E38;
MinReal: REAL = -1E38;
mask: ARRAY [0..M2D.WordSize) OF LONG CARDINAL ← [0B, 1B, 3B, 7B, 17B, 37B, 77B, 177B, 377B, 777B, 1777B, 3777B, 7777B, 17777B, 37777B, 77777B, 177777B, 377777B, 777777B, 1777777B, 3777777B, 77777777B, 17777777B, 37777777B, 77777777B, 177777777B, 377777777B, 777777777B, 1777777777B, 3777777777B, 7777777777B, 17777777777B];
rngchk: PUBLIC BOOL;
f: PROC [cell, cell0: CARDINAL] RETURNS [CARDINAL] = INLINE
{ IF cell # 0 THEN RETURN [cell] ELSE RETURN [cell0] };
SetOpn: PROC [opr: CARDINAL, x, y: ItemPtr] =
{ IF x^.mode = conMd THEN { x^.opt ← 1; x^.reg ← x^.val.C }
ELSE IF x^.mode = stkMd THEN { x^.opt ← 1; x^.reg ← 12 };
IF y^.mode = conMd THEN { y^.opt ← 1; y^.reg ← y^.val.C }
ELSE IF y^.mode = stkMd THEN { y^.opt ← 1; y^.reg ← 12 };
x^.opr ← opr; x^.opt2 ← y^.opt; x^.reg2 ← y^.reg; x^.mode ← opnMd };
SetJmp: PROC [rel: M2I.Relation, x: ItemPtr, opt, reg: CARDINAL] =
{ x^.typ ← M2D.booltyp; x^.mode ← jmpMd; x^.rel ← rel; x^.opt ← opt; x^.reg ← reg;
x^.Tjmp ← 0; x^.Fjmp ← 0 };
PrepJmp: PROC [rel, iRel: M2I.Relation, x, y: ItemPtr] =
{ IF x^.mode = conMd THEN
IF y^.mode = regMd THEN
{ LoadStk [x]; SetJmp [rel, x, x^.opt, x^.reg] }
ELSE IF x^.val.C >= 5 THEN { LoadStk [x]; SetJmp [iRel, x, 1, 12] }
ELSE SetJmp [iRel, x, 1, x^.val.C]
ELSE IF x^.mode = regMd THEN
 { LoadStk [y]; SetJmp [iRel, x, x^.opt, x^.reg] }
ELSE IF y^.mode = conMd THEN
IF y^.val.C >= 5 THEN { LoadStk [y]; SetJmp [rel, x, 1, 12] }
ELSE SetJmp [rel, x, 1, y^.val.C]
ELSE IF y^.mode = regMd THEN SetJmp [rel, x, y^.opt, y^.reg]
ELSE SetJmp [rel, x, 1, 12];
x^.typ ← M2D.booltyp };
PutLdAdr: PROC [x: ItemPtr] =
{ -- cell var --
dl: CARDINAL; pd: M2D.PDPtr;
var: M2D.VarPtr = NARROW[x^.obj];
IF var^.mod = 0 THEN
{ dl ← x^.contxt^.lev - var^.lev;
IF dl = 0 THEN
{ x^.mode ← ladrMd; x^.reg ← x^.contxt^.LNK+1; x^.off ← var^.cell;
IF var^.cell < 16 THEN x^.expRegs [var^.cell] ← TRUE }
ELSE { pd ← x^.contxt;
IF dl >= 2 THEN
{ M2I.PutLRB [LRI+x^.contxt^.LNK, 0]; pd ← pd^.pAnc; dl ← dl - 2;
WHILE dl # 0 DO M2I.PutOB [RB, 0]; pd ← pd^.pAnc; dl ← dl - 1 ENDLOOP;
x^.mode ← sadrMd; x^.off ← f[var^.cell, pd^.pAnc^.LNK] }
ELSE { x^.mode ← ladrMd;
x^.reg ← x^.contxt^.LNK; x^.off ← f[var^.cell, pd^.pAnc^.LNK] };
IF var^.cell < 16 THEN pd^.impRegs [var^.cell] ← TRUE }}
ELSE { M2I.Reloc; M2I.PutOQB [LIQB, var^.mod*256 + 1];
x^.mode ← sadrMd; x^.off ← var^.cell }};
PutLd: PROC [x: ItemPtr] =
{ dl: CARDINAL; pd: M2D.PDPtr;
var: M2D.VarPtr = NARROW[x^.obj];
IF var^.mod = 0 THEN
{ dl ← x^.contxt^.lev - var^.lev;
IF dl = 0 THEN
IF (var^.lev # 0) AND (var^.cell < 16) THEN
{ x^.opt ← 0; x^.reg ← var^.cell; x^.mode ← regMd }
ELSE { M2I.PutLRB [LRI+x^.contxt^.LNK+1, var^.cell]; x^.mode ← stkMd }
ELSE { pd ← x^.contxt;
IF dl >= 2 THEN
{ M2I.PutLRB [LRI+x^.contxt^.LNK, 0]; pd ← pd^.pAnc; dl ← dl - 2;
WHILE dl # 0 DO M2I.PutOB [RB, 0]; pd ← pd^.pAnc; dl ← dl - 1 ENDLOOP ;
M2I.PutOB [RB, f[var^.cell, pd^.pAnc^.LNK]] }
ELSE M2I.PutLRB [LRI+x^.contxt^.LNK, f[var^.cell, pd^.pAnc^.LNK]];
x^.mode ← stkMd;
IF var^.cell < 16 THEN pd^.impRegs [var^.cell] ← TRUE }}
ELSE { M2I.Reloc; M2I.PutOQB [LIQB, var^.mod*256 + 1];
M2I.PutOB [RB, var^.cell]; x^.mode ← stkMd }};
PutCompl: PROC [x: ItemPtr] =
{ IF x^.mode = conMd THEN LoadStk [x];
IF x^.mode = stkMd THEN M2I.PutRR [RXOR, 1,1,1,0, 12, 6, 12]
ELSE -- x^.mode = regMd
{ M2I.PutRR [RXOR, 1,1,0,0, 15, 6, x^.reg]; x^.mode ← stkMd }};
LoadAdr: PUBLIC PROC [x: ItemPtr] =
{ SELECT x^.mode FROM
typMd => err [104];
procMd, codMd => err [105];
conMd => err [103];
varMd => { var: M2D.VarPtr = NARROW[x^.obj];
   IF (x^.typ^.form = Array) OR (x^.typ^.form = Record) OR var^.varpar THEN
    { PutLd [x];
    IF x^.mode = regMd THEN x^.mode ← ladrMd ELSE x^.mode ← sadrMd;
    x^.off ← 0 }
    ELSE PutLdAdr [x] };
  sinxMd => { M2I.PutOI [ADD]; x^.mode ← sadrMd; x^.off ← 0 };
  linxMd => { M2I.PutQR [QADD, 0, 0, x^.reg]; x^.mode ← sadrMd; x^.off ← 0 };
  sadrMd, ladrMd => {};
  regMd, opnMd, stkMd, jmpMd => { err [106]; x^.mode ← sadrMd; x^.off ← 0 }
ENDCASE };
LoadAdrStk: PUBLIC PROC [x: ItemPtr] =
{ LoadAdr [x];
IF x^.mode = ladrMd THEN { M2I.PutLR [LR+x^.reg]; x^.mode ← sadrMd };
IF x^.off # 0 THEN { M2I.PutAdd [x^.off]; x^.off ← 0 }};
Load: PUBLIC PROC [x: ItemPtr] =
{ dl: CARDINAL;
SELECT x^.mode FROM
typMd => err [101];
procMd, codMd => err [102];
varMd => { var: M2D.VarPtr = NARROW[x^.obj];
   PutLd [x];
   IF var^.varpar AND (x^.typ^.form # Array)
   AND (x^.typ^.form # Record) THEN -- regMd --
   { M2I.PutLRB [LRI+x^.reg, 0]; x^.mode ← stkMd }};
sinxMd => { IF (x^.typ^.form = Array) OR (x^.typ^.form = Record) THEN
    M2I.PutOI [ADD]
   ELSE M2I.PutOI [RX];
   x^.mode ← stkMd };
linxMd => { IF (x^.typ^.form = Array) OR (x^.typ^.form = Record) THEN
    M2I.PutQR [QADD, 0, 0, x^.reg]
   ELSE M2I.PutQR [QRX, 0, 0, x^.reg];
   x^.mode ← stkMd };
sadrMd => { IF (x^.typ^.form = Array) OR (x^.typ^.form = Record) THEN
    M2I.PutAdd [x^.off]
   ELSE M2I.PutOB [RB, x^.off];
   x^.mode ← stkMd };
ladrMd => { IF (x^.typ^.form = Array) OR (x^.typ^.form = Record) THEN
    { M2I.PutLR [LR+x^.reg]; M2I.PutAdd [x^.off] }
   ELSE M2I.PutLRB [LRI+x^.reg, x^.off];
   x^.mode ← stkMd };
conMd => IF (x^.typ^.form = String) THEN
   { SL: CARDINAL = x^.contxt^.LNK; FRX: CARDINAL = SL+1;
   dl ← x^.contxt^.lev + 1;
   IF dl >= 2 THEN { M2I.PutLRB [LRI+SL, 0]; dl ← dl - 2;
   WHILE dl # 0 DO M2I.PutOB [RB, 0]; dl ← dl - 1 ENDLOOP }
  ELSE IF dl = 1 THEN M2I.PutLR [LR+SL]
  ELSE M2I.PutLR [LR+FRX];
  M2I.PutAdd [x^.val.D0]; x^.mode ← stkMd };
opnMd => { M2I.PutSOp [x^.opr, x^.opt, x^.reg, x^.opt2, x^.reg2]; x^.mode ← stkMd };
regMd, stkMd, jmpMd => {}
ENDCASE };
LoadStk: PUBLIC PROC [x: ItemPtr] =
{ IF x^.mode < regMd THEN Load[x];
IF x^.mode = conMd THEN { M2I.PutLod [x^.val.C]; x^.mode ← stkMd }
ELSE IF x^.mode = regMd THEN
{ IF x^.opt = 0 THEN M2I.PutLR [LR+x^.reg] ELSE M2I.PutOI [LC+x^.reg];
x^.mode ← stkMd }};
GenCFJ: PUBLIC PROC [x: ItemPtr] RETURNS [loc: CARDINAL] =
{ IF x^.typ^.form = Bool THEN
 { IF x^.mode < jmpMd THEN { LoadStk [x]; SetJmp [EQ, x, 1, 1] }}
ELSE { err [135]; SetJmp [EQ, x, 1, 1] };
loc ← M2I.PutFJ [M2I.inv[x^.rel], x^.opt, x^.reg, x^.Fjmp]; x^.Fjmp ← loc;
M2I.FixLink [x^.Tjmp, M2I.pc] };
GenFJ: PUBLIC PROC [loc: CARDINAL] RETURNS [Loc: CARDINAL] =
{ Loc ← M2I.pc; M2I.PutODB [JDB, loc] };
GenCBJ: PUBLIC PROC [x: ItemPtr, loc: CARDINAL] =
{ IF x^.typ^.form = Bool THEN
{ IF x^.mode < jmpMd THEN { LoadStk [x]; SetJmp [EQ, x, 1, 1] }}
ELSE { err [135]; SetJmp [EQ, x, 1, 1] };
M2I.PutBJ [M2I.inv[x^.rel], x^.opt, x^.reg, loc];
M2I.FixLink [x^.Fjmp, loc]; M2I.FixLink [x^.Tjmp, M2I.pc] };
GenBJ: PUBLIC PROC [loc: CARDINAL] = { M2I.PutODB [JDB, loc - M2I.pc] };
GenIn: PUBLIC PROC [x, y: ItemPtr] =
{ f: M2D.StrForm;
SRTest [x]; f ← x^.typ^.form;
IF ((f >= Bool) AND (f <= Int) OR (f = Enum)) AND (y^.typ^.form = Set) THEN
{ set: M2D.SetPtr = NARROW [y^.typ];
y^.typ ← set^.BaseTyp;
IF y^.typ^.form = Range THEN
{ range: M2D.RangePtr = NARROW [y^.typ];
y^.typ ← range^.BaseTyp };
IF x^.typ = y^.typ THEN
IF (x^.mode = conMd) AND (y^.mode = conMd) THEN
IF x^.val.C < M2D.WordSize THEN x^.val.B ← y^.val.S[x^.val.C]
ELSE { x^.val.B ← FALSE; err [202] }
ELSE
{ IF x^.mode = conMd THEN
IF x^.val.C < M2D.WordSize THEN
{ M2I.PutLod [mask[x^.val.C]+1]; x^.mode ← stkMd }
ELSE err [202]
ELSE -- x^.mode = stkMd
{ IF y^.mode = stkMd THEN M2I.PutExch;
M2I.PutOQB [CALL, MakeBit] };
IF y^.mode = conMd THEN LoadStk [y];
IF y^.mode = stkMd THEN M2I.PutRR [RAND, 1, 1, 1, 0, 13, 14, 13]
ELSE M2I.PutQR [QAND, y^.opt, 0, y^.reg];
SetJmp [NE, x, 1, 0] }
ELSE { err [114]; x^.mode ← stkMd }}
ELSE { err [115]; x^.mode ← stkMd };
x^.typ ← M2D.booltyp };
GenNeg: PUBLIC PROC [x: ItemPtr] =
{ f: M2D.StrForm;
SRTest [x]; f ← x^.typ^.form;
IF x^.mode = conMd THEN
IF (f = Int) OR (f = Card) AND (x^.val.C <= MaxInt) THEN
IF x^.val.I >= MinInt THEN
{ x^.val.I ← - x^.val.C; x^.typ ← M2D.inttyp }
ELSE err [201]
ELSE IF f = Real THEN x^.val.R ← - x^.val.R
ELSE err [112]
ELSE { Load [x];
IF f = Int THEN
{ IF x^.mode = regMd THEN
{ x^.mode ← opnMd;
x^.opr ← RSUB; x^.opt2 ← x^.opt; x^.reg2 ← x^.reg; x^.opt ← 1; x^.reg ← 0 }
ELSE M2I.PutRR [RSUB, 1,1,1,0, 12, 0, 12] }
ELSE err [112] }};
GenNot: PUBLIC PROC [x: ItemPtr] =
{ t: CARDINAL;
IF x^.typ^.form = Bool THEN
IF x^.mode = conMd THEN x^.val.B ← NOT x^.val.B
ELSE IF x^.mode = jmpMd THEN { x^.rel ← M2I.inv[x^.rel];
t ← x^.Tjmp; x^.Tjmp ← x^.Fjmp; x^.Fjmp ← t }
ELSE { LoadStk [x]; M2I.PutRR [RXOR, 1,1,1,0, 12, 6, 12] }
ELSE err [113] };
GenAnd: PUBLIC PROC [x: ItemPtr] =
{ IF x^.mode = jmpMd THEN
 { x^.Fjmp ← M2I.PutFJ [M2I.inv[x^.rel], x^.opt, x^.reg, x^.Fjmp];
 M2I.FixLink [x^.Tjmp, M2I.pc] }
ELSE IF (x^.typ^.form = Bool) AND (x^.mode # conMd) THEN { SetJmp [EQ, x, 1, 1];
 x^.Fjmp ← M2I.PutFJ [M2I.inv[x^.rel], x^.opt, x^.reg, x^.Fjmp];
 M2I.FixLink [x^.Tjmp, M2I.pc] }
ELSE IF x^.typ^.form # Bool THEN
 { err [122]; x^.mode ← conMd; x^.typ ← M2D.booltyp; x^.val.B ← FALSE }};
GenOr: PUBLIC PROC [x: ItemPtr] =
{ IF x^.mode = jmpMd THEN
 { x^.Tjmp ← M2I.PutFJ [x^.rel, x^.opt, x^.reg, x^.Tjmp];
 M2I.FixLink [x^.Fjmp, M2I.pc] }
ELSE IF (x^.typ^.form = Bool) AND (x^.mode # conMd) THEN { SetJmp [EQ, x, 1, 1];
 x^.Tjmp ← M2I.PutFJ [x^.rel, x^.opt, x^.reg, x^.Tjmp];
 M2I.FixLink [x^.Fjmp, M2I.pc] }
ELSE IF x^.typ^.form # Bool THEN
 { err [122]; x^.mode ← conMd; x^.typ ← M2D.booltyp; x^.val.B ← TRUE }};
ExecOp: PUBLIC PROC [op: M2S.Symbol, x, y: ItemPtr] =
{ f: M2D.StrForm = x^.typ^.form;
SELECT op FROM
times => { IF f = Card THEN
    IF y^.val.C <= MaxCard/x^.val.C THEN
     x^.val.C ← x^.val.C * y^.val.C
    ELSE err [203]
      ELSE IF f = Int THEN
      IF ABS[y^.val.I] <= MaxInt / ABS[x^.val.I] THEN
       x^.val.I ← x^.val.I * y^.val.I
      ELSE err [203]
     ELSE IF f = Real THEN
     IF (ABS[x^.val.R] <= 1.0) OR (ABS[y^.val.R] <= MaxReal/ABS[x^.val.R]) THEN
      x^.val.R ← x^.val.R * y^.val.R
     ELSE err [203]
    ELSE IF f = Set THEN
     x^.val.S ← M2D.INTERSECTION [x^.val.S, y^.val.S]
    ELSE err [118] };
slash,
div => { IF f = Card THEN
    IF y^.val.C > 0 THEN x^.val.C ← x^.val.C / y^.val.C
    ELSE err [205]
   ELSE IF f = Int THEN
    IF y^.val.I # 0 THEN x^.val.I ← x^.val.I / y^.val.I
    ELSE err [205]
   ELSE IF (f = Real) AND (op = slash) THEN
    IF (y^.val.R >= 1.0) OR
     (ABS[x^.val.R] <= MaxReal * ABS[y^.val.R]) THEN
     x^.val.R ← x^.val.R / y^.val.R
    ELSE err [204]
   ELSE IF (f = Set) AND (op = slash) THEN
   x^.val.S ← M2D.SYMMDIFF [x^.val.S, y^.val.S]
   ELSE err [120] };
div,
rem => { IF f = Card THEN
    IF y^.val.C > 0 THEN x^.val.C ← x^.val.C MOD y^.val.C
    ELSE err [205]
   ELSE IF f = Int THEN
    IF (x^.val.I >= 0) AND (y^.val.I > 0) THEN
     x^.val.I ← x^.val.I MOD y^.val.I
    ELSE err [205]
   ELSE err [121] };
and => { IF f = Bool THEN x^.val.B ← x^.val.B AND y^.val.B
   ELSE err [122] };
plus => { IF f = Card THEN
    IF y^.val.C <= MaxCard - x^.val.C THEN
     x^.val.C ← x^.val.C + y^.val.C
    ELSE err [206]
   ELSE IF f = Int THEN
    IF (x^.val.I >= 0) AND (y^.val.I <= MaxInt - x^.val.I) OR
     (x^.val.I < 0) AND (y^.val.I >= MinInt - x^.val.I) THEN
     x^.val.I ← x^.val.I + y^.val.I
    ELSE err [206]
   ELSE IF f = Real THEN
    IF (x^.val.R >= 0.0) AND (y^.val.R <= MaxReal - x^.val.R) OR
     (x^.val.R < 0) AND (y^.val.R >= MinReal - x^.val.R) THEN
     x^.val.R ← x^.val.R + y^.val.R
    ELSE err [206]
   ELSE IF f = Set THEN
   x^.val.S ← M2D.UNION [x^.val.S, y^.val.S]
   ELSE err [123] };
minus => { IF f = Card THEN
    IF y^.val.C <= x^.val.C THEN x^.val.C ← x^.val.C - y^.val.C
    ELSE
     IF y^.val.C - x^.val.C <= MaxInt THEN
      { x^.val.I ← -(y^.val.C - x^.val.C); x^.typ ← M2D.inttyp }
     ELSE err [207]
   ELSE IF f = Int THEN
    IF (x^.val.I >= 0) AND
     ((y^.val.I >= 0) OR (x^.val.I <= MaxInt + y^.val.I)) OR
     (x^.val.I < 0) AND
     ((y^.val.I < 0) OR (x^.val.I >= MinInt + y^.val.I)) THEN
     x^.val.I ← x^.val.I - y^.val.I
    ELSE err [207]
   ELSE IF f = Real THEN
    IF (x^.val.R >= 0.0) AND
     ((y^.val.R >= 0.0) OR (x^.val.R <= MaxReal + y^.val.R)) THEN
     x^.val.R ← x^.val.R - y^.val.R
    ELSE IF (x^.val.R < 0.0) AND
     ((y^.val.R < 0.0) OR (x^.val.R >= MinReal + y^.val.R)) THEN
     x^.val.R ← x^.val.R - y^.val.R
    ELSE err [207]
   ELSE IF f = Set THEN
   x^.val.S ← M2D.SETDIFF [x^.val.S, y^.val.S]
   ELSE err [124] };
or  => { IF f = Bool THEN x^.val.B ← x^.val.B OR y^.val.B
   ELSE err [125] };
eql => { IF f = Card THEN x^.val.B ← x^.val.C = y^.val.C
   ELSE IF f = Int THEN x^.val.B ← x^.val.I = y^.val.I
   ELSE IF f = Real THEN x^.val.B ← x^.val.R = y^.val.R
   ELSE IF f = Bool THEN x^.val.B ← x^.val.B = y^.val.B
   ELSE IF f = Set THEN x^.val.B ← x^.val.S = y^.val.S
   ELSE IF f = Char THEN x^.val.B ← x^.val.Ch = y^.val.Ch
   ELSE err [126];
   x^.typ ← M2D.booltyp };
neq => { IF f = Card THEN x^.val.B ← x^.val.C # y^.val.C
   ELSE IF f = Int THEN x^.val.B ← x^.val.I # y^.val.I
   ELSE IF f = Real THEN x^.val.B ← x^.val.R # y^.val.R
   ELSE IF f = Bool THEN x^.val.B ← x^.val.B # y^.val.B
   ELSE IF f = Set THEN x^.val.B ← x^.val.S # y^.val.S
   ELSE IF f = Char THEN x^.val.B ← x^.val.Ch # y^.val.Ch
   ELSE err [126];
   x^.typ ← M2D.booltyp };
lss  => { IF f = Card THEN x^.val.B ← x^.val.C < y^.val.C
   ELSE IF f = Int THEN x^.val.B ← x^.val.I < y^.val.I
   ELSE IF f = Real THEN x^.val.B ← x^.val.R < y^.val.R
   ELSE IF f = Bool THEN x^.val.B ← x^.val.B < y^.val.B
   ELSE IF f = Set THEN
    IF x^.val.S = y^.val.S THEN x^.val.B ← FALSE
    ELSE x^.val.B ← M2D.SUBSET [x^.val.S, y^.val.S]
   ELSE IF f = Char THEN x^.val.B ← x^.val.Ch < y^.val.Ch
   ELSE err [126];
   x^.typ ← M2D.booltyp };
leq => { IF f = Card THEN x^.val.B ← x^.val.C <= y^.val.C
   ELSE IF f = Int THEN x^.val.B ← x^.val.I <= y^.val.I
   ELSE IF f = Real THEN x^.val.B ← x^.val.R <= y^.val.R
   ELSE IF f = Bool THEN x^.val.B ← x^.val.B <= y^.val.B
   ELSE IF f = Set THEN x^.val.B ← M2D.SUBSET [x^.val.S, y^.val.S]
   ELSE IF f = Char THEN x^.val.B ← x^.val.Ch <= y^.val.Ch
   ELSE err [126];
   x^.typ ← M2D.booltyp };
gtr => { IF f = Card THEN x^.val.B ← x^.val.C > y^.val.C
   ELSE IF f = Int THEN x^.val.B ← x^.val.I > y^.val.I
   ELSE IF f = Real THEN x^.val.B ← x^.val.R > y^.val.R
   ELSE IF f = Bool THEN x^.val.B ← x^.val.B > y^.val.B
   ELSE IF f = Set THEN
    IF x^.val.S = y^.val.S THEN x^.val.B ← FALSE
    ELSE x^.val.B ← M2D.SUBSET [y^.val.S, x^.val.S]
   ELSE IF f = Char THEN x^.val.B ← x^.val.Ch > y^.val.Ch
   ELSE err [126];
   x^.typ ← M2D.booltyp };
geq => { IF f = Card THEN x^.val.B ← x^.val.C >= y^.val.C
   ELSE IF f = Int THEN x^.val.B ← x^.val.I >= y^.val.I
   ELSE IF f = Real THEN x^.val.B ← x^.val.R >= y^.val.R
   ELSE IF f = Bool THEN x^.val.B ← x^.val.B >= y^.val.B
   ELSE IF f = Set THEN x^.val.B ← M2D.SUBSET [y^.val.S, x^.val.S]
   ELSE IF f = Char THEN x^.val.B ← x^.val.Ch >= y^.val.Ch
   ELSE err [126];
   x^.typ ← M2D.booltyp }
ENDCASE };
GenOp: PUBLIC PROC [op: M2S.Symbol, x, y: ItemPtr] =
x and y loaded in right order (if necessary on stack, constants may be in conMd)
{ f, g: M2D.StrForm;
SRTest [x]; SRTest [y]; f ← x^.typ^.form;
IF x^.typ # y^.typ THEN { g ← y^.typ^.form;
IF (f = Int) AND (g = Card) THEN
IF (y^.mode = conMd) AND (y^.val.C <= MaxInt) THEN { y^.typ ← x^.typ; g ← Int }
ELSE IF (x^.mode = conMd) AND (x^.val.I >= 0) THEN { x^.typ ← y^.typ; f ← Card }
ELSE IF (f = Card) AND (g = Int) THEN
IF (x^.mode = conMd) AND (x^.val.C <= MaxInt) THEN { x^.typ ← y^.typ; f ← Int }
ELSE IF (y^.mode = conMd) AND (y^.val.I >= 0) THEN { y^.typ ← x^.typ; g ← Card }
ELSE IF (x^.typ = M2D.addrtyp) AND (g = Pointer) THEN f ← Pointer
ELSE IF ((f # Pointer) OR (y^.typ # M2D.addrtyp)) AND ((f # Card) OR (g # Card)) THEN err [117] };
IF (x^.mode = conMd) AND (y^.mode = conMd) THEN ExecOp [op, x, y]
ELSE
SELECT op FROM
times => { IF (f = Card) OR (f = Int) THEN
    { IF (x^.mode = conMd) AND (clog[x^.val.C] = 1) OR
    (y^.mode = conMd) AND (clog[y^.val.C] = 1) THEN
       M2I.PutODB [SHL, 32*64+exp]
      ELSE IF x^.mode = conMd THEN
       { LoadStk [x]; M2I.PutOQB [CALL, Mult] }
      ELSE IF y^.mode = conMd THEN
       { LoadStk [y]; M2I.PutOQB [CALL, Mult] }
      ELSE M2I.PutOQB [CALL, Mult];
      x^.mode ← stkMd }
    ELSE IF f = Double THEN err [216]
    ELSE IF f = Set THEN
     { IF x^.mode = conMd THEN LoadStk [x]
     ELSE IF y^.mode = conMd THEN LoadStk [y];
     SetOpn [RAND, x, y] }
    ELSE IF f = Real THEN
     { LoadStk [y]; LoadStk [x]; M2I.PutOQB [CALL, RealMult] }
    ELSE IF f # Undef THEN err [118] };
slash => { IF f = Set THEN
     { IF x^.mode = conMd THEN LoadStk [x]
     ELSE IF y^.mode = conMd THEN LoadStk [y];
     SetOpn [RXOR, x, y] }
    ELSE IF f = Real THEN { LoadStk [y];
     IF x^.mode # stkMd THEN { LoadStk [x]; M2I.PutExch };
     M2I.PutOQB [CALL, RealDiv] }
    ELSE err [119] };
div => { IF (f = Card) OR (f = Int) THEN
    { IF (y^.mode = conMd) AND (clog[y^.val.C] = 1) THEN
     M2I.PutODB [SHR, 32*64+exp]
    ELSE IF x^.mode = conMd THEN
     { LoadStk [x]; M2I.PutOQB [CALL, Div] }
    ELSE IF y^.mode = conMd THEN
     { LoadStk [y]; M2I.PutOQB [CALL, Div] }
    ELSE M2I.PutOQB [CALL, Div];
    x^.mode ← stkMd }
   ELSE IF f = Double THEN err [216]
   ELSE IF f # Undef THEN err [120] };
mod,
rem => { IF (f = Card) OR (f = Int) THEN
    { IF (y^.mode = conMd) AND (clog[y^.val.C] = 1) THEN
     { M2I.PutLod [mask[exp]];
     M2I.PutRR [RAND, 1, 1, 1, 0, 13, 14, 13] }
    ELSE IF x^.mode = conMd THEN
     { LoadStk [x]; M2I.PutOQB [CALL, Mod] }
    ELSE IF y^.mode = conMd THEN
     { LoadStk [y]; M2I.PutOQB [CALL, Mod] }
    ELSE M2I.PutOQB [CALL, Mod];
    x^.mode ← stkMd }
   ELSE IF f # Undef THEN err [121] };
and => { IF f = Bool THEN
    IF x^.mode = conMd THEN
    { IF y^.mode < jmpMd THEN SetJmp [EQ, y, 1, 1];
     IF NOT x^.val.B THEN { x^.rel ← false;
      x^.Fjmp ← M2I.MergedLinks [y^.Fjmp, y^.Tjmp]; x^.Tjmp ← 0 }
     ELSE x ← y }
    ELSE IF y^.mode = conMd THEN
     { IF NOT y^.val.B THEN
         { IF y^.Fjmp # 0 THEN
         x^.Fjmp ← M2I.MergedLinks [x^.Fjmp, y^.Fjmp];
        x^.rel ← false; x^.Tjmp ← y^.Tjmp }}
      ELSE
      { IF y^.mode < jmpMd THEN SetJmp [EQ, y, 1, 1];
      IF y^.Fjmp # 0 THEN x^.Fjmp ← M2I.MergedLinks [x^.Fjmp, y^.Fjmp];
      x^.rel ← y^.rel; x^.opt ← y^.opt; x^.reg ← y^.reg; x^.Tjmp ← y^.Tjmp }
     ELSE IF f # Undef THEN { err [122]; SetJmp [true, x, 0, 0] }};
  plus => { IF (f = Card) OR (f = Int) THEN
      IF (x^.mode = conMd) AND (x^.val.C >= 5) OR
       (y^.mode = conMd) AND (y^.val.C >= 5) THEN
       IF x^.mode = conMd THEN
        IF y^.mode = stkMd THEN
         { M2I.PutAdd [x^.val.I]; x^.mode ← stkMd }
        ELSE { LoadStk [x]; SetOpn [RADD, x, y] }
       ELSE
        IF x^.mode = stkMd THEN
         { M2I.PutAdd [y^.val.I]; x^.mode ← stkMd }
        ELSE { LoadStk [y]; SetOpn [RADD, x, y] }
      ELSE SetOpn [RADD, x, y]
      ELSE IF f = Set THEN
       { IF x^.mode = conMd THEN LoadStk [x]
       ELSE IF y^.mode = conMd THEN LoadStk [y];
       SetOpn [ROR, x, y] }
     ELSE IF f = Real THEN
      { LoadStk [y]; LoadStk [x]; M2I.PutOQB [CALL, RealAdd] }
     ELSE IF f # Undef THEN err [123] };
 minus => { IF (f = Card) OR (f = Int) THEN
     IF (x^.mode = conMd) AND (x^.val.C >= 5) OR
      (y^.mode = conMd) AND (y^.val.C >= 5) THEN
      IF x^.mode = conMd THEN { LoadStk [x];
        IF y^.mode = stkMd THEN M2I.PutExch;
        SetOpn [RSUB, x, y] }
       ELSE
        IF x^.mode = stkMd THEN
         { M2I.PutSub [y^.val.I]; x^.mode ← stkMd }
        ELSE { LoadStk [y]; SetOpn [RSUB, x, y] }
     ELSE SetOpn [RSUB, x, y]
    ELSE IF f = Set THEN { PutCompl [y];
     IF x^.mode = conMd THEN LoadStk [x];
     SetOpn [RAND, x, y] }
   ELSE IF f = Real THEN { LoadStk [y];
    IF x^.mode # stkMd THEN { LoadStk [x]; M2I.PutExch };
    M2I.PutOQB [CALL, RealSub] }
   ELSE IF f # Undef THEN err [123] };
 or  => { IF f = Bool THEN
     IF x^.mode = conMd THEN
     { IF y^.mode < jmpMd THEN SetJmp [EQ, y, 1, 1];
      IF x^.val.B THEN { x^.rel ← true;
       x^.Tjmp ← M2I.MergedLinks [y^.Tjmp, y^.Fjmp]; x^.Fjmp ← 0 }
      ELSE x ← y }
     ELSE IF y^.mode = conMd THEN
      { IF y^.val.B THEN
         { IF y^.Tjmp # 0 THEN
         x^.Tjmp ← M2I.MergedLinks [x^.Tjmp, y^.Tjmp];
        x^.rel ← true; x^.Fjmp ← y^.Fjmp }}
       ELSE
       { IF y^.mode < jmpMd THEN SetJmp [EQ, y, 1, 1];
       IF y^.Tjmp # 0 THEN x^.Tjmp ← M2I.MergedLinks [x^.Tjmp, y^.Tjmp];
       x^.rel ← y^.rel; x^.opt ← y^.opt; x^.reg ← y^.reg; x^.Fjmp ← y^.Fjmp }
      ELSE IF f # Undef THEN { err [123]; SetJmp [true, x, 0, 0] }};
  eql  => { PrepJmp [EQ, EQ, x, y];
      IF (f > Int) AND (f # Enum) AND (f # Pointer) AND (f # Set) AND
     (f # Opaque) AND (f # Real) AND (f # Double) THEN
     err [126] };
  neq  => { PrepJmp [NE, NE, x, y];
      IF (f > Int) AND (f # Enum) AND (f # Pointer) AND (f # Set) AND
     (f # Opaque) AND (f # Real) AND (f # Double) THEN
     err [126] };
 lss   => { IF (f < Bool) OR (f > LongReal) AND (f # Enum) THEN err [126];
     PrepJmp [LS, GT, x, y] };
 gtr => { IF (f < Bool) OR (f > LongReal) AND (f # Enum) THEN err [126];
    PrepJmp [GT, LS, x, y] };
 leq => { IF (f >= Bool) AND (f <= LongReal) OR (f = Enum) THEN
    PrepJmp [LE, GE, x, y]
   ELSE IF f = Set THEN { PutCompl [y];
    IF x^.mode = conMd THEN LoadStk [x];
    IF x^.mode = stkMd THEN M2I.PutRR [RAND, 1, 1, 1, 0, 13, 14, 13]
    ELSE --regMd-- M2I.PutRR [RAND, 1, 0, 1, 0, 12, x^.reg, 12];
    SetJmp [EQ, x, 1, 0] }
   ELSE err [126];
    x^.typ ← M2D.booltyp }; 
 geq => { IF (f >= Bool) AND (f <= LongReal) OR (f = Enum) THEN
    PrepJmp [GE, LE, x, y]
   ELSE IF f = Set THEN
    IF x^.mode = conMd THEN { PutCompl [x];
    IF y^.mode = conMd THEN LoadStk [y];
    IF y^.mode = stkMd THEN M2I.PutRR [RAND, 1, 1, 1, 0, 13, 14, 13]
    ELSE --regMd-- M2I.PutRR [RAND, 1, 0, 1, 0, 12, y^.reg, 12];
    SetJmp [EQ, x, 1, 0] }
    ELSE { PutCompl [y];
    IF x^.mode = conMd THEN LoadStk [x];
    IF x^.mode = stkMd THEN M2I.PutRR [ROR, 1, 1, 1, 0, 13, 14, 13]
    ELSE --regMd-- M2I.PutRR [ROR, 1, 0, 1, 0, 12, x^.reg, 12];
    SetJmp [EQ, x, 1, 6] }
   ELSE err [126];
    x^.typ ← M2D.booltyp }
ENDCASE };
GenStParam: PUBLIC PROC [p, x: ItemPtr, fctno, parno: CARDINAL] =
{ restyp: M2D.StrPtr; f: M2D.StrForm;
u: ItemPtr = NEW [Item]; v: ItemPtr = NEW [Item];
IF fctno < 20 THEN
IF parno = 0 THEN -- first parameter --
{ restyp ← p^.obj^.typ;
SELECT fctno FROM
0, 1 => {};
2  => { SRTest [x]; -- ABS --
   IF x^.typ = M2D.inttyp THEN
    { LoadStk [x]; M2I.PutRJB [RJLB, 0, 0, 1, 0, 0, 6];
    M2I.PutRR [RSUB, 1, 1, 1, 0, 12, 0, 12]; restyp ← M2D.inttyp }
   ELSE IF x^.typ = M2D.realtyp THEN
    { Load [x]; restyp ← M2D.realtyp }
   ELSE err [144] };
3  => { SRTest [x]; -- CAP --
   IF x^.typ = M2D.chartyp THEN { LoadStk [x];
    M2I.PutOB [LIB, 137B]; M2I.PutRR [RAND, 1, 1, 1, 0, 13, 14, 13] }
   ELSE err [144] };
4  => { SRTest [x]; -- FLOAT --
   IF x^.typ = M2D.cardtyp THEN Load [x] ELSE err [144] };
5  => { SRTest [x]; -- ODD --
   IF (x^.typ = M2D.cardtyp) OR (x^.typ = M2D.inttyp) THEN
    { LoadStk [x];
    M2I.PutOB [LIB, 1B]; M2I.PutRR [RAND, 1, 1, 1, 0, 13, 14, 13] }
   ELSE err [144] };
6  => { SRTest [x]; -- ORD --
   IF (x^.typ^.form <= Card) OR (x^.typ^.form = Enum) THEN Load [x]
   ELSE err [144] };
7  => { -- TRUNC --
   IF x^.typ = M2D.realtyp THEN Load [x] ELSE err [144] };
8  => { IF (x^.mode = typMd) OR (x^.mode = varMd) THEN
    x^.val.I ← x^.typ^.size -- SIZE, TSIZE --
   ELSE { err [145]; x^.val.I ← 1 };
   x^.mode ← conMd; restyp ← M2D.cardtyp };
9  => {};
10  => { LoadAdrStk [x]; x^.mode ← stkMd -- ADR --};
11  => { IF x^.mode = typMd THEN -- MIN --
    { x^.mode ← conMd; restyp ← x^.typ;
    SELECT x^.typ^.form FROM
     Bool => { x^.val.B ← FALSE };
     Char => { x^.val.Ch ← '\000 };
     Int => { x^.val.C ← 100000B };
     Card => { x^.val.C ← 0 };
     Real => { x^.val.D0 ← 177577B; x^.val.D1 ← 177777B };
     Double => { x^.val.D0 ← 100000B; x^.val.D1 ← 0 };
     Enum => { x^.val.C ← 0 };
     Range => { range: M2D.RangePtr = NARROW [x^.typ];
        x^.val.I ← range^.min }
    ENDCASE => err [144] }
   ELSE err [145] };
12  => {IF x^.mode = typMd THEN -- MAX --
    { x^.mode ← conMd; restyp ← x^.typ;
    SELECT x^.typ^.form FROM
     Bool => { x^.val.B ← TRUE };
     Char => { x^.val.Ch ← 377C };
     Int => { x^.val.C ← 77777B };
     Card => { x^.val.C ← 177777B };
     Real => { x^.val.D0 ← 77577B; x^.val.D1 ← 177777B };
     Double => { x^.val.D0 ← 77777B; x^.val.D1 ← 177777B };
     Enum => { enum: M2D.EnumPtr = NARROW [x^.typ];
        x^.val.C ← enum^.NofConst - 1 };
     Range => { range: M2D.RangePtr = NARROW [x^.typ];
        x^.val.I ← range^.max }
    ENDCASE => err [144] }
   ELSE err [145] };
13  => { IF (x^.mode = varMd) AND (x^.typ^.form = Array) THEN -- HIGH --
    { array: M2D.ArrayPtr = NARROW [x^.typ];
    IF array^.dyn THEN
     { var: M2D.VarPtr = NARROW [x^.obj];
     M2I.PutRR [RSUB, 1, 0, 1, 0, 15, var^.cell+1, 1]; -- SIZE-1
     x^.mode ← stkMd; restyp ← M2D.cardtyp }
    ELSE { range: M2D.RangePtr = NARROW [array^.IndexTyp];
     x^.mode ← conMd; x^.val.I ← range^.max;
     restyp ← array^.IndexTyp }}
   ELSE err [144] };
14  => { SRTest [x]; -- CHR --
   IF (x^.typ # M2D.cardtyp) AND (x^.typ # M2D.inttyp) THEN err [144];
   restyp ← M2D.chartyp };
15  => { SRTest [x]; -- LONG --
   IF x^.typ^.form = Int THEN {}
   ELSE IF x^.typ^.form = Card THEN {}
   ELSE IF x^.typ^.form = Real THEN {restyp ← M2D.lrltyp }};
16, 17 => { f ← x^.typ^.form; -- INC, DEC --
   IF (f <= Double) OR (f = Range) OR (f = Enum) THEN
    { SRTest [x]; PrepAss [x]; restyp ← x^.typ }
    ELSE err [144] };
18, 19 => { IF x^.typ^.form = Set THEN -- INCL, EXCL --
    { PrepAss [x]; restyp ← x^.typ }
   ELSE err [144] };
20  => { SRTest [x]; -- SHIFT --
   IF (x^.typ = M2D.cardtyp) OR (x^.typ = M2D.inttyp) THEN Load [x]
   ELSE err [144] }
ENDCASE;
p^ ← x^; p^.typ ← restyp }
ELSE
IF parno = 1 THEN-- second parameter --
IF fctno = 16 THEN -- INC --
{ u^ ← p^; Load [u]; Load [x];
GenOp [plus, u, x]; GenAssign [p, u] }
ELSE IF fctno = 17 THEN -- DEC --
{ u^ ← p^; Load [u]; Load [x];
GenOp [minus, u, x]; GenAssign [p, u] }
ELSE IF fctno = 18 THEN -- INCL --
{ u^ ← p^; v^.typ ← p^.typ; GenSingSet [v, x];
LoadStk [v]; GenOp [plus, u, v]; GenAssign [p, u];
p^.typ ← M2D.notyp }
ELSE IF fctno = 19 THEN -- EXCL --
{ u^ ← p^; v^.typ ← p^.typ; GenSingSet [v, x];
LoadStk [v]; M2I.PutRR [RXOR, 1,1,1,0, 12, 6, 12];
GenOp [times, u, v]; GenAssign [p, u];
p^.typ ← M2D.notyp }
ELSE IF fctno = 20 THEN -- SHIFT --
{ SRTest [p]; SRTest [x];
IF (x^.typ = M2D.cardtyp) OR (x^.typ = M2D.inttyp) THEN
 x^.typ ← M2D.chartyp
ELSE err [144];
IF (p^.typ # M2D.inttyp) AND (p^.typ # M2D.cardtyp) AND (p^.typ # M2D.bitstyp) AND (p^.typ # M2D.dbltyp) THEN err [144] }
ELSE err [64]
ELSE err [64] };
GenStFct: PUBLIC PROC [p: ItemPtr, fctno, parno: CARDINAL] =
{ x: ItemPtr = NEW [Item]; u: ItemPtr = NEW [Item];
IF parno < 1 THEN err [65]
ELSE IF fctno = 16 THEN -- INC --
{ IF parno = 1 THEN { x^.mode ← conMd; x^.typ ← M2D.inttyp; x^.val.C ← 1;
 u^ ← p^; Load [u]; Load [x]; GenOp [plus, u, x];
 GenAssign [p, u] };
p^.typ ← M2D.notyp }
ELSE IF fctno = 17 THEN -- DEC --
{ IF parno = 1 THEN { x^.mode ← conMd; x^.typ ← M2D.inttyp; x^.val.C ← 1;
 u^ ← p^; Load [u]; Load [x]; GenOp [minus, u, x];
 GenAssign [p, u] };
p^.typ ← M2D.notyp }
ELSE IF (fctno > 17) AND (parno < 2) THEN err [65] };
END.