Oberon/ETH Oberon/2.3.7/Compiler.Mod
Appearance
< Oberon | ETH Oberon
(* ETH Oberon, Copyright 1990-2003 Computer Systems Institute, ETH Zurich, CH-8092 Zurich.
Refer to the license.txt file provided with this distribution. *)
MODULE Compiler; (** portable, except where noted *)
IMPORT
OPP, OPB, OPV, OPT, OPS, OPC, OPL, OPO, OPM, Modules, Display, Oberon, Texts;
CONST
NoBreakPC = -1;
module = OPS.module; ident = OPS.ident; period = OPS.period; (* symbols *)
VAR
W: Texts.Writer;
PROCEDURE SignOn;
BEGIN
Texts.WriteString(W, "Oberon Portable Compiler / nw, rc, nm, tk, prk"); Texts.WriteLn(W);
Texts.WriteString(W, OPP.SignOnMessage); Texts.WriteLn(W);
Texts.Append(Oberon.Log, W.buf)
END SignOn;
PROCEDURE GetOptions(VAR S: Texts.Scanner; VAR opts: ARRAY OF CHAR);
VAR i: LONGINT; ch: CHAR;
BEGIN
WHILE (S.class = Texts.Char) & (S.c = Oberon.OptionChar) DO
i := 0;
WHILE opts[i] # 0X DO INC(i) END;
ch := S.nextCh;
WHILE ch > " " DO
opts[i] := ch; INC(i); Texts.Read(S, ch)
END;
opts[i] := " "; INC(i);
opts[i] := 0X; S.nextCh := ch; Texts.Scan(S)
END;
END GetOptions;
PROCEDURE InOptions(VAR opt: ARRAY OF CHAR; ch: CHAR): BOOLEAN;
VAR i: LONGINT;
BEGIN
i := 0;
WHILE (opt[i] # 0X) & (opt[i] # ch) DO
IF (opt[i] = ".") OR (opt[i] = "P") THEN
REPEAT INC(i) UNTIL (opt[i] = 0X) OR (opt[i] = " ")
ELSE INC(i) END
END;
RETURN opt[i] = ch
END InOptions;
PROCEDURE Locate(F: Display.Frame; T: Texts.Text; pos: LONGINT);
VAR M: Oberon.CaretMsg; N: Oberon.ControlMsg;
BEGIN
IF pos < 0 THEN pos := 0
ELSIF pos > T.len THEN pos := T.len
END;
N.F := NIL; N.id := Oberon.neutralize; Display.Broadcast(N);
Oberon.FadeCursor(Oberon.Pointer);
M.id := Oberon.set; M.F := F; M.car := F; M.text := T; M.pos := pos; Display.Broadcast(M)
END Locate;
PROCEDURE GetBreakPC(): LONGINT;
VAR S: Texts.Scanner; t: Texts.Text; beg, end, time: LONGINT;
BEGIN
Oberon.GetSelection(t, beg, end, time);
IF time >= 0 THEN
Texts.OpenScanner(S, t, beg); Texts.Scan(S);
end := S.line;
WHILE (S.class # Texts.Int) & (S.line = end) DO Texts.Scan(S) END;
END;
IF (time < 0) OR (S.class # Texts.Int) THEN
Texts.WriteString(W, " pc not selected"); Texts.WriteLn(W);
Texts.Append(Oberon.Log, W.buf);
RETURN NoBreakPC
ELSE
RETURN S.i
END
END GetBreakPC;
PROCEDURE ParseOptions(VAR name, options, path, pref, extension: ARRAY OF CHAR; VAR codeOpt, parserOpt: SET);
VAR i, j, k: LONGINT; ch: CHAR;
BEGIN
codeOpt := OPM.DefaultCodeOpt; parserOpt := OPM.DefaultParserOpt;
i := 0; path[0] := 0X; pref[0] := 0X;
COPY(Modules.extension, extension);
LOOP
ch := options[i]; INC(i);
IF ch = 0X THEN EXIT
ELSIF ch = "x" THEN codeOpt := codeOpt / {OPM.inxchk}
ELSIF ch = "v" THEN codeOpt := codeOpt / {OPM.ovflchk}
ELSIF ch = "t" THEN codeOpt := codeOpt / {OPM.typchk}
ELSIF ch = "p" THEN codeOpt := codeOpt / {OPM.ptrinit}
ELSIF ch = "a" THEN codeOpt := codeOpt / {OPM.assert}
ELSIF ch = "z" THEN codeOpt := codeOpt / {OPM.fullstackinit}
ELSIF ch = "q" THEN codeOpt := codeOpt / {OPM.trace}
ELSIF ch = "s" THEN parserOpt := parserOpt / {OPM.newsf}
ELSIF ch = "S" THEN parserOpt := parserOpt / {OPM.systemchk}
ELSIF ch = "n" THEN parserOpt := parserOpt / {OPM.nofiles}
ELSIF ch = "e" THEN parserOpt := parserOpt / {OPM.extsf}
ELSIF ch = "f" THEN parserOpt := parserOpt / {OPM.findpc}
ELSIF ch = "w" THEN parserOpt := parserOpt / {OPM.warning}
ELSIF ch = "X" THEN parserOpt := parserOpt + {OPM.prefix}
ELSIF ch = "2" THEN parserOpt := parserOpt / {OPM.oberon2}
ELSIF ch = "1" THEN parserOpt := parserOpt / {OPM.oberon1}
ELSIF ch = "T" THEN parserOpt := parserOpt / {OPM.traceprocs} (* temp *)
ELSIF ch = "." THEN
j := 0;
WHILE (ch # 0X) & (ch # " ") DO
extension[j] := ch; ch := options[i];
INC(j); INC(i)
END;
extension[j] := 0X
ELSIF ch = "P" THEN
ch := options[i]; INC(i);
k := 0;
WHILE (ch # 0X) & (ch # " ") DO
path[k] := ch; INC(k);
ch := options[i]; INC(i)
END;
path[k] := 0X
ELSIF ch = "O" THEN (* mutually exclusive with "X" *)
ch := options[i]; INC(i);
k := 0;
WHILE (ch # 0X) & (ch # " ") DO
pref[k] := ch; INC(k);
ch := options[i]; INC(i)
END;
pref[k] := 0X
END
END;
IF OPM.prefix IN parserOpt THEN
i := -1; REPEAT INC(i); pref[i] := name[i] UNTIL (name[i] = 0X) OR (name[i] = ".");
IF name[i] # "." THEN i := 0 ELSE INC(i) END;
pref[i] := 0X
END
END ParseOptions;
PROCEDURE WriteMsg(source: Texts.Reader; log: Texts.Text);
VAR sym: SHORTINT;
BEGIN
Texts.WriteString(W, " compiling ");
OPM.Init({}, {}, source, log); OPS.Get(sym);
IF sym = module THEN
OPS.Get(sym);
IF sym = ident THEN
Texts.WriteString(W, OPM.outputPath);
Texts.WriteString(W, OPM.outputPrefix);
OPS.Get(sym); Texts.WriteString(W, OPS.name);
WHILE sym = period DO
Texts.Write(W, ".");
OPS.Get(sym);
IF sym = ident THEN Texts.WriteString(W, OPS.name); OPS.Get(sym) END;
END;
IF OPM.extension # Modules.extension THEN
Texts.WriteString(W, OPM.extension)
ELSIF (OPM.outputPath = "") & (OPM.outputPrefix = "") THEN (* not cross-compiling *)
IF Modules.FindMod(OPS.name) # NIL THEN
Texts.WriteString(W, " (in use) ")
END
ELSE
(* skip *)
END
END
END;
Texts.Append(log, W.buf)
END WriteMsg;
PROCEDURE Module*(source: Texts.Reader; name, options: ARRAY OF CHAR; breakpc: LONGINT;
log: Texts.Text; VAR error: BOOLEAN);
VAR codeOpt, parserOpt: SET; extSF, newSF: BOOLEAN; p: OPT.Node; modName: OPS.Name;
BEGIN
ParseOptions(name, options, OPM.outputPath, OPM.outputPrefix, OPM.extension, codeOpt, parserOpt);
WriteMsg(source, log);
OPM.Init(codeOpt, parserOpt, source, log); OPS.ch := " ";
OPB.typSize := OPV.TypSize; OPV.Init(breakpc);
newSF := OPM.newsf IN parserOpt; extSF := OPM.extsf IN parserOpt;
OPP.Module(p, modName);
IF OPM.noerr THEN
OPL.Init;
OPM.errpos := 0;
OPM.Begin(modName);
IF OPM.noerr THEN
OPT.Export(modName, newSF, extSF);
OPV.AdrAndSize(OPT.topScope);
IF newSF THEN OPM.LogWStr(" new symbol file")
ELSIF extSF THEN OPM.LogWStr(" extended symbol file")
END;
IF OPM.noerr THEN
OPM.errpos := 0;
OPC.Init;
OPV.Module(p);
IF OPM.noerr THEN
OPL.OutCode(modName);
IF OPM.noerr THEN
OPM.LogWStr (" "); OPM.LogWNum(OPO.pc, 1)
END
END
END;
OPL.Close
END
END;
OPT.CloseScope; OPT.Close;
OPM.LogWLn; error := ~OPM.noerr;
OPM.outputPath := "!"; OPM.outputPrefix := "!" (* invalid filename *)
END Module;
PROCEDURE CompileText(t: Texts.Text; pos: LONGINT; frame: Display.Frame; opt: ARRAY OF CHAR; VAR error: BOOLEAN);
VAR f: BOOLEAN; pc: LONGINT; r: Texts.Reader;
BEGIN
IF t # NIL THEN
Texts.OpenReader(r, t, pos);
f := InOptions(opt, "f");
IF f THEN
pc := GetBreakPC();
IF pc = NoBreakPC THEN RETURN END
END;
OPS.Init;
Module(r, "", opt, pc, Oberon.Log, error);
IF f & (frame # NIL) THEN
Locate(frame, t, OPM.breakpos)
END
ELSE
Texts.WriteString(W, "No text marked"); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf);
error := TRUE
END
END CompileText;
PROCEDURE CompileFile*(name, opt: ARRAY OF CHAR; VAR error: BOOLEAN);
VAR t: Texts.Text; r: Texts.Reader; pc: LONGINT;
BEGIN
NEW(t); Texts.Open(t, name);
IF t.len # 0 THEN
Texts.OpenReader(r, t, 0);
IF InOptions(opt, "f") THEN
pc := GetBreakPC();
IF pc = NoBreakPC THEN RETURN END
END;
Texts.WriteString(W, name);
OPS.Init;
Module(r, name, opt, pc, Oberon.Log, error)
ELSE
Texts.WriteString(W, name); Texts.WriteString(W, " not found");
Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf);
error := TRUE
END
END CompileFile;
PROCEDURE Compile*;
VAR S: Texts.Scanner; globalOpt, localOpt: ARRAY 32 OF CHAR;
t: Texts.Text; pos, end, time: LONGINT; frame: Display.Frame;
name: ARRAY 64 OF CHAR; error: BOOLEAN;
BEGIN
error := FALSE;
Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
globalOpt := ""; GetOptions(S, globalOpt);
IF (S.class = Texts.Char) & ((S.c = "*") OR (S.c = "@")) THEN
IF S.c = "*" THEN
t := Oberon.MarkedText(); pos := 0; frame := Oberon.MarkedFrame();
ELSE (* S.c = "@" *)
Oberon.GetSelection(t, pos, end, time); frame := NIL;
IF time < 0 THEN RETURN END
END;
Texts.Scan(S);
GetOptions(S, globalOpt);
CompileText(t, pos, frame, globalOpt, error);
ELSIF ((S.class = Texts.Char) & (S.c = "^")) OR (S.class = Texts.Name) THEN
IF (S.c = "^") THEN
Oberon.GetSelection(t, pos, end, time);
Texts.OpenScanner(S, t, pos); Texts.Scan(S)
ELSE
end := MAX(LONGINT)
END;
WHILE (S.class = Texts.Name) & (Texts.Pos(S) - S.len <= end) & ~error DO
COPY(S.s, name); COPY(globalOpt, localOpt);
Texts.Scan(S); GetOptions(S, localOpt);
CompileFile(name, localOpt, error)
END
END
END Compile;
BEGIN
Texts.OpenWriter(W); SignOn
END Compiler.
Compiler.Compile Test.Mod ~
Compiler.Compile Test.Mod\s ~
Compiler.Compile Test.Mod\sX.Obx ~
Compiler.Compile *
Compiler.Compile *\s
Compiler.Compile \.Obx Test.Mod Test.Mod\.Obf Test.Mod ~
Compiler.Compile @