home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-06-29 | 66.1 KB | 2,273 lines |
- (*************************************************************************
-
- $RCSfile: Compiler.mod $
- Description: Recursive-descent parser
-
- Created by: fjc (Frank Copeland)
- $Revision: 5.30 $
- $Author: fjc $
- $Date: 1995/06/29 19:11:29 $
-
- Copyright © 1990-1993, ETH Zuerich
- Copyright © 1993-1995, 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.
-
- *************************************************************************)
-
- <* STANDARD- *> <* MAIN- *>
-
- MODULE Compiler;
-
- IMPORT
- SYS := SYSTEM, Kernel, Errors, e := Exec, ti := Timer, Str := Strings,
- OberonClock, Files, OCM, OCS, OCT, OCC, OCI, OCE, OCP, OCH, OCStrings,
- In, OCOut;
-
-
- (* --- Exported declarations ------------------------------------------ *)
-
- VAR
- newSF * : BOOLEAN;
- returnError*, returnWarn* : BOOLEAN;
-
-
- (* --- Local declarations --------------------------------------------- *)
-
- CONST
-
- NofCases = 128; RecDescSize = 8; AdrSize = OCM.PtrSize;
- ProcSize = OCM.ProcSize; PtrSize = OCM.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;
- for = OCS.for; by = OCS.by;
-
- (* object modes *)
- Var = OCM.Var; Ind = OCM.Ind; Con = OCM.Con; Reg = OCM.Reg;
- Fld = OCM.Fld; Typ = OCM.Typ; LProc = OCM.LProc; XProc = OCM.XProc;
- SProc = OCM.SProc; TProc = OCM.TProc; Mod = OCM.Mod; Abs = OCM.Abs;
- VarArg = OCM.VarArg; M2Proc = OCM.M2Proc; CProc = OCM.CProc;
- AProc = OCM.AProc;
-
- (* object modes for language extensions *)
- LibCall = OCM.LibCall;
-
- (* System flags *)
-
- DefaultFlag = OCM.DefaultFlag; OberonFlag = OCM.OberonFlag;
- M2Flag = OCM.M2Flag; CFlag = OCM.CFlag; BCPLFlag = OCM.BCPLFlag;
- AsmFlag = OCM.AsmFlag;
-
- (* 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; AdrTyp = OCT.AdrTyp; BPtrTyp = OCT.BPtrTyp;
- Pointer = OCT.Pointer; ProcTyp = OCT.ProcTyp; Array = OCT.Array;
- DynArr = OCT.DynArr; Record = OCT.Record;
-
- intSet = {SInt, Int, LInt};
- labeltyps = {Char, SInt, Int, LInt};
-
- NumLoopLevels = 16; MaxLoopLevel = NumLoopLevels - 1;
-
- VAR
-
- sym, procNo : INTEGER;
- LoopLevel, ExitNo : INTEGER;
- LoopExit : ARRAY NumLoopLevels OF LONGINT;
- defaultFlag : INTEGER;
-
- VAR
-
- file, batchFile : Files.File;
- r : Files.Rider;
- tr : ti.TimeRequestPtr;
-
- (* --- Procedure declarations ----------------------------------------- *)
-
-
- (*------------------------------------*)
- PROCEDURE^ Type (VAR typ : OCT.Struct; dynArr : BOOLEAN);
- PROCEDURE^ Expression (VAR x : OCT.Item);
- PROCEDURE^ Block
- (proc : OCT.Object; VAR dsize : LONGINT; VAR retList : LONGINT);
-
- (*------------------------------------*)
- PROCEDURE CheckSym (s : INTEGER);
-
- BEGIN (* CheckSym *)
- IF sym = s THEN OCS.Get (sym) ELSE OCS.Mark (s) END
- END CheckSym;
-
- (*------------------------------------*)
- PROCEDURE CheckNonStandard ();
- BEGIN (* CheckNonStandard *)
- IF OCS.option [OCS.standard] THEN OCS.Mark (915) END
- END CheckNonStandard;
-
- (*------------------------------------*)
- PROCEDURE SysFlag ( VAR flag : INTEGER );
- BEGIN (* SysFlag *)
- (* sym = lbrak *)
- OCS.Get (sym); flag := defaultFlag;
- IF (sym = number) & (OCS.numtyp = 2) THEN
- IF (OCS.intval < 0) OR (OCS.intval > AsmFlag) THEN OCS.Mark (353)
- ELSE flag := SHORT (OCS.intval)
- END;
- OCS.Get (sym)
- ELSE
- OCS.Mark (17); WHILE (sym # rbrak) & (sym # eof) DO OCS.Get (sym) END
- END;
- CheckSym (rbrak); CheckNonStandard ()
- END SysFlag;
-
- (*------------------------------------*)
- PROCEDURE qualident (VAR x : OCT.Item; allocDesc : BOOLEAN);
-
- VAR mnolev : INTEGER; obj : OCT.Object; desc : OCT.Desc; b : BOOLEAN;
-
- BEGIN (* qualident *)
- (* 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.label := obj.label;
- x.rdOnly := (mnolev < 0) & (obj.visible = OCT.RdOnly);
- IF
- allocDesc & (x.mode IN {Var, Ind}) & (x.typ # NIL)
- & (x.typ.form = DynArr)
- THEN
- NEW (desc); 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
- END qualident;
-
- (*------------------------------------*)
- PROCEDURE ConstExpression (VAR x : OCT.Item);
-
- CONST ConstTypes = {Undef .. NilTyp, AdrTyp, BPtrTyp, Pointer};
-
- BEGIN (* ConstExpression *)
- Expression (x);
- IF
- (x.mode # Con)
- OR ((x.typ.form = Pointer) & (x.typ.sysflg = OberonFlag))
- OR ~(x.typ.form IN ConstTypes)
- THEN
- OCS.Mark (50); x.mode := Con; x.typ := OCT.inttyp; x.a0 := 1;
- END;
- END ConstExpression;
-
- (*------------------------------------*)
- PROCEDURE NewStr (form : INTEGER) : OCT.Struct;
-
- VAR typ : OCT.Struct;
-
- BEGIN (* NewStr *)
- NEW (typ);
- typ.form := form; typ.mno := 0; typ.size := 4; typ.ref := 0;
- typ.BaseTyp := OCT.undftyp; typ.strobj := NIL; typ.link := NIL;
- IF (form = Record) OR (form = Pointer) THEN typ.sysflg := defaultFlag
- ELSE typ.sysflg := OberonFlag
- END;
- RETURN typ
- END NewStr;
-
- (*------------------------------------*)
- PROCEDURE HasTaggedPtr ( typ : OCT.Struct ) : BOOLEAN;
-
- VAR fld : OCT.Object;
-
- BEGIN (* HasTaggedPtr *)
- IF typ.sysflg = OberonFlag THEN
- IF typ.form = Pointer THEN RETURN TRUE
- ELSIF typ.form = Array THEN RETURN (HasTaggedPtr (typ.BaseTyp))
- ELSIF typ.form = Record THEN
- IF (typ.BaseTyp # NIL) & HasTaggedPtr (typ.BaseTyp) THEN
- RETURN TRUE
- END;
- fld := typ.link;
- WHILE fld # NIL DO
- IF (fld.mode = Fld) & ((fld.name < 0) OR HasTaggedPtr (fld.typ))
- THEN
- RETURN TRUE
- END;
- fld := fld.left
- END
- END
- END;
- RETURN FALSE
- END HasTaggedPtr;
-
- (*------------------------------------*)
- PROCEDURE CheckMark (VAR mk : SHORTINT; readOnly : BOOLEAN);
-
- BEGIN (* CheckMark *)
- 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
- END CheckMark;
-
- (*------------------------------------*)
- PROCEDURE 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 *)
- CheckObj (OCT.topScope.link)
- END CheckUndefPointerTypes;
-
- (*------------------------------------*)
- PROCEDURE CheckForwardProcs ();
-
- (*------------------------------------*)
- PROCEDURE CheckObj ( obj : OCT.Object );
-
- (*------------------------------------*)
- PROCEDURE CheckTyp ( typ : OCT.Struct );
- VAR fld : OCT.Object;
- BEGIN (* CheckTyp *)
- IF (typ # NIL) & (typ.form = Record) & (typ.sysflg = OberonFlag) THEN
- fld := typ.link;
- WHILE fld # NIL DO
- IF (fld.mode = TProc) & fld.fwd 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 *)
- CheckObj (OCT.topScope.link)
- END CheckForwardProcs;
-
- (*------------------------------------*)
- PROCEDURE RecordType (VAR typ : OCT.Struct);
-
- VAR
- adr, size : LONGINT;
- fld, fld0, fld1, fld2 : OCT.Object;
- ftyp : OCT.Struct;
- base : OCT.Item;
-
- BEGIN (* RecordType *)
- typ := NewStr (Record); typ.BaseTyp := NIL; typ.n := 0; adr := 0;
- IF sym = lbrak THEN SysFlag (typ.sysflg) END;
- 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;
- IF (typ.sysflg = OberonFlag) & (typ.n > OCM.ExtendLimit) THEN
- OCS.Mark (236)
- END;
- adr := base.typ.size
- ELSE OCS.Mark (52)
- END
- ELSE OCS.Mark (10)
- END;
- CheckSym (rparen);
- IF OCT.Tagged (typ) # OCT.Tagged (base.typ) THEN OCS.Mark (354) END
- END;
- OCT.OpenScope (0); fld := NIL; NEW (fld1); fld2 := NIL;
- LOOP
- IF sym = ident THEN
- LOOP
- 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 EXIT
- END
- END; (* LOOP *)
- CheckSym (colon); Type (ftyp, FALSE);
- IF (typ.sysflg # OberonFlag) & HasTaggedPtr (ftyp) THEN
- OCS.Mark (355)
- 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
- fld1 := fld1.link; fld1.typ := ftyp;
- fld1.a0 := adr;
- IF (OCM.MaxTypeSize - size) < adr THEN OCS.Mark (209)
- ELSE INC (adr, size)
- END
- END
- END; (* IF *)
- IF sym = semicolon THEN OCS.Get (sym)
- ELSIF sym = ident THEN OCS.Mark (38)
- ELSE EXIT
- END;
- END; (* LOOP *)
- typ.size := adr + (adr MOD 2); typ.link := OCT.topScope.right;
- CheckUndefPointerTypes ();
- fld0 := OCT.topScope.right;
- WHILE fld0 # NIL DO
- fld1 := fld0.link; fld0.link := NIL;
- fld0.left := fld1; fld0.right := NIL;
- fld0 := fld1
- END;
- OCT.CloseScope ();
- IF typ.sysflg = OberonFlag THEN OCC.AllocTypDesc (typ) END
- END RecordType;
-
- (*------------------------------------*)
- PROCEDURE ArrayType (VAR typ : OCT.Struct; dynArr : BOOLEAN);
-
- VAR x : OCT.Item; f : INTEGER; n : LONGINT;
-
- BEGIN (* ArrayType *)
- IF sym # of THEN
- typ := NewStr (Array); ConstExpression (x); f := x.typ.form;
- IF f IN intSet THEN
- IF (x.a0 > 0) & (x.a0 <= OCM.MaxTypeSize) THEN n := x.a0
- ELSE n := 1; OCS.Mark (68)
- END
- ELSE
- OCS.Mark (51); n := 1
- END;
- IF sym = of THEN OCS.Get (sym); Type (typ.BaseTyp, FALSE)
- ELSIF sym = comma THEN OCS.Get (sym); ArrayType (typ.BaseTyp, FALSE)
- ELSE OCS.Mark (34)
- END;
- IF (OCM.MaxTypeSize DIV typ.BaseTyp.size) < n THEN
- OCS.Mark (68); n := 1
- END;
- typ.n := n;
- 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, TRUE);
- 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;
- IF (typ.form = DynArr) & ~dynArr THEN
- typ := OCT.undftyp; OCS.Mark (325)
- END
- END ArrayType;
-
- (*------------------------------------*)
- (*
- $ FormalParameters = "(" [FPSection {";" FPSection}] ")"
- $ [":" qualident].
- $ FPSection = [VAR] ident [RegSpec] {"," ident [RegSpec]}
- $ ":" Type.
- $ RegSpec = "{" ConstExpression "}" [".."].
- *)
- PROCEDURE FormalParameters (
- VAR resTyp : OCT.Struct; VAR psize : LONGINT; sysflg : INTEGER);
-
- CONST
- D0 = 0; A5 = 13;
-
- VAR
- mode : SHORTINT; gotUpto, regPars : BOOLEAN;
- adr, size : LONGINT; res, reg : OCT.Item;
- par, par1, par2: OCT.Object; typ : OCT.Struct;
- close : INTEGER;
-
- BEGIN (* FormalParameters *)
- adr := 0; gotUpto := FALSE; regPars := (sysflg = AsmFlag);
- (* 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
- NEW (par1)
- END;
- par2 := par1;
- IF (sym = ident) OR (sym = var) THEN
- LOOP
- IF sym = var THEN OCS.Get (sym); mode := Ind
- 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) OR (sym = lbrace) THEN (* Register specification *)
- IF sym = lbrak THEN close := rbrak ELSE close := rbrace END;
- 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 (close);
- 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 = Var) & (sysflg IN {CFlag, AsmFlag}) 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, TRUE);
- IF (sysflg # OberonFlag) & OCT.Tagged (typ) THEN OCS.Mark (356) END;
- (*IF (mode = VarArg) & (typ.size > PtrSize) THEN OCS.Mark (338) END;*)
-
- IF sysflg = OberonFlag THEN
- IF mode = Ind THEN (* VAR param *)
- IF (typ.form = Record) & (typ.sysflg = OberonFlag) 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 sysflg = OberonFlag THEN
- psize := psize - adr;
- IF psize > OCM.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;
- END FormalParameters;
-
- (*------------------------------------*)
- PROCEDURE ProcType (VAR typ : OCT.Struct);
-
- VAR psize : LONGINT;
-
- BEGIN (* ProcType *)
- typ := NewStr (ProcTyp); typ.size := ProcSize;
- IF sym = lparen THEN
- OCS.Get (sym); OCT.OpenScope (OCC.level); psize := ParOrg;
- FormalParameters (typ.BaseTyp, psize, OberonFlag);
- typ.link := OCT.topScope.right; OCT.CloseScope ();
- ELSE
- typ.BaseTyp := OCT.notyp; typ.link := NIL
- END;
- END ProcType;
-
- (*------------------------------------*)
- PROCEDURE SetPtrBase (ptyp, btyp : OCT.Struct);
-
- BEGIN (* SetPtrBase *)
- IF
- ((btyp.form = Record) & (OCT.Tagged (ptyp) = OCT.Tagged (btyp)))
- OR (btyp.form = Array)
- THEN
- ptyp.BaseTyp := btyp; ptyp.label := OCT.PointerDesc
- ELSIF (btyp.form = DynArr) & (ptyp.sysflg = OberonFlag) THEN
- ptyp.BaseTyp := btyp; ptyp.size := btyp.size;
- OCC.AllocTypDesc (ptyp)
- ELSE
- ptyp.BaseTyp := OCT.undftyp; OCS.Mark (57)
- END
- END SetPtrBase;
-
- (*------------------------------------*)
- (*
- $ type = qualident | ArrayType | RecordType | StructType| PointerType |
- $ ProcedureType.
- *)
- PROCEDURE Type (VAR typ : OCT.Struct; dynArr : BOOLEAN);
-
- VAR lev : INTEGER; obj : OCT.Object; x : OCT.Item;
-
- BEGIN (* Type *)
- 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, TRUE)
- ELSIF sym = record THEN
- OCS.Get (sym); RecordType (typ); CheckSym (end)
- ELSIF (sym = pointer) THEN
- typ := NewStr (Pointer); typ.link := NIL; typ.size := PtrSize;
- OCS.Get (sym); IF sym = lbrak THEN SysFlag (typ.sysflg) END;
- 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, TRUE); SetPtrBase (typ, x.typ)
- END
- ELSIF sym = procedure THEN
- OCS.Get (sym); ProcType (typ)
- ELSE
- OCS.Mark (12)
- END;
- IF (typ.form = DynArr) & ~dynArr THEN
- typ := OCT.undftyp; OCS.Mark (325)
- 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
- END Type;
-
- (*------------------------------------*)
- (*
- $ designator = qualident
- $ {"." ident | "[" ExpList "]" | "(" qualident ")" | "^" }.
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- $ ExpList = expression {"," expression}.
- *)
- PROCEDURE selector (VAR x, rcvr : OCT.Item);
-
- VAR fld : OCT.Object; y : OCT.Item; t : OCT.Struct; f : INTEGER;
-
- BEGIN (* selector *)
- IF x.mode = LibCall THEN
- rcvr.mode := Var; rcvr.lev := x.lev; rcvr.a0 := x.a1; rcvr.a1 := 0;
- rcvr.a2 := 0; rcvr.typ := OCT.lwordtyp; rcvr.rdOnly := TRUE
- ELSE rcvr.mode := Undef
- END;
- LOOP
- IF sym = lbrak THEN
- OCS.Get (sym);
- LOOP
- IF (x.typ # NIL) & (x.typ.form = Pointer) THEN
- OCE.DeRef (x, TRUE)
- 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 = Pointer 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 = Pointer THEN OCE.DeRef (x, TRUE) 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.label := fld.label
- 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.obj.name, rcvr.typ, fld);
- IF fld # NIL THEN
- x.a2 := -1; x.obj := fld; x.label := fld.label
- ELSE OCS.Mark (333)
- END
- ELSE OCS.Mark (332)
- END;
- OCS.Get (sym)
- ELSE
- OCS.Get (sym); OCE.DeRef (x, FALSE)
- 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 *)
- END selector;
-
- (*------------------------------------*)
- PROCEDURE IsParam (obj : OCT.Object) : BOOLEAN;
-
- BEGIN (* IsParam *)
- RETURN (obj # NIL) & (obj.mode <= Ind) & (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.VarArgParam (apar, fpar, load); INC (stackload, fpar.typ.size)
- END VarArgs;
-
- (*------------------------------------*)
- PROCEDURE ReverseParam
- ( VAR apar : OCT.Item;
- VAR fpar : OCT.Object;
- VAR stackload : LONGINT );
-
- VAR x : OCT.Item; next : OCT.Object;
-
- BEGIN (* ReverseParam *)
- IF IsParam (fpar) THEN
- next := fpar.link;
- IF sym = comma THEN
- OCS.Get (sym); Expression (x);
- IF fpar.mode = VarArg THEN VarArgs (x, fpar, stackload, FALSE)
- ELSE ReverseParam (x, next, stackload)
- END;
- END;
- OCH.Param (apar, fpar, CProc); INC (stackload, fpar.typ.size);
- fpar := next
- ELSE
- OCS.Mark (64)
- END
- END ReverseParam;
-
- (*------------------------------------*)
- (*
- $ ActualParameters = "(" [ExpList] ")" .
- $ ExpList = expression {"," expression}.
- *)
-
- PROCEDURE ActualParameters
- ( fpar : OCT.Object;
- mode : INTEGER;
- VAR stackload : LONGINT );
-
- VAR apar : OCT.Item; R : OCC.RegState;
-
- BEGIN (* ActualParameters *)
- IF sym # rparen THEN
- R := OCC.regState;
- IF mode = CProc THEN
- Expression (apar); ReverseParam (apar, fpar, stackload)
- ELSE
- LOOP
- Expression (apar);
- IF IsParam (fpar) THEN
- IF fpar.mode = VarArg THEN VarArgs (apar, fpar, stackload, TRUE)
- ELSE OCH.Param (apar, fpar, mode)
- 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;
- END; (* IF *)
- OCC.FreeRegs (R);
- END;
- IF IsParam (fpar) THEN OCS.Mark (65) END
- END ActualParameters;
-
- (*------------------------------------*)
- PROCEDURE StandProcCall (VAR x : OCT.Item);
-
- VAR y, z : OCT.Item; m, n : INTEGER; R : OCC.RegState;
-
- BEGIN (* StandProcCall *)
- m := SHORT (x.a0); n := 0; R.regs := {};
- IF m = OCT.pASSERT THEN OCC.genCode := OCS.pragma [OCS.assertChk] END;
- OCP.SaveRegs (m, 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
- IF n = 1 THEN y.mode := Undef END;
- Expression (z); OCP.NewPar (x, y, z, 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);
- OCC.genCode := TRUE
- ELSE
- OCS.Mark (29)
- END;
- END StandProcCall;
-
- (*------------------------------------*)
- (*
- $ element = expression [".." expression].
- *)
- PROCEDURE Element (VAR x : OCT.Item);
-
- VAR e1, e2 : OCT.Item;
-
- BEGIN (* Element *)
- Expression (e1);
- IF sym = upto THEN
- OCS.Get (sym); Expression (e2); OCE.Set1 (x, e1, e2)
- ELSE
- OCE.Set0 (x, e1)
- END;
- END Element;
-
- (*------------------------------------*)
- (*
- $ set = "{" [element {"," element}] "}".
- *)
- PROCEDURE Sets (VAR x : OCT.Item);
-
- VAR y : OCT.Item;
-
- BEGIN (* Sets *)
- 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);
- END Sets;
-
- (*------------------------------------*)
- (*
- $ factor = number | CharConstant | string | NIL | set |
- $ designator [ActualParameters] | "(" expression ")" | "~" factor.
- *)
- PROCEDURE Factor (VAR x : OCT.Item);
-
- VAR
- fpar : OCT.Object; rcvr : OCT.Item; R : OCC.RegState; mask : SET;
- stackload : LONGINT;
-
- BEGIN (* Factor *)
- 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);
- IF x.mode IN {TProc, LibCall} THEN
- OCC.SaveRegisters (R, rcvr, mask);
- IF x.mode = TProc THEN
- OCH.Receiver (TProc, rcvr, x.obj.link, mask)
- ELSE
- OCH.Receiver (LibCall, rcvr, NIL, mask)
- END
- ELSE
- OCC.SaveRegisters (R, x, mask);
- END;
- OCS.Get (sym); stackload := 0;
- ActualParameters (fpar, x.mode, stackload);
- OCH.Call (x, rcvr, stackload, mask);
- IF x.mode # LibCall THEN OCC.ForgetRegs 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.option [OCS.standard] 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;
- END Factor;
-
- (*------------------------------------*)
- (*
- $ term = factor {MulOperator factor}.
- $ MulOperator = "*" | "/" | DIV | MOD | "&" .
- *)
- PROCEDURE Term (VAR x : OCT.Item);
-
- VAR
- y : OCT.Item; mulop : INTEGER;
-
- BEGIN (* Term *)
- 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);
- IF mulop = and THEN OCC.ForgetRegs END;
- END;
- END Term;
-
- (*------------------------------------*)
- (*
- $ SimpleExpression = ["+"|"-"] term {AddOperator term}.
- $ AddOperator = "+" | "-" | OR .
- *)
- PROCEDURE SimpleExpression (VAR x : OCT.Item);
-
- VAR y : OCT.Item; addop : INTEGER;
-
- BEGIN (* SimpleExpression *)
- 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);
- IF addop = or THEN OCC.ForgetRegs END;
- END;
- END SimpleExpression;
-
- (*------------------------------------*)
- (*
- $ expression = SimpleExpression [relation SimpleExpression].
- $ relation = "=" | "#" | "<" | "<=" | ">" | ">=" | IN | IS.
- *)
- PROCEDURE Expression (VAR x : OCT.Item);
-
- VAR
- y : OCT.Item; relation : INTEGER;
-
- BEGIN (* Expression *)
- 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;
- END Expression;
-
- (*------------------------------------*)
- PROCEDURE Receiver (VAR rtyp : OCT.Struct);
-
- VAR
- mode : SHORTINT; mnolev : INTEGER; recvr, obj : OCT.Object;
- typ : OCT.Struct;
-
- BEGIN (* Receiver *)
- 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
- NEW (recvr); 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
- IF typ.mno > 0 THEN OCS.Mark (305) END;
- IF
- (mode = Ind)
- & ((typ.form # Record) OR (typ.sysflg # OberonFlag))
- THEN
- OCS.Mark (307); typ := OCT.undftyp
- ELSIF (mode = Var) THEN
- IF typ.form # Pointer THEN OCS.Mark (306); typ := OCT.undftyp END
- END;
- ELSE typ := OCT.undftyp
- END;
- IF typ.form = Pointer THEN rtyp := typ.BaseTyp ELSE rtyp := typ END;
- recvr.typ := typ;
- IF mode = Var THEN recvr.a0 := -AdrSize
- ELSE recvr.a0 := -RecDescSize
- END
- ELSE OCS.Mark (52)
- END
- ELSE OCS.Mark (10)
- END;
- CheckSym (rparen);
- END Receiver;
-
- (*------------------------------------*)
- (*
- $ 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 : LONGINT; lvl, sysflg, close : INTEGER; mode : SHORTINT;
- body, forward : BOOLEAN;
- psize, dsize : LONGINT;
- x : OCT.Item;
- label : OCT.Label;
-
- BEGIN (* ProcedureDeclaration *)
- dsize := 0; proc := NIL; body := TRUE; forward := FALSE; mode := LProc;
- label := NIL; sysflg := defaultFlag;
-
- IF sym # ident THEN
- IF sym = arrow THEN
- forward := TRUE; body := FALSE; OCS.Get (sym)
- ELSIF sym = times THEN
- CheckNonStandard ();
- IF OCC.level = 0 THEN mode := XProc ELSE OCS.Mark (46) END;
- OCS.Get (sym)
- END;
- IF sym = lbrak THEN SysFlag (sysflg) END;
- END;
-
- IF sysflg # OberonFlag THEN
- IF mode = XProc THEN OCS.Mark (119)
- ELSIF forward THEN OCS.Mark (343)
- END;
- IF sysflg = M2Flag THEN mode := M2Proc
- ELSIF sysflg = CFlag THEN mode := CProc
- ELSIF sysflg = AsmFlag THEN mode := AProc
- ELSE OCS.Mark (900); mode := M2Proc
- END;
- body := FALSE
- END;
-
- IF sym = lparen THEN (* Type-bound procedure *)
- OCT.OpenScope (OCC.level + 1); OCS.Get (sym); Receiver (rtyp);
- IF OCC.level > 0 THEN OCS.Mark (46)
- ELSIF mode = XProc THEN OCS.Mark (119)
- ELSIF sysflg # OberonFlag THEN OCS.Mark (344)
- END;
- mode := TProc
- ELSIF sym # ident THEN OCS.Mark (10)
- END;
-
- IF sym = ident THEN
- IF mode = TProc THEN
- (*
- We must be aware of three possibilities for type-bound procedures:
- - There is a forward declaration for the *same* type
- (proc1.a1 = rtyp.n) & (proc1.fwd = TRUE);
- - There is a forward declaration for a *base* type
- (proc1.a1 # rtyp.n) & (proc1.fwd = TRUE);
- - It is a redefinition of a procedure from a base type
- (proc1.a1 # rtyp.n) & (proc1.fwd = FALSE).
- *)
- 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.fwd = FALSE) THEN
- (* Procedure already declared *)
- OCS.Mark (1); proc1 := NIL
- END
- END;
- NEW (proc); 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 := -1
- END;
- IF proc.a0 < 0 THEN proc.a2 := 1
- ELSE proc.a2 := 0
- END;
- (* Note the type level *)
- proc.a1 := rtyp.n;
- (* Prepare to parse the parameters *)
- INC (OCC.level);
- IF (*(proc.visible = OCT.Exp)
- &*) ~OCS.pragma [OCS.longVars]
- & ~OCM.SmallData & ~OCM.Resident
- 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 *)
- OCT.Find (proc1, lvl); IF lvl # OCC.level THEN proc1 := NIL END;
- IF (sysflg = OberonFlag) & (proc1 # NIL) & proc1.fwd THEN
- (* there exists a corresponding forward declaration *)
- NEW (proc); 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 (mode = LProc) & (OCC.level > 0) THEN
- proc.a0 := procNo; INC (procNo)
- ELSE
- proc.a0 := 0
- END
- END;
-
- IF (sym = lbrak) OR (sym = lbrace) THEN
- (* External name or library call *)
- IF sym = lbrak THEN close := rbrak ELSE close := rbrace END;
- IF forward THEN OCS.Mark (343); forward := FALSE END;
- body := FALSE; OCS.Get (sym);
- IF sym = string THEN (* External name *)
- IF sysflg = OberonFlag THEN
- CheckNonStandard(); sysflg := AsmFlag; mode := AProc
- END;
- NEW (label, Str.Length (OCS.name) + 1); COPY (OCS.name, label^);
- OCS.Get (sym)
- ELSIF sym = ident THEN (* LibCall *)
- mode := LibCall; sysflg := AsmFlag; label := NIL;
- qualident (x, FALSE);
- IF
- (x.mode # Var) OR (x.lev # (OCC.level)) OR (x.typ.size # 4)
- THEN
- OCS.Mark (352); proc.a1 := 0
- ELSE proc.a1 := x.a0
- END;
- CheckSym (comma);
- IF sym = minus THEN proc.a0 := -1; OCS.Get (sym)
- ELSE proc.a0 := 1
- END;
- IF (sym = number) & (OCS.numtyp = 2) THEN
- proc.a0 := proc.a0 * OCS.intval; OCS.Get (sym)
- ELSE OCS.Mark (17)
- END;
- ELSE OCS.Mark (342); label := NIL
- END;
- CheckSym (close);
- IF (sysflg = M2Proc) OR (sysflg = CProc) THEN OCS.Warn (923) END
- ELSIF sysflg # OberonFlag THEN
- OCS.Mark (342); label := NIL
- END;
-
- INC (OCC.level); OCT.OpenScope (OCC.level);
-
- (* work out offset of procedure parameters *)
- IF sysflg # OberonFlag THEN
- psize := 0
- ELSIF (mode = LProc) & (OCC.level > 1) THEN
- psize := LParOrg (* return address + frame ptr + static link *)
- ELSIF (mode = XProc)
- & ~OCS.pragma [OCS.longVars]
- & ~OCM.SmallData & ~OCM.Resident
- THEN (* return address + frame ptr + saved global var base *)
- psize := XParOrg
- ELSE (* return address + frame ptr *)
- psize := ParOrg
- END
- END;
-
- proc.mode := mode; proc.typ := OCT.notyp;
- IF forward THEN proc.fwd := TRUE ELSE proc.fwd := FALSE END;
-
- IF sym = lparen THEN (* Get formal parameters *)
- OCS.Get (sym); FormalParameters (proc.typ, psize, sysflg)
- 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.fwd & (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
- (((mode = TProc) & (proc.a1 = proc1.a1)) OR (mode # TProc))
- & proc1.fwd
- THEN (* forward declaration *)
- proc := proc1; proc.link := OCT.topScope.right
- END
- END;
-
- IF forward OR (~proc.fwd) THEN
- IF mode = TProc THEN
- IF rtyp # OCT.undftyp THEN
- proc.left := rtyp.link; rtyp.link := proc;
- OCT.MakeTProcLabel (rtyp, proc)
- END
- ELSIF sysflg = OberonFlag THEN
- OCT.MakeProcLabel (proc)
- ELSE
- proc.label := label
- END
- END;
- IF ~forward THEN proc.fwd := FALSE 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;
- par.link := NIL
- END;
- DEC (OCC.level); OCT.CloseScope ()
- END; (* IF *)
- 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 *)
- 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 := x.a0; tab[i].high := 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 *)
- 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 : LONGINT);
-
- (* CONST pname = "StatSeq"; *)
-
- VAR
- fpar : OCT.Object; xtyp : OCT.Struct; stackload, L0, L1 : LONGINT;
- x, rcvr, y, z, step : OCT.Item; ExitIndex : INTEGER;
- R, R1 : OCC.RegState; mask : SET;
-
- (*------------------------------------*)
- PROCEDURE CasePart ();
-
- (* CONST pname = "CasePart"; *)
-
- VAR
- x : OCT.Item; n : INTEGER; L0, L1, L2 : LONGINT;
- tab : ARRAY NofCases OF OCH.LabelRange;
-
- BEGIN (* CasePart *)
- n := 0; L1 := 0;
- Expression (x); OCH.CaseIn (x, L0); CheckSym (of);
- R := OCC.regState;
- LOOP
- IF sym < bar THEN
- CaseLabelList (x.typ.form, n, tab); CheckSym (colon);
- OCC.regState := R; 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); OCC.regState := R; StatSeq (retList); OCH.FJ (L1)
- ELSE
- IF OCS.pragma [OCS.caseChk] THEN OCC.Trap (OCC.CaseCheck)
- ELSE OCH.FJ (L1)
- END
- END;
- OCH.CaseOut (x, L0, L1, L2, n, tab)
- END CasePart;
-
- BEGIN (* StatSeq *)
- R := OCC.regState;
- 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);
- IF x.mode IN {TProc, LibCall} THEN
- OCC.SaveRegisters (R1, rcvr, mask);
- IF x.mode = TProc THEN
- OCH.Receiver (TProc, rcvr, x.obj.link, mask)
- ELSE
- OCH.Receiver (LibCall, rcvr, NIL, mask)
- END
- ELSE
- OCC.SaveRegisters (R1, x, mask);
- END;
- stackload := 0;
- IF sym = lparen THEN
- OCS.Get (sym); ActualParameters (fpar, x.mode, stackload);
- CheckSym (rparen);
- ELSIF IsParam (fpar) THEN (* parameters missing *)
- OCS.Mark (65)
- END;
- OCH.Call (x, rcvr, stackload, mask);
- IF x.mode # LibCall THEN OCC.ForgetRegs END;
- OCC.RestoreRegisters (R1, x);
- IF x.typ # OCT.notyp THEN OCS.Mark (55) END;
- END;
-
- ELSIF sym = if THEN (* if statement *)
- OCS.Get (sym); Expression (x); OCH.CFJ (x, L0);
- OCC.FreeRegs (R); R := OCC.regState;
- CheckSym (then); StatSeq (retList); L1 := 0;
- WHILE sym = elsif DO
- OCS.Get (sym); OCH.FJ (L1); OCC.FixLink (L0);
- OCC.regState := R; Expression (x); OCH.CFJ (x, L0);
- OCC.FreeRegs (R); R := OCC.regState;
- CheckSym (then); StatSeq (retList)
- END;
- IF sym = else THEN
- OCS.Get (sym); OCH.FJ (L1); OCC.FixLink (L0);
- OCC.regState := R; StatSeq (retList)
- ELSE
- OCC.FixLink (L0)
- END;
- OCC.FixLink (L1); CheckSym (end); OCC.ForgetRegs
-
- ELSIF sym = case THEN (* case statement *)
- OCS.Get (sym); CasePart (); CheckSym (end); OCC.ForgetRegs
-
- ELSIF sym = while THEN (* while statement *)
- OCC.ForgetRegs; R := OCC.regState;
- 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); OCC.ForgetRegs
-
- ELSIF sym = repeat THEN (* repeat statement *)
- OCC.ForgetRegs; R := OCC.regState;
- 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;
- OCC.ForgetRegs
-
- ELSIF sym = for THEN
- OCC.ForgetRegs; R := OCC.regState;
- 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, R, L0, L1);
- CheckSym (do); StatSeq (retList);
- OCH.EndFor (x, step, z, L0, L1); CheckSym (end)
- ELSE OCS.Mark (10)
- END;
- OCC.ForgetRegs
-
- ELSIF sym = loop THEN (* loop statement *)
- OCC.ForgetRegs; R := OCC.regState;
- 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); OCC.ForgetRegs
-
- ELSIF sym = with THEN (* regional type guard *)
- L1 := 0;
- REPEAT
- OCC.regState := R; 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); OCH.CFJ (x, L0); OCC.FreeRegs (R); 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); OCC.regState := R; StatSeq (retList)
- ELSIF OCS.pragma [OCS.typeChk] THEN OCC.TypeTrap (L0)
- ELSE OCC.FixLink (L0)
- END;
- OCC.FixLink (L1); CheckSym (end); OCC.ForgetRegs
-
- 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);
- OCC.ForgetRegs
- 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 *)
- 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 : LONGINT);
-
- (* CONST pname = "Block"; *)
-
- VAR
- typ, forward : OCT.Struct;
- obj, first, last : OCT.Object;
- x : OCT.Item;
- L0 : LONGINT;
- adr, size : LONGINT;
- mk : SHORTINT;
- id0 : ARRAY 32 OF CHAR;
-
- BEGIN (* Block *)
- (* 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.label := x.label;
-
- 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, TRUE);
- ELSIF (sym = becomes) OR (sym = colon) THEN
- OCS.Mark (9);
- OCS.Get (sym); Type (typ, TRUE);
- ELSE
- OCS.Mark (9); typ := OCT.undftyp
- 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, FALSE);
- 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;
- IF (OCM.VarLimit - size) < adr THEN OCS.Mark (209)
- ELSE INC (adr, size)
- END;
- 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;
- IF (OCM.LVarLimit + size) > adr THEN OCS.Mark (209)
- ELSE DEC (adr, size)
- END;
- 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 ();
-
- IF (OCC.level = 0) & (dsize = 0) & ~OCM.SmallData & ~OCM.Resident THEN
- OCS.pragma [OCS.longVars] := TRUE
- 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 *)
- OCC.ForgetRegs;
- IF OCC.level = 0 THEN
- OCH.StartModuleBody (dsize, retList)
- ELSE
- IF proc.link = NIL THEN proc.link := OCT.topScope.right END;
- OCH.StartProcBody (proc, dsize)
- END;
- IF sym = begin THEN (* Main body of block *)
- OCS.Get (sym); StatSeq (retList);
- END;
-
- CheckSym (end);
- 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 : INTEGER; retList : LONGINT; ch : CHAR;
- time, date, key, dsize : LONGINT;
- name, alias : ARRAY 32 OF CHAR;
- FName : ARRAY 256 OF CHAR;
-
- BEGIN (* CompilationUnit *)
- procNo := 1; dsize := 0; LoopLevel := 0; ExitNo := 0;
- defaultFlag := OberonFlag;
- OCC.Init (); OCT.Init (); OCS.Init (source);
-
- REPEAT OCS.Get (sym) UNTIL (sym = eof) OR (sym = module);
- IF sym # module THEN
- OCOut.Str0 (OCStrings.Compiler1);
- RETURN
- END;
-
- OCS.allowOptions := FALSE; OCS.Get (sym);
- IF sym = lbrak THEN SysFlag (defaultFlag) END;
-
- 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 ();
- OCC.StartModule (OCT.ModuleName);
- OCT.OpenScope (0);
-
- OCS.Get (sym);
- IF sym = lbrak THEN (* List of external modules *)
- REPEAT
- OCS.Get (sym);
- IF sym = string THEN OCT.ExtLib (); OCS.Get (sym)
- ELSE OCS.Mark (342)
- END
- UNTIL sym # comma;
- CheckSym (rbrak); CheckNonStandard ()
- END;
- CheckSym (semicolon);
-
- OCH.ModulePrologue ();
-
- IF sym = import THEN
- OCS.Get (sym);
-
- LOOP
- IF sym = ident THEN
- COPY (OCS.name, alias); OCS.Get (sym);
- name := alias;
- IF sym = becomes THEN
- OCS.Get (sym);
- IF sym = ident THEN COPY (OCS.name, name); OCS.Get (sym);
- ELSE OCS.Mark (10);
- END
- END;
- OCT.Import (name, alias)
- 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 (dsize, 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 OCM.Force THEN
- OCC.AllocSlots;
- OberonClock.GetClock (time, date);
- key := (date MOD 4000H) * 20000H + time;
- OCT.Export (OCT.ModuleName, newSF, key);
- IF ~OCS.scanerr OR OCM.Force THEN
- OCM.ObjectFileName (OCT.ModuleName, FName);
- IF OCM.Verbose THEN OCOut.Str1 (OCStrings.Compiler2, FName) END;
- OCC.OutCode (FName, key, dsize);
- IF OCM.Verbose THEN
- OCOut.Int4
- ( OCStrings.Compiler3, OCC.pc, OCC.DataSize(), dsize,
- OCC.pc + dsize + OCC.DataSize ());
- END
- END
- END (* IF *)
- END; (* IF *)
- OCT.CloseScope ();
- OCT.EndModule (); OCS.EndModule ();
- ELSE
- OCOut.Str0 (OCStrings.Compiler4)
- END;
-
- END CompilationUnit;
-
- (*------------------------------------*)
- PROCEDURE ReportTime (VAR t1, t2 : ti.TimeVal);
-
- PROCEDURE Pair ( ch : CHAR; x : LONGINT );
- BEGIN (* Pair *)
- OCOut.Char (ch);
- OCOut.Char (CHR (x DIV 10 + 30H));
- OCOut.Char (CHR (x MOD 10 + 30H))
- END Pair;
-
- BEGIN (* ReportTime *)
- ti.SubTime (t2, t1);
- OCOut.Str (" Elapsed time =");
- Pair (" ", t2.secs DIV 60);
- Pair (":", t2.secs MOD 60);
- OCOut.Char ("."); OCOut.Int (t2.micro DIV 100000);
- OCOut.Ln; OCOut.Ln
- END ReportTime;
-
- (*------------------------------------*)
- PROCEDURE Reset ();
-
- VAR
- t1, t2 : ti.TimeVal;
-
- BEGIN (* Reset *)
- IF OCM.Verbose THEN
- OCOut.Str0 (OCStrings.OC8);
- ti.GetSysTime (t1);
- END;
-
- OCC.Close (); OCT.Close ();
- Kernel.GC;
-
- IF OCM.Verbose THEN
- ti.GetSysTime (t2);
- ReportTime (t1, t2)
- END;
- END Reset;
-
- (*------------------------------------*)
- PROCEDURE Compile* (source : ARRAY OF CHAR; newSymFile : BOOLEAN);
-
- VAR
- t1, t2 : ti.TimeVal;
-
- <*$CopyArrays-*>
- BEGIN (* Compile *)
- IF OCM.Verbose THEN ti.GetSysTime (t1) END;
-
- file := Files.Old (source);
- IF file = NIL THEN
- OCOut.Str1 (OCStrings.OC6, source)
- ELSE
- OCOut.Str1 (OCStrings.OC7, source);
- newSF := newSymFile;
- CompilationUnit (file);
- IF OCS.scanerr THEN returnError := TRUE
- ELSIF OCS.warned THEN returnWarn := TRUE
- END;
- Files.Close (file); file := NIL
- END;
-
- IF OCM.Verbose THEN
- ti.GetSysTime (t2);
- ReportTime (t1, t2)
- END;
-
- Reset
- END Compile;
-
- (*------------------------------------*)
- PROCEDURE Batch* (batchName : ARRAY OF CHAR; newSymFile : BOOLEAN);
-
- VAR
- sourceName : ARRAY 256 OF CHAR;
- i : INTEGER;
- ch : CHAR;
- t1, t2 : ti.TimeVal;
-
- <*$CopyArrays-*>
- BEGIN (* Batch *)
- batchFile := Files.Old (batchName);
- IF batchFile # NIL THEN
- IF OCM.Verbose THEN ti.GetSysTime (t1) END;
-
- Files.Set (r, batchFile, 0);
- LOOP
- Files.Read (r, ch);
- IF r.eof THEN EXIT END;
- WHILE ch <= " " DO (* Skip whitespace *)
- Files.Read (r, ch);
- IF r.eof THEN EXIT END
- END;
- i := 0;
- REPEAT
- sourceName [i] := ch; INC (i); Files.Read (r, ch)
- UNTIL r.eof OR (ch = "\n");
- sourceName [i] := 0X;
- Compile (sourceName, newSymFile);
- IF r.eof THEN EXIT END
- END;
- Files.Set (r, NIL, 0); Files.Close (batchFile); batchFile := NIL;
-
- IF OCM.Verbose THEN
- ti.GetSysTime (t2);
- OCOut.Str0 (OCStrings.OC10);
- ReportTime (t1, t2)
- END;
- ELSE
- OCOut.Str1 (OCStrings.OC11, batchName)
- END
- END Batch;
-
- (*------------------------------------*)
- PROCEDURE Interactive* (newSymFile : BOOLEAN);
-
- CONST prompt = "Source file ? : ";
-
- VAR nameBuffer : ARRAY 256 OF CHAR;
-
- BEGIN (* Interactive *)
- OCOut.Str0 (OCStrings.OC9);
- In.Open; In.Name (nameBuffer);
- IF nameBuffer [0] # 0X THEN
- Compile (nameBuffer, newSymFile);
- LOOP
- OCOut.Str0 (OCStrings.OC9);
- In.Open; In.Name (nameBuffer);
- IF nameBuffer = "" THEN EXIT END;
- Compile (nameBuffer, newSymFile)
- END
- END
- END Interactive;
-
- (*------------------------------------*)
- PROCEDURE* Cleanup (VAR rc : LONGINT);
-
- BEGIN (* Cleanup *)
- IF file # NIL THEN Files.Close (file); file := NIL END;
- IF batchFile # NIL THEN Files.Close (batchFile); batchFile := NIL END;
- IF ti.base # NIL THEN e.CloseDevice (tr); ti.base := NIL END;
- END Cleanup;
-
- (*------------------------------------*)
- PROCEDURE Init ();
-
- BEGIN (* Init *)
- Kernel.SetCleanup (Cleanup);
- returnWarn := FALSE; returnError := FALSE;
-
- NEW (tr);
- Errors.Assert
- ( e.OpenDevice (ti.timerName, ti.vBlank, tr, {}) = 0,
- "OC -- failed to open timer.device" );
- ti.base := tr.node.device;
- END Init;
-
- BEGIN (* Compiler *)
- Init
- END Compiler.
-
- (***************************************************************************
-
- $Log: Compiler.mod $
- Revision 5.30 1995/06/29 19:11:29 fjc
- - Removed code that was second-guessing the garbage collector
-
- Revision 5.29 1995/06/15 18:16:21 fjc
- - Changed the parameters to OCH.PrepCall().
-
- Revision 5.28 1995/06/04 22:52:04 fjc
- - Changed to reflect new interfaces to OCH procedures.
-
- Revision 5.27 1995/06/03 00:37:33 fjc
- - Uses new interface to OCH.PrepCall.
-
- Revision 5.26 1995/06/02 18:44:23 fjc
- - Implemented the SMALLDATA and RESIDENT options.
- - Enforces ExtendLimit.
- - Implemented the AssertChk pragma.
-
- Revision 5.25 1995/05/19 16:06:18 fjc
- - Uses OCOut for console IO.
- - Reinstated Interactive() procedure.
-
- Revision 5.24 1995/05/13 23:11:28 fjc
- - Changed INTEGER to LONGINT where necessary.
- - Moved Compile(), Batch(), etc. from OC.
-
- Revision 5.22 1995/04/02 13:57:16 fjc
- - Changed to implement the small data model.
-
- Revision 5.21 1995/03/25 17:12:16 fjc
- - Minor fix in HasTaggedPtr().
-
- Revision 5.20 1995/03/23 18:30:31 fjc
- - More work on remembering registers
-
- Revision 5.18 1995/03/09 19:13:32 fjc
- - Incorporated changes from 5.22.
-
- Revision 5.17 1995/02/27 17:11:46 fjc
- - Removed tracing code.
- - Changed to use new register handling procedures.
-
- Revision 5.16.1.1 1995/03/08 19:27:57 fjc
- - OC 5.22
-
- Revision 5.16 1995/02/08 13:56:11 fjc
- - OC 5.20
-
- Revision 5.15 1995/01/26 00:17:17 fjc
- - Release 1.5
-
- Revision 5.13 1995/01/09 13:59:06 fjc
- - Changed console output depending on OCM.Verbose.
-
- Revision 5.12 1995/01/05 11:39:48 fjc
- - Changed forceCode to OCM.Force.
-
- Revision 5.11 1995/01/03 21:26:02 fjc
- - Changed OCG to OCM.
- - Changed to use catalogs:
- - Uses OCM for console I/O instead of Out.
- - Gets text from OCStrings instead of hard-coding it.
-
- Revision 5.10 1994/12/16 17:43:38 fjc
- - Changed Symbol to Label.
- - Uses module OCG for constructing file names.
- - Changed handling of forward declarations.
- - Added call to OCC.AllocSlots().
-
- Revision 5.9 1994/11/13 11:40:01 fjc
- - Fixed bug in handling sysflags when module default was
- not Oberon.
- - Now allows braces in place of square brackets for some
- purposes.
-
- Revision 5.8 1994/10/23 16:34:03 fjc
- - Replaced StdIO with Out for console IO.
- - Uses new interface for module Strings.
- - Changed to reflect changes in interfaces to OCH and OCP.
-
- Revision 5.7 1994/09/25 18:12:09 fjc
- - Changed to reflect new object modes and system flags:
- - Removed code for parsing CPOINTER, BPOINTER and LIBCALL
- declarations.
- - Added code to parse system flags.
- - Added checks for system flags in record, pointer and
- procedure declarations.
- - Simplified checking for dynamic array types.
-
- Revision 5.6 1994/09/19 23:10:05 fjc
- - Re-implemented Amiga library calls
-
- Revision 5.5 1994/09/16 17:37:41 fjc
- - Removed defunct error message.
-
- Revision 5.4 1994/09/15 11:34:09 fjc
- - Merged in bug fix from 4.17.
-
- Revision 5.3 1994/09/15 10:44:05 fjc
- - Replaced switches with pragmas.
-
- Revision 5.2 1994/09/08 10:53:28 fjc
- - Changed to use pragmas/options.
-
- Revision 5.1 1994/09/03 19:29:08 fjc
- - Bumped version number
-
- ***************************************************************************)
-