|
|
@@ -13,15 +13,17 @@ IMPORT AST, SymTab, QbeGen;
|
|
|
Names live in flat CHAR arrays indexed manually at slot * 64. *)
|
|
|
|
|
|
CONST
|
|
|
- MaxSym = 512;
|
|
|
+ MaxSym = 4096;
|
|
|
MaxName = 63;
|
|
|
- MaxProc = 64;
|
|
|
+ MaxProc = 2048; (* whole-session: the compiler declares >1200 procs *)
|
|
|
MaxPar = 32;
|
|
|
+ HashSize = 8192; (* power of two > MaxSym, MaxProc: open addressing *)
|
|
|
|
|
|
VAR
|
|
|
symName : ARRAY [0 .. MaxSym * 64 - 1] OF CHAR;
|
|
|
symKind : ARRAY [0 .. MaxSym - 1] OF INTEGER;
|
|
|
symTy : ARRAY [0 .. MaxSym - 1] OF SymTab.TypeIndex;
|
|
|
+ symVal : ARRAY [0 .. MaxSym - 1] OF QbeGen.QVal; (* const value *)
|
|
|
nSyms : CARDINAL;
|
|
|
procName : ARRAY [0 .. MaxProc * 64 - 1] OF CHAR;
|
|
|
procUid : ARRAY [0 .. MaxProc - 1] OF CARDINAL;
|
|
|
@@ -33,6 +35,11 @@ VAR
|
|
|
parVar : ARRAY [0 .. MaxProc * MaxPar - 1] OF BOOLEAN;
|
|
|
parName : ARRAY [0 .. MaxProc * MaxPar * 64 - 1] OF CHAR;
|
|
|
nProcs : CARDINAL;
|
|
|
+ (* Open-addressing indexes into symName/procName: entry = index+1,
|
|
|
+ 0 = empty. A whole-session linear scan is too slow (thousands of
|
|
|
+ lookups over thousands of entries), so FindSym/FindProc hash. *)
|
|
|
+ symHash : ARRAY [0 .. HashSize - 1] OF INTEGER;
|
|
|
+ procHash : ARRAY [0 .. HashSize - 1] OF INTEGER;
|
|
|
withRec : ARRAY [0 .. 15] OF SymTab.TypeIndex;
|
|
|
withTop : CARDINAL;
|
|
|
curMethCls : SymTab.TypeIndex; (* class bound by the last obj.Method *)
|
|
|
@@ -47,8 +54,11 @@ PROCEDURE CopyN (src: ARRAY OF CHAR; VAR dst: ARRAY OF CHAR);
|
|
|
dst[i] := CHR(0)
|
|
|
END CopyN;
|
|
|
|
|
|
-PROCEDURE CopySpan (src: ARRAY OF CHAR; VAR dst: ARRAY OF CHAR;
|
|
|
+PROCEDURE CopySpan (VAR src: ARRAY OF CHAR; VAR dst: ARRAY OF CHAR;
|
|
|
srcOff, dstOff: CARDINAL);
|
|
|
+(* src is a VAR open array on purpose: gm2 copies a value open-array
|
|
|
+ formal to a stack VLA of its full length, which overflows the stack
|
|
|
+ for the multi-megabyte tables below. *)
|
|
|
VAR i: CARDINAL;
|
|
|
BEGIN
|
|
|
i := 0;
|
|
|
@@ -58,18 +68,83 @@ PROCEDURE CopySpan (src: ARRAY OF CHAR; VAR dst: ARRAY OF CHAR;
|
|
|
dst[dstOff + i] := CHR(0)
|
|
|
END CopySpan;
|
|
|
|
|
|
+PROCEDURE HashStr (name: ARRAY OF CHAR): CARDINAL;
|
|
|
+ VAR h: CARDINAL; i: CARDINAL;
|
|
|
+ BEGIN
|
|
|
+ h := 5381; i := 0;
|
|
|
+ WHILE (i <= HIGH(name)) AND (name[i] # CHR(0)) DO
|
|
|
+ h := (h * 33 + VAL(CARDINAL, ORD(name[i]))) MOD HashSize; INC(i)
|
|
|
+ END;
|
|
|
+ RETURN h
|
|
|
+ END HashStr;
|
|
|
+
|
|
|
+PROCEDURE SpanEq (VAR arr: ARRAY OF CHAR; off: CARDINAL;
|
|
|
+ name: ARRAY OF CHAR): BOOLEAN;
|
|
|
+ VAR j: CARDINAL;
|
|
|
+ BEGIN
|
|
|
+ j := 0;
|
|
|
+ WHILE (j < MaxName) AND (name[j] # CHR(0)) DO
|
|
|
+ IF arr[off + j] # name[j] THEN RETURN FALSE END;
|
|
|
+ INC(j)
|
|
|
+ END;
|
|
|
+ RETURN arr[off + j] = name[j]
|
|
|
+ END SpanEq;
|
|
|
+
|
|
|
+PROCEDURE HashPut (VAR htab: ARRAY OF INTEGER; VAR names: ARRAY OF CHAR;
|
|
|
+ name: ARRAY OF CHAR; idx: CARDINAL);
|
|
|
+(* Insert idx, replacing an existing entry with the same name so the
|
|
|
+ latest declaration wins (the linear scan used to search backward). *)
|
|
|
+ VAR h: CARDINAL;
|
|
|
+ BEGIN
|
|
|
+ h := HashStr(name);
|
|
|
+ LOOP
|
|
|
+ IF htab[h] = 0 THEN htab[h] := VAL(INTEGER, idx) + 1; RETURN END;
|
|
|
+ IF SpanEq(names, VAL(CARDINAL, htab[h] - 1) * 64, name) THEN
|
|
|
+ htab[h] := VAL(INTEGER, idx) + 1; RETURN
|
|
|
+ END;
|
|
|
+ h := (h + 1) MOD HashSize
|
|
|
+ END
|
|
|
+ END HashPut;
|
|
|
+
|
|
|
+PROCEDURE HashGet (VAR htab: ARRAY OF INTEGER; VAR names: ARRAY OF CHAR;
|
|
|
+ name: ARRAY OF CHAR): INTEGER;
|
|
|
+ VAR h: CARDINAL;
|
|
|
+ BEGIN
|
|
|
+ h := HashStr(name);
|
|
|
+ LOOP
|
|
|
+ IF htab[h] = 0 THEN RETURN -1 END;
|
|
|
+ IF SpanEq(names, VAL(CARDINAL, htab[h] - 1) * 64, name) THEN
|
|
|
+ RETURN htab[h] - 1
|
|
|
+ END;
|
|
|
+ h := (h + 1) MOD HashSize
|
|
|
+ END
|
|
|
+ END HashGet;
|
|
|
+
|
|
|
PROCEDURE Reset;
|
|
|
+ VAR i: CARDINAL;
|
|
|
BEGIN
|
|
|
- nSyms := 0; nProcs := 0
|
|
|
+ nSyms := 0; nProcs := 0;
|
|
|
+ i := 0;
|
|
|
+ WHILE i < HashSize DO symHash[i] := 0; procHash[i] := 0; INC(i) END
|
|
|
END Reset;
|
|
|
|
|
|
PROCEDURE NoteVar (name: ARRAY OF CHAR; kind: INTEGER; t: SymTab.TypeIndex);
|
|
|
BEGIN
|
|
|
IF nSyms >= MaxSym THEN RETURN END;
|
|
|
CopySpan(name, symName, 0, nSyms * 64);
|
|
|
- symKind[nSyms] := kind; symTy[nSyms] := t; INC(nSyms)
|
|
|
+ symKind[nSyms] := kind; symTy[nSyms] := t;
|
|
|
+ HashPut(symHash, symName, name, nSyms);
|
|
|
+ INC(nSyms)
|
|
|
END NoteVar;
|
|
|
|
|
|
+PROCEDURE NoteConstVal (val: ARRAY OF CHAR);
|
|
|
+(* Records the evaluated value of the CONST just entered by NoteVar.
|
|
|
+ Const values are per-unit and cross-module names collide (every
|
|
|
+ module has EOL), so they live here, not in SymTab. *)
|
|
|
+ BEGIN
|
|
|
+ IF nSyms > 0 THEN CopyN(val, symVal[nSyms - 1]) END
|
|
|
+ END NoteConstVal;
|
|
|
+
|
|
|
PROCEDURE ScopeEnter;
|
|
|
BEGIN
|
|
|
END ScopeEnter;
|
|
|
@@ -86,9 +161,17 @@ PROCEDURE NoteProc (name: ARRAY OF CHAR; uid: CARDINAL;
|
|
|
procUid[nProcs] := uid; procRes[nProcs] := res;
|
|
|
procDep[nProcs] := depth; procExt[nProcs] := ext;
|
|
|
procNpar[nProcs] := 0;
|
|
|
+ HashPut(procHash, procName, name, nProcs);
|
|
|
INC(nProcs)
|
|
|
END NoteProc;
|
|
|
|
|
|
+PROCEDURE MarkProcExternal;
|
|
|
+(* The grammar calls this from the EXTERNAL branch, after NoteProc, so
|
|
|
+ the walk records that the callee takes no static link. *)
|
|
|
+ BEGIN
|
|
|
+ IF nProcs > 0 THEN procExt[nProcs - 1] := TRUE END
|
|
|
+ END MarkProcExternal;
|
|
|
+
|
|
|
PROCEDURE SetProcRes (t: SymTab.TypeIndex);
|
|
|
BEGIN
|
|
|
IF nProcs > 0 THEN procRes[nProcs - 1] := t END
|
|
|
@@ -108,37 +191,25 @@ PROCEDURE NoteParam (name: ARRAY OF CHAR; t: SymTab.TypeIndex; isVar: BOOLEAN);
|
|
|
|
|
|
PROCEDURE FindSym (name: ARRAY OF CHAR; VAR kind: INTEGER;
|
|
|
VAR t: SymTab.TypeIndex): BOOLEAN;
|
|
|
- VAR i: CARDINAL; j: CARDINAL; ok: BOOLEAN;
|
|
|
- BEGIN
|
|
|
- i := nSyms;
|
|
|
- WHILE i > 0 DO
|
|
|
- DEC(i);
|
|
|
- ok := TRUE; j := 0;
|
|
|
- WHILE ok AND (j < 64) AND (symName[i * 64 + j] # CHR(0)) DO
|
|
|
- IF symName[i * 64 + j] # name[j] THEN ok := FALSE END;
|
|
|
- INC(j)
|
|
|
- END;
|
|
|
- IF ok AND (symName[i * 64 + j] = name[j]) THEN
|
|
|
- kind := symKind[i]; t := symTy[i]; RETURN TRUE
|
|
|
- END
|
|
|
- END;
|
|
|
- RETURN FALSE
|
|
|
+ VAR i: INTEGER;
|
|
|
+ BEGIN
|
|
|
+ i := HashGet(symHash, symName, name);
|
|
|
+ IF i < 0 THEN RETURN FALSE END;
|
|
|
+ kind := symKind[i]; t := symTy[i]; RETURN TRUE
|
|
|
END FindSym;
|
|
|
|
|
|
+PROCEDURE GetConstVal (name: ARRAY OF CHAR; VAR v: ARRAY OF CHAR): BOOLEAN;
|
|
|
+ VAR i: INTEGER;
|
|
|
+ BEGIN
|
|
|
+ i := HashGet(symHash, symName, name);
|
|
|
+ IF (i < 0) OR (symKind[i] # SymTab.KindConst) THEN RETURN FALSE END;
|
|
|
+ CopyN(symVal[i], v);
|
|
|
+ RETURN v[0] # CHR(0)
|
|
|
+ END GetConstVal;
|
|
|
+
|
|
|
PROCEDURE FindProc (name: ARRAY OF CHAR): INTEGER;
|
|
|
- VAR i: CARDINAL; j: CARDINAL; ok: BOOLEAN;
|
|
|
- BEGIN
|
|
|
- i := nProcs;
|
|
|
- WHILE i > 0 DO
|
|
|
- DEC(i);
|
|
|
- ok := TRUE; j := 0;
|
|
|
- WHILE ok AND (j < 64) AND (procName[i * 64 + j] # CHR(0)) DO
|
|
|
- IF procName[i * 64 + j] # name[j] THEN ok := FALSE END;
|
|
|
- INC(j)
|
|
|
- END;
|
|
|
- IF ok AND (procName[i * 64 + j] = name[j]) THEN RETURN VAL(INTEGER, i) END
|
|
|
- END;
|
|
|
- RETURN -1
|
|
|
+ BEGIN
|
|
|
+ RETURN HashGet(procHash, procName, name)
|
|
|
END FindProc;
|
|
|
|
|
|
PROCEDURE Resolve (nm: ARRAY OF CHAR; VAR k: INTEGER;
|
|
|
@@ -158,9 +229,10 @@ PROCEDURE ProcInfo (nm: ARRAY OF CHAR; VAR uid: CARDINAL;
|
|
|
VAR i: INTEGER;
|
|
|
BEGIN
|
|
|
i := FindProc(nm);
|
|
|
- IF i < 0 THEN RETURN FALSE END;
|
|
|
+ IF (i < 0) OR (i >= MaxProc) THEN RETURN FALSE END;
|
|
|
uid := procUid[i]; res := procRes[i]; depth := procDep[i];
|
|
|
ext := procExt[i]; npar := procNpar[i];
|
|
|
+ IF npar > MaxPar THEN npar := MaxPar END;
|
|
|
RETURN TRUE
|
|
|
END ProcInfo;
|
|
|
|
|
|
@@ -170,7 +242,8 @@ PROCEDURE ParamInfo (nm: ARRAY OF CHAR; i: CARDINAL;
|
|
|
VAR k: INTEGER;
|
|
|
BEGIN
|
|
|
k := FindProc(nm);
|
|
|
- IF (k < 0) OR (i >= procNpar[k]) THEN RETURN FALSE END;
|
|
|
+ IF (k < 0) OR (k >= MaxProc) THEN RETURN FALSE END;
|
|
|
+ IF (i >= procNpar[k]) OR (procNpar[k] > MaxPar) THEN RETURN FALSE END;
|
|
|
t := parTy[VAL(CARDINAL, k) * MaxPar + i];
|
|
|
isVar := parVar[VAL(CARDINAL, k) * MaxPar + i];
|
|
|
CopySpan(parName, pn, VAL(CARDINAL, k) * MaxPar * 64 + i * 64, 0);
|
|
|
@@ -831,7 +904,7 @@ PROCEDURE LowerDesign (n: AST.Node; VAR t: SymTab.TypeIndex; VAR k: INTEGER;
|
|
|
t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
|
|
|
ELSIF SymTab.Equal(nm, "NIL") THEN
|
|
|
QbeGen.CopyOp("0", q)
|
|
|
- ELSIF SymTab.GetSymVal(nm, cv) AND QbeGen.IsImm(cv) THEN
|
|
|
+ ELSIF GetConstVal(nm, cv) AND QbeGen.IsImm(cv) THEN
|
|
|
QbeGen.CopyOp(cv, q)
|
|
|
ELSE QbeGen.CopyOp("0", q)
|
|
|
END
|
|
|
@@ -925,25 +998,52 @@ PROCEDURE LowerDesign (n: AST.Node; VAR t: SymTab.TypeIndex; VAR k: INTEGER;
|
|
|
|
|
|
PROCEDURE LowerCall (n: AST.Node; VAR t: SymTab.TypeIndex;
|
|
|
VAR q: QbeGen.QVal; want: BOOLEAN);
|
|
|
- VAR nm, pn: SymTab.Name; i: CARDINAL; at, ft, res: SymTab.TypeIndex;
|
|
|
- qa, qt, qe, mg: QbeGen.QVal; conv, isV, qual: BOOLEAN;
|
|
|
- uid, depth, np: CARDINAL; ext: BOOLEAN;
|
|
|
+ VAR nm, pn, cqn: SymTab.Name; i: CARDINAL; at, ft, res: SymTab.TypeIndex;
|
|
|
+ qa, qt, qe, mg: QbeGen.QVal; conv, isV, qual, ind: BOOLEAN;
|
|
|
+ uid, depth, np: CARDINAL; ext: BOOLEAN; ck: INTEGER;
|
|
|
+ ct: SymTab.TypeIndex; csfx: BOOLEAN;
|
|
|
BEGIN
|
|
|
qual := CalleeAlias(n, nm);
|
|
|
+ ind := FALSE;
|
|
|
IF qual THEN
|
|
|
uid := SymTab.ProcUid(nm); res := SymTab.ProcRes(nm);
|
|
|
depth := SymTab.ProcDepthOf(nm); ext := SymTab.IsExternal(nm);
|
|
|
- np := SymTab.ProcNPar(nm)
|
|
|
+ np := SymTab.ProcNPar(nm);
|
|
|
+ IF ext THEN QbeGen.CopyOp(nm, mg) ELSE QbeGen.Mangled(nm, uid, mg) END;
|
|
|
+ QbeGen.CallBegin(mg, res, depth, ext)
|
|
|
ELSE
|
|
|
CalleeName(n, nm);
|
|
|
- IF NOT ProcInfo(nm, uid, res, depth, ext, np) THEN END
|
|
|
+ IF FindSym(nm, ck, ct)
|
|
|
+ AND ((ck = SymTab.KindVar) OR (ck = SymTab.KindParam))
|
|
|
+ AND (SymTab.ClassOf(ct) = SymTab.ClProc) THEN
|
|
|
+ (* indirect call through a procedure-typed variable *)
|
|
|
+ ind := TRUE;
|
|
|
+ LowerDesign(AST.Child(n, 0), ct, ck, qa, cqn, csfx);
|
|
|
+ res := SymTab.ProcTypeRes(ct);
|
|
|
+ np := SymTab.ProcTypeNPar(ct);
|
|
|
+ QbeGen.CallBeginInd(qa, res, FALSE)
|
|
|
+ ELSIF ProcInfo(nm, uid, res, depth, ext, np) THEN
|
|
|
+ IF ext THEN
|
|
|
+ (* External callee: bind to its C link name (the procedure's
|
|
|
+ own name); SymTab.ProcLink cannot be consulted after
|
|
|
+ EndUnit. *)
|
|
|
+ QbeGen.CopyOp(nm, mg)
|
|
|
+ ELSE
|
|
|
+ QbeGen.Mangled(nm, uid, mg)
|
|
|
+ END;
|
|
|
+ QbeGen.CallBegin(mg, res, depth, ext)
|
|
|
+ ELSE
|
|
|
+ res := SymTab.InvalidType;
|
|
|
+ QbeGen.CallBegin(nm, res, 0, FALSE)
|
|
|
+ END
|
|
|
END;
|
|
|
- QbeGen.Mangled(nm, uid, mg);
|
|
|
- QbeGen.CallBegin(mg, res, depth, ext);
|
|
|
i := 1;
|
|
|
WHILE i < AST.NChild(n) DO
|
|
|
LowerExpr(AST.Child(n, i), at, qe);
|
|
|
- IF qual THEN
|
|
|
+ IF ind THEN
|
|
|
+ ft := SymTab.ProcTypeParamType(ct, i - 1);
|
|
|
+ isV := SymTab.ProcTypeParamIsVar(ct, i - 1)
|
|
|
+ ELSIF qual THEN
|
|
|
ft := SymTab.ParamType(nm, i - 1);
|
|
|
isV := SymTab.ParamIsVar(nm, i - 1)
|
|
|
ELSE
|
|
|
@@ -977,6 +1077,7 @@ PROCEDURE IsBuiltin (nm: ARRAY OF CHAR): BOOLEAN;
|
|
|
RETURN SymTab.Equal(nm, "ABS") OR SymTab.Equal(nm, "CAP")
|
|
|
OR SymTab.Equal(nm, "CHR") OR SymTab.Equal(nm, "ORD")
|
|
|
OR SymTab.Equal(nm, "SIZE") OR SymTab.Equal(nm, "TSIZE")
|
|
|
+ OR SymTab.Equal(nm, "LEN") OR SymTab.Equal(nm, "HIGH")
|
|
|
OR SymTab.Equal(nm, "MIN") OR SymTab.Equal(nm, "MAX")
|
|
|
OR SymTab.Equal(nm, "SHIFT") OR SymTab.Equal(nm, "ROTATE")
|
|
|
OR SymTab.Equal(nm, "ADR")
|
|
|
@@ -1022,6 +1123,22 @@ PROCEDURE LowerBuiltinExpr (n: AST.Node; nm: SymTab.Name;
|
|
|
t := SymTab.IntType()
|
|
|
ELSE t := SymTab.InvalidType; QbeGen.CopyOp("0", q)
|
|
|
END
|
|
|
+ ELSIF SymTab.Equal(nm, "LEN") OR SymTab.Equal(nm, "HIGH") THEN
|
|
|
+ LowerDesign(AST.Child(n, 1), dt, k, qd, qn, sfx);
|
|
|
+ IF dt = SymTab.InvalidType THEN
|
|
|
+ t := SymTab.InvalidType; QbeGen.CopyOp("0", q)
|
|
|
+ ELSIF SymTab.ClassOf(dt) = SymTab.ClArray THEN
|
|
|
+ IF SymTab.Equal(nm, "HIGH") THEN
|
|
|
+ IF SymTab.IsOpenArray(dt) THEN QbeGen.OpenHi(qd, q)
|
|
|
+ ELSE QbeGen.IntStr(SymTab.ArrayHi(dt), q) END
|
|
|
+ ELSE
|
|
|
+ IF SymTab.IsOpenArray(dt) THEN QbeGen.LoadCount(qd, q)
|
|
|
+ ELSE QbeGen.IntStr(VAL(INTEGER, SymTab.ArrayLen(dt)), q) END
|
|
|
+ END;
|
|
|
+ t := SymTab.IntType()
|
|
|
+ ELSE
|
|
|
+ t := SymTab.InvalidType; QbeGen.CopyOp("0", q)
|
|
|
+ END
|
|
|
ELSIF SymTab.Equal(nm, "SHIFT") OR SymTab.Equal(nm, "ROTATE") THEN
|
|
|
LowerExpr(AST.Child(n, 1), et, q);
|
|
|
LowerExpr(AST.Child(n, 2), et2, q2);
|
|
|
@@ -1760,9 +1877,13 @@ PROCEDURE LowerDecls (seq: AST.Node);
|
|
|
END
|
|
|
ELSIF AST.Kind(c) = AST.NkConstDecl THEN
|
|
|
Name(AST.Child(c, 0), nm);
|
|
|
- Name(AST.Child(c, 1), txt);
|
|
|
- QbeGen.NormInt(txt, qv);
|
|
|
- QbeGen.DeclConst(nm, qv, AST.Ty(c))
|
|
|
+ (* The value is a constant expression (CHR(..), arithmetic, a
|
|
|
+ prior CONST): use the evaluated value recorded by NoteConstVal,
|
|
|
+ not the AST text. Aggregates/strings store a descriptor
|
|
|
+ address and are not scalar data. *)
|
|
|
+ IF GetConstVal(nm, qv) AND QbeGen.IsImm(qv) THEN
|
|
|
+ QbeGen.DeclConst(nm, qv, AST.Ty(c))
|
|
|
+ END
|
|
|
ELSIF AST.Kind(c) = AST.NkProcDecl THEN
|
|
|
Name(AST.Child(c, 0), nm);
|
|
|
IF ProcInfo(nm, uid, res, depth, ext, np) THEN
|
|
|
@@ -1863,6 +1984,50 @@ PROCEDURE LowerSession (units: ARRAY OF AST.Node; n: CARDINAL;
|
|
|
QbeGen.EndModule(pn)
|
|
|
END LowerSession;
|
|
|
|
|
|
+PROCEDURE BeginSession (progName: ARRAY OF CHAR);
|
|
|
+(* Per-unit Lower emission. The grammar still runs its inline emit while
|
|
|
+ parsing, but under NoEmit it only mutates QbeGen's counters (nothing
|
|
|
+ reaches the buffer). For each unit: BeginUnit snapshots the state
|
|
|
+ *before* parsing; after parsing, LowerUnitNow restores that snapshot
|
|
|
+ and lets Lower re-emit the unit from the same counter values the
|
|
|
+ legacy inline path would have used, so the image stays byte-identical.
|
|
|
+ EndSession writes the accumulated session image. *)
|
|
|
+ BEGIN
|
|
|
+ withTop := 0;
|
|
|
+ curImplCls := SymTab.InvalidType;
|
|
|
+ QbeGen.OpenModule(progName);
|
|
|
+ QbeGen.SetNoEmit(TRUE)
|
|
|
+ END BeginSession;
|
|
|
+
|
|
|
+PROCEDURE BeginUnit;
|
|
|
+(* Snapshot the pre-parse state so Lower can discard the grammar's
|
|
|
+ suppressed inline mutations for this unit. *)
|
|
|
+ BEGIN
|
|
|
+ QbeGen.SaveSession
|
|
|
+ END BeginUnit;
|
|
|
+
|
|
|
+PROCEDURE LowerUnitNow (unit: AST.Node; isProg: BOOLEAN);
|
|
|
+ BEGIN
|
|
|
+ IF unit = AST.NoNode THEN RETURN END;
|
|
|
+ QbeGen.RestoreSession;
|
|
|
+ QbeGen.SetNoEmit(FALSE);
|
|
|
+ LowerOneUnit(unit, isProg);
|
|
|
+ QbeGen.SetNoEmit(TRUE)
|
|
|
+ END LowerUnitNow;
|
|
|
+
|
|
|
+PROCEDURE EndSession;
|
|
|
+ VAR out: ARRAY [0 .. 255] OF CHAR; j: CARDINAL;
|
|
|
+ BEGIN
|
|
|
+ j := 0;
|
|
|
+ WHILE (j <= 254) AND (curUnitName[j] # CHR(0)) DO
|
|
|
+ out[j] := curUnitName[j]; INC(j)
|
|
|
+ END;
|
|
|
+ out[j] := "L"; INC(j); out[j] := CHR(0);
|
|
|
+ QbeGen.SetNoEmit(FALSE);
|
|
|
+ QbeGen.SetOutName(out);
|
|
|
+ QbeGen.EndModule(curUnitName)
|
|
|
+ END EndSession;
|
|
|
+
|
|
|
PROCEDURE LowerUnit (unit: AST.Node);
|
|
|
VAR nm: SymTab.Name; out: ARRAY [0 .. 255] OF CHAR; i: CARDINAL;
|
|
|
BEGIN
|