home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 2
/
goldfish_vol2_cd1.bin
/
files
/
dev
/
obero
/
oberon-a
/
source
/
oc
/
compiler.mod
< prev
next >
Wrap
Text File
|
1994-08-19
|
62KB
|
2,046 lines
(***************************************************************************
$RCSfile: Compiler.mod $
Description: Recursive-descent parser
Created by: fjc (Frank Copeland)
$Revision: 4.12 $
$Author: fjc $
$Date: 1994/08/19 20:02:03 $
Copyright © 1990-1993, ETH Zuerich
Copyright © 1993-1994, Frank Copeland
This module forms part of the OC program
See OC.doc for conditions of use and distribution
Log entries are at the end of the file.
***************************************************************************)
MODULE Compiler;
(*
** $C= CaseChk $I= IndexChk $L= LongAdr $N= NilChk
** $P- PortableCode $R= RangeChk $S= StackChk $T= TypeChk
** $V= OvflChk $Z= ZeroVars
*)
IMPORT
Str := Strings, IO := StdIO, Oberon, Files, OCG, OCS, OCT, OCC, OCI,
OCE, OCP, OCH, SYS := SYSTEM;
(* --- Exported declarations -------------------------------------------- *)
VAR
newSF * : BOOLEAN;
forceCode * : BOOLEAN;
(* --- Local declarations ----------------------------------------------- *)
CONST
NofCases = 128; RecDescSize = 8; AdrSize = OCG.PtrSize;
ProcSize = OCG.ProcSize; PtrSize = OCG.PtrSize; ParOrg = 2 * AdrSize;
LParOrg = 3 * AdrSize; XParOrg = 3 * AdrSize; ProcVarSize = 32768;
ModNameLen = 26; (* Max. module name length, imposed by AmigaDOS *)
(* Symbols *)
null = OCS.null; times = OCS.times; slash = OCS.slash;
div = OCS.div; mod = OCS.mod; and = OCS.and;
plus = OCS.plus; minus = OCS.minus; or = OCS.or;
eql = OCS.eql; neq = OCS.neq; lss = OCS.lss;
leq = OCS.leq; gtr = OCS.gtr; geq = OCS.geq;
in = OCS.in; is = OCS.is; arrow = OCS.arrow;
period = OCS.period; comma = OCS.comma; colon = OCS.colon;
upto = OCS.upto; rparen = OCS.rparen; rbrak = OCS.rbrak;
rbrace = OCS.rbrace; of = OCS.of; then = OCS.then;
do = OCS.do; to = OCS.to; lparen = OCS.lparen;
lbrak = OCS.lbrak; lbrace = OCS.lbrace; not = OCS.not;
becomes = OCS.becomes; number = OCS.number; nil = OCS.nil;
string = OCS.string; ident = OCS.ident; semicolon = OCS.semicolon;
bar = OCS.bar; end = OCS.end; else = OCS.else;
elsif = OCS.elsif; until = OCS.until; if = OCS.if;
case = OCS.case; while = OCS.while; repeat = OCS.repeat;
loop = OCS.loop; with = OCS.with; exit = OCS.exit;
return = OCS.return; array = OCS.array; record = OCS.record;
pointer = OCS.pointer; begin = OCS.begin; const = OCS.const;
type = OCS.type; var = OCS.var; procedure = OCS.procedure;
import = OCS.import; module = OCS.module; eof = OCS.eof;
cpointer = OCS.cpointer; bpointer = OCS.bpointer; libcall = OCS.libcall;
for = OCS.for; by = OCS.by;
(* object modes *)
Var = OCG.Var; VarR = OCG.VarR; Ind = OCG.Ind; IndR = OCG.IndR;
Con = OCG.Con; Reg = OCG.Reg; Fld = OCG.Fld; Typ = OCG.Typ;
LProc = OCG.LProc; XProc = OCG.XProc; SProc = OCG.SProc;
TProc = OCG.TProc; FProc = OCG.FProc; Mod = OCG.Mod; Abs = OCG.Abs;
VarArg = OCG.VarArg;
(* object modes for language extensions *)
LibCall = OCG.LibCall;
(* structure forms *)
Undef = OCT.Undef; Byte = OCT.Byte; Bool = OCT.Bool; Char = OCT.Char;
SInt = OCT.SInt; Int = OCT.Int; LInt = OCT.LInt; Real = OCT.Real;
LReal = OCT.LReal; BSet = OCT.BSet; WSet = OCT.WSet; Set = OCT.Set;
String = OCT.String; NilTyp = OCT.NilTyp; NoTyp = OCT.NoTyp;
PtrTyp = OCT.PtrTyp; CPtrTyp = OCT.CPtrTyp; BPtrTyp = OCT.BPtrTyp;
Pointer = OCT.Pointer; CPointer = OCT.CPointer; BPointer = OCT.BPointer;
ProcTyp = OCT.ProcTyp; Array = OCT.Array; DynArr = OCT.DynArr;
Record = OCT.Record;
intSet = {SInt, Int, LInt};
ptrSet = {Pointer, CPointer, BPointer};
uptrSet = {CPointer, BPointer};
labeltyps = {Char, SInt, Int, LInt};
NumLoopLevels = 16; MaxLoopLevel = NumLoopLevels - 1;
VAR
sym, procNo : INTEGER;
LoopLevel, ExitNo : INTEGER;
LoopExit : ARRAY NumLoopLevels OF INTEGER;
(* CONST mname = "Compiler"; *)
(* --- Procedure declarations ------------------------------------------- *)
(*----------------------------------)-*)
PROCEDURE^ Type (VAR typ : OCT.Struct);
PROCEDURE^ Expression (VAR x : OCT.Item);
PROCEDURE^ Block
(proc : OCT.Object; VAR dsize : LONGINT; VAR retList : INTEGER);
(*------------------------------------*)
PROCEDURE CheckSym (s : INTEGER);
BEGIN (* CheckSym *)
IF sym = s THEN OCS.Get (sym) ELSE OCS.Mark (s) END
END CheckSym;
(*------------------------------------*)
PROCEDURE qualident (VAR x : OCT.Item; allocDesc : BOOLEAN);
(* CONST pname = "qualident"; *)
VAR mnolev : INTEGER; obj : OCT.Object; desc : OCT.Desc; b : BOOLEAN;
BEGIN (* qualident *)
(* OCG.TraceIn (mname, pname); *)
(* sym = ident *)
OCT.Find (obj, mnolev); IF obj = NIL THEN OCS.Mark (0) END; OCS.Get (sym);
IF (sym = period) & (obj # NIL) & (obj.mode = Mod) THEN
OCS.Get (sym); mnolev := SHORT (-obj.a0);
IF sym = ident THEN
OCT.FindImport (obj, obj); IF obj = NIL THEN OCS.Mark (0) END;
OCS.Get (sym)
ELSE
OCS.Mark (10); obj := NIL
END;
END;
x.lev := mnolev; x.obj := obj;
IF obj # NIL THEN
x.mode := obj.mode; x.typ := obj.typ; x.a0 := obj.a0;
x.a1 := obj.a1; x.a2 := obj.a2; x.symbol := obj.symbol;
x.rdOnly := (mnolev < 0) & (obj.visible = OCT.RdOnly);
(*
IF mnolev < 0 THEN
b := (obj.visible = OCT.RdOnly); x.rdOnly := b
ELSE x.rdOnly := FALSE
END;
*)
IF
allocDesc & (x.mode IN {Var, Ind}) & (x.typ # NIL)
& (x.typ.form = DynArr)
THEN
desc := OCT.AllocDesc (); desc.mode := Var; desc.lev := x.lev;
desc.a0 := x.a0; desc.a1 := 0; desc.a2 := 0; x.desc := desc
ELSE
x.desc := NIL
END
ELSE
x.mode := Var; x.typ := OCT.undftyp; x.a0 := 0; x.obj := NIL;
x.rdOnly := FALSE; x.desc := NIL
END
(* ;OCG.TraceOut (mname, pname); *)
END qualident;
(*------------------------------------*)
PROCEDURE ConstExpression (VAR x : OCT.Item);
(* CONST pname = "ConstExpression"; *)
CONST
ConstTypes = {Undef .. NilTyp, CPtrTyp, BPtrTyp, CPointer, BPointer};
BEGIN (* ConstExpression *)
(* OCG.TraceIn (mname, pname); *)
Expression (x);
IF (x.mode # Con) OR ~(x.typ.form IN ConstTypes) THEN
OCS.Mark (50); x.mode := Con; x.typ := OCT.inttyp; x.a0 := 1;
END;
(* ;OCG.TraceOut (mname, pname); *)
END ConstExpression;
(*------------------------------------*)
PROCEDURE NewStr (form : INTEGER) : OCT.Struct;
(* CONST pname = "NewStr"; *)
VAR typ : OCT.Struct;
BEGIN (* NewStr *)
(* OCG.TraceIn (mname, pname); *)
typ := OCT.AllocStruct ();
typ.form := form; typ.mno := 0; typ.size := 4; typ.ref := 0;
typ.BaseTyp := OCT.undftyp; typ.strobj := NIL; typ.link := NIL;
(* ;OCG.TraceOut (mname, pname); *)
RETURN typ
END NewStr;
(*------------------------------------*)
PROCEDURE CheckMark (VAR mk : SHORTINT; readOnly : BOOLEAN);
(* CONST pname = "CheckMark"; *)
BEGIN (* CheckMark *)
(* OCG.TraceIn (mname, pname); *)
OCS.Get (sym);
IF sym = times THEN
IF OCC.level = 0 THEN mk := OCT.Exp
ELSE mk := OCT.NotExp; OCS.Mark (46)
END;
OCS.Get (sym)
ELSIF sym = minus THEN
IF (OCC.level = 0) & readOnly THEN mk := OCT.RdOnly
ELSE mk := OCT.NotExp; OCS.Mark (47)
END;
OCS.Get (sym)
ELSE
mk := OCT.NotExp
END
(* ;OCG.TraceOut (mname, pname); *)
END CheckMark;
(*------------------------------------*)
PROCEDURE CheckUndefPointerTypes ();
(* CONST pname = "CheckUndefPointerTypes"; *)
(*------------------------------------*)
PROCEDURE CheckObj (obj : OCT.Object);
BEGIN (* CheckObj *)
IF obj # NIL THEN
IF obj.mode = Undef THEN OCS.Mark (48) END;
CheckObj (obj.left); CheckObj (obj.right)
END
END CheckObj;
BEGIN (* CheckUndefPointerTypes *)
(* OCG.TraceIn (mname, pname); *)
CheckObj (OCT.topScope.link)
(* ;OCG.TraceOut (mname, pname); *)
END CheckUndefPointerTypes;
(*------------------------------------*)
PROCEDURE CheckForwardProcs ();
(* CONST pname = "CheckForwardProcs"; *)
(*------------------------------------*)
PROCEDURE CheckObj ( obj : OCT.Object );
(*------------------------------------*)
PROCEDURE CheckTyp ( typ : OCT.Struct );
VAR fld : OCT.Object;
BEGIN (* CheckTyp *)
IF (typ # NIL) & (typ.form = Record) THEN
fld := typ.link;
WHILE fld # NIL DO
IF (fld.mode = TProc) & (fld.a2 < 0) THEN OCS.Mark (129) END;
fld := fld.left
END
END
END CheckTyp;
BEGIN (* CheckObj *)
IF obj # NIL THEN
IF obj.mode IN {XProc, LProc} THEN
IF obj.a2 < 0 THEN OCS.Mark (129) END
ELSIF obj.mode = Typ THEN
CheckTyp (obj.typ)
END;
CheckObj (obj.left); CheckObj (obj.right)
END
END CheckObj;
BEGIN (* CheckForwardProcs *)
(* OCG.TraceIn (mname, pname); *)
CheckObj (OCT.topScope.link)
(* ;OCG.TraceOut (mname, pname); *)
END CheckForwardProcs;
(*------------------------------------*)
PROCEDURE RecordType (VAR typ : OCT.Struct);
(* CONST pname = "RecordType"; *)
VAR
adr, size : LONGINT;
fld, fld0, fld1, fld2 : OCT.Object;
ftyp : OCT.Struct;
base : OCT.Item;
BEGIN (* RecordType *)
(* OCG.TraceIn (mname, pname); *)
typ := NewStr (Record); typ.BaseTyp := NIL; typ.n := 0; adr := 0;
IF sym = lparen THEN
OCS.Get (sym); (* record extension *)
IF sym = ident THEN
qualident (base, FALSE);
IF (base.mode = Typ) & (base.typ.form = Record) THEN
typ.BaseTyp := base.typ; typ.n := base.typ.n + 1;
adr := base.typ.size
ELSE
OCS.Mark (52)
END;
ELSE
OCS.Mark (10)
END;
CheckSym (rparen)
END;
OCT.OpenScope (0); fld := NIL; fld1 := OCT.AllocObj(); fld2 := NIL;
LOOP
(* OCG.TraceIn (mname, "LOOP1"); *)
IF sym = ident THEN
LOOP
(* OCG.TraceIn (mname, "LOOP2"); *)
IF sym = ident THEN
IF typ.BaseTyp # NIL THEN
OCT.FindField (typ.BaseTyp, fld0);
IF fld0 # NIL THEN OCS.Mark (1) END
END;
OCT.Insert (OCS.name, fld, Fld); CheckMark (fld.visible, TRUE);
IF (fld # fld2) & (fld.link = NIL) THEN
IF fld2 = NIL THEN fld1.link := fld; OCT.topScope.right := fld
ELSE fld2.link := fld
END;
fld2 := fld
END;
ELSE
OCS.Mark (10)
END;
IF sym = comma THEN
OCS.Get (sym)
ELSIF sym = ident THEN
OCS.Mark (19)
ELSE
(* ;OCG.TraceOut (mname, "LOOP2"); *)
EXIT
END;
(* ;OCG.TraceOut (mname, "LOOP2"); *)
END; (* LOOP *)
CheckSym (colon); Type (ftyp);
IF ftyp.form = DynArr THEN ftyp := OCT.undftyp; OCS.Mark (325) END;
size := ftyp.size;
IF size > 1 THEN
INC (adr, adr MOD 2); INC (size, size MOD 2) (* word align *)
END;
WHILE fld1.link # NIL DO
(* OCG.TraceIn (mname, "WHILE1"); *)
fld1 := fld1.link; fld1.typ := ftyp;
fld1.a0 := adr; INC (adr, size)
(* ;OCG.TraceOut (mname, "WHILE1"); *)
END;
END; (* IF *)
IF sym = semicolon THEN
OCS.Get (sym)
ELSIF sym = ident THEN
OCS.Mark (38)
ELSE
(* ;OCG.TraceOut (mname, "LOOP1"); *)
EXIT
END;
(* ;OCG.TraceOut (mname, "LOOP1"); *)
END; (* LOOP *)
typ.size := adr + (adr MOD 2); typ.link := OCT.topScope.right;
CheckUndefPointerTypes ();
fld0 := OCT.topScope.right;
WHILE fld0 # NIL DO
(* OCG.TraceIn (mname, "WHILE2"); *)
fld1 := fld0.link; fld0.link := NIL;
fld0.left := fld1; fld0.right := NIL;
fld0 := fld1
(* ;OCG.TraceOut (mname, "WHILE2"); *)
END;
OCT.CloseScope ();
(* ;OCG.TraceOut (mname, pname); *)
END RecordType;
(*------------------------------------*)
PROCEDURE ArrayType (VAR typ : OCT.Struct);
(* CONST pname = "ArrayType"; *)
VAR x : OCT.Item; f, n : INTEGER;
BEGIN (* ArrayType *)
(* OCG.TraceIn (mname, pname); *)
IF sym # of THEN
typ := NewStr (Array); ConstExpression (x); f := x.typ.form;
IF f IN intSet THEN
IF (x.a0 > 0) & (x.a0 <= MAX (INTEGER)) THEN n := SHORT (x.a0)
ELSE n := 1; OCS.Mark (68)
END
ELSE
OCS.Mark (51); n := 1
END;
typ.n := n;
IF sym = of THEN OCS.Get (sym); Type (typ.BaseTyp)
ELSIF sym = comma THEN OCS.Get (sym); ArrayType (typ.BaseTyp)
ELSE OCS.Mark (34)
END;
IF typ.BaseTyp.form = DynArr THEN
typ.BaseTyp := OCT.undftyp; OCS.Mark (325)
END;
typ.size := n * typ.BaseTyp.size;
INC (typ.size, typ.size MOD 2); (* keep word alignment *)
ELSE
typ := NewStr (DynArr); OCS.Get (sym); Type (typ.BaseTyp);
IF typ.BaseTyp.form = DynArr THEN
typ.size := typ.BaseTyp.size + 4; typ.adr := typ.BaseTyp.adr + 4
ELSE
typ.size := 8; typ.adr := 4
END
END
(* ;OCG.TraceOut (mname, pname); *)
END ArrayType;
(*------------------------------------*)
(*
$ FormalParameters = "(" [FPSection {";" FPSection}] ")"
$ [":" qualident].
$ FPSection = [VAR] ident [RegSpec] {"," ident [RegSpec]}
$ ":" Type.
$ RegSpec = "{" ConstExpression "}" [".."].
*)
PROCEDURE FormalParameters (
VAR resTyp : OCT.Struct; VAR psize : LONGINT; regPars : BOOLEAN);
(* CONST pname = "FormalParameters"; *)
CONST
D0 = 0; A5 = 13;
VAR
mode : SHORTINT; gotUpto : BOOLEAN;
adr, size : LONGINT; res, reg : OCT.Item;
par, par1, par2: OCT.Object; typ : OCT.Struct;
BEGIN (* FormalParameters *)
(* OCG.TraceIn (mname, pname); *)
adr := 0; gotUpto := FALSE;
(* Make allowance for the receiver of type-bound and libcall procedures *)
IF OCT.topScope.right # NIL THEN
par1 := OCT.topScope.right; adr := par1.a0
ELSE
par1 := OCT.AllocObj()
END;
par2 := par1;
IF (sym = ident) OR (sym = var) THEN
LOOP
IF sym = var THEN
OCS.Get (sym); IF regPars THEN mode := IndR ELSE mode := Ind END
ELSIF regPars THEN mode := VarR
ELSE mode := Var
END;
LOOP
IF sym = ident THEN
OCT.Insert (OCS.name, par, mode); OCS.Get (sym);
IF OCT.topScope.right = NIL THEN OCT.topScope.right := par END;
IF (par # par2) & (par.link = NIL) THEN
par2.link := par;
IF par1.link = NIL THEN par1.link := par END;
END;
par2 := par
ELSE OCS.Mark (10)
END;
IF sym = lbrak THEN (* Register specification *)
OCS.Get (sym); ConstExpression (reg);
IF reg.typ.form IN intSet THEN
IF (reg.a0 >= D0) & (reg.a0 <= A5) THEN par.a0 := reg.a0;
ELSE OCS.Mark (903)
END
ELSE OCS.Mark (902)
END;
CheckSym (rbrak);
IF ~regPars THEN OCS.Mark (901); par.mode := Var; par.a0 := 0 END
ELSIF regPars THEN OCS.Mark (340)
END;
IF sym = upto THEN
IF mode = VarR THEN par.mode := VarArg ELSE OCS.Mark (336) END;
gotUpto := TRUE; OCS.Get (sym)
END;
IF sym = comma THEN OCS.Get (sym)
ELSIF sym = ident THEN OCS.Mark (19)
ELSIF sym = var THEN OCS.Mark (19); OCS.Get (sym)
ELSE EXIT
END;
END; (* LOOP *)
CheckSym (colon); Type (typ);
(*IF (mode = VarArg) & (typ.size > PtrSize) THEN OCS.Mark (338) END;*)
IF ~regPars THEN
IF mode = Ind THEN (* VAR param *)
IF typ.form = Record THEN size := RecDescSize
ELSIF typ.form = DynArr THEN size := typ.size
ELSE size := AdrSize
END
ELSE
size := typ.size; IF ODD (size) THEN INC (size) END;
END;
WHILE par1.link # NIL DO
par1 := par1.link; par1.typ := typ;
DEC (adr, size); par1.a0 := adr
END;
ELSE
WHILE par1.link # NIL DO par1 := par1.link; par1.typ := typ END
END;
IF sym = semicolon THEN OCS.Get (sym)
ELSIF sym = ident THEN OCS.Mark (38)
ELSE EXIT
END;
IF gotUpto THEN OCS.Mark (337) END
END; (* LOOP *)
END; (* IF *)
IF ~regPars THEN
psize := psize - adr;
IF psize > OCG.ParLimit THEN OCS.Mark (209); psize := 0 END;
par := OCT.topScope.right;
WHILE par # NIL DO INC (par.a0, psize); par := par.link END;
END;
CheckSym (rparen);
IF sym = colon THEN
OCS.Get (sym); resTyp := OCT.undftyp;
IF sym = ident THEN
qualident (res, FALSE);
IF res.mode = Typ THEN
IF res.typ.form <= ProcTyp THEN
resTyp := res.typ
ELSE
OCS.Mark (54)
END
ELSE
OCS.Mark (52)
END
ELSE
OCS.Mark (10)
END;
ELSE
resTyp := OCT.notyp
END;
(* ;OCG.TraceOut (mname, pname); *)
END FormalParameters;
(*------------------------------------*)
PROCEDURE ProcType (VAR typ : OCT.Struct);
(* CONST pname = "ProcType"; *)
VAR psize : LONGINT;
BEGIN (* ProcType *)
(* OCG.TraceIn (mname, pname); *)
typ := NewStr (ProcTyp); typ.size := ProcSize;
IF sym = lparen THEN
OCS.Get (sym); OCT.OpenScope (OCC.level); psize := ParOrg;
FormalParameters (typ.BaseTyp, psize, FALSE);
typ.link := OCT.topScope.right; OCT.CloseScope ();
ELSE
typ.BaseTyp := OCT.notyp; typ.link := NIL
END;
(* ;OCG.TraceOut (mname, pname); *)
END ProcType;
(*------------------------------------*)
PROCEDURE SetPtrBase (ptyp, btyp : OCT.Struct);
(* CONST pname = "SetPtrBase"; *)
BEGIN (* SetPtrBase *)
(* OCG.TraceIn (mname, pname); *)
ptyp.symbol := OCT.OberonSysPtr;
IF (ptyp.form IN {CPointer, BPointer}) THEN
IF btyp.form = DynArr THEN
ptyp.BaseTyp := OCT.undftyp; OCS.Mark (326)
ELSE
ptyp.BaseTyp := btyp
END
ELSIF btyp.form IN {Record, Array, DynArr} THEN
ptyp.BaseTyp := btyp;
IF btyp.form = DynArr THEN
ptyp.size := btyp.size; OCC.AllocTypDesc (ptyp)
END
ELSE
ptyp.BaseTyp := OCT.undftyp; OCS.Mark (57)
END
(* ;OCG.TraceOut (mname, pname); *)
END SetPtrBase;
(*------------------------------------*)
(*
$ type = qualident | ArrayType | RecordType | StructType| PointerType |
$ ProcedureType.
*)
PROCEDURE Type (VAR typ : OCT.Struct);
(* CONST pname = "Type"; *)
VAR lev : INTEGER; obj : OCT.Object; x : OCT.Item;
BEGIN (* Type *)
(* OCG.TraceIn (mname, pname); *)
typ := OCT.undftyp;
IF sym < lparen THEN
OCS.Mark (12); REPEAT OCS.Get (sym) UNTIL sym >= lparen
END;
IF sym = ident THEN
qualident (x, FALSE);
IF x.mode = Typ THEN
typ := x.typ; IF typ = OCT.notyp THEN OCS.Mark (58) END
ELSE
OCS.Mark (52)
END
ELSIF sym = array THEN
OCS.Get (sym); ArrayType (typ)
ELSIF sym = record THEN
OCS.Get (sym); (*IF ~OCS.createObj THEN OCS.Mark (917) END;*)
RecordType (typ); OCC.AllocTypDesc (typ); CheckSym (end)
ELSIF (sym = pointer) OR (sym = cpointer) OR (sym = bpointer) THEN
typ := NewStr (Pointer);
IF sym = cpointer THEN
IF OCS.portableCode THEN OCS.Mark (915) END;
typ.form := CPointer
ELSIF sym = bpointer THEN
IF OCS.portableCode THEN OCS.Mark (915) END;
typ.form := BPointer
END;
OCS.Get (sym); typ.link := NIL; typ.size := PtrSize; CheckSym (to);
IF sym = ident THEN
OCT.Find (obj, lev);
IF obj = NIL THEN (* forward reference *)
OCT.Insert (OCS.name, obj, Undef); typ.BaseTyp := OCT.undftyp;
obj.typ := typ; OCS.Get (sym)
ELSE
qualident (x, FALSE);
IF x.mode = Typ THEN SetPtrBase (typ, x.typ)
ELSE typ.BaseTyp := OCT.undftyp; OCS.Mark (52)
END
END
ELSE Type (x.typ); SetPtrBase (typ, x.typ)
END
ELSIF sym = procedure THEN
OCS.Get (sym); ProcType (typ)
ELSE
OCS.Mark (12)
END;
IF (sym # semicolon) & (sym # rparen) & (sym # end) THEN
OCS.Mark (15);
WHILE (sym < ident) OR (else < sym) & (sym < begin) DO
OCS.Get (sym)
END
END
(* ;OCG.TraceOut (mname, pname); *)
END Type;
(*------------------------------------*)
(*
$ designator = qualident
$ {"." ident | "[" ExpList "]" | "(" qualident ")" | "^" }.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
$ ExpList = expression {"," expression}.
*)
PROCEDURE selector (VAR x, rcvr : OCT.Item);
(* CONST pname = "selector"; *)
VAR fld : OCT.Object; y : OCT.Item; t : OCT.Struct; f : INTEGER;
BEGIN (* selector *)
(* OCG.TraceIn (mname, pname); *)
rcvr.mode := Undef;
LOOP
IF sym = lbrak THEN
OCS.Get (sym);
LOOP
IF (x.typ # NIL) & (x.typ.form IN ptrSet) THEN OCE.DeRef (x) END;
Expression (y); OCE.Index (x, y);
IF sym = comma THEN OCS.Get (sym) ELSE EXIT END
END;
CheckSym (rbrak)
ELSIF sym = period THEN
OCS.Get (sym);
IF sym = ident THEN
IF x.typ # NIL THEN
t := x.typ; f := t.form; IF f IN ptrSet THEN t := t.BaseTyp END;
IF (t.form = Record) THEN
OCT.FindField (t, fld);
IF fld # NIL THEN
IF fld.mode = Fld THEN
IF f IN ptrSet THEN OCE.DeRef (x) END; OCE.Field (x, fld)
ELSIF fld.mode = TProc THEN
rcvr := x; x.mode := TProc; x.a0 := fld.a0; x.a2 := 0;
x.obj := fld; x.typ := fld.typ; x.symbol := fld.symbol
ELSIF fld.mode = LibCall THEN
rcvr := x; x.mode := LibCall; x.a0 := fld.a0;
x.obj := fld; x.typ := fld.typ
END
ELSE
OCS.Mark (83); x.typ := OCT.undftyp; x.mode := Var;
x.rdOnly := FALSE
END
ELSE
OCS.Mark (53)
END;
ELSE
OCS.Mark (52) (* ? *)
END;
OCS.Get (sym)
ELSE
OCS.Mark (10)
END;
ELSIF sym = arrow THEN
IF x.mode = TProc THEN
IF (rcvr.mode IN {Var,Ind}) & (rcvr.a2 < 0) THEN
OCT.SuperCall (x.a0, rcvr.typ, fld);
IF fld # NIL THEN
x.a2 := -1; x.obj := fld; x.symbol := fld.symbol
ELSE OCS.Mark (333)
END
ELSE OCS.Mark (332)
END;
OCS.Get (sym)
ELSE
OCS.Get (sym); OCE.DeRef (x)
END
ELSIF (sym = lparen) & (x.mode < Typ) & (x.typ.form # ProcTyp) THEN
OCS.Get (sym);
IF sym = ident THEN
qualident (y, FALSE);
IF y.mode = Typ THEN OCE.TypTest (x, y, FALSE)
ELSE OCS.Mark (52)
END
ELSE
OCS.Mark (10)
END;
CheckSym (rparen)
ELSE
EXIT
END;
END; (* LOOP *)
(* ;OCG.TraceOut (mname, pname); *)
END selector;
(*------------------------------------*)
PROCEDURE IsParam (obj : OCT.Object) : BOOLEAN;
BEGIN (* IsParam *)
RETURN (obj # NIL) & (obj.mode <= IndR) & (obj.a0 >= 0)
END IsParam;
(*------------------------------------*)
PROCEDURE VarArgs
( VAR apar : OCT.Item; fpar : OCT.Object;
VAR stackload : LONGINT; load : BOOLEAN );
VAR x : OCT.Item;
BEGIN (* VarArgs *)
IF sym = comma THEN
OCS.Get (sym); Expression (x); VarArgs (x, fpar, stackload, FALSE)
END;
OCH.VarArg (apar, fpar, stackload, load)
END VarArgs;
(*------------------------------------*)
(*
$ ActualParameters = "(" [ExpList] ")" .
$ ExpList = expression {"," expression}.
*)
PROCEDURE ActualParameters (fpar: OCT.Object; VAR stackload : LONGINT);
(* CONST pname = "ActualParameters"; *)
VAR apar : OCT.Item; R : SET;
BEGIN (* ActualParameters *)
(* OCG.TraceIn (mname, pname); *)
IF sym # rparen THEN
R := OCC.RegSet;
LOOP
Expression (apar);
IF IsParam (fpar) THEN
IF fpar.mode = VarArg THEN VarArgs (apar, fpar, stackload, TRUE)
ELSE OCH.Param (apar, fpar)
END;
fpar := fpar.link
ELSE
OCS.Mark (64)
END;
IF sym = comma THEN OCS.Get (sym)
ELSIF (lparen <= sym) & (sym <= ident) THEN OCS.Mark (19)
ELSE EXIT
END
END;
OCC.FreeRegs (R);
END;
IF IsParam (fpar) THEN OCS.Mark (65) END
(* ;OCG.TraceOut (mname, pname); *)
END ActualParameters;
(*------------------------------------*)
PROCEDURE StandProcCall (VAR x : OCT.Item);
(* CONST pname = "StandProcCall"; *)
VAR y : OCT.Item; m, n : INTEGER; R : SET;
BEGIN (* StandProcCall *)
(* OCG.TraceIn (mname, pname); *)
m := SHORT (x.a0); n := 0; R := {};
IF (sym = lparen) THEN
OCS.Get (sym);
IF sym # rparen THEN
LOOP
IF m = OCT.pINLINE THEN
Expression (x); OCP.Inline (x);
ELSIF n = 0 THEN
Expression (x); OCP.StPar1 (x, m, R); n := 1
ELSIF m = OCT.pNEW THEN
Expression (y); OCP.NewPar (x, y, n); INC (n)
ELSIF n = 1 THEN
Expression (y); OCP.StPar2 (x, y, m, R); n := 2;
ELSIF n = 2 THEN
Expression (y); OCP.StPar3 (x, y, m, R); n := 3;
ELSE
OCS.Mark (64); Expression (y);
END;
IF sym = comma THEN
OCS.Get (sym)
ELSIF (lparen <= sym) & (sym <= ident) THEN
OCS.Mark (19)
ELSE
EXIT
END;
END; (* LOOP *)
CheckSym (rparen)
ELSE
OCS.Get (sym)
END;
OCP.StFct (x, m, n, R)
ELSIF m = OCT.pGC THEN
OCP.StFct (x, m, n, R)
ELSE
OCS.Mark (29)
END;
(* ;OCG.TraceOut (mname, pname); *)
END StandProcCall;
(*------------------------------------*)
(*
$ element = expression [".." expression].
*)
PROCEDURE Element (VAR x : OCT.Item);
(* CONST pname = "Element"; *)
VAR e1, e2 : OCT.Item;
BEGIN (* Element *)
(* OCG.TraceIn (mname, pname); *)
Expression (e1);
IF sym = upto THEN
OCS.Get (sym); Expression (e2); OCE.Set1 (x, e1, e2)
ELSE
OCE.Set0 (x, e1)
END;
(* ;OCG.TraceOut (mname, pname); *)
END Element;
(*------------------------------------*)
(*
$ set = "{" [element {"," element}] "}".
*)
PROCEDURE Sets (VAR x : OCT.Item);
(* CONST pname = "Sets"; *)
VAR y : OCT.Item;
BEGIN (* Sets *)
(* OCG.TraceIn (mname, pname); *)
x.typ := OCT.settyp; y.typ := OCT.settyp;
IF sym # rbrace THEN
Element (x);
LOOP
IF sym = comma THEN
OCS.Get (sym)
ELSIF (lparen <= sym) & (sym <= ident) THEN
OCS.Mark (19)
ELSE
EXIT
END;
Element (y); OCE.Op (plus, x, y, TRUE) (* x := x + y *)
END; (* LOOP *)
ELSE
x.mode := Con; x.a0 := 0
END;
CheckSym (rbrace);
(* ;OCG.TraceOut (mname, pname); *)
END Sets;
(*------------------------------------*)
(*
$ factor = number | CharConstant | string | NIL | set |
$ designator [ActualParameters] | "(" expression ")" | "~" factor.
*)
PROCEDURE Factor (VAR x : OCT.Item);
(* CONST pname = "Factor"; *)
VAR
fpar : OCT.Object; rcvr : OCT.Item; R, mask : SET;
stackload : LONGINT;
BEGIN (* Factor *)
(* OCG.TraceIn (mname, pname); *)
IF sym < lparen THEN
OCS.Mark (13);
REPEAT OCS.Get (sym) UNTIL sym >= lparen
END;
x.desc := NIL;
IF sym = ident THEN
qualident (x, TRUE); selector (x, rcvr);
IF x.mode = SProc THEN
StandProcCall (x)
ELSIF sym = lparen THEN
OCH.PrepCall (x, fpar, mask); OCC.SaveRegisters (R, x, mask);
IF x.mode = TProc THEN OCH.Receiver (rcvr, x.obj.link) END;
OCS.Get (sym); stackload := 0; ActualParameters (fpar, stackload);
IF x.mode = LibCall THEN OCH.CallLibCall (x, rcvr, stackload)
ELSIF x.mode = TProc THEN OCH.CallTypeBound (x, rcvr)
ELSE OCH.Call (x)
END;
OCC.RestoreRegisters (R, x);
CheckSym (rparen)
END;
ELSIF sym = number THEN
OCS.Get (sym); x.mode := Con;
CASE OCS.numtyp OF
1 : x.typ := OCT.chartyp; x.a0 := OCS.intval
|
2 : x.a0 := OCS.intval; OCE.SetIntType (x)
|
3 : x.typ := OCT.realtyp; OCE.AssReal (x, OCS.realval)
|
4 : x.typ := OCT.lrltyp; OCE.AssLReal (x, OCS.lrlval)
|
END; (* CASE OCS.numtyp *)
ELSIF sym = string THEN
x.typ := OCT.stringtyp; x.mode := Con;
OCC.AllocString (OCS.name, OCS.intval, x); OCS.Get (sym);
IF ~OCS.portableCode THEN
WHILE sym = string DO
OCC.ConcatString (OCS.name, OCS.intval, x); OCS.Get (sym)
END
END
ELSIF sym = nil THEN
OCS.Get (sym); x.typ := OCT.niltyp; x.mode := Con; x.a0 := 0
ELSIF sym = lparen THEN
OCS.Get (sym); Expression (x); CheckSym (rparen)
ELSIF sym = lbrak THEN
OCS.Get (sym); OCS.Mark (29); Expression (x); CheckSym (rparen)
ELSIF sym = lbrace THEN
OCS.Get (sym); Sets (x)
ELSIF sym = not THEN
OCS.Get (sym); Factor (x); OCE.MOp (not, x)
ELSE
OCS.Mark (13); OCS.Get (sym); x.typ := OCT.undftyp; x.mode := Var;
x.a0 := 0
END;
(* ;OCG.TraceOut (mname, pname); *)
END Factor;
(*------------------------------------*)
(*
$ term = factor {MulOperator factor}.
$ MulOperator = "*" | "/" | DIV | MOD | "&" .
*)
PROCEDURE Term (VAR x : OCT.Item);
(* CONST pname = "Term"; *)
VAR
y : OCT.Item; mulop : INTEGER;
BEGIN (* Term *)
(* OCG.TraceIn (mname, pname); *)
Factor (x);
WHILE (times <= sym) & (sym <= and) DO
mulop := sym; OCS.Get (sym);
IF mulop = and THEN OCE.MOp (and, x) END;
Factor (y); OCE.Op (mulop, x, y, TRUE);
END;
(* ;OCG.TraceOut (mname, pname); *)
END Term;
(*------------------------------------*)
(*
$ SimpleExpression = ["+"|"-"] term {AddOperator term}.
$ AddOperator = "+" | "-" | OR .
*)
PROCEDURE SimpleExpression (VAR x : OCT.Item);
(* CONST pname = "SimpleExpression"; *)
VAR y : OCT.Item; addop : INTEGER;
BEGIN (* SimpleExpression *)
(* OCG.TraceIn (mname, pname); *)
IF sym = minus THEN OCS.Get (sym); Term (x); OCE.MOp (minus, x)
ELSIF sym = plus THEN OCS.Get (sym); Term (x); OCE.MOp (plus, x)
ELSE Term (x)
END;
WHILE (plus <= sym) & (sym <= or) DO
addop := sym; OCS.Get (sym); IF addop = or THEN OCE.MOp (or, x) END;
Term (y); OCE.Op (addop, x, y, TRUE);
END;
(* ;OCG.TraceOut (mname, pname); *)
END SimpleExpression;
(*------------------------------------*)
(*
$ expression = SimpleExpression [relation SimpleExpression].
$ relation = "=" | "#" | "<" | "<=" | ">" | ">=" | IN | IS.
*)
PROCEDURE Expression (VAR x : OCT.Item);
(* CONST pname = "Expression"; *)
VAR
y : OCT.Item; relation : INTEGER;
BEGIN (* Expression *)
(* OCG.TraceIn (mname, pname); *)
SimpleExpression (x);
IF (eql <= sym) & (sym <= geq) THEN
relation := sym; OCS.Get (sym);
IF x.typ = OCT.booltyp THEN OCE.MOp (relation, x) END;
SimpleExpression (y); OCE.Op (relation, x, y, TRUE)
ELSIF sym = in THEN
OCS.Get (sym); SimpleExpression (y); OCE.In (x, y)
ELSIF sym = is THEN
IF x.mode >= Typ THEN OCS.Mark (112) END;
OCS.Get (sym);
IF sym = ident THEN
qualident (y, FALSE);
IF y.mode = Typ THEN OCE.TypTest (x, y, TRUE) ELSE OCS.Mark (52) END
ELSE
OCS.Mark (10)
END;
END;
(* ;OCG.TraceOut (mname, pname); *)
END Expression;
(*------------------------------------*)
PROCEDURE Receiver (VAR rtyp : OCT.Struct; libCall : BOOLEAN);
(* CONST pname = "Receiver"; *)
VAR
mode : SHORTINT; mnolev : INTEGER; recvr, obj : OCT.Object;
typ : OCT.Struct;
BEGIN (* Receiver *)
(* OCG.TraceIn (mname, pname); *)
recvr := NIL; rtyp := OCT.undftyp;
IF sym = var THEN mode := Ind; OCS.Get (sym)
ELSE mode := Var
END;
IF sym = ident THEN
OCT.Insert (OCS.name, recvr, mode); OCS.Get (sym);
OCT.topScope.right := recvr
ELSE
recvr := OCT.AllocObj (); OCS.Mark (10)
END;
recvr.typ := OCT.undftyp; recvr.a2 := -1; CheckSym (colon);
IF sym = ident THEN
OCT.Find (obj, mnolev); IF obj = NIL THEN OCS.Mark (0) END;
OCS.Get (sym);
IF (sym = period) & (obj # NIL) & (obj.mode = Mod) THEN
OCS.Get (sym);
IF sym = ident THEN
OCT.FindImport (obj, obj); IF obj = NIL THEN OCS.Mark (0) END;
OCS.Get (sym)
ELSE
OCS.Mark (10); obj := NIL
END;
OCS.Mark (305)
END;
IF (obj # NIL) & (obj.mode = Typ) THEN
typ := obj.typ; IF typ = NIL THEN typ := OCT.undftyp END;
IF typ = OCT.undftyp THEN OCS.Mark (58)
ELSIF (mode = Ind) & (typ.form # Record) THEN
OCS.Mark (307); typ := OCT.undftyp
ELSIF (mode = Var) THEN
IF libCall THEN
IF typ.form # CPointer THEN OCS.Mark (308); typ := OCT.undftyp END
ELSE
IF typ.form # Pointer THEN OCS.Mark (306); typ := OCT.undftyp END
END;
END;
IF typ.form IN ptrSet THEN rtyp := typ.BaseTyp ELSE rtyp := typ END;
recvr.typ := typ;
IF libCall THEN recvr.a0 := 0
ELSIF mode = Var THEN recvr.a0 := -AdrSize
ELSE recvr.a0 := -RecDescSize
END
ELSE
OCS.Mark (52)
END;
ELSE
OCS.Mark (10)
END;
CheckSym (rparen);
(* ;OCG.TraceOut (mname, pname); *)
END Receiver;
(*------------------------------------*)
(*
$ LibCallDeclaration = LIBCALL identdef ["*"] LibCallSpec
$ [FormalParameters]
$ LibCallSpec = "{" identdef "," ConstExpression "}"
*)
PROCEDURE LibCallDeclaration ();
(* CONST pname = "LibCallDeclaration"; *)
VAR
proc, par : OCT.Object;
psize, dsize : LONGINT;
rtyp : OCT.Struct;
BEGIN (* LibCallDeclaration *)
(* OCG.TraceIn (mname, pname); *)
IF OCS.portableCode THEN OCS.Mark (915) END;
rtyp := OCT.undftyp;
IF sym = lparen THEN
OCT.OpenScope (OCC.level + 1); OCS.Get (sym); Receiver (rtyp, TRUE)
ELSE OCS.Mark (303)
END;
IF sym = ident THEN
(* See if there is a forward declaration already *)
OCT.FindField (rtyp, proc);
IF proc # NIL THEN (* multiple definition *) OCS.Mark (1) END;
proc := OCT.AllocObj(); proc.name := OCT.InsertName (OCS.name);
IF rtyp # OCT.undftyp THEN
proc.left := rtyp.link; rtyp.link := proc
END;
CheckMark (proc.visible, FALSE);
proc.mode := LibCall; proc.typ := OCT.notyp; proc.link := NIL;
proc.a0 := 0; proc.a1 := 0;
INC (OCC.level);
IF sym = lparen THEN (* Get formal parameters *)
psize := 0; OCS.Get (sym); FormalParameters (proc.typ, psize, TRUE);
proc.link := OCT.topScope.right
END;
CheckSym (semicolon);
IF sym = minus THEN OCS.Get (sym) END;
IF sym = number THEN proc.a0 := -OCS.intval; OCS.Get (sym)
ELSE OCS.Mark (17)
END;
DEC (OCC.level); OCT.CloseScope ()
END; (* IF *)
(* ;OCG.TraceOut (mname, pname); *)
END LibCallDeclaration;
(*------------------------------------*)
(*
$ ProcedureDeclaration = ProcedureHeading ";" ProcedureBody ident.
$ ProcedureHeading = PROCEDURE ["*"] identdef [FormalParameters].
$ ForwardDeclaration = PROCEDURE "^" identdef [FormalParameters].
*)
PROCEDURE ProcedureDeclaration ();
(* CONST pname = "ProcedureDeclaration"; *)
VAR
proc, proc1, par : OCT.Object;
rtyp : OCT.Struct;
retList, L1 : INTEGER; mode : SHORTINT;
body, forward : BOOLEAN;
psize, dsize : LONGINT;
x : OCT.Item;
symbol : OCT.Symbol;
BEGIN (* ProcedureDeclaration *)
(* OCG.TraceIn (mname, pname); *)
dsize := 0; proc := NIL; body := TRUE; forward := FALSE; mode := LProc;
IF (sym # ident) & (OCC.level = 0) THEN
(* Process specifier after procedure symbol *)
IF sym = times THEN mode := XProc; OCS.Get (sym)
ELSIF sym = arrow THEN forward := TRUE; body := FALSE; OCS.Get (sym)
END;
IF sym = lparen THEN (* Type-bound procedure *)
mode := TProc; OCS.Get (sym); OCT.OpenScope (OCC.level + 1);
Receiver (rtyp, FALSE)
ELSIF sym # ident THEN OCS.Mark (10)
END;
END;
IF sym = ident THEN
IF mode = TProc THEN
(*
We must be aware of two possibilities for type-bound procedures:
- There is a forward declaration for the *same* type
(proc1.a1 = rtyp.n) & (proc1.a2 = -1);
- It is a redefinition of a procedure from a base type
(proc1.a1 # rtyp.n) & (proc1.a2 = 0).
*)
OCT.FindField (rtyp, proc1);
IF proc1 # NIL THEN
IF proc1.mode # TProc THEN (* Name used for a record field *)
OCS.Mark (329); proc1 := NIL
ELSIF (proc1.a1 = rtyp.n) & (proc1.a2 = 0) THEN
(* Procedure already declared *)
OCS.Mark (1); proc1 := NIL
END
END;
proc := OCT.AllocObj (); proc.name := OCT.InsertName (OCS.name);
CheckMark (proc.visible, FALSE);
(* Assign a procedure number *)
IF proc1 # NIL THEN proc.a0 := proc1.a0
ELSE proc.a0 := OCT.NextProc (rtyp)
END;
(* Note the type level *)
proc.a1 := rtyp.n;
(* Prepare to parse the parameters *)
INC (OCC.level);
IF (proc.visible = OCT.Exp) & ~OCS.longVars THEN
(* return address + frame ptr + global var base *)
psize := XParOrg
ELSE
(* return address + frame ptr *)
psize := ParOrg
END
ELSE
(* See if there is a forward declaration already *)
IF OCC.level = 0 THEN OCT.Find (proc1, L1) ELSE proc1 := NIL END;
IF (proc1 # NIL) & (proc1.a2 < 0) THEN
(* there exists a corresponding forward declaration *)
proc := OCT.AllocObj (); CheckMark (proc.visible, FALSE);
IF proc.visible = OCT.Exp THEN mode := XProc END;
ELSE
IF proc1 # NIL THEN OCS.Mark (1); proc1 := NIL END;
OCT.Insert (OCS.name, proc, mode); CheckMark (proc.visible, FALSE);
IF (proc.visible = OCT.Exp) & (mode = LProc) THEN mode := XProc END;
IF (proc.visible # OCT.Exp) & (OCC.level > 0) THEN
proc.a0 := procNo; INC (procNo)
ELSE
proc.a0 := 0
END
END;
INC (OCC.level); OCT.OpenScope (OCC.level);
(* work out offset of procedure parameters *)
IF (mode = LProc) & (OCC.level > 1) THEN
psize := LParOrg (* return address + frame ptr + static link *)
ELSIF (mode = XProc) & ~OCS.longVars THEN
psize := XParOrg (* return address + frame ptr + global var base *)
ELSE
psize := ParOrg (* return address + frame ptr *)
END;
END;
IF sym = lbrak THEN (* Foreign procedure *)
IF mode = TProc THEN OCS.Mark (344)
ELSIF forward THEN OCS.Mark (343); forward := FALSE
END;
mode := FProc; body := FALSE; OCS.Get (sym);
IF sym = string THEN
NEW (symbol, Str.Length (OCS.name) + 1); COPY (OCS.name, symbol^);
OCS.Get (sym)
ELSE OCS.Mark (342); symbol := NIL
END;
CheckSym (rbrak);
END;
proc.mode := mode; proc.typ := OCT.notyp;
IF forward THEN proc.a2 := -1 ELSE proc.a2 := 0 END;
IF sym = lparen THEN (* Get formal parameters *)
OCS.Get (sym); FormalParameters (proc.typ, psize, (mode = FProc));
ELSIF mode = TProc THEN (* fixup receiver parameter *)
par := OCT.topScope.right;
IF par # NIL THEN
par.a0 := psize;
IF par.mode = Ind THEN INC (psize, RecDescSize)
ELSE INC (psize, AdrSize)
END
END
END;
proc.link := OCT.topScope.right;
IF proc1 # NIL THEN
IF mode = TProc THEN (* forward declaration or redefinition *)
IF
(proc1.a2 = 0) & (rtyp.strobj.visible = OCT.Exp)
& (proc1.visible = OCT.Exp) & (proc.visible # OCT.Exp)
THEN (* Redefined procedure must be exported *)
OCS.Mark (330)
END;
OCH.CompareParLists (proc.link.link, proc1.link.link);
ELSE (* forward declaration *)
OCH.CompareParLists (proc.link, proc1.link);
END;
IF proc.typ # proc1.typ THEN OCS.Mark (118) END;
IF proc1.a2 < 0 THEN (* forward declaration *)
proc.link := NIL; OCT.FreeObj (proc);
proc := proc1; OCT.FreeObj (proc.link);
proc.link := OCT.topScope.right
END
END;
IF forward OR (proc.a2 = 0) THEN
IF mode = TProc THEN
IF rtyp # OCT.undftyp THEN
proc.left := rtyp.link; rtyp.link := proc;
OCT.MakeTProcSymbol (rtyp.symbol, proc)
END
ELSIF mode = FProc THEN
proc.symbol := symbol
ELSE
OCT.MakeProcSymbol (proc)
END
END;
IF ~forward THEN proc.a2 := 0 END;
IF body THEN
CheckSym (semicolon); OCT.topScope.typ := proc.typ;
OCH.StartProcedure (proc);
Block (proc, dsize, retList);
proc.link := OCT.topScope.right; (* update *)
OCH.EndProcBody (proc, SHORT (psize), retList, dsize # 0);
OCS.ResetProcSwitches ();
(* Check size of local variables *)
IF dsize > ProcVarSize THEN OCS.Mark (209); dsize := 0 END;
(* Check name at end of procedure *)
IF sym = ident THEN
IF OCT.InsertName (OCS.name) # proc.name THEN OCS.Mark (4) END;
OCS.Get (sym)
ELSE
OCS.Mark (10)
END;
END; (* IF *)
IF proc.link # NIL THEN
par := proc.link; WHILE IsParam (par.link) DO par := par.link END;
(*OCT.FreeObj (par.link);*) par.link := NIL
END;
DEC (OCC.level); OCT.CloseScope ()
END; (* IF *)
(* ;OCG.TraceOut (mname, pname); *)
END ProcedureDeclaration;
(*------------------------------------*)
(*
$ CaseLabelList = CaseLabels {"," CaseLabels}.
$ CaseLabels = ConstExpression [".." ConstExpression].
*)
PROCEDURE CaseLabelList (
LabelForm : INTEGER; VAR n : INTEGER; VAR tab : ARRAY OF OCH.LabelRange);
(* CONST pname = "CaseLabelList"; *)
VAR
x, y : OCT.Item; i, f, g : INTEGER;
BEGIN (* CaseLabelList *)
(* OCG.TraceIn (mname, pname); *)
IF ~(LabelForm IN labeltyps) THEN OCS.Mark (61) END;
LOOP
ConstExpression (x); f := x.typ.form;
IF (f = String) & (x.a1 <= 2) THEN
x.a0 := x.a2; x.typ := OCT.chartyp; f := Char
END;
IF f IN intSet THEN
IF LabelForm < f THEN OCS.Mark (60) END
ELSIF f # LabelForm THEN
OCS.Mark (60)
END;
IF sym = upto THEN
OCS.Get (sym); ConstExpression (y); g := y.typ.form;
IF (g = String) & (y.a1 <= 2) THEN
y.a0 := y.a2; y.typ := OCT.chartyp; g := Char
END;
IF (g # f) & ~((f IN intSet) & (g IN intSet)) THEN
OCS.Mark (60)
END;
IF y.a0 < x.a0 THEN OCS.Mark (63); y.a0 := x.a0 END
ELSE
y := x
END;
(* enter label range into ordered table *)
i := n;
IF i < NofCases THEN
LOOP
IF i = 0 THEN EXIT END;
IF tab [i-1].low <= y.a0 THEN
IF tab[i-1].high >= x.a0 THEN OCS.Mark (62) END;
EXIT
END;
tab [i] := tab[i-1]; DEC (i)
END; (* LOOP *)
tab [i].low := SHORT (x.a0); tab[i].high := SHORT (y.a0);
tab[i].label := OCC.pc; INC (n)
ELSE
OCS.Mark (213)
END;
IF sym = comma THEN
OCS.Get (sym)
ELSIF (sym = number) OR (sym = ident) THEN
OCS.Mark (19)
ELSE
EXIT
END;
END; (* LOOP *)
(* ;OCG.TraceOut (mname, pname); *)
END CaseLabelList;
(*------------------------------------*)
(*
$ StatementSequence = statement {";" statement}.
$ statement = [assignment | ProcedureCall |
$ IfStatement | CaseStatement | WhileStatement | RepeatStatement |
$ LoopStatement | WithStatement | EXIT | RETURN [expression] ].
$ assignment = designator ":=" expression.
$ ProcedureCall = designator [ActualParameters].
$ IfStatement = IF expression THEN StatementSequence
$ {ELSIF expression THEN StatementSequence}
$ [ELSE StatementSequence]
$ END.
$ CaseStatement = CASE expression OF case {"|" case}
$ [ELSE StatementSequence] END.
$ case = [CaseLabelList ":" StatementSequence].
$ WhileStatement = WHILE expression DO StatementSequence END.
$ RepeatStatement = REPEAT StatementSequence UNTIL expression.
$ LoopStatement = LOOP StatementSequence END.
$ WithStatement = WITH qualident ":" qualident DO
$ StatementSequence END.
*)
PROCEDURE StatSeq (VAR retList : INTEGER);
(* CONST pname = "StatSeq"; *)
VAR
fpar : OCT.Object; xtyp : OCT.Struct; stackload : LONGINT;
x, rcvr, y, z, step : OCT.Item; L0, L1, ExitIndex : INTEGER;
R, R1, mask : SET;
(*------------------------------------*)
PROCEDURE CasePart ();
(* CONST pname = "CasePart"; *)
VAR
x : OCT.Item; n, L0, L1, L2 : INTEGER;
tab : ARRAY NofCases OF OCH.LabelRange;
BEGIN (* CasePart *)
(* OCG.TraceIn (mname, pname); *)
n := 0; L1 := 0;
Expression (x); OCH.CaseIn (x, L0); CheckSym (of);
LOOP
IF sym < bar THEN
CaseLabelList (x.typ.form, n, tab);
CheckSym (colon); StatSeq (retList); OCH.FJ (L1)
END;
IF sym = bar THEN OCS.Get (sym) ELSE EXIT END
END; (* LOOP *)
L2 := OCC.pc;
IF sym = else THEN
OCS.Get (sym); StatSeq (retList); OCH.FJ (L1)
ELSE
IF OCS.caseCheck THEN OCC.Trap (OCC.CaseCheck)
ELSE OCH.FJ (L1)
END
END;
OCH.CaseOut (x, L0, L1, L2, n, tab)
(* ;OCG.TraceOut (mname, pname); *)
END CasePart;
BEGIN (* StatSeq *)
(* OCG.TraceIn (mname, pname); *)
R := OCC.RegSet;
LOOP
IF sym < ident THEN (* illegal symbol *)
OCS.Mark (14);
REPEAT OCS.Get (sym) UNTIL sym >= ident;
END;
IF sym = ident THEN (* assignment or procedure call *)
qualident (x, TRUE); selector (x, rcvr);
IF sym = becomes THEN (* assignment *)
OCS.Get (sym); Expression (y); OCH.Assign (x, y, FALSE)
ELSIF sym = eql THEN (* typo ? *)
OCS.Mark (33); OCS.Get (sym); Expression (y);
OCH.Assign (x, y, FALSE)
ELSIF x.mode = SProc THEN (* standard procedure call *)
StandProcCall (x); IF x.typ # OCT.notyp THEN OCS.Mark (55) END
ELSE (* procedure call *)
OCH.PrepCall (x, fpar, mask); OCC.SaveRegisters (R1, x, mask);
IF x.mode = TProc THEN OCH.Receiver (rcvr, x.obj.link) END;
stackload := 0;
IF sym = lparen THEN
OCS.Get (sym); ActualParameters (fpar, stackload);
CheckSym (rparen);
ELSIF IsParam (fpar) THEN (* parameters missing *)
OCS.Mark (65)
END;
IF x.mode = LibCall THEN OCH.CallLibCall (x, rcvr, stackload)
ELSIF x.mode = TProc THEN OCH.CallTypeBound (x, rcvr)
ELSE OCH.Call (x)
END;
OCC.RestoreRegisters (R1, x);
IF x.typ # OCT.notyp THEN OCS.Mark (55) END;
END;
(*OCT.FreeDesc (x.desc);*)
ELSIF sym = if THEN (* if statement *)
OCS.Get (sym); Expression (x); OCH.CFJ (x, L0); OCC.FreeRegs (R);
CheckSym (then); StatSeq (retList); L1 := 0;
WHILE sym = elsif DO
OCS.Get (sym); OCH.FJ (L1); OCC.FixLink (L0);
Expression (x); OCH.CFJ (x, L0); OCC.FreeRegs (R);
CheckSym (then); StatSeq (retList)
END;
IF sym = else THEN
OCS.Get (sym); OCH.FJ (L1); OCC.FixLink (L0);
StatSeq (retList)
ELSE
OCC.FixLink (L0)
END;
OCC.FixLink (L1); CheckSym (end)
ELSIF sym = case THEN (* case statement *)
OCS.Get (sym); CasePart (); CheckSym (end)
ELSIF sym = while THEN (* while statement *)
OCS.Get (sym); L1 := OCC.pc;
Expression (x); OCH.CFJ (x, L0); OCC.FreeRegs (R);
CheckSym (do); StatSeq (retList); OCH.BJ (L1); OCC.FixLink (L0);
CheckSym (end)
ELSIF sym = repeat THEN (* repeat statement *)
OCS.Get (sym); L0 := OCC.pc; StatSeq (retList);
IF sym = until THEN
OCS.Get (sym); Expression (x); OCH.CBJ (x, L0)
ELSE
OCS.Mark (43)
END;
ELSIF sym = for THEN
OCS.Get (sym);
IF sym = ident THEN
qualident (x, FALSE);
IF x.lev < 0 THEN OCS.Mark (327)
ELSIF ~(x.typ.form IN intSet) THEN OCS.Mark (314)
END;
CheckSym (becomes); Expression (y);
IF ~(y.typ.form IN intSet) THEN OCS.Mark (315) END;
CheckSym (to); Expression (z);
IF ~(z.typ.form IN intSet) THEN OCS.Mark (315) END;
IF sym = by THEN OCS.Get (sym); ConstExpression (step);
IF ~(step.typ.form IN intSet) THEN OCS.Mark (17)
ELSIF step.a0 = 0 THEN OCS.Mark (316); step.a0 := 1
END;
ELSE step.mode := Con; step.a0 := 1; step.typ := OCT.sinttyp
END;
OCH.BeginFor (x, y, z, step, L0, L1); OCC.FreeRegs (R);
IF z.mode = Reg THEN OCC.ReserveReg (SHORT (z.a0)) END;
CheckSym (do); StatSeq (retList); OCH.EndFor (x, step, L0, L1);
IF z.mode = Reg THEN OCC.UnReserveReg (SHORT (z.a0)) END;
CheckSym (end)
ELSE OCS.Mark (10)
END;
ELSIF sym = loop THEN (* loop statement *)
OCS.Get (sym); ExitIndex := ExitNo; INC (LoopLevel);
L0 := OCC.pc; StatSeq (retList); OCH.BJ (L0); DEC (LoopLevel);
WHILE ExitNo > ExitIndex DO
DEC (ExitNo); OCC.fixup (LoopExit [ExitNo])
END;
CheckSym (end)
ELSIF sym = with THEN (* regional type guard *)
L1 := 0;
REPEAT
OCS.Get (sym); x.obj := NIL; xtyp := NIL;
IF sym = ident THEN (* got variable OK *)
qualident (x, FALSE); CheckSym (colon);
IF sym = ident THEN
qualident (y, FALSE);
IF y.mode = Typ THEN (* got type OK *)
IF x.obj # NIL THEN
xtyp := x.typ; x.obj.typ := y.typ; OCE.TypTest (x, y, TRUE)
ELSE OCS.Mark (130) (* variable has anonymous type *)
END
ELSE OCS.Mark (52) (* not a type *)
END
ELSE OCS.Mark (10)
END
ELSE OCS.Mark (10)
END;
CheckSym (do); OCC.FreeRegs (R); OCH.CFJ (x, L0); StatSeq (retList);
IF (sym = bar) OR (sym = else) THEN
OCH.FJ (L1); OCC.FixLink (L0)
END;
IF xtyp # NIL THEN x.obj.typ := xtyp END;
UNTIL sym # bar;
IF sym = else THEN OCS.Get (sym); StatSeq (retList)
ELSIF OCS.typeCheck THEN OCC.TypeTrap (L0)
ELSE OCC.FixLink (L0)
END;
OCC.FixLink (L1);
CheckSym (end);
ELSIF sym = exit THEN (* Loop exit statement *)
OCS.Get (sym); L0 := 0; OCH.FJ (L0);
IF LoopLevel = 0 THEN OCS.Mark (45)
ELSIF ExitNo < NumLoopLevels THEN
LoopExit [ExitNo] := L0; INC (ExitNo)
ELSE OCS.Mark (214)
END;
ELSIF sym = return THEN (* Procedure return statement *)
OCS.Get (sym);
IF OCC.level > 0 THEN (* Return from procedure *)
IF sym < semicolon THEN
Expression (x); OCH.Result (x, OCT.topScope.typ)
ELSIF OCT.topScope.typ # OCT.notyp THEN (* expression missing *)
OCS.Mark (124)
END;
OCH.FJ (retList)
ELSE (* return from module body *)
IF sym < semicolon THEN Expression (x); OCS.Mark (124) END;
OCH.FJ (retList)
END;
END;
OCC.FreeRegs (R);
IF sym = semicolon THEN
OCS.Get (sym)
ELSIF (sym <= ident) OR (if <= sym) & (sym <= return) THEN
OCS.Mark (38)
ELSE
EXIT
END;
END; (* LOOP *)
(* ;OCG.TraceOut (mname, pname); *)
END StatSeq;
(*------------------------------------*)
(*
$ module = MODULE ident ";" [ImportList]
$ DeclarationSequence [BEGIN StatementSequence] END ident "." .
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
$ ProcedureBody = DeclarationSequence [BEGIN StatementSequence] END.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
$ DeclarationSequence = {CONST {ConstantDeclaration ";"} |
$ TYPE {TypeDeclaration ";"} | VAR {VariableDeclaration ";"}}
$ {ProcedureDeclaration ";" | ForwardDeclaration ";"}.
*)
PROCEDURE Block (
proc : OCT.Object; VAR dsize : LONGINT; VAR retList : INTEGER);
(* CONST pname = "Block"; *)
VAR
typ, forward : OCT.Struct;
obj, first, last : OCT.Object;
x : OCT.Item;
L0 : INTEGER;
adr, size : LONGINT;
mk : SHORTINT;
id0 : ARRAY 32 OF CHAR;
BEGIN (* Block *)
(* OCG.TraceIn (mname, pname); *)
(* Calculate base address of variables *)
IF OCC.level = 0 THEN
(* +ve offsets from module variable base *)
adr := dsize;
ELSE
(* -ve offsets from frame pointer *)
adr := -dsize;
END;
last := OCT.topScope.right;
IF last # NIL THEN
WHILE last.link # NIL DO last := last.link END;
END;
LOOP
IF sym = const THEN (* Constant declaration(s) *)
OCS.Get (sym);
WHILE sym = ident DO
COPY (OCS.name, id0); CheckMark (mk, FALSE);
IF sym = eql THEN
OCS.Get (sym); ConstExpression (x)
ELSIF sym = becomes THEN
OCS.Mark (9); OCS.Get (sym); ConstExpression (x)
ELSE
OCS.Mark (9)
END;
(* Enforce limitation on aliasing imported string constants *)
IF (x.lev < 0) & (x.typ = OCT.stringtyp) & (x.a1 > 2) THEN
OCS.Mark (323)
END;
(* Insert in symbol table *)
OCT.Insert (id0, obj, SHORT (x.mode));
obj.typ := x.typ; obj.a0 := x.a0; obj.a1 := x.a1; obj.a2 := x.a2;
obj.visible := mk; obj.symbol := x.symbol;
CheckSym (semicolon)
END; (* WHILE *)
END; (* IF *)
IF sym = type THEN (* Type declaration(s) *)
OCS.Get (sym);
WHILE sym = ident DO
(* Insert in symbol table *)
typ := OCT.undftyp; OCT.Insert (OCS.name, obj, Typ);
forward := obj.typ; obj.typ := OCT.notyp;
CheckMark (obj.visible, FALSE);
IF sym = eql THEN
OCS.Get (sym); Type (typ);
ELSIF (sym = becomes) OR (sym = colon) THEN
OCS.Mark (9);
OCS.Get (sym); Type (typ);
ELSE
OCS.Mark (9); typ := OCT.undftyp
END;
IF typ.form = DynArr THEN typ := OCT.undftyp; OCS.Mark (325) END;
obj.typ := typ;
IF typ.strobj = NIL THEN typ.strobj := obj END;
IF forward # NIL THEN (* fixup *) SetPtrBase (forward, typ) END;
CheckSym (semicolon);
END; (* WHILE *)
END; (* IF *)
IF sym = var THEN (* Variable declarations *)
(*IF (OCC.level = 0) & ~OCS.createObj THEN OCS.Mark (918) END;*)
OCS.Get (sym);
WHILE sym = ident DO
(* Insert in symbol table *)
OCT.Insert (OCS.name, obj, Var); CheckMark (obj.visible, TRUE);
IF (obj # last) & (obj.link = NIL) THEN
IF last = NIL THEN OCT.topScope.right := obj
ELSE last.link := obj
END;
first := obj; last := obj
END;
LOOP (* Get identifier list *)
IF sym = comma THEN OCS.Get (sym)
ELSIF sym = ident THEN OCS.Mark (19)
ELSE EXIT
END;
IF sym = ident THEN
OCT.Insert (OCS.name, obj, Var); CheckMark (obj.visible, TRUE);
IF (obj # last) & (obj.link = NIL) THEN
last.link := obj; last := obj
END
ELSE
OCS.Mark (10)
END;
END; (* LOOP *)
(* Get type *)
CheckSym (colon); Type (typ);
IF typ.form = DynArr THEN typ := OCT.undftyp; OCS.Mark (325) END;
size := typ.size;
IF (size > 1) & ODD (size) THEN INC (size) END;
(* Calculate variable addresses *)
IF OCC.level = 0 THEN (* Global variable *)
IF (size > 1) & ODD (adr) THEN INC (adr) END; (* Word align *)
WHILE first # NIL DO
first.typ := typ; first.a0 := adr; INC (adr, size);
first := first.link
END;
ELSE (* Local procedure variable *)
IF (size > 1) & ODD (adr) THEN DEC (adr) END; (* Word align *)
WHILE first # NIL DO
first.typ := typ; DEC (adr, size); first.a0 := adr;
first := first.link
END;
END;
CheckSym (semicolon);
END; (* WHILE *)
END; (* IF *)
IF (sym < const) OR (sym > var) THEN EXIT END;
END; (* LOOP *)
CheckUndefPointerTypes ();
WHILE sym = libcall DO (* Library call declarations *)
OCS.Get (sym); LibCallDeclaration (); CheckSym (semicolon)
END;
WHILE sym = procedure DO (* Procedure declarations *)
OCS.Get (sym); ProcedureDeclaration (); CheckSym (semicolon)
END;
CheckForwardProcs ();
(* Calculate data size (rounded up to even value) *)
IF OCC.level = 0 THEN dsize := adr
ELSE dsize := -adr
END;
IF ODD (dsize) THEN INC (dsize) END;
retList := 0; (* set up list of return branches *)
IF OCC.level = 0 THEN OCH.StartModuleBody (dsize, retList) END;
IF sym = begin THEN (* Main body of block *)
(*IF (OCC.level <= 1) & ~OCS.createObj THEN OCS.Mark (919) END;*)
IF OCC.level > 0 THEN OCH.StartProcBody (proc, dsize) END;
OCS.Get (sym); StatSeq (retList);
END;
CheckSym (end);
(* ;OCG.TraceOut (mname, pname); *)
END Block;
(*------------------------------------*)
(*
$ module = MODULE ident ";" [ImportList] DeclarationSequence
$ [BEGIN StatementSequence] END ident "." .
$ ImportList = IMPORT import {"," import} ";" .
$ import = identdef [":" ident].
*)
PROCEDURE CompilationUnit * ( source : Files.File);
(* CONST pname = "CompilationUnit"; *)
VAR
L0, retList : INTEGER; ch : CHAR;
time, date, key, dsize : LONGINT;
impid : ARRAY 32 OF CHAR;
FName : ARRAY 256 OF CHAR;
(*------------------------------------*)
(* $D- disable copying of open arrays *)
PROCEDURE MakeFileName (
path, module, ext : ARRAY OF CHAR;
VAR FName : ARRAY OF CHAR);
BEGIN (* MakeFileName *)
COPY (path, FName); Str.Append (FName, module); Str.Append (FName, ext)
END MakeFileName;
BEGIN (* CompilationUnit *)
(* OCG.TraceIn (mname, pname); *)
procNo := 1; dsize := 0; LoopLevel := 0; ExitNo := 0;
OCC.Init (); OCT.Init (); OCS.Init (source);
REPEAT OCS.Get (sym) UNTIL (sym = eof) OR (sym = module);
IF sym # module THEN
IO.WriteStr (" !! Err #16: MODULE keyword not found\n");
RETURN
END;
OCS.Get (sym);
IF sym = ident THEN
L0 := 0; ch := OCS.name [0];
WHILE (ch # 0X) & (L0 < ModNameLen) DO
OCT.ModuleName [L0] := ch; INC (L0); ch := OCS.name [L0];
END;
OCT.ModuleName [L0] := 0X;
IF ch # 0X THEN OCS.Mark (334) END;
OCS.StartModule (OCT.ModuleName); OCT.StartModule ();
OCT.OpenScope (0);
OCS.Get (sym); CheckSym (semicolon);
OCS.allowGlobalSwitches := FALSE;
OCH.ModulePrologue ();
IF sym = import THEN
OCS.Get (sym);
LOOP
IF sym = ident THEN
COPY (OCS.name, impid);
OCS.Get (sym);
MakeFileName ("", impid, ".Sym", FName);
IF sym = becomes THEN
OCS.Get (sym);
IF sym = ident THEN
MakeFileName ("", OCS.name, ".Sym", FName);
OCS.Get (sym);
ELSE
OCS.Mark (10);
END;
END;
OCT.Import (impid, FName);
ELSE
OCS.Mark (10);
END;
IF sym = comma THEN OCS.Get (sym);
ELSIF sym = ident THEN OCS.Mark (19);
ELSE EXIT;
END;
END; (* LOOP *)
CheckSym (semicolon);
END; (* IF *)
IF ~OCS.scanerr THEN
Block (NIL, dsize, retList);
OCH.EndModuleBody (retList);
IF sym = ident THEN
IF OCS.name # OCT.ModuleName THEN OCS.Mark (4) END;
OCS.Get (sym);
ELSE
OCS.Mark (10);
END;
IF sym # period THEN OCS.Mark (18) END;
IF ~OCS.scanerr OR forceCode THEN
IF ~OCS.scanerr THEN
Oberon.GetClock (time, date);
key := (date MOD 4000H) * 20000H + time;
MakeFileName ("", OCT.ModuleName, ".Sym", FName);
OCT.Export (FName, newSF, key);
IF newSF THEN
MakeFileName (OCT.DestPath, OCT.ModuleName, ".Sym", FName);
IO.WriteF1 (" >> New symbol file : %s\n", SYS.ADR (FName))
END
END;
IF ~OCS.scanerr OR forceCode THEN
MakeFileName (OCT.DestPath, OCT.ModuleName, ".Obj", FName);
IO.WriteF1 (" >> Object file : %s\n", SYS.ADR (FName));
OCC.OutCode (FName, key, dsize);
IO.WriteF3
( " CODE: %ld, DATA: %ld, VARS: %ld",
LONG (OCC.pc), OCC.DataSize (), dsize);
IO.WriteF1 (", TOTAL: %ld\n", OCC.pc + dsize + OCC.DataSize ())
END;
END; (* IF *)
END; (* IF *)
OCT.CloseScope ();
OCT.EndModule (); OCS.EndModule ();
ELSE
IO.WriteStr (" !! Err #10: identifier expected after MODULE\n")
END;
IF OCS.scanerr THEN IO.WriteStr (" !! Errors detected\n") END;
(* ;OCG.TraceOut (mname, pname); *)
END CompilationUnit;
BEGIN (* Compiler *)
newSF := FALSE; forceCode := FALSE
END Compiler.
(***************************************************************************
$Log: Compiler.mod $
Revision 4.12 1994/08/19 20:02:03 fjc
- Fixed bug in FormalParameters() which caused an infinite
loop if a parameter name was declared twice.
Revision 4.10 1994/07/25 00:54:09 fjc
- Implemented check for parameter list limit.
Revision 4.9 1994/07/24 00:31:02 fjc
- Changed to using square brackets in register parameter
declarations, in line with Oakwood guidelines.
Revision 4.8 1994/07/23 16:07:02 fjc
- Changed to allow A5 as a legal register parameter.
- Changed to use new formats for OCC.SaveRegisters() and
OCH.PrepCall().
Revision 4.7 1994/07/22 14:23:06 fjc
- Added code to parse foreign procedure declarations.
- Changed to use new procedure names in OCH.
- Fixed bug in register parameter declarations.
Revision 4.6 1994/07/10 13:33:04 fjc
- Commented out trace code.
- Added check for unimplemented forward declared procedures.
Revision 4.5 1994/06/17 17:39:00 fjc
- Fixed stackload bug
Revision 4.4 1994/06/10 12:50:39 fjc
- Changed Factor() to concatenate string literals.
Revision 4.3 1994/06/06 18:28:42 fjc
- Implemented varargs for LibCall procedures:
- Created VarArgs() to push the parameters in reverse order;
- Modified ActualParameters() to call VarArgs();
- Modified Factor() and StatSeq() to fix up stack afterwards;
- Modified FormalParameters() to parse the new syntax.
Revision 4.2 1994/06/05 22:31:46 fjc
- Changed to conform to new symbol table format.
- Added forceCode option.
Revision 4.1 1994/06/01 09:33:44 fjc
- Bumped version number
***************************************************************************)