mirror of
https://github.com/vishapoberon/compiler.git
synced 2026-04-05 23:22:25 +00:00
Merge branch 'master' of https://github.com/vishaps/voc
This commit is contained in:
commit
f72b4280b7
19 changed files with 0 additions and 5404 deletions
|
|
@ -1,585 +0,0 @@
|
|||
MODULE CompatTexts; (*JG 21.11.90 / NW 11.7.90 / 24.12.95 / 22.11.10 / 26.3.2014*)
|
||||
IMPORT Files := CompatFiles, Fonts;
|
||||
|
||||
TYPE INTEGER = LONGINT; (* voc adaptation by noch *)
|
||||
BYTE = CHAR;
|
||||
|
||||
CONST (*scanner symbol classes*)
|
||||
Inval* = 0; (*invalid symbol*)
|
||||
Name* = 1; (*name s (length len)*)
|
||||
String* = 2; (*literal string s (length len)*)
|
||||
Int* = 3; (*integer i (decimal or hexadecimal)*)
|
||||
Real* = 4; (*real number x*)
|
||||
Char* = 6; (*special character c*)
|
||||
|
||||
(* TextBlock = TextTag "1" offset run {run} "0" len {AsciiCode}.
|
||||
run = fnt [name] col voff len. *)
|
||||
|
||||
TAB = 9X; CR = 0DX; maxD = 9;
|
||||
TextTag = 0F1X;
|
||||
replace* = 0; insert* = 1; delete* = 2; unmark* = 3; (*op-codes*)
|
||||
|
||||
TYPE Piece = POINTER TO PieceDesc;
|
||||
PieceDesc = RECORD
|
||||
f: Files.File;
|
||||
off, len: LONGINT;
|
||||
fnt: Fonts.Font;
|
||||
col, voff: INTEGER;
|
||||
prev, next: Piece
|
||||
END;
|
||||
|
||||
Text* = POINTER TO TextDesc;
|
||||
Notifier* = PROCEDURE (T: Text; op: INTEGER; beg, end: LONGINT);
|
||||
TextDesc* = RECORD
|
||||
len*: LONGINT;
|
||||
changed*: BOOLEAN;
|
||||
notify*: Notifier;
|
||||
trailer: Piece;
|
||||
pce: Piece; (*cache*)
|
||||
org: LONGINT; (*cache*)
|
||||
END;
|
||||
|
||||
Reader* = RECORD
|
||||
eot*: BOOLEAN;
|
||||
fnt*: Fonts.Font;
|
||||
col*, voff*: INTEGER;
|
||||
ref: Piece;
|
||||
org: LONGINT;
|
||||
off: LONGINT;
|
||||
rider: Files.Rider
|
||||
END;
|
||||
|
||||
Scanner* = RECORD (Reader)
|
||||
nextCh*: CHAR;
|
||||
line*, class*: INTEGER;
|
||||
i*: LONGINT;
|
||||
x*: REAL;
|
||||
y*: LONGREAL;
|
||||
c*: CHAR;
|
||||
len*: INTEGER;
|
||||
s*: ARRAY 32 OF CHAR
|
||||
END;
|
||||
|
||||
Buffer* = POINTER TO BufDesc;
|
||||
BufDesc* = RECORD
|
||||
len*: LONGINT;
|
||||
header, last: Piece
|
||||
END;
|
||||
|
||||
Writer* = RECORD
|
||||
buf*: Buffer;
|
||||
fnt*: Fonts.Font;
|
||||
col*, voff*: INTEGER;
|
||||
rider: Files.Rider
|
||||
END;
|
||||
|
||||
VAR TrailerFile: Files.File;
|
||||
|
||||
(* voc adaptation by noch *)
|
||||
PROCEDURE FLOOR(x : REAL): INTEGER;
|
||||
BEGIN
|
||||
RETURN ENTIER(x)
|
||||
END FLOOR;
|
||||
|
||||
PROCEDURE LSL (x, n : INTEGER): INTEGER;
|
||||
BEGIN
|
||||
RETURN ASH(x, n);
|
||||
END LSL;
|
||||
|
||||
PROCEDURE ASR (x, n : INTEGER): INTEGER;
|
||||
BEGIN
|
||||
RETURN ASH(x, n);
|
||||
END ASR;
|
||||
|
||||
|
||||
(* -------------------- Filing ------------------------*)
|
||||
|
||||
PROCEDURE Trailer(): Piece;
|
||||
VAR Q: Piece;
|
||||
BEGIN NEW(Q);
|
||||
Q.f := TrailerFile; Q.off := -1; Q.len := 1; Q.fnt := NIL; Q.col := 0; Q.voff := 0; RETURN Q
|
||||
END Trailer;
|
||||
|
||||
PROCEDURE Load* (VAR R: Files.Rider; T: Text);
|
||||
VAR Q, q, p: Piece;
|
||||
off: LONGINT;
|
||||
N, fno: INTEGER; bt: BYTE;
|
||||
f: Files.File;
|
||||
FName: ARRAY 32 OF CHAR;
|
||||
Dict: ARRAY 32 OF Fonts.Font;
|
||||
BEGIN f := Files.Base(R); N := 1; Q := Trailer(); p := Q;
|
||||
Files.ReadInt(R, off); Files.ReadByte(R, bt);
|
||||
(*fno := bt;*)
|
||||
fno := ORD(bt); (* voc adaptation by noch *)
|
||||
WHILE fno # 0 DO
|
||||
IF fno = N THEN
|
||||
Files.ReadString(R, FName);
|
||||
Dict[N] := Fonts.This(FName); INC(N)
|
||||
END;
|
||||
NEW(q); q.fnt := Dict[fno];
|
||||
Files.ReadByte(R, bt);
|
||||
(*q.col := bt;*)
|
||||
q.col := ORD(bt); (* voc adaptation by noch *)
|
||||
Files.ReadByte(R, bt);
|
||||
(*q.voff := ASR(LSL(bt, -24), 24);*)
|
||||
q.voff := ASR(LSL(ORD(bt), -24), 24); (* voc adaptation by noch *)
|
||||
Files.ReadInt(R, q.len);
|
||||
Files.ReadByte(R, bt);
|
||||
(*fno := bt;*)
|
||||
fno := ORD(bt); (* voc adaptation by noch *)
|
||||
q.f := f; q.off := off; off := off + q.len;
|
||||
p.next := q; q.prev := p; p := q
|
||||
END;
|
||||
p.next := Q; Q.prev := p;
|
||||
T.trailer := Q; Files.ReadInt(R, T.len); (*Files.Set(R, f, Files.Pos(R) + T.len)*)
|
||||
END Load;
|
||||
|
||||
PROCEDURE Open* (T: Text; name: ARRAY OF CHAR);
|
||||
VAR f: Files.File; R: Files.Rider; Q, q: Piece;
|
||||
tag: CHAR; len: LONGINT;
|
||||
BEGIN f := Files.Old(name);
|
||||
IF f # NIL THEN
|
||||
Files.Set(R, f, 0); Files.Read(R, tag);
|
||||
IF tag = TextTag THEN Load(R, T)
|
||||
ELSE (*Ascii file*)
|
||||
len := Files.Length(f); Q := Trailer();
|
||||
NEW(q); q.fnt := Fonts.Default; q.col := 1; q.voff := 0; q.f := f; q.off := 0; q.len := len;
|
||||
Q.next := q; q.prev := Q; q.next := Q; Q.prev := q; T.trailer := Q; T.len := len
|
||||
END
|
||||
ELSE (*create new text*)
|
||||
Q := Trailer(); Q.next := Q; Q.prev := Q; T.trailer := Q; T.len := 0
|
||||
END ;
|
||||
T.changed := FALSE; T.org := -1; T.pce := T.trailer (*init cache*)
|
||||
END Open;
|
||||
|
||||
PROCEDURE Store* (VAR W: Files.Rider; T: Text);
|
||||
VAR p, q: Piece;
|
||||
R: Files.Rider;
|
||||
off, rlen, pos: LONGINT;
|
||||
N, n: INTEGER;
|
||||
ch: CHAR;
|
||||
Dict: ARRAY 32, 32 OF CHAR;
|
||||
BEGIN pos := Files.Pos(W); Files.WriteInt(W, 0); (*place holder*)
|
||||
N := 1; p := T.trailer.next;
|
||||
WHILE p # T.trailer DO
|
||||
rlen := p.len; q := p.next;
|
||||
WHILE (q # T.trailer) & (q.fnt = p.fnt) & (q.col = p.col) & (q.voff = p.voff) DO
|
||||
rlen := rlen + q.len; q := q.next
|
||||
END;
|
||||
(*Dict[N] := p.fnt.name;*)
|
||||
IF p.fnt # NIL THEN COPY(p.fnt.name, Dict[N]) END; (* voc adaptation by noch *)
|
||||
n := 1;
|
||||
IF p.fnt # NIL THEN (* voc adaptation by noch *)
|
||||
WHILE Dict[n] # p.fnt.name DO INC(n) END;
|
||||
END;
|
||||
(*Files.WriteByte(W, n);*)
|
||||
Files.WriteByte(W, SHORT(SHORT(n))); (* voc adaptation by noch *)
|
||||
IF p.fnt # NIL THEN (* voc adaptation by noch *)
|
||||
IF n = N THEN Files.WriteString(W, p.fnt.name); INC(N) END;
|
||||
END;
|
||||
(*Files.WriteByte(W, p.col);*)
|
||||
Files.WriteByte(W, SHORT(SHORT(p.col))); (* voc adaptation by noch *)
|
||||
(*Files.WriteByte(W, p.voff);*)
|
||||
Files.WriteByte(W, SHORT(SHORT(p.voff))); (* voc adaptation by noch *)
|
||||
Files.WriteInt(W, rlen);
|
||||
p := q
|
||||
END;
|
||||
Files.WriteByte(W, 0); Files.WriteInt(W, T.len);
|
||||
off := Files.Pos(W); p := T.trailer.next;
|
||||
WHILE p # T.trailer DO
|
||||
rlen := p.len; Files.Set(R, p.f, p.off);
|
||||
WHILE rlen > 0 DO Files.Read(R, ch); Files.Write(W, ch); DEC(rlen) END ;
|
||||
p := p.next
|
||||
END ;
|
||||
Files.Set(W, Files.Base(W), pos); Files.WriteInt(W, off); (*fixup*)
|
||||
T.changed := FALSE;
|
||||
IF T.notify # NIL THEN T.notify(T, unmark, 0, 0) END
|
||||
END Store;
|
||||
|
||||
PROCEDURE Close*(T: Text; name: ARRAY OF CHAR);
|
||||
VAR f: Files.File; w: Files.Rider;
|
||||
BEGIN f := Files.New(name); Files.Set(w, f, 0);
|
||||
Files.Write(w, TextTag); Store(w, T); Files.Register(f)
|
||||
END Close;
|
||||
|
||||
(* -------------------- Editing ----------------------- *)
|
||||
|
||||
PROCEDURE OpenBuf* (B: Buffer);
|
||||
BEGIN NEW(B.header); (*null piece*)
|
||||
B.last := B.header; B.len := 0
|
||||
END OpenBuf;
|
||||
|
||||
PROCEDURE FindPiece (T: Text; pos: LONGINT; VAR org: LONGINT; VAR pce: Piece);
|
||||
VAR p: Piece; porg: LONGINT;
|
||||
BEGIN p := T.pce; porg := T.org;
|
||||
IF pos >= porg THEN
|
||||
WHILE pos >= porg + p.len DO INC(porg, p.len); p := p.next END
|
||||
ELSE p := p.prev; DEC(porg, p.len);
|
||||
WHILE pos < porg DO p := p.prev; DEC(porg, p.len) END
|
||||
END ;
|
||||
T.pce := p; T.org := porg; (*update cache*)
|
||||
pce := p; org := porg
|
||||
END FindPiece;
|
||||
|
||||
PROCEDURE SplitPiece (p: Piece; off: LONGINT; VAR pr: Piece);
|
||||
VAR q: Piece;
|
||||
BEGIN
|
||||
IF off > 0 THEN NEW(q);
|
||||
q.fnt := p.fnt; q.col := p.col; q.voff := p.voff;
|
||||
q.len := p.len - off;
|
||||
q.f := p.f; q.off := p.off + off;
|
||||
p.len := off;
|
||||
q.next := p.next; p.next := q;
|
||||
q.prev := p; q.next.prev := q;
|
||||
pr := q
|
||||
ELSE pr := p
|
||||
END
|
||||
END SplitPiece;
|
||||
|
||||
PROCEDURE Save* (T: Text; beg, end: LONGINT; B: Buffer);
|
||||
VAR p, q, qb, qe: Piece; org: LONGINT;
|
||||
BEGIN
|
||||
IF end > T.len THEN end := T.len END;
|
||||
FindPiece(T, beg, org, p);
|
||||
NEW(qb); qb^ := p^;
|
||||
qb.len := qb.len - (beg - org);
|
||||
qb.off := qb.off + (beg - org);
|
||||
qe := qb;
|
||||
WHILE end > org + p.len DO
|
||||
org := org + p.len; p := p.next;
|
||||
NEW(q); q^ := p^; qe.next := q; q.prev := qe; qe := q
|
||||
END;
|
||||
qe.next := NIL; qe.len := qe.len - (org + p.len - end);
|
||||
B.last.next := qb; qb.prev := B.last; B.last := qe;
|
||||
B.len := B.len + (end - beg)
|
||||
END Save;
|
||||
|
||||
PROCEDURE Copy* (SB, DB: Buffer);
|
||||
VAR Q, q, p: Piece;
|
||||
BEGIN p := SB.header; Q := DB.last;
|
||||
WHILE p # SB.last DO p := p.next;
|
||||
NEW(q); q^ := p^; Q.next := q; q.prev := Q; Q := q
|
||||
END;
|
||||
DB.last := Q; DB.len := DB.len + SB.len
|
||||
END Copy;
|
||||
|
||||
PROCEDURE Insert* (T: Text; pos: LONGINT; B: Buffer);
|
||||
VAR pl, pr, p, qb, qe: Piece; org, end: LONGINT;
|
||||
BEGIN
|
||||
FindPiece(T, pos, org, p); SplitPiece(p, pos - org, pr);
|
||||
IF T.org >= org THEN T.org := org - p.prev.len; T.pce := p.prev END ;
|
||||
pl := pr.prev; qb := B.header.next;
|
||||
IF (qb # NIL) & (qb.f = pl.f) & (qb.off = pl.off + pl.len)
|
||||
& (qb.fnt = pl.fnt) & (qb.col = pl.col) & (qb.voff = pl.voff) THEN
|
||||
pl.len := pl.len + qb.len; qb := qb.next
|
||||
END;
|
||||
IF qb # NIL THEN qe := B.last;
|
||||
qb.prev := pl; pl.next := qb; qe.next := pr; pr.prev := qe
|
||||
END;
|
||||
T.len := T.len + B.len; end := pos + B.len;
|
||||
B.last := B.header; B.last.next := NIL; B.len := 0;
|
||||
T.changed := TRUE;
|
||||
(*T.notify(T, insert, pos, end)*)
|
||||
IF T.notify # NIL THEN
|
||||
T.notify(T, insert, pos, end)
|
||||
END(* voc adaptation by noch *)
|
||||
END Insert;
|
||||
|
||||
PROCEDURE Append* (T: Text; B: Buffer);
|
||||
BEGIN Insert(T, T.len, B)
|
||||
END Append;
|
||||
|
||||
PROCEDURE Delete* (T: Text; beg, end: LONGINT; B: Buffer);
|
||||
VAR pb, pe, pbr, per: Piece; orgb, orge: LONGINT;
|
||||
BEGIN
|
||||
IF end > T.len THEN end := T.len END;
|
||||
FindPiece(T, beg, orgb, pb); SplitPiece(pb, beg - orgb, pbr);
|
||||
FindPiece(T, end, orge, pe);
|
||||
SplitPiece(pe, end - orge, per);
|
||||
IF T.org >= orgb THEN (*adjust cache*)
|
||||
T.org := orgb - pb.prev.len; T.pce := pb.prev
|
||||
END;
|
||||
B.header.next := pbr; B.last := per.prev;
|
||||
B.last.next := NIL; B.len := end - beg;
|
||||
per.prev := pbr.prev; pbr.prev.next := per;
|
||||
T.len := T.len - B.len;
|
||||
T.changed := TRUE;
|
||||
IF T.notify # NIL THEN (* noch *)
|
||||
T.notify(T, delete, beg, end)
|
||||
END
|
||||
END Delete;
|
||||
|
||||
PROCEDURE ChangeLooks* (T: Text; beg, end: LONGINT; sel: SET; fnt: Fonts.Font; col, voff: INTEGER);
|
||||
VAR pb, pe, p: Piece; org: LONGINT;
|
||||
BEGIN
|
||||
IF end > T.len THEN end := T.len END;
|
||||
FindPiece(T, beg, org, p); SplitPiece(p, beg - org, pb);
|
||||
FindPiece(T, end, org, p); SplitPiece(p, end - org, pe);
|
||||
p := pb;
|
||||
REPEAT
|
||||
IF 0 IN sel THEN p.fnt := fnt END;
|
||||
IF 1 IN sel THEN p.col := col END;
|
||||
IF 2 IN sel THEN p.voff := voff END;
|
||||
p := p.next
|
||||
UNTIL p = pe;
|
||||
T.changed := TRUE;
|
||||
IF T.notify # NIL THEN (* noch *)
|
||||
T.notify(T, replace, beg, end)
|
||||
END
|
||||
END ChangeLooks;
|
||||
|
||||
PROCEDURE Attributes*(T: Text; pos: LONGINT; VAR fnt: Fonts.Font; VAR col, voff: INTEGER);
|
||||
VAR p: Piece; org: LONGINT;
|
||||
BEGIN FindPiece(T, pos, org, p); fnt := p.fnt; col := p.col; voff := p.voff
|
||||
END Attributes;
|
||||
|
||||
(* ------------------ Access: Readers ------------------------- *)
|
||||
|
||||
PROCEDURE OpenReader* (VAR R: Reader; T: Text; pos: LONGINT);
|
||||
VAR p: Piece; org: LONGINT;
|
||||
BEGIN FindPiece(T, pos, org, p);
|
||||
R.ref := p; R.org := org; R.off := pos - org;
|
||||
Files.Set(R.rider, p.f, p.off + R.off); R.eot := FALSE
|
||||
END OpenReader;
|
||||
|
||||
PROCEDURE Read* (VAR R: Reader; VAR ch: CHAR);
|
||||
BEGIN Files.Read(R.rider, ch);
|
||||
R.fnt := R.ref.fnt; R.col := R.ref.col; R.voff := R.ref.voff;
|
||||
INC(R.off);
|
||||
IF R.off = R.ref.len THEN
|
||||
IF R.ref.f = TrailerFile THEN R.eot := TRUE END;
|
||||
R.org := R.org + R.off; R.off := 0;
|
||||
R.ref := R.ref.next; R.org := R.org + R.off; R.off := 0;
|
||||
Files.Set(R.rider, R.ref.f, R.ref.off)
|
||||
END
|
||||
END Read;
|
||||
|
||||
PROCEDURE Pos* (VAR R: Reader): LONGINT;
|
||||
BEGIN RETURN R.org + R.off
|
||||
END Pos;
|
||||
|
||||
(* ------------------ Access: Scanners (NW) ------------------------- *)
|
||||
|
||||
PROCEDURE OpenScanner* (VAR S: Scanner; T: Text; pos: LONGINT);
|
||||
BEGIN OpenReader(S, T, pos); S.line := 0; S.nextCh := " "
|
||||
END OpenScanner;
|
||||
|
||||
(*floating point formats:
|
||||
x = 1.m * 2^(e-127) bit 0: sign, bits 1- 8: e, bits 9-31: m
|
||||
x = 1.m * 2^(e-1023) bit 0: sign, bits 1-11: e, bits 12-63: m *)
|
||||
|
||||
PROCEDURE Ten(n: INTEGER): REAL;
|
||||
VAR t, p: REAL;
|
||||
BEGIN t := 1.0; p := 10.0; (*compute 10^n *)
|
||||
WHILE n > 0 DO
|
||||
IF ODD(n) THEN t := p * t END ;
|
||||
p := p*p; n := n DIV 2
|
||||
END ;
|
||||
RETURN t
|
||||
END Ten;
|
||||
|
||||
PROCEDURE Scan* (VAR S: Scanner);
|
||||
CONST maxExp = 38; maxM = 16777216; (*2^24*)
|
||||
VAR ch, term: CHAR;
|
||||
neg, negE, hex: BOOLEAN;
|
||||
i, j, h, d, e, n, s: INTEGER;
|
||||
k: LONGINT;
|
||||
x: REAL;
|
||||
BEGIN ch := S.nextCh; i := 0;
|
||||
WHILE (ch = " ") OR (ch = TAB) OR (ch = CR) DO
|
||||
IF ch = CR THEN INC(S.line) END ;
|
||||
Read(S, ch)
|
||||
END ;
|
||||
IF ("A" <= ch) & (ch <= "Z") OR ("a" <= ch) & (ch <= "z") THEN (*name*)
|
||||
REPEAT S.s[i] := ch; INC(i); Read(S, ch)
|
||||
UNTIL ((ch < "0") & (ch # ".") OR ("9" < ch) & (ch < "A") OR ("Z" < ch) & (ch < "a") OR ("z" < ch)) OR (i = 31);
|
||||
S.s[i] := 0X; S.len := i; S.class := Name
|
||||
ELSIF ch = 22X THEN (*string*)
|
||||
Read(S, ch);
|
||||
WHILE (ch # 22X) & (ch >= " ") & (i # 31) DO S.s[i] := ch; INC(i); Read(S, ch) END;
|
||||
S.s[i] := 0X; S.len := i+1; Read(S, ch); S.class := String
|
||||
ELSE hex := FALSE;
|
||||
IF ch = "-" THEN neg := TRUE; Read(S, ch) ELSE neg := FALSE END ;
|
||||
IF ("0" <= ch) & (ch <= "9") THEN (*number*)
|
||||
n := ORD(ch) - 30H; h := n; Read(S, ch);
|
||||
WHILE ("0" <= ch) & (ch <= "9") OR ("A" <= ch) & (ch <= "F") DO
|
||||
IF ch <= "9" THEN d := ORD(ch) - 30H ELSE d := ORD(ch) - 37H; hex := TRUE END ;
|
||||
n := 10*n + d; h := 10H*h + d; Read(S, ch)
|
||||
END ;
|
||||
IF ch = "H" THEN (*hex integer*) Read(S, ch); S.i := h; S.class := Int (*neg?*)
|
||||
ELSIF ch = "." THEN (*real number*)
|
||||
Read(S, ch); x := 0.0; e := 0; j := 0;
|
||||
WHILE ("0" <= ch) & (ch <= "9") DO (*fraction*)
|
||||
h := 10*n + (ORD(ch) - 30H);
|
||||
IF h < maxM THEN n := h; INC(j) END ;
|
||||
Read(S, ch)
|
||||
END ;
|
||||
IF ch = "E" THEN (*scale factor*)
|
||||
s := 0; Read(S, ch);
|
||||
IF ch = "-" THEN negE := TRUE; Read(S, ch)
|
||||
ELSE negE := FALSE;
|
||||
IF ch = "+" THEN Read(S, ch) END
|
||||
END ;
|
||||
WHILE ("0" <= ch) & (ch <= "9") DO
|
||||
s := s*10 + ORD(ch) - 30H; Read(S, ch)
|
||||
END ;
|
||||
IF negE THEN DEC(e, s) ELSE INC(e, s) END ;
|
||||
END ;
|
||||
(*x := FLT(n);*)
|
||||
x := n; (* voc adaptation by noch *)
|
||||
DEC(e, j);
|
||||
IF e < 0 THEN
|
||||
IF e >= -maxExp THEN x := x / Ten(-e) ELSE x := 0.0 END
|
||||
ELSIF e > 0 THEN
|
||||
IF e <= maxExp THEN x := Ten(e) * x ELSE x := 0.0 END
|
||||
END ;
|
||||
IF neg THEN S.x := -x ELSE S.x := x END ;
|
||||
IF hex THEN S.class := 0 ELSE S.class := Real END
|
||||
ELSE (*decimal integer*)
|
||||
IF neg THEN S.i := -n ELSE S.i := n END;
|
||||
IF hex THEN S.class := Inval ELSE S.class := Int END
|
||||
END
|
||||
ELSE (*spectal character*) S.class := Char;
|
||||
IF neg THEN S.c := "-" ELSE S.c := ch; Read(S, ch) END
|
||||
END
|
||||
END ;
|
||||
S.nextCh := ch
|
||||
END Scan;
|
||||
|
||||
(* --------------- Access: Writers (NW) ------------------ *)
|
||||
|
||||
PROCEDURE OpenWriter* (VAR W: Writer);
|
||||
BEGIN NEW(W.buf);
|
||||
OpenBuf(W.buf); W.fnt := Fonts.Default; W.col := 15; W.voff := 0;
|
||||
Files.Set(W.rider, Files.New(""), 0)
|
||||
END OpenWriter;
|
||||
|
||||
PROCEDURE SetFont* (VAR W: Writer; fnt: Fonts.Font);
|
||||
BEGIN W.fnt := fnt
|
||||
END SetFont;
|
||||
|
||||
PROCEDURE SetColor* (VAR W: Writer; col: INTEGER);
|
||||
BEGIN W.col := col
|
||||
END SetColor;
|
||||
|
||||
PROCEDURE SetOffset* (VAR W: Writer; voff: INTEGER);
|
||||
BEGIN W.voff := voff
|
||||
END SetOffset;
|
||||
|
||||
PROCEDURE Write* (VAR W: Writer; ch: CHAR);
|
||||
VAR p: Piece;
|
||||
BEGIN
|
||||
IF (W.buf.last.fnt # W.fnt) OR (W.buf.last.col # W.col) OR (W.buf.last.voff # W.voff) THEN
|
||||
NEW(p); p.f := Files.Base(W.rider); p.off := Files.Pos(W.rider); p.len := 0;
|
||||
p.fnt := W.fnt; p.col := W.col; p.voff:= W.voff;
|
||||
p.next := NIL; W.buf.last.next := p;
|
||||
p.prev := W.buf.last; W.buf.last := p
|
||||
END;
|
||||
Files.Write(W.rider, ch);
|
||||
INC(W.buf.last.len); INC(W.buf.len)
|
||||
END Write;
|
||||
|
||||
PROCEDURE WriteLn* (VAR W: Writer);
|
||||
BEGIN Write(W, CR)
|
||||
END WriteLn;
|
||||
|
||||
PROCEDURE WriteString* (VAR W: Writer; s: ARRAY OF CHAR);
|
||||
VAR i: INTEGER;
|
||||
BEGIN i := 0;
|
||||
WHILE s[i] >= " " DO Write(W, s[i]); INC(i) END
|
||||
END WriteString;
|
||||
|
||||
PROCEDURE WriteInt* (VAR W: Writer; x, n: LONGINT);
|
||||
VAR i: INTEGER; x0: LONGINT;
|
||||
a: ARRAY 10 OF CHAR;
|
||||
BEGIN
|
||||
(*IF ROR(x, 31) = 1 THEN WriteString(W, " -2147483648")
|
||||
ELSE*) i := 0; (* voc adaptation by noch *)
|
||||
IF x < 0 THEN DEC(n); x0 := -x ELSE x0 := x END;
|
||||
REPEAT
|
||||
a[i] := CHR(x0 MOD 10 + 30H); x0 := x0 DIV 10; INC(i)
|
||||
UNTIL x0 = 0;
|
||||
WHILE n > i DO Write(W, " "); DEC(n) END;
|
||||
IF x < 0 THEN Write(W, "-") END;
|
||||
REPEAT DEC(i); Write(W, a[i]) UNTIL i = 0
|
||||
(*END*)
|
||||
END WriteInt;
|
||||
|
||||
PROCEDURE WriteHex* (VAR W: Writer; x: LONGINT);
|
||||
VAR i: INTEGER; y: LONGINT;
|
||||
a: ARRAY 10 OF CHAR;
|
||||
BEGIN i := 0; Write(W, " ");
|
||||
REPEAT y := x MOD 10H;
|
||||
IF y < 10 THEN a[i] := CHR(y + 30H) ELSE a[i] := CHR(y + 37H) END;
|
||||
x := x DIV 10H; INC(i)
|
||||
UNTIL i = 8;
|
||||
REPEAT DEC(i); Write(W, a[i]) UNTIL i = 0
|
||||
END WriteHex;
|
||||
(* commented out because it's not necessary to compile OR compiler; -- noch
|
||||
PROCEDURE WriteReal* (VAR W: Writer; x: REAL; n: INTEGER);
|
||||
VAR e, i, m: INTEGER; x0: REAL; neg: BOOLEAN;
|
||||
d: ARRAY 16 OF CHAR;
|
||||
BEGIN
|
||||
IF x = 0.0 THEN
|
||||
WriteString(W, " 0.0"); i := 5;
|
||||
WHILE i < n DO Write(W, " "); INC(i) END
|
||||
ELSE
|
||||
IF x < 0.0 THEN x := -x; neg := TRUE ELSE neg := FALSE END ;
|
||||
x0 := x; UNPK(x0, e);
|
||||
IF e = 255 THEN WriteString(W, " NaN")
|
||||
ELSE
|
||||
REPEAT Write(W, " "); DEC(n) UNTIL n <= 14;
|
||||
IF neg THEN Write(W, "-") ELSE Write(W, " ") END ;
|
||||
e := e * 77 DIV 256 - 6;
|
||||
IF e >= 0 THEN x := x / Ten(e) ELSE x := x * Ten(-e) END ;
|
||||
IF x >= 10.0E6 THEN x := 0.1*x; INC(e) END ;
|
||||
m := FLOOR(x + 0.5); i := 0;
|
||||
IF x >= 10.0E6 THEN x := 0.1*x; INC(e) END ;
|
||||
REPEAT d[i] := CHR(m MOD 10 + 30H); m := m DIV 10; INC(i) UNTIL m = 0;
|
||||
DEC(i); Write(W, d[i]); Write(W, ".");
|
||||
IF i < n-6 THEN n := 0 ELSE n := 13-n END ;
|
||||
WHILE i > n DO DEC(i); Write(W, d[i]) END ;
|
||||
Write(W, "E"); INC(e, 6);
|
||||
IF e < 0 THEN Write(W, "-"); e := -e ELSE Write(W, "+") END ;
|
||||
Write(W, CHR(e DIV 10 + 30H)); Write(W, CHR(e MOD 10 + 30H))
|
||||
END
|
||||
END
|
||||
END WriteReal;
|
||||
*)
|
||||
PROCEDURE WriteRealFix* (VAR W: Writer; x: REAL; n, k: INTEGER);
|
||||
VAR i, m: INTEGER; neg: BOOLEAN;
|
||||
d: ARRAY 12 OF CHAR;
|
||||
BEGIN
|
||||
IF x = 0.0 THEN WriteString(W, " 0")
|
||||
ELSE
|
||||
IF x < 0.0 THEN x := -x; neg := TRUE ELSE neg := FALSE END ;
|
||||
IF k > 7 THEN k := 7 END ;
|
||||
x := Ten(k) * x; m := FLOOR(x + 0.5);
|
||||
i := 0;
|
||||
REPEAT d[i] := CHR(m MOD 10 + 30H); m := m DIV 10; INC(i) UNTIL m = 0;
|
||||
REPEAT Write(W, " "); DEC(n) UNTIL n <= i+3;
|
||||
IF neg THEN Write(W, "-"); DEC(n) ELSE Write(W, " ") END ;
|
||||
WHILE i > k DO DEC(i); Write(W, d[i]) END ;
|
||||
Write(W, ".");
|
||||
WHILE k > i DO DEC(k); Write(W, "0") END ;
|
||||
WHILE i > 0 DO DEC(i); Write(W, d[i]) END
|
||||
END
|
||||
END WriteRealFix;
|
||||
|
||||
PROCEDURE WritePair(VAR W: Writer; ch: CHAR; x: LONGINT);
|
||||
BEGIN Write(W, ch);
|
||||
Write(W, CHR(x DIV 10 + 30H)); Write(W, CHR(x MOD 10 + 30H))
|
||||
END WritePair;
|
||||
|
||||
PROCEDURE WriteClock* (VAR W: Writer; d: LONGINT);
|
||||
BEGIN
|
||||
WritePair(W, " ", d DIV 20000H MOD 20H); (*day*)
|
||||
WritePair(W, ".", d DIV 400000H MOD 10H); (*month*)
|
||||
WritePair(W, ".", d DIV 4000000H MOD 40H); (*year*)
|
||||
WritePair(W, " ", d DIV 1000H MOD 20H); (*hour*)
|
||||
WritePair(W, ":", d DIV 40H MOD 40H); (*min*)
|
||||
WritePair(W, ":", d MOD 40H) (*sec*)
|
||||
END WriteClock;
|
||||
|
||||
BEGIN TrailerFile := Files.New("")
|
||||
END CompatTexts.
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
MODULE Fonts; (*JG 18.11.90; PDR 8.6.12; NW 25.3.2013*)
|
||||
IMPORT SYSTEM, Files := CompatFiles;
|
||||
|
||||
TYPE INTEGER = LONGINT; (* voc adaptation by noch *)
|
||||
BYTE = CHAR;
|
||||
|
||||
CONST FontFileId = 0DBH;
|
||||
|
||||
TYPE Font* = POINTER TO FontDesc;
|
||||
FontDesc* = RECORD
|
||||
name*: ARRAY 32 OF CHAR;
|
||||
height*, minX*, maxX*, minY*, maxY*: INTEGER;
|
||||
next*: Font;
|
||||
T: ARRAY 128 OF INTEGER;
|
||||
raster: ARRAY 2360 OF BYTE
|
||||
END ;
|
||||
|
||||
LargeFontDesc = RECORD (FontDesc) ext: ARRAY 2560 OF BYTE END ;
|
||||
LargeFont = POINTER TO LargeFontDesc;
|
||||
|
||||
(* raster sizes: Syntax8 1367, Syntax10 1628, Syntax12 1688, Syntax14 1843, Syntax14b 1983,
|
||||
Syntax16 2271, Syntax20 3034, Syntac24 4274, Syntax24b 4302 *)
|
||||
|
||||
VAR Default*, root*: Font;
|
||||
|
||||
PROCEDURE GetPat*(fnt: Font; ch: CHAR; VAR dx, x, y, w, h, patadr: INTEGER);
|
||||
VAR pa: INTEGER; dxb, xb, yb, wb, hb: BYTE;
|
||||
BEGIN pa := fnt.T[ORD(ch) MOD 80H]; patadr := pa;
|
||||
SYSTEM.GET(pa-3, dxb); SYSTEM.GET(pa-2, xb); SYSTEM.GET(pa-1, yb); SYSTEM.GET(pa, wb); SYSTEM.GET(pa+1, hb);
|
||||
(*dx := dxb;*)
|
||||
dx := ORD(dxb); (* voc adaptation by noch *)
|
||||
(*x := xb;*)
|
||||
x := ORD(xb); (* voc adaptation by noch *)
|
||||
(*y := yb;*)
|
||||
y := ORD(yb); (* voc adaptation by noch *)
|
||||
(*w := wb;*)
|
||||
w := ORD(wb); (* voc adaptation by noch *)
|
||||
(*h := hb;*)
|
||||
h := ORD(hb); (* voc adaptation by noch *)
|
||||
(*IF yb < 128 THEN y := yb ELSE y := yb - 256 END*)
|
||||
IF ORD(yb) < 128 THEN y := ORD(yb) ELSE y := ORD(yb) - 256 END (* voc adaptation by noch *)
|
||||
END GetPat;
|
||||
|
||||
PROCEDURE This*(name: ARRAY OF CHAR): Font;
|
||||
|
||||
TYPE RunRec = RECORD beg, end: BYTE END ;
|
||||
BoxRec = RECORD dx, x, y, w, h: BYTE END ;
|
||||
|
||||
VAR F: Font; LF: LargeFont;
|
||||
f: Files.File; R: Files.Rider;
|
||||
NofRuns, NofBoxes: BYTE;
|
||||
NofBytes: INTEGER;
|
||||
height, minX, maxX, minY, maxY: BYTE;
|
||||
i, j, k, m, n: INTEGER;
|
||||
a, a0: INTEGER;
|
||||
b, beg, end: BYTE;
|
||||
run: ARRAY 16 OF RunRec;
|
||||
box: ARRAY 512 OF BoxRec;
|
||||
|
||||
PROCEDURE RdInt16(VAR R: Files.Rider; VAR b0: BYTE);
|
||||
VAR b1: BYTE;
|
||||
BEGIN Files.ReadByte(R, b0); Files.ReadByte(R, b1)
|
||||
END RdInt16;
|
||||
|
||||
BEGIN F := root;
|
||||
WHILE (F # NIL) & (name # F.name) DO F := F.next END;
|
||||
IF F = NIL THEN
|
||||
f := Files.Old(name);
|
||||
IF f # NIL THEN
|
||||
Files.Set(R, f, 0); Files.ReadByte(R, b);
|
||||
(*IF b = FontFileId THEN*)
|
||||
IF ORD(b) = FontFileId THEN (* voc adaptation by noch *)
|
||||
Files.ReadByte(R, b); (*abstraction*)
|
||||
Files.ReadByte(R, b); (*family*)
|
||||
Files.ReadByte(R, b); (*variant*)
|
||||
NEW(F);
|
||||
(*F.name := name;*)
|
||||
COPY(name, F.name); (* voc adaptation by noch *)
|
||||
RdInt16(R, height); RdInt16(R, minX); RdInt16(R, maxX); RdInt16(R, minY); RdInt16(R, maxY); RdInt16(R, NofRuns);
|
||||
(*NofBoxes := 0;*) (* voc adaptation by noch *)
|
||||
NofBoxes := 0X;
|
||||
k := 0;
|
||||
(*WHILE k # NofRuns DO*)
|
||||
WHILE k # ORD(NofRuns) DO (* voc adaptation by noch *)
|
||||
RdInt16(R, beg);
|
||||
run[k].beg := beg; RdInt16(R, end);
|
||||
run[k].end := end;
|
||||
(*NofBoxes := NofBoxes + end - beg;*)
|
||||
NofBoxes := CHR(ORD(NofBoxes) + ORD(end) - ORD(beg)); (* voc adaptation by noch *)
|
||||
INC(k)
|
||||
END;
|
||||
NofBytes := 5; j := 0;
|
||||
(*WHILE j # NofBoxes DO*)
|
||||
WHILE j # ORD(NofBoxes) DO (* voc adaptation by noch *)
|
||||
RdInt16(R, box[j].dx); RdInt16(R, box[j].x); RdInt16(R, box[j].y);
|
||||
RdInt16(R, box[j].w); RdInt16(R, box[j].h);
|
||||
(*NofBytes := NofBytes + 5 + (box[j].w + 7) DIV 8 * box[j].h;*)
|
||||
NofBytes := (NofBytes + 5 + (ORD(box[j].w) + 7) DIV 8 * ORD(box[j].h)); (* voc adaptation by noch *)
|
||||
INC(j)
|
||||
END;
|
||||
IF NofBytes < 2300 THEN NEW(F) ELSE NEW(LF); F := LF END ;
|
||||
(*F.name := name;*)
|
||||
COPY(name, F.name); (* voc adaptation by noch *)
|
||||
(*F.height := height; F.minX := minX; F.maxX := maxX; F.maxY := maxY;*)
|
||||
F.height := ORD(height); F.minX := ORD(minX); F.maxX := ORD(maxX); F.maxY := ORD(maxY); (* voc adaptation by noch *)
|
||||
(*IF minY >= 80H THEN F.minY := minY - 100H ELSE F.minY := minY END ;*)
|
||||
IF ORD(minY) >= 80H THEN F.minY := ORD(minY) - 100H ELSE F.minY := ORD(minY) END ; (* voc adaptation by noch *)
|
||||
a0 := SYSTEM.ADR(F.raster);
|
||||
SYSTEM.PUT(a0, 0X); SYSTEM.PUT(a0+1, 0X); SYSTEM.PUT(a0+2, 0X); SYSTEM.PUT(a0+3, 0X); SYSTEM.PUT(a0+4, 0X);
|
||||
(*null pattern for characters not in a run*)
|
||||
INC(a0, 2); a := a0+3; j := 0; k := 0; m := 0;
|
||||
(*WHILE k < NofRuns DO*)
|
||||
WHILE k < ORD(NofRuns) DO
|
||||
(*WHILE (m < run[k].beg) & (m < 128) DO F.T[m] := a0; INC(m) END;*)
|
||||
WHILE (m < ORD(run[k].beg)) & (m < 128) DO F.T[m] := a0; INC(m) END; (* voc adaptation by noch *)
|
||||
(*WHILE (m < run[k].end) & (m < 128) DO*) (* voc adaptation by noch *)
|
||||
WHILE (m < ORD(run[k].end)) & (m < 128) DO
|
||||
F.T[m] := a+3;
|
||||
SYSTEM.PUT(a, box[j].dx); SYSTEM.PUT(a+1, box[j].x); SYSTEM.PUT(a+2, box[j].y);
|
||||
SYSTEM.PUT(a+3, box[j].w); SYSTEM.PUT(a+4, box[j].h); INC(a, 5);
|
||||
(*n := (box[j].w + 7) DIV 8 * box[j].h;*)
|
||||
n := (ORD(box[j].w) + 7) DIV 8 * ORD(box[j].h); (* voc adaptation by noch *)
|
||||
WHILE n # 0 DO DEC(n); Files.ReadByte(R, b); SYSTEM.PUT(a, b); INC(a) END ;
|
||||
INC(j); INC(m)
|
||||
END;
|
||||
INC(k)
|
||||
END;
|
||||
WHILE m < 128 DO F.T[m] := a0; INC(m) END ;
|
||||
F.next := root; root := F
|
||||
ELSE (*bad file id*) F := Default
|
||||
END
|
||||
ELSE (*font file not available*) F := Default
|
||||
END
|
||||
END;
|
||||
RETURN F
|
||||
END This;
|
||||
|
||||
PROCEDURE Free*; (*remove all but first two from font list*)
|
||||
VAR f: Font;
|
||||
BEGIN f := root.next;
|
||||
IF f # NIL THEN f := f.next END ;
|
||||
f.next := NIL
|
||||
END Free;
|
||||
|
||||
BEGIN root := NIL; Default := This("Oberon10.Scn.Fnt")
|
||||
END Fonts.
|
||||
|
|
@ -1,447 +0,0 @@
|
|||
MODULE ORB; (*NW 25.6.2014 in Oberon-07*)
|
||||
IMPORT Files := CompatFiles (* voc adaptation by noch *)
|
||||
, ORS;
|
||||
(*Definition of data types Object and Type, which together form the data structure
|
||||
called "symbol table". Contains procedures for creation of Objects, and for search:
|
||||
NewObj, this, thisimport, thisfield (and OpenScope, CloseScope).
|
||||
Handling of import and export, i.e. reading and writing of "symbol files" is done by procedures
|
||||
Import and Export. This module contains the list of standard identifiers, with which
|
||||
the symbol table (universe), and that of the pseudo-module SYSTEM are initialized. *)
|
||||
|
||||
TYPE INTEGER = LONGINT; (* voc adaptation by noch *)
|
||||
BYTE = CHAR;
|
||||
|
||||
CONST versionkey* = 1; maxTypTab = 64;
|
||||
(* class values*) Head* = 0;
|
||||
Const* = 1; Var* = 2; Par* = 3; Fld* = 4; Typ* = 5;
|
||||
SProc* = 6; SFunc* = 7; Mod* = 8;
|
||||
|
||||
(* form values*)
|
||||
Byte* = 1; Bool* = 2; Char* = 3; Int* = 4; Real* = 5; Set* = 6;
|
||||
Pointer* = 7; NilTyp* = 8; NoTyp* = 9; Proc* = 10;
|
||||
String* = 11; Array* = 12; Record* = 13;
|
||||
|
||||
TYPE Object* = POINTER TO ObjDesc;
|
||||
Module* = POINTER TO ModDesc;
|
||||
Type* = POINTER TO TypeDesc;
|
||||
|
||||
ObjDesc*= RECORD
|
||||
class*, lev*, exno*: INTEGER;
|
||||
expo*, rdo*: BOOLEAN; (*exported / read-only*)
|
||||
next*, dsc*: Object;
|
||||
type*: Type;
|
||||
name*: ORS.Ident;
|
||||
val*: LONGINT
|
||||
END ;
|
||||
|
||||
ModDesc* = RECORD (ObjDesc) orgname*: ORS.Ident END ;
|
||||
|
||||
TypeDesc* = RECORD
|
||||
form*, ref*, mno*: INTEGER; (*ref is only used for import/export*)
|
||||
nofpar*: INTEGER; (*for procedures, extension level for records*)
|
||||
len*: LONGINT; (*for arrays, len < 0 => open array; for records: adr of descriptor*)
|
||||
dsc*, typobj*: Object;
|
||||
base*: Type; (*for arrays, records, pointers*)
|
||||
size*: LONGINT; (*in bytes; always multiple of 4, except for Byte, Bool and Char*)
|
||||
END ;
|
||||
|
||||
(* Object classes and the meaning of "val":
|
||||
class val
|
||||
----------
|
||||
Var address
|
||||
Par address
|
||||
Const value
|
||||
Fld offset
|
||||
Typ type descriptor (TD) address
|
||||
SProc inline code number
|
||||
SFunc inline code number
|
||||
Mod key
|
||||
|
||||
Type forms and the meaning of "dsc" and "base":
|
||||
form dsc base
|
||||
------------------------
|
||||
Pointer - type of dereferenced object
|
||||
Proc params result type
|
||||
Array - type of elements
|
||||
Record fields extension *)
|
||||
|
||||
VAR topScope*, universe, system*: Object;
|
||||
byteType*, boolType*, charType*: Type;
|
||||
intType*, realType*, setType*, nilType*, noType*, strType*: Type;
|
||||
nofmod, Ref: INTEGER;
|
||||
typtab: ARRAY maxTypTab OF Type;
|
||||
|
||||
PROCEDURE NewObj*(VAR obj: Object; id: ORS.Ident; class: INTEGER); (*insert new Object with name id*)
|
||||
VAR new, x: Object;
|
||||
BEGIN x := topScope;
|
||||
WHILE (x.next # NIL) & (x.next.name # id) DO x := x.next END ;
|
||||
IF x.next = NIL THEN
|
||||
NEW(new); new.name := id; new.class := class; new.next := NIL; new.rdo := FALSE; new.dsc := NIL;
|
||||
x.next := new; obj := new
|
||||
ELSE obj := x.next; ORS.Mark("mult def")
|
||||
END
|
||||
END NewObj;
|
||||
|
||||
PROCEDURE thisObj*(): Object;
|
||||
VAR s, x: Object;
|
||||
BEGIN s := topScope;
|
||||
REPEAT x := s.next;
|
||||
WHILE (x # NIL) & (x.name # ORS.id) DO x := x.next END ;
|
||||
s := s.dsc
|
||||
UNTIL (x # NIL) OR (s = NIL);
|
||||
RETURN x
|
||||
END thisObj;
|
||||
|
||||
PROCEDURE thisimport*(mod: Object): Object;
|
||||
VAR obj: Object;
|
||||
BEGIN
|
||||
IF mod.rdo THEN
|
||||
IF mod.name[0] # 0X THEN
|
||||
obj := mod.dsc;
|
||||
WHILE (obj # NIL) & (obj.name # ORS.id) DO obj := obj.next END
|
||||
ELSE obj := NIL
|
||||
END
|
||||
ELSE obj := NIL
|
||||
END ;
|
||||
RETURN obj
|
||||
END thisimport;
|
||||
|
||||
PROCEDURE thisfield*(rec: Type): Object;
|
||||
VAR fld: Object;
|
||||
BEGIN fld := rec.dsc;
|
||||
WHILE (fld # NIL) & (fld.name # ORS.id) DO fld := fld.next END ;
|
||||
RETURN fld
|
||||
END thisfield;
|
||||
|
||||
PROCEDURE OpenScope*;
|
||||
VAR s: Object;
|
||||
BEGIN NEW(s); s.class := Head; s.dsc := topScope; s.next := NIL; topScope := s
|
||||
END OpenScope;
|
||||
|
||||
PROCEDURE CloseScope*;
|
||||
BEGIN topScope := topScope.dsc
|
||||
END CloseScope;
|
||||
|
||||
(*------------------------------- Import ---------------------------------*)
|
||||
|
||||
PROCEDURE MakeFileName*(VAR FName: ORS.Ident; name, ext: ARRAY OF CHAR);
|
||||
VAR i, j: INTEGER;
|
||||
BEGIN i := 0; j := 0; (*assume name suffix less than 4 characters*)
|
||||
WHILE (i < ORS.IdLen-5) & (name[i] > 0X) DO FName[i] := name[i]; INC(i) END ;
|
||||
REPEAT FName[i]:= ext[j]; INC(i); INC(j) UNTIL ext[j] = 0X;
|
||||
FName[i] := 0X
|
||||
END MakeFileName;
|
||||
|
||||
PROCEDURE ThisModule(name, orgname: ORS.Ident; non: BOOLEAN; key: LONGINT): Object;
|
||||
VAR mod: Module; obj, obj1: Object;
|
||||
BEGIN obj1 := topScope; obj := obj1.next; (*search for module*)
|
||||
WHILE (obj # NIL) & (obj.name # name) DO obj1 := obj; obj := obj1.next END ;
|
||||
IF obj = NIL THEN (*insert new module*)
|
||||
NEW(mod); mod.class := Mod; mod.rdo := FALSE;
|
||||
mod.name := name; mod.orgname := orgname; mod.val := key;
|
||||
mod.lev := nofmod; INC(nofmod); mod.type := noType; mod.dsc := NIL; mod.next := NIL;
|
||||
obj1.next := mod; obj := mod
|
||||
ELSE (*module already present*)
|
||||
IF non THEN ORS.Mark("invalid import order") END
|
||||
END ;
|
||||
RETURN obj
|
||||
END ThisModule;
|
||||
|
||||
PROCEDURE Read(VAR R: Files.Rider; VAR x: INTEGER);
|
||||
VAR b: BYTE;
|
||||
BEGIN Files.ReadByte(R, b);
|
||||
(*IF b < 80H THEN x := b ELSE x := b - 100H END*)
|
||||
IF b < 80X THEN x := ORD(b) ELSE x := ORD(b) - 100H END (* voc adaptation by noch *)
|
||||
END Read;
|
||||
|
||||
PROCEDURE InType(VAR R: Files.Rider; thismod: Object; VAR T: Type);
|
||||
VAR key: LONGINT;
|
||||
ref, class, mno, form, np, readonly: INTEGER;
|
||||
new, fld, par, obj, mod, impmod: Object;
|
||||
t: Type;
|
||||
name, modname: ORS.Ident;
|
||||
BEGIN Read(R, ref);
|
||||
IF ref < 0 THEN T := typtab[-ref] (*already read*)
|
||||
ELSE NEW(t); T := t; typtab[ref] := t; t.mno := thismod.lev;
|
||||
Read(R, form); t.form := form;
|
||||
IF form = Pointer THEN InType(R, thismod, t.base); t.size := 4
|
||||
ELSIF form = Array THEN
|
||||
InType(R, thismod, t.base); Files.ReadNum(R, t.len); Files.ReadNum(R, t.size)
|
||||
ELSIF form = Record THEN
|
||||
InType(R, thismod, t.base);
|
||||
IF t.base.form = NoTyp THEN t.base := NIL; obj := NIL ELSE obj := t.base.dsc END ;
|
||||
Files.ReadNum(R, t.len); (*TD adr/exno*)
|
||||
Files.ReadNum(R, t.nofpar); (*ext level*)
|
||||
Files.ReadNum(R, t.size);
|
||||
Read(R, class);
|
||||
WHILE class # 0 DO (*fields*)
|
||||
NEW(fld); fld.class := class; Files.ReadString(R, fld.name);
|
||||
IF fld.name[0] # 0X THEN fld.expo := TRUE; InType(R, thismod, fld.type) ELSE fld.expo := FALSE; fld.type := nilType END ;
|
||||
Files.ReadNum(R, fld.val); fld.next := obj; obj := fld; Read(R, class)
|
||||
END ;
|
||||
t.dsc := obj
|
||||
ELSIF form = Proc THEN
|
||||
InType(R, thismod, t.base);
|
||||
obj := NIL; np := 0; Read(R, class);
|
||||
WHILE class # 0 DO (*parameters*)
|
||||
NEW(par); par.class := class; Read(R, readonly); par.rdo := readonly = 1;
|
||||
InType(R, thismod, par.type); par.next := obj; obj := par; INC(np); Read(R, class)
|
||||
END ;
|
||||
t.dsc := obj; t.nofpar := np; t.size := 4
|
||||
END ;
|
||||
Files.ReadString(R, modname);
|
||||
IF modname[0] # 0X THEN (*re-import*)
|
||||
Files.ReadInt(R, key); Files.ReadString(R, name);
|
||||
mod := ThisModule(modname, modname, FALSE, key);
|
||||
obj := mod.dsc; (*search type*)
|
||||
WHILE (obj # NIL) & (obj.name # name) DO obj := obj.next END ;
|
||||
IF obj # NIL THEN T := obj.type (*type object found in object list of mod*)
|
||||
ELSE (*insert new type object in object list of mod*)
|
||||
NEW(obj); obj.name := name; obj.class := Typ; obj.next := mod.dsc; mod.dsc := obj; obj.type := t;
|
||||
t.mno := mod.lev; t.typobj := obj; T := t
|
||||
END ;
|
||||
typtab[ref] := T
|
||||
END
|
||||
END
|
||||
END InType;
|
||||
|
||||
PROCEDURE Import*(VAR modid, modid1: ORS.Ident);
|
||||
VAR key: LONGINT; class, k: INTEGER;
|
||||
obj: Object; t: Type;
|
||||
thismod: Object;
|
||||
modname, fname: ORS.Ident;
|
||||
F: Files.File; R: Files.Rider;
|
||||
BEGIN
|
||||
IF modid1 = "SYSTEM" THEN
|
||||
thismod := ThisModule(modid, modid1, TRUE, key); DEC(nofmod);
|
||||
thismod.lev := 0; thismod.dsc := system; thismod.rdo := TRUE
|
||||
ELSE MakeFileName(fname, modid1, ".smb"); F := Files.Old(fname);
|
||||
IF F # NIL THEN
|
||||
Files.Set(R, F, 0); Files.ReadInt(R, key); Files.ReadInt(R, key); Files.ReadString(R, modname);
|
||||
thismod := ThisModule(modid, modid1, TRUE, key); thismod.rdo := TRUE;
|
||||
Read(R, class); (*version key*)
|
||||
IF class # versionkey THEN ORS.Mark("wrong version") END ;
|
||||
Read(R, class);
|
||||
WHILE class # 0 DO
|
||||
NEW(obj); obj.class := class; Files.ReadString(R, obj.name);
|
||||
InType(R, thismod, obj.type); obj.lev := -thismod.lev;
|
||||
IF class = Typ THEN
|
||||
t := obj.type; t.typobj := obj; Read(R, k); (*fixup bases of previously declared pointer types*)
|
||||
WHILE k # 0 DO typtab[k].base := t; Read(R, k) END
|
||||
ELSE
|
||||
IF class = Const THEN
|
||||
IF obj.type.form = Real THEN Files.ReadInt(R, obj.val) ELSE Files.ReadNum(R, obj.val) END
|
||||
ELSIF class = Var THEN Files.ReadNum(R, obj.val); obj.rdo := TRUE
|
||||
END
|
||||
END ;
|
||||
obj.next := thismod.dsc; thismod.dsc := obj; Read(R, class)
|
||||
END ;
|
||||
ELSE ORS.Mark("import not available")
|
||||
END
|
||||
END
|
||||
END Import;
|
||||
|
||||
(*-------------------------------- Export ---------------------------------*)
|
||||
|
||||
PROCEDURE Write(VAR R: Files.Rider; x: INTEGER);
|
||||
BEGIN
|
||||
(*Files.WriteByte(R, x)*)
|
||||
Files.WriteByte(R, SHORT(SHORT(x))) (* voc adaptation by noch *)
|
||||
END Write;
|
||||
|
||||
PROCEDURE OutType(VAR R: Files.Rider; t: Type);
|
||||
VAR obj, mod, fld: Object;
|
||||
|
||||
PROCEDURE OutPar(VAR R: Files.Rider; par: Object; n: INTEGER);
|
||||
VAR cl: INTEGER;
|
||||
BEGIN
|
||||
IF n > 0 THEN
|
||||
OutPar(R, par.next, n-1); cl := par.class;
|
||||
Write(R, cl);
|
||||
IF par.rdo THEN Write(R, 1) ELSE Write(R, 0) END ;
|
||||
OutType(R, par.type)
|
||||
END
|
||||
END OutPar;
|
||||
|
||||
PROCEDURE FindHiddenPointers(VAR R: Files.Rider; typ: Type; offset: LONGINT);
|
||||
VAR fld: Object; i, n: LONGINT;
|
||||
BEGIN
|
||||
IF (typ.form = Pointer) OR (typ.form = NilTyp) THEN Write(R, Fld); Write(R, 0); Files.WriteNum(R, offset)
|
||||
ELSIF typ.form = Record THEN fld := typ.dsc;
|
||||
WHILE fld # NIL DO FindHiddenPointers(R, fld.type, fld.val + offset); fld := fld.next END
|
||||
ELSIF typ.form = Array THEN i := 0; n := typ.len;
|
||||
WHILE i < n DO FindHiddenPointers(R, typ.base, typ.base.size * i + offset); INC(i) END
|
||||
END
|
||||
END FindHiddenPointers;
|
||||
|
||||
BEGIN
|
||||
IF t.ref > 0 THEN (*type was already output*) Write(R, -t.ref)
|
||||
ELSE obj := t.typobj;
|
||||
IF obj # NIL THEN Write(R, Ref); t.ref := Ref; INC(Ref) ELSE (*anonymous*) Write(R, 0) END ;
|
||||
Write(R, t.form);
|
||||
IF t.form = Pointer THEN OutType(R, t.base)
|
||||
ELSIF t.form = Array THEN OutType(R, t.base); Files.WriteNum(R, t.len); Files.WriteNum(R, t.size)
|
||||
ELSIF t.form = Record THEN
|
||||
IF t.base # NIL THEN OutType(R, t.base) ELSE OutType(R, noType) END ;
|
||||
IF obj # NIL THEN Files.WriteNum(R, obj.exno) ELSE Write(R, 0) END ;
|
||||
Files.WriteNum(R, t.nofpar); Files.WriteNum(R, t.size);
|
||||
fld := t.dsc;
|
||||
WHILE fld # NIL DO (*fields*)
|
||||
IF fld.expo THEN
|
||||
Write(R, Fld); Files.WriteString(R, fld.name); OutType(R, fld.type); Files.WriteNum(R, fld.val)
|
||||
ELSE FindHiddenPointers(R, fld.type, fld.val) (*offset*)
|
||||
END ;
|
||||
fld := fld.next
|
||||
END ;
|
||||
Write(R, 0)
|
||||
ELSIF t.form = Proc THEN OutType(R, t.base); OutPar(R, t.dsc, t.nofpar); Write(R, 0)
|
||||
END ;
|
||||
IF (t.mno > 0) & (obj # NIL) THEN (*re-export, output name*)
|
||||
mod := topScope.next;
|
||||
WHILE (mod # NIL) & (mod.lev # t.mno) DO mod := mod.next END ;
|
||||
IF mod # NIL THEN Files.WriteString(R, mod.name); Files.WriteInt(R, mod.val); Files.WriteString(R, obj.name)
|
||||
ELSE ORS.Mark("re-export not found"); Write(R, 0)
|
||||
END
|
||||
ELSE Write(R, 0)
|
||||
END
|
||||
END
|
||||
END OutType;
|
||||
|
||||
PROCEDURE Export*(VAR modid: ORS.Ident; VAR newSF: BOOLEAN; VAR key: LONGINT);
|
||||
VAR x, sum, oldkey: LONGINT;
|
||||
obj, obj0: Object;
|
||||
filename: ORS.Ident;
|
||||
F, F1: Files.File; R, R1: Files.Rider;
|
||||
BEGIN Ref := Record + 1; MakeFileName(filename, modid, ".smb");
|
||||
F := Files.New(filename); Files.Set(R, F, 0);
|
||||
Files.WriteInt(R, 0); (*placeholder*)
|
||||
Files.WriteInt(R, 0); (*placeholder for key to be inserted at the end*)
|
||||
Files.WriteString(R, modid); Write(R, versionkey);
|
||||
obj := topScope.next;
|
||||
WHILE obj # NIL DO
|
||||
IF obj.expo THEN
|
||||
Write(R, obj.class); Files.WriteString(R, obj.name);
|
||||
OutType(R, obj.type);
|
||||
IF obj.class = Typ THEN
|
||||
IF obj.type.form = Record THEN
|
||||
obj0 := topScope.next; (*check whether this is base of previously declared pointer types*)
|
||||
WHILE obj0 # obj DO
|
||||
IF (obj0.type.form = Pointer) & (obj0.type.base = obj.type) & (obj0.type.ref > 0) THEN Write(R, obj0.type.ref) END ;
|
||||
obj0 := obj0.next
|
||||
END
|
||||
END ;
|
||||
Write(R, 0)
|
||||
ELSIF obj.class = Const THEN
|
||||
IF obj.type.form = Proc THEN Files.WriteNum(R, obj.exno)
|
||||
ELSIF obj.type.form = Real THEN Files.WriteInt(R, obj.val)
|
||||
ELSE Files.WriteNum(R, obj.val)
|
||||
END
|
||||
ELSIF obj.class = Var THEN
|
||||
Files.WriteNum(R, obj.exno);
|
||||
IF obj.type.form = String THEN
|
||||
Files.WriteNum(R, obj.val DIV 10000H); obj.val := obj.val MOD 10000H
|
||||
END
|
||||
END
|
||||
END ;
|
||||
obj := obj.next
|
||||
END ;
|
||||
REPEAT Write(R, 0) UNTIL Files.Length(F) MOD 4 = 0;
|
||||
FOR Ref := Record+1 TO maxTypTab-1 DO typtab[Ref] := NIL END ;
|
||||
Files.Set(R, F, 0); sum := 0; Files.ReadInt(R, x); (* compute key (checksum) *)
|
||||
WHILE ~R.eof DO sum := sum + x; Files.ReadInt(R, x) END ;
|
||||
F1 := Files.Old(filename); (*sum is new key*)
|
||||
IF F1 # NIL THEN Files.Set(R1, F1, 4); Files.ReadInt(R1, oldkey) ELSE oldkey := sum+1 END ;
|
||||
IF sum # oldkey THEN
|
||||
IF newSF OR (F1 = NIL) THEN
|
||||
key := sum; newSF := TRUE; Files.Set(R, F, 4); Files.WriteInt(R, sum); Files.Register(F) (*insert checksum*)
|
||||
ELSE ORS.Mark("new symbol file inhibited")
|
||||
END
|
||||
ELSE newSF := FALSE; key := sum
|
||||
END
|
||||
END Export;
|
||||
|
||||
PROCEDURE Init*;
|
||||
BEGIN topScope := universe; nofmod := 1
|
||||
END Init;
|
||||
|
||||
PROCEDURE type(ref, form: INTEGER; size: LONGINT): Type;
|
||||
VAR tp: Type;
|
||||
BEGIN NEW(tp); tp.form := form; tp.size := size; tp.ref := ref; tp.base := NIL;
|
||||
typtab[ref] := tp; RETURN tp
|
||||
END type;
|
||||
|
||||
PROCEDURE enter(name: ARRAY OF CHAR; cl: INTEGER; type: Type; n: LONGINT);
|
||||
VAR obj: Object;
|
||||
BEGIN
|
||||
NEW(obj);
|
||||
(*obj.name := name; *)
|
||||
COPY(name, obj.name); (* voc adaptation by noch *)
|
||||
obj.class := cl;
|
||||
obj.type := type;
|
||||
obj.val := n;
|
||||
obj.dsc := NIL;
|
||||
IF cl = Typ THEN type.typobj := obj END ;
|
||||
obj.next := system; system := obj
|
||||
END enter;
|
||||
|
||||
BEGIN
|
||||
byteType := type(Byte, Int, 1);
|
||||
boolType := type(Bool, Bool, 1);
|
||||
charType := type(Char, Char,1);
|
||||
intType := type(Int, Int, 4);
|
||||
realType := type(Real, Real, 4);
|
||||
setType := type(Set, Set,4);
|
||||
nilType := type(NilTyp, NilTyp, 4);
|
||||
noType := type(NoTyp, NoTyp, 4);
|
||||
strType := type(String, String, 8);
|
||||
|
||||
(*initialize universe with data types and in-line procedures;
|
||||
LONGINT is synonym to INTEGER, LONGREAL to REAL.
|
||||
LED, ADC, SBC; LDPSR, LDREG, REG, COND are not in language definition*)
|
||||
system := NIL; (*n = procno*10 + nofpar*)
|
||||
enter("UML", SFunc, intType, 132); (*functions*)
|
||||
enter("SBC", SFunc, intType, 122);
|
||||
enter("ADC", SFunc, intType, 112);
|
||||
enter("ROR", SFunc, intType, 92);
|
||||
enter("ASR", SFunc, intType, 82);
|
||||
enter("LSL", SFunc, intType, 72);
|
||||
enter("LEN", SFunc, intType, 61);
|
||||
enter("CHR", SFunc, charType, 51);
|
||||
enter("ORD", SFunc, intType, 41);
|
||||
enter("FLT", SFunc, realType, 31);
|
||||
enter("FLOOR", SFunc, intType, 21);
|
||||
enter("ODD", SFunc, boolType, 11);
|
||||
enter("ABS", SFunc, intType, 1);
|
||||
enter("LED", SProc, noType, 81); (*procedures*)
|
||||
enter("UNPK", SProc, noType, 72);
|
||||
enter("PACK", SProc, noType, 62);
|
||||
enter("NEW", SProc, noType, 51);
|
||||
enter("ASSERT", SProc, noType, 41);
|
||||
enter("EXCL", SProc, noType, 32);
|
||||
enter("INCL", SProc, noType, 22);
|
||||
enter("DEC", SProc, noType, 11);
|
||||
enter("INC", SProc, noType, 1);
|
||||
enter("SET", Typ, setType, 0); (*types*)
|
||||
enter("BOOLEAN", Typ, boolType, 0);
|
||||
enter("BYTE", Typ, byteType, 0);
|
||||
enter("CHAR", Typ, charType, 0);
|
||||
enter("LONGREAL", Typ, realType, 0);
|
||||
enter("REAL", Typ, realType, 0);
|
||||
enter("LONGINT", Typ, intType, 0);
|
||||
enter("INTEGER", Typ, intType, 0);
|
||||
topScope := NIL; OpenScope; topScope.next := system; universe := topScope;
|
||||
|
||||
system := NIL; (* initialize "unsafe" pseudo-module SYSTEM*)
|
||||
enter("H", SFunc, intType, 201); (*functions*)
|
||||
enter("COND", SFunc, boolType, 191);
|
||||
enter("SIZE", SFunc, intType, 181);
|
||||
enter("ADR", SFunc, intType, 171);
|
||||
enter("VAL", SFunc, intType, 162);
|
||||
enter("REG", SFunc, intType, 151);
|
||||
enter("BIT", SFunc, boolType, 142);
|
||||
enter("LDREG", SProc, noType, 142); (*procedures*)
|
||||
enter("LDPSR", SProc, noType, 131);
|
||||
enter("COPY", SProc, noType, 123);
|
||||
enter("PUT", SProc, noType, 112);
|
||||
enter("GET", SProc, noType, 102);
|
||||
END ORB.
|
||||
1134
src/voc07R/ORG.Mod
1134
src/voc07R/ORG.Mod
File diff suppressed because it is too large
Load diff
|
|
@ -1,997 +0,0 @@
|
|||
MODULE ORP; (*N. Wirth 1.7.97 / 7.6.2014 Oberon compiler for RISC in Oberon-07*)
|
||||
IMPORT Texts := CompatTexts, Oberon, ORS, ORB, ORG;
|
||||
(*Author: Niklaus Wirth, 2014.
|
||||
Parser of Oberon-RISC compiler. Uses Scanner ORS to obtain symbols (tokens),
|
||||
ORB for definition of data structures and for handling import and export, and
|
||||
ORG to produce binary code. ORP performs type checking and data allocation.
|
||||
Parser is target-independent, except for part of the handling of allocations.*)
|
||||
|
||||
TYPE INTEGER = LONGINT; (* voc adaptation by noch *)
|
||||
|
||||
TYPE PtrBase = POINTER TO PtrBaseDesc;
|
||||
PtrBaseDesc = RECORD (*list of names of pointer base types*)
|
||||
name: ORS.Ident; type: ORB.Type; next: PtrBase
|
||||
END ;
|
||||
|
||||
VAR sym: INTEGER; (*last symbol read*)
|
||||
dc: LONGINT; (*data counter*)
|
||||
level, exno, version: INTEGER;
|
||||
newSF: BOOLEAN; (*option flag*)
|
||||
expression: PROCEDURE (VAR x: ORG.Item); (*to avoid forward reference*)
|
||||
Type: PROCEDURE (VAR type: ORB.Type);
|
||||
FormalType: PROCEDURE (VAR typ: ORB.Type; dim: INTEGER);
|
||||
modid: ORS.Ident;
|
||||
pbsList: PtrBase; (*list of names of pointer base types*)
|
||||
dummy: ORB.Object;
|
||||
W: Texts.Writer;
|
||||
|
||||
PROCEDURE Check(s: INTEGER; msg: ARRAY OF CHAR);
|
||||
BEGIN
|
||||
IF sym = s THEN ORS.Get(sym) ELSE ORS.Mark(msg) END
|
||||
END Check;
|
||||
|
||||
PROCEDURE qualident(VAR obj: ORB.Object);
|
||||
BEGIN obj := ORB.thisObj(); ORS.Get(sym);
|
||||
IF obj = NIL THEN ORS.Mark("undef"); obj := dummy END ;
|
||||
IF (sym = ORS.period) & (obj.class = ORB.Mod) THEN
|
||||
ORS.Get(sym);
|
||||
IF sym = ORS.ident THEN obj := ORB.thisimport(obj); ORS.Get(sym);
|
||||
IF obj = NIL THEN ORS.Mark("undef"); obj := dummy END
|
||||
ELSE ORS.Mark("identifier expected"); obj := dummy
|
||||
END
|
||||
END
|
||||
END qualident;
|
||||
|
||||
PROCEDURE CheckBool(VAR x: ORG.Item);
|
||||
BEGIN
|
||||
IF x.type.form # ORB.Bool THEN ORS.Mark("not Boolean"); x.type := ORB.boolType END
|
||||
END CheckBool;
|
||||
|
||||
PROCEDURE CheckInt(VAR x: ORG.Item);
|
||||
BEGIN
|
||||
IF x.type.form # ORB.Int THEN ORS.Mark("not Integer"); x.type := ORB.intType END
|
||||
END CheckInt;
|
||||
|
||||
PROCEDURE CheckReal(VAR x: ORG.Item);
|
||||
BEGIN
|
||||
IF x.type.form # ORB.Real THEN ORS.Mark("not Real"); x.type := ORB.realType END
|
||||
END CheckReal;
|
||||
|
||||
PROCEDURE CheckSet(VAR x: ORG.Item);
|
||||
BEGIN
|
||||
IF x.type.form # ORB.Set THEN ORS.Mark("not Set"); x.type := ORB.setType END
|
||||
END CheckSet;
|
||||
|
||||
PROCEDURE CheckSetVal(VAR x: ORG.Item);
|
||||
BEGIN
|
||||
IF x.type.form # ORB.Int THEN ORS.Mark("not Int"); x.type := ORB.setType
|
||||
ELSIF x.mode = ORB.Const THEN
|
||||
IF (x.a < 0) OR (x.a >= 32) THEN ORS.Mark("invalid set") END
|
||||
END
|
||||
END CheckSetVal;
|
||||
|
||||
PROCEDURE CheckConst(VAR x: ORG.Item);
|
||||
BEGIN
|
||||
IF x.mode # ORB.Const THEN ORS.Mark("not a constant"); x.mode := ORB.Const END
|
||||
END CheckConst;
|
||||
|
||||
PROCEDURE CheckReadOnly(VAR x: ORG.Item);
|
||||
BEGIN
|
||||
IF x.rdo THEN ORS.Mark("read-only") END
|
||||
END CheckReadOnly;
|
||||
|
||||
PROCEDURE CheckExport(VAR expo: BOOLEAN);
|
||||
BEGIN
|
||||
IF sym = ORS.times THEN
|
||||
expo := TRUE; ORS.Get(sym);
|
||||
IF level # 0 THEN ORS.Mark("remove asterisk") END
|
||||
ELSE expo := FALSE
|
||||
END
|
||||
END CheckExport;
|
||||
|
||||
PROCEDURE IsExtension(t0, t1: ORB.Type): BOOLEAN;
|
||||
BEGIN (*t1 is an extension of t0*)
|
||||
RETURN (t0 = t1) OR (t1 # NIL) & IsExtension(t0, t1.base)
|
||||
END IsExtension;
|
||||
|
||||
(* expressions *)
|
||||
|
||||
PROCEDURE TypeTest(VAR x: ORG.Item; T: ORB.Type; guard: BOOLEAN);
|
||||
VAR xt: ORB.Type;
|
||||
BEGIN xt := x.type;
|
||||
WHILE (xt # T) & (xt # NIL) DO xt := xt.base END ;
|
||||
IF xt # T THEN xt := x.type;
|
||||
IF (xt.form = ORB.Pointer) & (T.form = ORB.Pointer) THEN
|
||||
IF IsExtension(xt.base, T.base) THEN ORG.TypeTest(x, T.base, FALSE, guard); x.type := T
|
||||
ELSE ORS.Mark("not an extension")
|
||||
END
|
||||
ELSIF (xt.form = ORB.Record) & (T.form = ORB.Record) & (x.mode = ORB.Par) THEN
|
||||
IF IsExtension(xt, T) THEN ORG.TypeTest(x, T, TRUE, guard); x.type := T
|
||||
ELSE ORS.Mark("not an extension")
|
||||
END
|
||||
ELSE ORS.Mark("incompatible types")
|
||||
END
|
||||
ELSIF ~guard THEN ORG.MakeConstItem(x, ORB.boolType, 1)
|
||||
END ;
|
||||
IF ~guard THEN x.type := ORB.boolType END
|
||||
END TypeTest;
|
||||
|
||||
PROCEDURE selector(VAR x: ORG.Item);
|
||||
VAR y: ORG.Item; obj: ORB.Object;
|
||||
BEGIN
|
||||
WHILE (sym = ORS.lbrak) OR (sym = ORS.period) OR (sym = ORS.arrow)
|
||||
OR (sym = ORS.lparen) & (x.type.form IN {ORB.Record, ORB.Pointer}) DO
|
||||
IF sym = ORS.lbrak THEN
|
||||
REPEAT ORS.Get(sym); expression(y);
|
||||
IF x.type.form = ORB.Array THEN
|
||||
CheckInt(y); ORG.Index(x, y); x.type := x.type.base
|
||||
ELSE ORS.Mark("not an array")
|
||||
END
|
||||
UNTIL sym # ORS.comma;
|
||||
Check(ORS.rbrak, "no ]")
|
||||
ELSIF sym = ORS.period THEN ORS.Get(sym);
|
||||
IF sym = ORS.ident THEN
|
||||
IF x.type.form = ORB.Pointer THEN ORG.DeRef(x); x.type := x.type.base END ;
|
||||
IF x.type.form = ORB.Record THEN
|
||||
obj := ORB.thisfield(x.type); ORS.Get(sym);
|
||||
IF obj # NIL THEN ORG.Field(x, obj); x.type := obj.type
|
||||
ELSE ORS.Mark("undef")
|
||||
END
|
||||
ELSE ORS.Mark("not a record")
|
||||
END
|
||||
ELSE ORS.Mark("ident?")
|
||||
END
|
||||
ELSIF sym = ORS.arrow THEN
|
||||
ORS.Get(sym);
|
||||
IF x.type.form = ORB.Pointer THEN ORG.DeRef(x); x.type := x.type.base
|
||||
ELSE ORS.Mark("not a pointer")
|
||||
END
|
||||
ELSIF (sym = ORS.lparen) & (x.type.form IN {ORB.Record, ORB.Pointer}) THEN (*type guard*)
|
||||
ORS.Get(sym);
|
||||
IF sym = ORS.ident THEN
|
||||
qualident(obj);
|
||||
IF obj.class = ORB.Typ THEN TypeTest(x, obj.type, TRUE)
|
||||
ELSE ORS.Mark("guard type expected")
|
||||
END
|
||||
ELSE ORS.Mark("not an identifier")
|
||||
END ;
|
||||
Check(ORS.rparen, " ) missing")
|
||||
END
|
||||
END
|
||||
END selector;
|
||||
|
||||
PROCEDURE CompTypes(t0, t1: ORB.Type; varpar: BOOLEAN): BOOLEAN;
|
||||
|
||||
PROCEDURE EqualSignatures(t0, t1: ORB.Type): BOOLEAN;
|
||||
VAR p0, p1: ORB.Object; com: BOOLEAN;
|
||||
BEGIN com := TRUE;
|
||||
IF (t0.base = t1.base) & (t0.nofpar = t1.nofpar) THEN
|
||||
p0 := t0.dsc; p1 := t1.dsc;
|
||||
WHILE p0 # NIL DO
|
||||
IF (p0.class = p1.class) & CompTypes(p0.type, p1.type, TRUE) &
|
||||
(*(ORD(p0.rdo) = ORD(p1.rdo))*)
|
||||
(p0.rdo = p1.rdo) (* voc adaptation by noch *)
|
||||
THEN
|
||||
IF p0.type.form >= ORB.Array THEN com := CompTypes(p0.type, p1.type, (p0.class = ORB.Par)) END ;
|
||||
p0 := p0.next; p1 := p1.next
|
||||
ELSE p0 := NIL; com := FALSE
|
||||
END
|
||||
END
|
||||
ELSE com := FALSE
|
||||
END ;
|
||||
RETURN com
|
||||
END EqualSignatures;
|
||||
|
||||
BEGIN (*Compatible Types*)
|
||||
RETURN (t0 = t1)
|
||||
OR (t0.form = ORB.Array) & (t1.form = ORB.Array) & CompTypes(t0.base, t1.base, varpar)
|
||||
OR (t0.form = ORB.Pointer) & (t1.form = ORB.Pointer) & IsExtension(t0.base, t1.base)
|
||||
OR (t0.form = ORB.Record) & (t1.form = ORB.Record) & IsExtension(t0, t1)
|
||||
OR (t0.form = ORB.Proc) & (t1.form = ORB.Proc) & EqualSignatures(t0, t1)
|
||||
OR (t0.form IN {ORB.Pointer, ORB.Proc}) & (t1.form = ORB.NilTyp)
|
||||
OR (t0.form = ORB.NilTyp) & (t1.form IN {ORB.Pointer, ORB.Proc})
|
||||
OR ~varpar & (t0.form = ORB.Int) & (t1.form = ORB.Int)
|
||||
END CompTypes;
|
||||
|
||||
PROCEDURE Parameter(par: ORB.Object);
|
||||
VAR x: ORG.Item; varpar: BOOLEAN;
|
||||
BEGIN expression(x);
|
||||
IF par # NIL THEN
|
||||
varpar := par.class = ORB.Par;
|
||||
IF CompTypes(par.type, x.type, varpar) THEN
|
||||
IF ~varpar THEN ORG.ValueParam(x)
|
||||
ELSE (*par.class = Par*)
|
||||
IF ~par.rdo THEN CheckReadOnly(x) END ;
|
||||
ORG.VarParam(x, par.type)
|
||||
END
|
||||
ELSIF ~varpar & (par.type.form = ORB.Int) & (x.type.form = ORB.Int) THEN
|
||||
ORG.ValueParam(x)
|
||||
ELSIF (x.type.form = ORB.String) & (x.b = 2) & (par.class = ORB.Var) & (par.type.form = ORB.Char) THEN
|
||||
ORG.StrToChar(x); ORG.ValueParam(x)
|
||||
ELSIF (x.type.form = ORB.Array) & (par.type.form = ORB.Array) &
|
||||
(x.type.base.form = par.type.base.form) & (par.type.len < 0) THEN
|
||||
ORG.OpenArrayParam(x);
|
||||
ELSIF (x.type.form = ORB.String) & varpar & par.rdo & (par.type.form = ORB.Array) &
|
||||
(par.type.base.form = ORB.Char) & (par.type.len < 0) THEN ORG.StringParam(x)
|
||||
ELSIF (par.type.form = ORB.Array) & (par.type.base.form = ORB.Int) & (par.type.size = x.type.size) THEN
|
||||
ORG.VarParam(x, par.type)
|
||||
ELSE ORS.Mark("incompatible parameters")
|
||||
END
|
||||
END
|
||||
END Parameter;
|
||||
|
||||
PROCEDURE ParamList(VAR x: ORG.Item);
|
||||
VAR n: INTEGER; par: ORB.Object;
|
||||
BEGIN par := x.type.dsc; n := 0;
|
||||
IF sym # ORS.rparen THEN
|
||||
Parameter(par); n := 1;
|
||||
WHILE sym <= ORS.comma DO
|
||||
Check(sym, "comma?");
|
||||
IF par # NIL THEN par := par.next END ;
|
||||
INC(n); Parameter(par)
|
||||
END ;
|
||||
Check(ORS.rparen, ") missing")
|
||||
ELSE ORS.Get(sym);
|
||||
END ;
|
||||
IF n < x.type.nofpar THEN ORS.Mark("too few params")
|
||||
ELSIF n > x.type.nofpar THEN ORS.Mark("too many params")
|
||||
END
|
||||
END ParamList;
|
||||
|
||||
PROCEDURE StandFunc(VAR x: ORG.Item; fct: LONGINT; restyp: ORB.Type);
|
||||
VAR y: ORG.Item; n, npar: LONGINT;
|
||||
BEGIN Check(ORS.lparen, "no (");
|
||||
npar := fct MOD 10; fct := fct DIV 10; expression(x); n := 1;
|
||||
WHILE sym = ORS.comma DO ORS.Get(sym); expression(y); INC(n) END ;
|
||||
Check(ORS.rparen, "no )");
|
||||
IF n = npar THEN
|
||||
IF fct = 0 THEN (*ABS*)
|
||||
IF x.type.form IN {ORB.Int, ORB.Real} THEN ORG.Abs(x); restyp := x.type ELSE ORS.Mark("bad type") END
|
||||
ELSIF fct = 1 THEN (*ODD*) CheckInt(x); ORG.Odd(x)
|
||||
ELSIF fct = 2 THEN (*FLOOR*) CheckReal(x); ORG.Floor(x)
|
||||
ELSIF fct = 3 THEN (*FLT*) CheckInt(x); ORG.Float(x)
|
||||
ELSIF fct = 4 THEN (*ORD*)
|
||||
IF x.type.form <= ORB.Proc THEN ORG.Ord(x)
|
||||
ELSIF (x.type.form = ORB.String) & (x.b = 2) THEN ORG.StrToChar(x)
|
||||
ELSE ORS.Mark("bad type")
|
||||
END
|
||||
ELSIF fct = 5 THEN (*CHR*) CheckInt(x); ORG.Ord(x)
|
||||
ELSIF fct = 6 THEN (*LEN*)
|
||||
IF x.type.form = ORB.Array THEN ORG.Len(x) ELSE ORS.Mark("not an array") END
|
||||
ELSIF fct IN {7, 8, 9} THEN (*LSL, ASR, ROR*) CheckInt(y);
|
||||
IF x.type.form IN {ORB.Int, ORB.Set} THEN ORG.Shift(fct-7, x, y); restyp := x.type ELSE ORS.Mark("bad type") END
|
||||
ELSIF fct = 11 THEN (*ADC*) ORG.ADC(x, y)
|
||||
ELSIF fct = 12 THEN (*SBC*) ORG.SBC(x, y)
|
||||
ELSIF fct = 13 THEN (*UML*) ORG.UML(x, y)
|
||||
ELSIF fct = 14 THEN (*BIT*) CheckInt(x); CheckInt(y); ORG.Bit(x, y)
|
||||
ELSIF fct = 15 THEN (*REG*) CheckConst(x); CheckInt(x); ORG.Register(x)
|
||||
ELSIF fct = 16 THEN (*VAL*)
|
||||
IF (x.mode= ORB.Typ) & (x.type.size <= y.type.size) THEN restyp := x.type; x := y
|
||||
ELSE ORS.Mark("casting not allowed")
|
||||
END
|
||||
ELSIF fct = 17 THEN (*ADR*) ORG.Adr(x)
|
||||
ELSIF fct = 18 THEN (*SIZE*)
|
||||
IF x.mode = ORB.Typ THEN ORG.MakeConstItem(x, ORB.intType, x.type.size)
|
||||
ELSE ORS.Mark("must be a type")
|
||||
END
|
||||
ELSIF fct = 19 THEN (*COND*) CheckConst(x); CheckInt(x); ORG.Condition(x)
|
||||
ELSIF fct = 20 THEN (*H*) CheckConst(x); CheckInt(x); ORG.H(x)
|
||||
END ;
|
||||
x.type := restyp
|
||||
ELSE ORS.Mark("wrong nof params")
|
||||
END
|
||||
END StandFunc;
|
||||
|
||||
PROCEDURE element(VAR x: ORG.Item);
|
||||
VAR y: ORG.Item;
|
||||
BEGIN expression(x); CheckSetVal(x);
|
||||
IF sym = ORS.upto THEN ORS.Get(sym); expression(y); CheckSetVal(y); ORG.Set(x, y)
|
||||
ELSE ORG.Singleton(x)
|
||||
END ;
|
||||
x.type := ORB.setType
|
||||
END element;
|
||||
|
||||
PROCEDURE set(VAR x: ORG.Item);
|
||||
VAR y: ORG.Item;
|
||||
BEGIN
|
||||
IF sym >= ORS.if THEN
|
||||
IF sym # ORS.rbrace THEN ORS.Mark(" } missing") END ;
|
||||
ORG.MakeConstItem(x, ORB.setType, 0) (*empty set*)
|
||||
ELSE element(x);
|
||||
WHILE (sym < ORS.rparen) OR (sym > ORS.rbrace) DO
|
||||
IF sym = ORS.comma THEN ORS.Get(sym)
|
||||
ELSIF sym # ORS.rbrace THEN ORS.Mark("missing comma")
|
||||
END ;
|
||||
element(y); ORG.SetOp(ORS.plus, x, y)
|
||||
END
|
||||
END
|
||||
END set;
|
||||
|
||||
PROCEDURE factor(VAR x: ORG.Item);
|
||||
VAR obj: ORB.Object; rx: LONGINT;
|
||||
BEGIN (*sync*)
|
||||
IF (sym < ORS.char) OR (sym > ORS.ident) THEN ORS.Mark("expression expected");
|
||||
REPEAT ORS.Get(sym) UNTIL (sym >= ORS.char) & (sym <= ORS.ident)
|
||||
END ;
|
||||
IF sym = ORS.ident THEN
|
||||
qualident(obj);
|
||||
IF obj.class = ORB.SFunc THEN StandFunc(x, obj.val, obj.type)
|
||||
ELSE ORG.MakeItem(x, obj, level); selector(x);
|
||||
IF sym = ORS.lparen THEN
|
||||
ORS.Get(sym);
|
||||
IF (x.type.form = ORB.Proc) & (x.type.base.form # ORB.NoTyp) THEN
|
||||
ORG.PrepCall(x, rx); ParamList(x); ORG.Call(x, rx); x.type := x.type.base
|
||||
ELSE ORS.Mark("not a function"); ParamList(x)
|
||||
END
|
||||
END
|
||||
END
|
||||
ELSIF sym = ORS.int THEN ORG.MakeConstItem(x, ORB.intType, ORS.ival); ORS.Get(sym)
|
||||
ELSIF sym = ORS.real THEN ORG.MakeRealItem(x, ORS.rval); ORS.Get(sym)
|
||||
ELSIF sym = ORS.char THEN ORG.MakeConstItem(x, ORB.charType, ORS.ival); ORS.Get(sym)
|
||||
ELSIF sym = ORS.nil THEN ORS.Get(sym); ORG.MakeConstItem(x, ORB.nilType, 0)
|
||||
ELSIF sym = ORS.string THEN ORG.MakeStringItem(x, ORS.slen); ORS.Get(sym)
|
||||
ELSIF sym = ORS.lparen THEN ORS.Get(sym); expression(x); Check(ORS.rparen, "no )")
|
||||
ELSIF sym = ORS.lbrace THEN ORS.Get(sym); set(x); Check(ORS.rbrace, "no }")
|
||||
ELSIF sym = ORS.not THEN ORS.Get(sym); factor(x); CheckBool(x); ORG.Not(x)
|
||||
ELSIF sym = ORS.false THEN ORS.Get(sym); ORG.MakeConstItem(x, ORB.boolType, 0)
|
||||
ELSIF sym = ORS.true THEN ORS.Get(sym); ORG.MakeConstItem(x, ORB.boolType, 1)
|
||||
ELSE ORS.Mark("not a factor"); ORG.MakeItem(x, NIL, level)
|
||||
END
|
||||
END factor;
|
||||
|
||||
PROCEDURE term(VAR x: ORG.Item);
|
||||
VAR y: ORG.Item; op, f: INTEGER;
|
||||
BEGIN factor(x); f := x.type.form;
|
||||
WHILE (sym >= ORS.times) & (sym <= ORS.and) DO
|
||||
op := sym; ORS.Get(sym);
|
||||
IF op = ORS.times THEN
|
||||
IF f = ORB.Int THEN factor(y); CheckInt(y); ORG.MulOp(x, y)
|
||||
ELSIF f = ORB.Real THEN factor(y); CheckReal(y); ORG.RealOp(op, x, y)
|
||||
ELSIF f = ORB.Set THEN factor(y); CheckSet(y); ORG.SetOp(op, x, y)
|
||||
ELSE ORS.Mark("bad type")
|
||||
END
|
||||
ELSIF (op = ORS.div) OR (op = ORS.mod) THEN
|
||||
CheckInt(x); factor(y); CheckInt(y); ORG.DivOp(op, x, y)
|
||||
ELSIF op = ORS.rdiv THEN
|
||||
IF f = ORB.Real THEN factor(y); CheckReal(y); ORG.RealOp(op, x, y)
|
||||
ELSIF f = ORB.Set THEN factor(y); CheckSet(y); ORG.SetOp(op, x, y)
|
||||
ELSE ORS.Mark("bad type")
|
||||
END
|
||||
ELSE (*op = and*) CheckBool(x); ORG.And1(x); factor(y); CheckBool(y); ORG.And2(x, y)
|
||||
END
|
||||
END
|
||||
END term;
|
||||
|
||||
PROCEDURE SimpleExpression(VAR x: ORG.Item);
|
||||
VAR y: ORG.Item; op: INTEGER;
|
||||
BEGIN
|
||||
IF sym = ORS.minus THEN ORS.Get(sym); term(x);
|
||||
IF x.type.form IN {ORB.Int, ORB.Real, ORB.Set} THEN ORG.Neg(x) ELSE CheckInt(x) END
|
||||
ELSIF sym = ORS.plus THEN ORS.Get(sym); term(x);
|
||||
ELSE term(x)
|
||||
END ;
|
||||
WHILE (sym >= ORS.plus) & (sym <= ORS.or) DO
|
||||
op := sym; ORS.Get(sym);
|
||||
IF op = ORS.or THEN ORG.Or1(x); CheckBool(x); term(y); CheckBool(y); ORG.Or2(x, y)
|
||||
ELSIF x.type.form = ORB.Int THEN term(y); CheckInt(y); ORG.AddOp(op, x, y)
|
||||
ELSIF x.type.form = ORB.Real THEN term(y); CheckReal(y); ORG.RealOp(op, x, y)
|
||||
ELSE CheckSet(x); term(y); CheckSet(y); ORG.SetOp(op, x, y)
|
||||
END
|
||||
END
|
||||
END SimpleExpression;
|
||||
|
||||
PROCEDURE expression0(VAR x: ORG.Item);
|
||||
VAR y: ORG.Item; obj: ORB.Object; rel, xf, yf: INTEGER;
|
||||
BEGIN SimpleExpression(x);
|
||||
IF (sym >= ORS.eql) & (sym <= ORS.geq) THEN
|
||||
rel := sym; ORS.Get(sym); SimpleExpression(y); xf := x.type.form; yf := y.type.form;
|
||||
IF CompTypes(x.type, y.type, FALSE) OR
|
||||
(xf = ORB.Pointer) & (yf = ORB.Pointer) & IsExtension(y.type.base, x.type.base) THEN
|
||||
IF (xf IN {ORB.Char, ORB.Int}) THEN ORG.IntRelation(rel, x, y)
|
||||
ELSIF xf = ORB.Real THEN ORG.RealRelation(rel, x, y)
|
||||
ELSIF xf = ORB.Set THEN ORG.SetRelation(rel, x, y)
|
||||
ELSIF (xf IN {ORB.Pointer, ORB.Proc, ORB.NilTyp}) THEN
|
||||
IF rel <= ORS.neq THEN ORG.IntRelation(rel, x, y) ELSE ORS.Mark("only = or #") END
|
||||
ELSIF (xf = ORB.Array) & (x.type.base.form = ORB.Char) OR (xf = ORB.String) THEN
|
||||
ORG.StringRelation(rel, x, y)
|
||||
ELSE ORS.Mark("illegal comparison")
|
||||
END
|
||||
ELSIF (xf = ORB.Array) & (x.type.base.form = ORB.Char) &
|
||||
((yf = ORB.String) OR (yf = ORB.Array) & (y.type.base.form = ORB.Char))
|
||||
OR (yf = ORB.Array) & (y.type.base.form = ORB.Char) & (xf = ORB.String) THEN
|
||||
ORG.StringRelation(rel, x, y)
|
||||
ELSIF (xf = ORB.Char) & (yf = ORB.String) & (y.b = 2) THEN
|
||||
ORG.StrToChar(y); ORG.IntRelation(rel, x, y)
|
||||
ELSIF (yf = ORB.Char) & (xf = ORB.String) & (x.b = 2) THEN
|
||||
ORG.StrToChar(x); ORG.IntRelation(rel, x, y)
|
||||
ELSE ORS.Mark("illegal comparison")
|
||||
END ;
|
||||
x.type := ORB.boolType
|
||||
ELSIF sym = ORS.in THEN
|
||||
ORS.Get(sym); SimpleExpression(y);
|
||||
IF (x.type.form = ORB.Int) & (y.type.form = ORB.Set) THEN ORG.In(x, y)
|
||||
ELSE ORS.Mark("illegal operands of IN")
|
||||
END ;
|
||||
x.type := ORB.boolType
|
||||
ELSIF sym = ORS.is THEN
|
||||
ORS.Get(sym); qualident(obj); TypeTest(x, obj.type, FALSE) ;
|
||||
x.type := ORB.boolType
|
||||
END
|
||||
END expression0;
|
||||
|
||||
(* statements *)
|
||||
|
||||
PROCEDURE StandProc(pno: LONGINT);
|
||||
VAR nap, npar: LONGINT; (*nof actual/formal parameters*)
|
||||
x, y, z: ORG.Item;
|
||||
BEGIN Check(ORS.lparen, "no (");
|
||||
npar := pno MOD 10; pno := pno DIV 10; expression(x); nap := 1;
|
||||
IF sym = ORS.comma THEN
|
||||
ORS.Get(sym); expression(y); nap := 2; z.type := ORB.noType;
|
||||
WHILE sym = ORS.comma DO ORS.Get(sym); expression(z); INC(nap) END
|
||||
ELSE y.type := ORB.noType
|
||||
END ;
|
||||
Check(ORS.rparen, "no )");
|
||||
IF (npar = nap) OR (pno IN {0, 1}) THEN
|
||||
IF pno IN {0, 1} THEN (*INC, DEC*)
|
||||
CheckInt(x); CheckReadOnly(x);
|
||||
IF y.type # ORB.noType THEN CheckInt(y) END ;
|
||||
ORG.Increment(pno, x, y)
|
||||
ELSIF pno IN {2, 3} THEN (*INCL, EXCL*)
|
||||
CheckSet(x); CheckReadOnly(x); CheckInt(y); ORG.Include(pno-2, x, y)
|
||||
ELSIF pno = 4 THEN CheckBool(x); ORG.Assert(x)
|
||||
ELSIF pno = 5 THEN(*NEW*) CheckReadOnly(x);
|
||||
IF (x.type.form = ORB.Pointer) & (x.type.base.form = ORB.Record) THEN ORG.New(x)
|
||||
ELSE ORS.Mark("not a pointer to record")
|
||||
END
|
||||
ELSIF pno = 6 THEN CheckReal(x); CheckInt(y); CheckReadOnly(x); ORG.Pack(x, y)
|
||||
ELSIF pno = 7 THEN CheckReal(x); CheckInt(y); CheckReadOnly(x); ORG.Unpk(x, y)
|
||||
ELSIF pno = 8 THEN
|
||||
IF x.type.form <= ORB.Set THEN ORG.Led(x) ELSE ORS.Mark("bad type") END
|
||||
ELSIF pno = 10 THEN CheckInt(x); ORG.Get(x, y)
|
||||
ELSIF pno = 11 THEN CheckInt(x); ORG.Put(x, y)
|
||||
ELSIF pno = 12 THEN CheckInt(x); CheckInt(y); CheckInt(z); ORG.Copy(x, y, z)
|
||||
ELSIF pno = 13 THEN CheckConst(x); CheckInt(x); ORG.LDPSR(x)
|
||||
ELSIF pno = 14 THEN CheckInt(x); ORG.LDREG(x, y)
|
||||
END
|
||||
ELSE ORS.Mark("wrong nof parameters")
|
||||
END
|
||||
END StandProc;
|
||||
|
||||
PROCEDURE StatSequence;
|
||||
VAR obj: ORB.Object;
|
||||
orgtype: ORB.Type; (*original type of case var*)
|
||||
x, y, z, w: ORG.Item;
|
||||
L0, L1, rx: LONGINT;
|
||||
|
||||
PROCEDURE TypeCase(obj: ORB.Object; VAR x: ORG.Item);
|
||||
VAR typobj: ORB.Object;
|
||||
BEGIN
|
||||
IF sym = ORS.ident THEN
|
||||
qualident(typobj); ORG.MakeItem(x, obj, level);
|
||||
IF typobj.class # ORB.Typ THEN ORS.Mark("not a type") END ;
|
||||
TypeTest(x, typobj.type, FALSE); obj.type := typobj.type;
|
||||
ORG.CFJump(x); Check(ORS.colon, ": expected"); StatSequence
|
||||
ELSE ORG.CFJump(x); ORS.Mark("type id expected")
|
||||
END
|
||||
END TypeCase;
|
||||
|
||||
PROCEDURE SkipCase;
|
||||
BEGIN
|
||||
WHILE sym # ORS.colon DO ORS.Get(sym) END ;
|
||||
ORS.Get(sym); StatSequence
|
||||
END SkipCase;
|
||||
|
||||
BEGIN (* StatSequence *)
|
||||
REPEAT (*sync*) obj := NIL;
|
||||
IF ~((sym = ORS.ident) OR (sym >= ORS.if) & (sym <= ORS.for) OR (sym >= ORS.semicolon)) THEN
|
||||
ORS.Mark("statement expected");
|
||||
REPEAT ORS.Get(sym) UNTIL (sym = ORS.ident) OR (sym >= ORS.if)
|
||||
END ;
|
||||
IF sym = ORS.ident THEN
|
||||
qualident(obj); ORG.MakeItem(x, obj, level);
|
||||
IF x.mode = ORB.SProc THEN StandProc(obj.val)
|
||||
ELSE selector(x);
|
||||
IF sym = ORS.becomes THEN (*assignment*)
|
||||
ORS.Get(sym); CheckReadOnly(x); expression(y);
|
||||
IF CompTypes(x.type, y.type, FALSE) OR (x.type.form = ORB.Int) & (y.type.form = ORB.Int) THEN
|
||||
IF (x.type.form <= ORB.Pointer) OR (x.type.form = ORB.Proc) THEN ORG.Store(x, y)
|
||||
ELSIF y.type.size # 0 THEN ORG.StoreStruct(x, y)
|
||||
END
|
||||
ELSIF (x.type.form = ORB.Char) & (y.type.form = ORB.String) & (y.b = 2) THEN
|
||||
ORG.StrToChar(y); ORG.Store(x, y)
|
||||
ELSIF (x.type.form = ORB.Array) & (x.type.base.form = ORB.Char) &
|
||||
(y.type.form = ORB.String) THEN ORG.CopyString(y, x)
|
||||
ELSE ORS.Mark("illegal assignment")
|
||||
END
|
||||
ELSIF sym = ORS.eql THEN ORS.Mark("should be :="); ORS.Get(sym); expression(y)
|
||||
ELSIF sym = ORS.lparen THEN (*procedure call*)
|
||||
ORS.Get(sym);
|
||||
IF (x.type.form = ORB.Proc) & (x.type.base.form = ORB.NoTyp) THEN
|
||||
ORG.PrepCall(x, rx); ParamList(x); ORG.Call(x, rx)
|
||||
ELSE ORS.Mark("not a procedure"); ParamList(x)
|
||||
END
|
||||
ELSIF x.type.form = ORB.Proc THEN (*procedure call without parameters*)
|
||||
IF x.type.nofpar > 0 THEN ORS.Mark("missing parameters") END ;
|
||||
IF x.type.base.form = ORB.NoTyp THEN ORG.PrepCall(x, rx); ORG.Call(x, rx) ELSE ORS.Mark("not a procedure") END
|
||||
ELSIF x.mode = ORB.Typ THEN ORS.Mark("illegal assignment")
|
||||
ELSE ORS.Mark("not a procedure")
|
||||
END
|
||||
END
|
||||
ELSIF sym = ORS.if THEN
|
||||
ORS.Get(sym); expression(x); CheckBool(x); ORG.CFJump(x);
|
||||
Check(ORS.then, "no THEN");
|
||||
StatSequence; L0 := 0;
|
||||
WHILE sym = ORS.elsif DO
|
||||
ORS.Get(sym); ORG.FJump(L0); ORG.Fixup(x); expression(x); CheckBool(x);
|
||||
ORG.CFJump(x); Check(ORS.then, "no THEN"); StatSequence
|
||||
END ;
|
||||
IF sym = ORS.else THEN ORS.Get(sym); ORG.FJump(L0); ORG.Fixup(x); StatSequence
|
||||
ELSE ORG.Fixup(x)
|
||||
END ;
|
||||
ORG.FixLink(L0); Check(ORS.end, "no END")
|
||||
ELSIF sym = ORS.while THEN
|
||||
ORS.Get(sym); L0 := ORG.Here(); expression(x); CheckBool(x); ORG.CFJump(x);
|
||||
Check(ORS.do, "no DO"); StatSequence; ORG.BJump(L0);
|
||||
WHILE sym = ORS.elsif DO
|
||||
ORS.Get(sym); ORG.Fixup(x); expression(x); CheckBool(x); ORG.CFJump(x);
|
||||
Check(ORS.do, "no DO"); StatSequence; ORG.BJump(L0)
|
||||
END ;
|
||||
ORG.Fixup(x); Check(ORS.end, "no END")
|
||||
ELSIF sym = ORS.repeat THEN
|
||||
ORS.Get(sym); L0 := ORG.Here(); StatSequence;
|
||||
IF sym = ORS.until THEN
|
||||
ORS.Get(sym); expression(x); CheckBool(x); ORG.CBJump(x, L0)
|
||||
ELSE ORS.Mark("missing UNTIL")
|
||||
END
|
||||
ELSIF sym = ORS.for THEN
|
||||
ORS.Get(sym);
|
||||
IF sym = ORS.ident THEN
|
||||
qualident(obj); ORG.MakeItem(x, obj, level); CheckInt(x); CheckReadOnly(x);
|
||||
IF sym = ORS.becomes THEN
|
||||
ORS.Get(sym); expression(y); CheckInt(y); ORG.For0(x, y); L0 := ORG.Here();
|
||||
Check(ORS.to, "no TO"); expression(z); CheckInt(z); obj.rdo := TRUE;
|
||||
IF sym = ORS.by THEN ORS.Get(sym); expression(w); CheckConst(w); CheckInt(w)
|
||||
ELSE ORG.MakeConstItem(w, ORB.intType, 1)
|
||||
END ;
|
||||
Check(ORS.do, "no DO"); ORG.For1(x, y, z, w, L1);
|
||||
StatSequence; Check(ORS.end, "no END");
|
||||
ORG.For2(x, y, w); ORG.BJump(L0); ORG.FixLink(L1); obj.rdo := FALSE
|
||||
ELSE ORS.Mark(":= expected")
|
||||
END
|
||||
ELSE ORS.Mark("identifier expected")
|
||||
END
|
||||
ELSIF sym = ORS.case THEN
|
||||
ORS.Get(sym);
|
||||
IF sym = ORS.ident THEN
|
||||
qualident(obj); orgtype := obj.type;
|
||||
IF (orgtype.form = ORB.Pointer) OR (orgtype.form = ORB.Record) & (obj.class = ORB.Par) THEN
|
||||
Check(ORS.of, "OF expected"); TypeCase(obj, x); L0 := 0;
|
||||
WHILE sym = ORS.bar DO
|
||||
ORS.Get(sym); ORG.FJump(L0); ORG.Fixup(x); obj.type := orgtype; TypeCase(obj, x)
|
||||
END ;
|
||||
ORG.Fixup(x); ORG.FixLink(L0); obj.type := orgtype
|
||||
ELSE ORS.Mark("numeric case not implemented");
|
||||
Check(ORS.of, "OF expected"); SkipCase;
|
||||
WHILE sym = ORS.bar DO SkipCase END
|
||||
END
|
||||
ELSE ORS.Mark("ident expected")
|
||||
END ;
|
||||
Check(ORS.end, "no END")
|
||||
END ;
|
||||
ORG.CheckRegs;
|
||||
IF sym = ORS.semicolon THEN ORS.Get(sym)
|
||||
ELSIF sym < ORS.semicolon THEN ORS.Mark("missing semicolon?")
|
||||
END
|
||||
UNTIL sym > ORS.semicolon
|
||||
END StatSequence;
|
||||
|
||||
(* Types and declarations *)
|
||||
|
||||
PROCEDURE IdentList(class: INTEGER; VAR first: ORB.Object);
|
||||
VAR obj: ORB.Object;
|
||||
BEGIN
|
||||
IF sym = ORS.ident THEN
|
||||
ORB.NewObj(first, ORS.id, class); ORS.Get(sym); CheckExport(first.expo);
|
||||
WHILE sym = ORS.comma DO
|
||||
ORS.Get(sym);
|
||||
IF sym = ORS.ident THEN ORB.NewObj(obj, ORS.id, class); ORS.Get(sym); CheckExport(obj.expo)
|
||||
ELSE ORS.Mark("ident?")
|
||||
END
|
||||
END;
|
||||
IF sym = ORS.colon THEN ORS.Get(sym) ELSE ORS.Mark(":?") END
|
||||
ELSE first := NIL
|
||||
END
|
||||
END IdentList;
|
||||
|
||||
PROCEDURE ArrayType(VAR type: ORB.Type);
|
||||
VAR x: ORG.Item; typ: ORB.Type; len: LONGINT;
|
||||
BEGIN NEW(typ); typ.form := ORB.NoTyp;
|
||||
IF sym = ORS.of THEN (*dynamic array*) len := -1
|
||||
ELSE expression(x);
|
||||
IF (x.mode = ORB.Const) & (x.type.form = ORB.Int) & (x.a >= 0) THEN len := x.a
|
||||
ELSE len := 0; ORS.Mark("not a valid length")
|
||||
END
|
||||
END ;
|
||||
IF sym = ORS.of THEN ORS.Get(sym); Type(typ.base);
|
||||
IF (typ.base.form = ORB.Array) & (typ.base.len < 0) THEN ORS.Mark("dyn array not allowed") END
|
||||
ELSIF sym = ORS.comma THEN ORS.Get(sym); ArrayType(typ.base)
|
||||
ELSE ORS.Mark("missing OF"); typ.base := ORB.intType
|
||||
END ;
|
||||
IF len >= 0 THEN typ.size := (len * typ.base.size + 3) DIV 4 * 4 ELSE typ.size := 2*ORG.WordSize (*array desc*) END ;
|
||||
typ.form := ORB.Array; typ.len := len; type := typ
|
||||
END ArrayType;
|
||||
|
||||
PROCEDURE RecordType(VAR type: ORB.Type);
|
||||
VAR obj, obj0, new, bot, base: ORB.Object;
|
||||
typ, tp: ORB.Type;
|
||||
offset, off, n: LONGINT;
|
||||
BEGIN NEW(typ); typ.form := ORB.NoTyp; typ.base := NIL; typ.mno := -level; typ.nofpar := 0; offset := 0; bot := NIL;
|
||||
IF sym = ORS.lparen THEN
|
||||
ORS.Get(sym); (*record extension*)
|
||||
IF level # 0 THEN ORS.Mark("extension of local types not implemented") END ;
|
||||
IF sym = ORS.ident THEN
|
||||
qualident(base);
|
||||
IF base.class = ORB.Typ THEN
|
||||
IF base.type.form = ORB.Record THEN typ.base := base.type
|
||||
ELSE typ.base := ORB.intType; ORS.Mark("invalid extension")
|
||||
END ;
|
||||
typ.nofpar := typ.base.nofpar + 1; (*"nofpar" here abused for extension level*)
|
||||
bot := typ.base.dsc; offset := typ.base.size
|
||||
ELSE ORS.Mark("type expected")
|
||||
END
|
||||
ELSE ORS.Mark("ident expected")
|
||||
END ;
|
||||
Check(ORS.rparen, "no )")
|
||||
END ;
|
||||
WHILE sym = ORS.ident DO (*fields*)
|
||||
n := 0; obj := bot;
|
||||
WHILE sym = ORS.ident DO
|
||||
obj0 := obj;
|
||||
WHILE (obj0 # NIL) & (obj0.name # ORS.id) DO obj0 := obj0.next END ;
|
||||
IF obj0 # NIL THEN ORS.Mark("mult def") END ;
|
||||
NEW(new); ORS.CopyId(new.name); new.class := ORB.Fld; new.next := obj; obj := new; INC(n);
|
||||
ORS.Get(sym); CheckExport(new.expo);
|
||||
IF (sym # ORS.comma) & (sym # ORS.colon) THEN ORS.Mark("comma expected")
|
||||
ELSIF sym = ORS.comma THEN ORS.Get(sym)
|
||||
END
|
||||
END ;
|
||||
Check(ORS.colon, "colon expected"); Type(tp);
|
||||
IF (tp.form = ORB.Array) & (tp.len < 0) THEN ORS.Mark("dyn array not allowed") END ;
|
||||
IF tp.size > 1 THEN offset := (offset+3) DIV 4 * 4 END ;
|
||||
offset := offset + n * tp.size; off := offset; obj0 := obj;
|
||||
WHILE obj0 # bot DO obj0.type := tp; obj0.lev := 0; off := off - tp.size; obj0.val := off; obj0 := obj0.next END ;
|
||||
bot := obj;
|
||||
IF sym = ORS.semicolon THEN ORS.Get(sym) ELSIF sym # ORS.end THEN ORS.Mark(" ; or END") END
|
||||
END ;
|
||||
typ.form := ORB.Record; typ.dsc := bot; typ.size := (offset + 3) DIV 4 * 4; type := typ
|
||||
END RecordType;
|
||||
|
||||
PROCEDURE FPSection(VAR adr: LONGINT; VAR nofpar: INTEGER);
|
||||
VAR obj, first: ORB.Object; tp: ORB.Type;
|
||||
parsize: LONGINT; cl: INTEGER; rdo: BOOLEAN;
|
||||
BEGIN
|
||||
IF sym = ORS.var THEN ORS.Get(sym); cl := ORB.Par ELSE cl := ORB.Var END ;
|
||||
IdentList(cl, first); FormalType(tp, 0); rdo := FALSE;
|
||||
IF (cl = ORB.Var) & (tp.form >= ORB.Array) THEN cl := ORB.Par; rdo := TRUE END ;
|
||||
IF (tp.form = ORB.Array) & (tp.len < 0) OR (tp.form = ORB.Record) THEN
|
||||
parsize := 2*ORG.WordSize (*open array or record, needs second word for length or type tag*)
|
||||
ELSE parsize := ORG.WordSize
|
||||
END ;
|
||||
obj := first;
|
||||
WHILE obj # NIL DO
|
||||
INC(nofpar); obj.class := cl; obj.type := tp; obj.rdo := rdo; obj.lev := level; obj.val := adr;
|
||||
adr := adr + parsize; obj := obj.next
|
||||
END ;
|
||||
IF adr >= 52 THEN ORS.Mark("too many parameters") END
|
||||
END FPSection;
|
||||
|
||||
PROCEDURE ProcedureType(ptype: ORB.Type; VAR parblksize: LONGINT);
|
||||
VAR obj: ORB.Object; size: LONGINT; nofpar: INTEGER;
|
||||
BEGIN ptype.base := ORB.noType; size := parblksize; nofpar := 0; ptype.dsc := NIL;
|
||||
IF sym = ORS.lparen THEN
|
||||
ORS.Get(sym);
|
||||
IF sym = ORS.rparen THEN ORS.Get(sym)
|
||||
ELSE FPSection(size, nofpar);
|
||||
WHILE sym = ORS.semicolon DO ORS.Get(sym); FPSection(size, nofpar) END ;
|
||||
Check(ORS.rparen, "no )")
|
||||
END ;
|
||||
ptype.nofpar := nofpar; parblksize := size;
|
||||
IF sym = ORS.colon THEN (*function*)
|
||||
ORS.Get(sym);
|
||||
IF sym = ORS.ident THEN qualident(obj);
|
||||
IF (obj.class = ORB.Typ) & (obj.type.form IN {ORB.Byte .. ORB.Pointer, ORB.Proc}) THEN ptype.base := obj.type
|
||||
ELSE ORS.Mark("illegal function type")
|
||||
END
|
||||
ELSE ORS.Mark("type identifier expected")
|
||||
END
|
||||
END
|
||||
END
|
||||
END ProcedureType;
|
||||
|
||||
PROCEDURE FormalType0(VAR typ: ORB.Type; dim: INTEGER);
|
||||
VAR obj: ORB.Object; dmy: LONGINT;
|
||||
BEGIN
|
||||
IF sym = ORS.ident THEN
|
||||
qualident(obj);
|
||||
IF obj.class = ORB.Typ THEN typ := obj.type ELSE ORS.Mark("not a type"); typ := ORB.intType END
|
||||
ELSIF sym = ORS.array THEN
|
||||
ORS.Get(sym); Check(ORS.of, "OF ?");
|
||||
IF dim >= 1 THEN ORS.Mark("multi-dimensional open arrays not implemented") END ;
|
||||
NEW(typ); typ.form := ORB.Array; typ.len := -1; typ.size := 2*ORG.WordSize;
|
||||
FormalType(typ.base, dim+1)
|
||||
ELSIF sym = ORS.procedure THEN
|
||||
ORS.Get(sym); ORB.OpenScope;
|
||||
NEW(typ); typ.form := ORB.Proc; typ.size := ORG.WordSize; dmy := 0; ProcedureType(typ, dmy);
|
||||
typ.dsc := ORB.topScope.next; ORB.CloseScope
|
||||
ELSE ORS.Mark("identifier expected"); typ := ORB.noType
|
||||
END
|
||||
END FormalType0;
|
||||
|
||||
PROCEDURE CheckRecLevel(lev: INTEGER);
|
||||
BEGIN
|
||||
IF lev # 0 THEN ORS.Mark("ptr base must be global") END
|
||||
END CheckRecLevel;
|
||||
|
||||
PROCEDURE Type0(VAR type: ORB.Type);
|
||||
VAR dmy: LONGINT; obj: ORB.Object; ptbase: PtrBase;
|
||||
BEGIN type := ORB.intType; (*sync*)
|
||||
IF (sym # ORS.ident) & (sym < ORS.array) THEN ORS.Mark("not a type");
|
||||
REPEAT ORS.Get(sym) UNTIL (sym = ORS.ident) OR (sym >= ORS.array)
|
||||
END ;
|
||||
IF sym = ORS.ident THEN
|
||||
qualident(obj);
|
||||
IF obj.class = ORB.Typ THEN
|
||||
IF (obj.type # NIL) & (obj.type.form # ORB.NoTyp) THEN type := obj.type END
|
||||
ELSE ORS.Mark("not a type or undefined")
|
||||
END
|
||||
ELSIF sym = ORS.array THEN ORS.Get(sym); ArrayType(type)
|
||||
ELSIF sym = ORS.record THEN
|
||||
ORS.Get(sym); RecordType(type); Check(ORS.end, "no END")
|
||||
ELSIF sym = ORS.pointer THEN
|
||||
ORS.Get(sym); Check(ORS.to, "no TO");
|
||||
NEW(type); type.form := ORB.Pointer; type.size := ORG.WordSize; type.base := ORB.intType;
|
||||
IF sym = ORS.ident THEN
|
||||
obj := ORB.thisObj(); ORS.Get(sym);
|
||||
IF obj # NIL THEN
|
||||
IF (obj.class = ORB.Typ) & (obj.type.form IN {ORB.Record, ORB.NoTyp}) THEN
|
||||
CheckRecLevel(obj.lev); type.base := obj.type
|
||||
ELSE ORS.Mark("no valid base type")
|
||||
END
|
||||
ELSE CheckRecLevel(level); (*enter into list of forward references to be fixed in Declarations*)
|
||||
NEW(ptbase); ORS.CopyId(ptbase.name); ptbase.type := type; ptbase.next := pbsList; pbsList := ptbase
|
||||
END
|
||||
ELSE Type(type.base);
|
||||
IF type.base.form # ORB.Record THEN ORS.Mark("must point to record") END ;
|
||||
CheckRecLevel(level)
|
||||
END
|
||||
ELSIF sym = ORS.procedure THEN
|
||||
ORS.Get(sym); ORB.OpenScope;
|
||||
NEW(type); type.form := ORB.Proc; type.size := ORG.WordSize; dmy := 0;
|
||||
ProcedureType(type, dmy); type.dsc := ORB.topScope.next; ORB.CloseScope
|
||||
ELSE ORS.Mark("illegal type")
|
||||
END
|
||||
END Type0;
|
||||
|
||||
PROCEDURE Declarations(VAR varsize: LONGINT);
|
||||
VAR obj, first: ORB.Object;
|
||||
x: ORG.Item; tp: ORB.Type; ptbase: PtrBase;
|
||||
expo: BOOLEAN; id: ORS.Ident;
|
||||
BEGIN (*sync*) pbsList := NIL;
|
||||
IF (sym < ORS.const) & (sym # ORS.end) THEN ORS.Mark("declaration?");
|
||||
REPEAT ORS.Get(sym) UNTIL (sym >= ORS.const) OR (sym = ORS.end)
|
||||
END ;
|
||||
IF sym = ORS.const THEN
|
||||
ORS.Get(sym);
|
||||
WHILE sym = ORS.ident DO
|
||||
ORS.CopyId(id); ORS.Get(sym); CheckExport(expo);
|
||||
IF sym = ORS.eql THEN ORS.Get(sym) ELSE ORS.Mark("= ?") END;
|
||||
expression(x);
|
||||
IF (x.type.form = ORB.String) & (x.b = 2) THEN ORG.StrToChar(x) END ;
|
||||
ORB.NewObj(obj, id, ORB.Const); obj.expo := expo;
|
||||
IF x.mode = ORB.Const THEN obj.val := x.a; obj.lev := x.b; obj.type := x.type
|
||||
ELSE ORS.Mark("expression not constant"); obj.type := ORB.intType
|
||||
END;
|
||||
Check(ORS.semicolon, "; missing")
|
||||
END
|
||||
END ;
|
||||
IF sym = ORS.type THEN
|
||||
ORS.Get(sym);
|
||||
WHILE sym = ORS.ident DO
|
||||
ORS.CopyId(id); ORS.Get(sym); CheckExport(expo);
|
||||
IF sym = ORS.eql THEN ORS.Get(sym) ELSE ORS.Mark("=?") END ;
|
||||
Type(tp);
|
||||
ORB.NewObj(obj, id, ORB.Typ); obj.type := tp; obj.expo := expo; obj.lev := level; tp.typobj := obj;
|
||||
IF expo & (obj.type.form = ORB.Record) THEN obj.exno := exno; INC(exno) ELSE obj.exno := 0 END ;
|
||||
IF tp.form = ORB.Record THEN
|
||||
ptbase := pbsList; (*check whether this is base of a pointer type; search and fixup*)
|
||||
WHILE ptbase # NIL DO
|
||||
IF obj.name = ptbase.name THEN ptbase.type.base := obj.type END ;
|
||||
ptbase := ptbase.next
|
||||
END ;
|
||||
IF level = 0 THEN ORG.BuildTD(tp, dc) END (*type descriptor; len used as its address*)
|
||||
END ;
|
||||
Check(ORS.semicolon, "; missing")
|
||||
END
|
||||
END ;
|
||||
IF sym = ORS.var THEN
|
||||
ORS.Get(sym);
|
||||
WHILE sym = ORS.ident DO
|
||||
IdentList(ORB.Var, first); Type(tp);
|
||||
obj := first;
|
||||
WHILE obj # NIL DO
|
||||
obj.type := tp; obj.lev := level;
|
||||
IF tp.size > 1 THEN varsize := (varsize + 3) DIV 4 * 4 (*align*) END ;
|
||||
obj.val := varsize; varsize := varsize + obj.type.size;
|
||||
IF obj.expo THEN obj.exno := exno; INC(exno) END ;
|
||||
obj := obj.next
|
||||
END ;
|
||||
Check(ORS.semicolon, "; missing")
|
||||
END
|
||||
END ;
|
||||
varsize := (varsize + 3) DIV 4 * 4;
|
||||
ptbase := pbsList;
|
||||
WHILE ptbase # NIL DO
|
||||
IF ptbase.type.base.form = ORB.Int THEN ORS.Mark("undefined pointer base of") END ;
|
||||
ptbase := ptbase.next
|
||||
END ;
|
||||
IF (sym >= ORS.const) & (sym <= ORS.var) THEN ORS.Mark("declaration in bad order") END
|
||||
END Declarations;
|
||||
|
||||
PROCEDURE ProcedureDecl;
|
||||
VAR proc: ORB.Object;
|
||||
type: ORB.Type;
|
||||
procid: ORS.Ident;
|
||||
x: ORG.Item;
|
||||
locblksize, parblksize, L: LONGINT;
|
||||
int: BOOLEAN;
|
||||
BEGIN (* ProcedureDecl *) int := FALSE; ORS.Get(sym);
|
||||
IF sym = ORS.times THEN ORS.Get(sym); int := TRUE END ;
|
||||
IF sym = ORS.ident THEN
|
||||
ORS.CopyId(procid); ORS.Get(sym);
|
||||
ORB.NewObj(proc, ORS.id, ORB.Const); parblksize := 4;
|
||||
NEW(type); type.form := ORB.Proc; type.size := ORG.WordSize; proc.type := type;
|
||||
CheckExport(proc.expo);
|
||||
IF proc.expo THEN proc.exno := exno; INC(exno) END ;
|
||||
ORB.OpenScope; INC(level); proc.val := -1; type.base := ORB.noType;
|
||||
ProcedureType(type, parblksize); (*formal parameter list*)
|
||||
Check(ORS.semicolon, "no ;"); locblksize := parblksize;
|
||||
Declarations(locblksize);
|
||||
proc.val := ORG.Here() * 4; proc.type.dsc := ORB.topScope.next;
|
||||
IF sym = ORS.procedure THEN
|
||||
L := 0; ORG.FJump(L);
|
||||
REPEAT ProcedureDecl; Check(ORS.semicolon, "no ;") UNTIL sym # ORS.procedure;
|
||||
ORG.FixLink(L); proc.val := ORG.Here() * 4; proc.type.dsc := ORB.topScope.next
|
||||
END ;
|
||||
ORG.Enter(parblksize, locblksize, int);
|
||||
IF sym = ORS.begin THEN ORS.Get(sym); StatSequence END ;
|
||||
IF sym = ORS.return THEN
|
||||
ORS.Get(sym); expression(x);
|
||||
IF type.base = ORB.noType THEN ORS.Mark("this is not a function")
|
||||
ELSIF ~CompTypes(type.base, x.type, FALSE) THEN ORS.Mark("wrong result type")
|
||||
END
|
||||
ELSIF type.base.form # ORB.NoTyp THEN
|
||||
ORS.Mark("function without result"); type.base := ORB.noType
|
||||
END ;
|
||||
ORG.Return(type.base.form, x, locblksize, int);
|
||||
ORB.CloseScope; DEC(level); Check(ORS.end, "no END");
|
||||
IF sym = ORS.ident THEN
|
||||
IF ORS.id # procid THEN ORS.Mark("no match") END ;
|
||||
ORS.Get(sym)
|
||||
ELSE ORS.Mark("no proc id")
|
||||
END
|
||||
END ;
|
||||
int := FALSE
|
||||
END ProcedureDecl;
|
||||
|
||||
PROCEDURE Module;
|
||||
VAR key: LONGINT;
|
||||
obj: ORB.Object;
|
||||
impid, impid1: ORS.Ident;
|
||||
BEGIN Texts.WriteString(W, " compiling "); ORS.Get(sym);
|
||||
IF sym = ORS.module THEN
|
||||
ORS.Get(sym);
|
||||
IF sym = ORS.times THEN version := 0; Texts.Write(W, "*"); ORS.Get(sym) ELSE version := 1 END ;
|
||||
ORB.Init; ORB.OpenScope;
|
||||
IF sym = ORS.ident THEN
|
||||
ORS.CopyId(modid); ORS.Get(sym);
|
||||
Texts.WriteString(W, modid); Texts.Append(Oberon.Log, W.buf);
|
||||
Oberon.DumpLog; (* voc adaptation; -- noch *)
|
||||
ELSE ORS.Mark("identifier expected")
|
||||
END ;
|
||||
Check(ORS.semicolon, "no ;"); level := 0; dc := 0; exno := 1; key := 0;
|
||||
IF sym = ORS.import THEN
|
||||
ORS.Get(sym);
|
||||
WHILE sym = ORS.ident DO
|
||||
ORS.CopyId(impid); ORS.Get(sym);
|
||||
IF sym = ORS.becomes THEN
|
||||
ORS.Get(sym);
|
||||
IF sym = ORS.ident THEN ORS.CopyId(impid1); ORS.Get(sym)
|
||||
ELSE ORS.Mark("id expected")
|
||||
END
|
||||
ELSE impid1 := impid
|
||||
END ;
|
||||
ORB.Import(impid, impid1);
|
||||
IF sym = ORS.comma THEN ORS.Get(sym)
|
||||
ELSIF sym = ORS.ident THEN ORS.Mark("comma missing")
|
||||
END
|
||||
END ;
|
||||
Check(ORS.semicolon, "no ;")
|
||||
END ;
|
||||
obj := ORB.topScope.next;
|
||||
ORG.Open(version); Declarations(dc); ORG.SetDataSize((dc + 3) DIV 4 * 4);
|
||||
WHILE sym = ORS.procedure DO ProcedureDecl; Check(ORS.semicolon, "no ;") END ;
|
||||
ORG.Header;
|
||||
IF sym = ORS.begin THEN ORS.Get(sym); StatSequence END ;
|
||||
Check(ORS.end, "no END");
|
||||
IF sym = ORS.ident THEN
|
||||
IF ORS.id # modid THEN ORS.Mark("no match") END ;
|
||||
ORS.Get(sym)
|
||||
ELSE ORS.Mark("identifier missing")
|
||||
END ;
|
||||
IF sym # ORS.period THEN ORS.Mark("period missing") END ;
|
||||
IF (ORS.errcnt = 0) & (version # 0) THEN
|
||||
ORB.Export(modid, newSF, key);
|
||||
IF newSF THEN Texts.WriteString(W, " new symbol file") END
|
||||
END ;
|
||||
IF ORS.errcnt = 0 THEN
|
||||
ORG.Close(modid, key, exno);
|
||||
Texts.WriteInt(W, ORG.pc, 6); Texts.WriteInt(W, dc, 6); Texts.WriteHex(W, key)
|
||||
ELSE Texts.WriteLn(W); Texts.WriteString(W, "compilation FAILED")
|
||||
END ;
|
||||
Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf);
|
||||
Oberon.DumpLog; (* voc adaptation; -- noch *)
|
||||
ORB.CloseScope; pbsList := NIL
|
||||
ELSE ORS.Mark("must start with MODULE")
|
||||
END
|
||||
END Module;
|
||||
|
||||
PROCEDURE Option(VAR S: Texts.Scanner);
|
||||
BEGIN newSF := FALSE;
|
||||
IF S.nextCh = "/" THEN
|
||||
Texts.Scan(S); Texts.Scan(S);
|
||||
IF (S.class = Texts.Name) & (S.s[0] = "s") THEN newSF := TRUE END
|
||||
END
|
||||
END Option;
|
||||
|
||||
PROCEDURE Compile*;
|
||||
VAR beg, end, time: LONGINT;
|
||||
T: Texts.Text;
|
||||
S: Texts.Scanner;
|
||||
BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
|
||||
IF S.class = Texts.Char THEN
|
||||
IF S.c = "@" THEN
|
||||
Option(S); Oberon.GetSelection(T, beg, end, time);
|
||||
IF time >= 0 THEN ORS.Init(T, beg); Module END
|
||||
ELSIF S.c = "^" THEN
|
||||
Option(S); Oberon.GetSelection(T, beg, end, time);
|
||||
IF time >= 0 THEN
|
||||
Texts.OpenScanner(S, T, beg); Texts.Scan(S);
|
||||
IF S.class = Texts.Name THEN
|
||||
Texts.WriteString(W, S.s); NEW(T); Texts.Open(T, S.s);
|
||||
IF T.len > 0 THEN ORS.Init(T, 0); Module END
|
||||
END
|
||||
END
|
||||
END
|
||||
ELSE
|
||||
WHILE S.class = Texts.Name DO
|
||||
NEW(T); Texts.Open(T, S.s);
|
||||
IF T.len > 0 THEN Option(S); ORS.Init(T, 0); Module
|
||||
ELSE Texts.WriteString(W, S.s); Texts.WriteString(W, " not found");
|
||||
Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf);
|
||||
Oberon.DumpLog; (* voc adaptation; -- noch *)
|
||||
END ;
|
||||
IF (T.len # 0) & (ORS.errcnt = 0) THEN Texts.Scan(S) ELSE S.class := 0 END
|
||||
END
|
||||
END ;
|
||||
Oberon.Collect(0)
|
||||
END Compile;
|
||||
|
||||
BEGIN Texts.OpenWriter(W); Texts.WriteString(W, "OR Compiler 7.6.2014");
|
||||
Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf);
|
||||
Oberon.DumpLog; (* voc adaptation; -- noch *)
|
||||
NEW(dummy); dummy.class := ORB.Var; dummy.type := ORB.intType;
|
||||
expression := expression0; Type := Type0; FormalType := FormalType0;
|
||||
|
||||
Compile (* voc adaptation; -- noch *)
|
||||
END ORP.
|
||||
|
|
@ -1,325 +0,0 @@
|
|||
MODULE ORS; (* NW 19.9.93 / 1.4.2014 Scanner in Oberon-07*)
|
||||
IMPORT SYSTEM, Texts := CompatTexts, Oberon; (* CompatTexts is voc adaptation by noch *)
|
||||
|
||||
TYPE INTEGER = LONGINT; (* voc adaptation by noch *)
|
||||
|
||||
(* Oberon Scanner does lexical analysis. Input is Oberon-Text, output is
|
||||
sequence of symbols, i.e identifiers, numbers, strings, and special symbols.
|
||||
Recognises all Oberon keywords and skips comments. The keywords are
|
||||
recorded in a table.
|
||||
Get(sym) delivers next symbol from input text with Reader R.
|
||||
Mark(msg) records error and delivers error message with Writer W.
|
||||
If Get delivers ident, then the identifier (a string) is in variable id, if int or char
|
||||
in ival, if real in rval, and if string in str (and slen) *)
|
||||
|
||||
CONST IdLen* = 32;
|
||||
NKW = 34; (*nof keywords*)
|
||||
maxExp = 38; stringBufSize = 256;
|
||||
|
||||
(*lexical symbols*)
|
||||
null = 0; times* = 1; rdiv* = 2; div* = 3; mod* = 4;
|
||||
and* = 5; plus* = 6; minus* = 7; or* = 8; eql* = 9;
|
||||
neq* = 10; lss* = 11; leq* = 12; gtr* = 13; geq* = 14;
|
||||
in* = 15; is* = 16; arrow* = 17; period* = 18;
|
||||
char* = 20; int* = 21; real* = 22; false* = 23; true* = 24;
|
||||
nil* = 25; string* = 26; not* = 27; lparen* = 28; lbrak* = 29;
|
||||
lbrace* = 30; ident* = 31;
|
||||
if* = 32; while* = 34; repeat* = 35; case* = 36; for* = 37;
|
||||
comma* = 40; colon* = 41; becomes* = 42; upto* = 43; rparen* = 44;
|
||||
rbrak* = 45; rbrace* = 46; then* = 47; of* = 48; do* = 49;
|
||||
to* = 50; by* = 51; semicolon* = 52; end* = 53; bar* = 54;
|
||||
else* = 55; elsif* = 56; until* = 57; return* = 58;
|
||||
array* = 60; record* = 61; pointer* = 62; const* = 63; type* = 64;
|
||||
var* = 65; procedure* = 66; begin* = 67; import* = 68; module* = 69;
|
||||
|
||||
TYPE Ident* = ARRAY IdLen OF CHAR;
|
||||
|
||||
VAR ival*, slen*: LONGINT; (*results of Get*)
|
||||
rval*: REAL;
|
||||
id*: Ident; (*for identifiers*)
|
||||
str*: ARRAY stringBufSize OF CHAR;
|
||||
errcnt*: INTEGER;
|
||||
|
||||
ch: CHAR; (*last character read*)
|
||||
errpos: LONGINT;
|
||||
R: Texts.Reader;
|
||||
W: Texts.Writer;
|
||||
k: INTEGER;
|
||||
KWX: ARRAY 10 OF INTEGER;
|
||||
keyTab: ARRAY NKW OF
|
||||
RECORD sym: INTEGER; id: ARRAY 12 OF CHAR END;
|
||||
|
||||
PROCEDURE CopyId*(VAR ident: Ident);
|
||||
BEGIN ident := id
|
||||
END CopyId;
|
||||
|
||||
PROCEDURE Pos*(): LONGINT;
|
||||
BEGIN RETURN Texts.Pos(R) - 1
|
||||
END Pos;
|
||||
|
||||
PROCEDURE Mark*(msg: ARRAY OF CHAR);
|
||||
VAR p: LONGINT;
|
||||
BEGIN p := Pos();
|
||||
IF (p > errpos) & (errcnt < 25) THEN
|
||||
Texts.WriteLn(W); Texts.WriteString(W, " pos "); Texts.WriteInt(W, p, 1); Texts.Write(W, " ");
|
||||
Texts.WriteString(W, msg); Texts.Append(Oberon.Log, W.buf);
|
||||
Oberon.DumpLog; (* voc adaptation by noch *)
|
||||
END ;
|
||||
INC(errcnt); errpos := p + 4
|
||||
END Mark;
|
||||
|
||||
PROCEDURE Identifier(VAR sym: INTEGER);
|
||||
VAR i, k: INTEGER;
|
||||
BEGIN i := 0;
|
||||
REPEAT
|
||||
IF i < IdLen-1 THEN id[i] := ch; INC(i) END ;
|
||||
Texts.Read(R, ch)
|
||||
UNTIL (ch < "0") OR (ch > "9") & (ch < "A") OR (ch > "Z") & (ch < "a") OR (ch > "z");
|
||||
id[i] := 0X;
|
||||
IF i < 10 THEN k := KWX[i-1]; (*search for keyword*)
|
||||
WHILE (id # keyTab[k].id) & (k < KWX[i]) DO INC(k) END ;
|
||||
IF k < KWX[i] THEN sym := keyTab[k].sym ELSE sym := ident END
|
||||
ELSE sym := ident
|
||||
END
|
||||
END Identifier;
|
||||
|
||||
PROCEDURE String;
|
||||
VAR i: INTEGER;
|
||||
BEGIN i := 0; Texts.Read(R, ch);
|
||||
WHILE ~R.eot & (ch # 22X) DO
|
||||
IF ch >= " " THEN
|
||||
IF i < stringBufSize-1 THEN str[i] := ch; INC(i) ELSE Mark("string too long") END ;
|
||||
END ;
|
||||
Texts.Read(R, ch)
|
||||
END ;
|
||||
str[i] := 0X; INC(i); Texts.Read(R, ch); slen := i
|
||||
END String;
|
||||
|
||||
PROCEDURE HexString;
|
||||
VAR i, m, n: INTEGER;
|
||||
BEGIN i := 0; Texts.Read(R, ch);
|
||||
WHILE ~R.eot & (ch # "$") DO
|
||||
WHILE (ch = " ") OR (ch = 9X) OR (ch = 0DX) DO Texts.Read(R, ch) END ; (*skip*)
|
||||
IF ("0" <= ch) & (ch <= "9") THEN m := ORD(ch) - 30H
|
||||
ELSIF ("A" <= ch) & (ch <= "F") THEN m := ORD(ch) - 37H
|
||||
ELSE m := 0; Mark("hexdig expected")
|
||||
END ;
|
||||
Texts.Read(R, ch);
|
||||
IF ("0" <= ch) & (ch <= "9") THEN n := ORD(ch) - 30H
|
||||
ELSIF ("A" <= ch) & (ch <= "F") THEN n := ORD(ch) - 37H
|
||||
ELSE n := 0; Mark("hexdig expected")
|
||||
END ;
|
||||
IF i < stringBufSize THEN str[i] := CHR(m*10H + n); INC(i) ELSE Mark("string too long") END ;
|
||||
Texts.Read(R, ch)
|
||||
END ;
|
||||
Texts.Read(R, ch); slen := i (*no 0X appended!*)
|
||||
END HexString;
|
||||
|
||||
PROCEDURE Ten(e: LONGINT): REAL;
|
||||
VAR x, t: REAL;
|
||||
BEGIN x := 1.0; t := 10.0;
|
||||
WHILE e > 0 DO
|
||||
IF ODD(e) THEN x := t * x END ;
|
||||
t := t * t; e := e DIV 2
|
||||
END ;
|
||||
RETURN x
|
||||
END Ten;
|
||||
|
||||
PROCEDURE Number(VAR sym: INTEGER);
|
||||
CONST max = 2147483647 (*2^31 - 1*);
|
||||
VAR i, k, e, n, s, h: LONGINT; x: REAL;
|
||||
d: ARRAY 16 OF INTEGER;
|
||||
negE: BOOLEAN;
|
||||
BEGIN ival := 0; i := 0; n := 0; k := 0;
|
||||
REPEAT
|
||||
IF n < 16 THEN d[n] := ORD(ch)-30H; INC(n) ELSE Mark("too many digits"); n := 0 END ;
|
||||
Texts.Read(R, ch)
|
||||
UNTIL (ch < "0") OR (ch > "9") & (ch < "A") OR (ch > "F");
|
||||
IF (ch = "H") OR (ch = "R") OR (ch = "X") THEN (*hex*)
|
||||
REPEAT h := d[i];
|
||||
IF h >= 10 THEN h := h-7 END ;
|
||||
k := k*10H + h; INC(i) (*no overflow check*)
|
||||
UNTIL i = n;
|
||||
IF ch = "X" THEN sym := char;
|
||||
IF k < 100H THEN ival := k ELSE Mark("illegal value"); ival := 0 END
|
||||
ELSIF ch = "R" THEN sym := real; rval := SYSTEM.VAL(REAL, k)
|
||||
ELSE sym := int; ival := k
|
||||
END ;
|
||||
Texts.Read(R, ch)
|
||||
ELSIF ch = "." THEN
|
||||
Texts.Read(R, ch);
|
||||
IF ch = "." THEN (*double dot*) ch := 7FX; (*decimal integer*)
|
||||
REPEAT
|
||||
IF d[i] < 10 THEN
|
||||
IF k <= (max-d[i]) DIV 10 THEN k := k *10 + d[i] ELSE Mark("too large"); k := 0 END
|
||||
ELSE Mark("bad integer")
|
||||
END ;
|
||||
INC(i)
|
||||
UNTIL i = n;
|
||||
sym := int; ival := k
|
||||
ELSE (*real number*) x := 0.0; e := 0;
|
||||
REPEAT (*integer part*)
|
||||
(*x := x * 10.0 + FLT(d[i]); *)
|
||||
x := x * 10.0 + (d[i]); (* voc adaptation by noch *)
|
||||
INC(i)
|
||||
UNTIL i = n;
|
||||
WHILE (ch >= "0") & (ch <= "9") DO (*fraction*)
|
||||
(*x := x * 10.0 + FLT(ORD(ch) - 30H);*)
|
||||
x := x * 10.0 + (ORD(ch) - 30H); (* voc adaptation by noch *)
|
||||
DEC(e);
|
||||
Texts.Read(R, ch)
|
||||
END ;
|
||||
IF (ch = "E") OR (ch = "D") THEN (*scale factor*)
|
||||
Texts.Read(R, ch); s := 0;
|
||||
IF ch = "-" THEN negE := TRUE; Texts.Read(R, ch)
|
||||
ELSE negE := FALSE;
|
||||
IF ch = "+" THEN Texts.Read(R, ch) END
|
||||
END ;
|
||||
IF (ch >= "0") & (ch <= "9") THEN
|
||||
REPEAT s := s*10 + ORD(ch)-30H; Texts.Read(R, ch)
|
||||
UNTIL (ch < "0") OR (ch >"9");
|
||||
IF negE THEN e := e-s ELSE e := e+s END
|
||||
ELSE Mark("digit?")
|
||||
END
|
||||
END ;
|
||||
IF e < 0 THEN
|
||||
IF e >= -maxExp THEN x := x / Ten(-e) ELSE x := 0.0 END
|
||||
ELSIF e > 0 THEN
|
||||
IF e <= maxExp THEN x := Ten(e) * x ELSE x := 0.0; Mark("too large") END
|
||||
END ;
|
||||
sym := real; rval := x
|
||||
END
|
||||
ELSE (*decimal integer*)
|
||||
REPEAT
|
||||
IF d[i] < 10 THEN
|
||||
IF k <= (max-d[i]) DIV 10 THEN k := k*10 + d[i] ELSE Mark("too large"); k := 0 END
|
||||
ELSE Mark("bad integer")
|
||||
END ;
|
||||
INC(i)
|
||||
UNTIL i = n;
|
||||
sym := int; ival := k
|
||||
END
|
||||
END Number;
|
||||
|
||||
PROCEDURE comment;
|
||||
BEGIN Texts.Read(R, ch);
|
||||
REPEAT
|
||||
WHILE ~R.eot & (ch # "*") DO
|
||||
IF ch = "(" THEN Texts.Read(R, ch);
|
||||
IF ch = "*" THEN comment END
|
||||
ELSE Texts.Read(R, ch)
|
||||
END
|
||||
END ;
|
||||
WHILE ch = "*" DO Texts.Read(R, ch) END
|
||||
UNTIL (ch = ")") OR R.eot;
|
||||
IF ~R.eot THEN Texts.Read(R, ch) ELSE Mark("unterminated comment") END
|
||||
END comment;
|
||||
|
||||
PROCEDURE Get*(VAR sym: INTEGER);
|
||||
BEGIN
|
||||
REPEAT
|
||||
WHILE ~R.eot & (ch <= " ") DO Texts.Read(R, ch) END;
|
||||
IF ch < "A" THEN
|
||||
IF ch < "0" THEN
|
||||
IF ch = 22X THEN String; sym := string
|
||||
ELSIF ch = "#" THEN Texts.Read(R, ch); sym := neq
|
||||
ELSIF ch = "$" THEN HexString; sym := string
|
||||
ELSIF ch = "&" THEN Texts.Read(R, ch); sym := and
|
||||
ELSIF ch = "(" THEN Texts.Read(R, ch);
|
||||
IF ch = "*" THEN sym := null; comment ELSE sym := lparen END
|
||||
ELSIF ch = ")" THEN Texts.Read(R, ch); sym := rparen
|
||||
ELSIF ch = "*" THEN Texts.Read(R, ch); sym := times
|
||||
ELSIF ch = "+" THEN Texts.Read(R, ch); sym := plus
|
||||
ELSIF ch = "," THEN Texts.Read(R, ch); sym := comma
|
||||
ELSIF ch = "-" THEN Texts.Read(R, ch); sym := minus
|
||||
ELSIF ch = "." THEN Texts.Read(R, ch);
|
||||
IF ch = "." THEN Texts.Read(R, ch); sym := upto ELSE sym := period END
|
||||
ELSIF ch = "/" THEN Texts.Read(R, ch); sym := rdiv
|
||||
ELSE Texts.Read(R, ch); (* ! % ' *) sym := null
|
||||
END
|
||||
ELSIF ch < ":" THEN Number(sym)
|
||||
ELSIF ch = ":" THEN Texts.Read(R, ch);
|
||||
IF ch = "=" THEN Texts.Read(R, ch); sym := becomes ELSE sym := colon END
|
||||
ELSIF ch = ";" THEN Texts.Read(R, ch); sym := semicolon
|
||||
ELSIF ch = "<" THEN Texts.Read(R, ch);
|
||||
IF ch = "=" THEN Texts.Read(R, ch); sym := leq ELSE sym := lss END
|
||||
ELSIF ch = "=" THEN Texts.Read(R, ch); sym := eql
|
||||
ELSIF ch = ">" THEN Texts.Read(R, ch);
|
||||
IF ch = "=" THEN Texts.Read(R, ch); sym := geq ELSE sym := gtr END
|
||||
ELSE (* ? @ *) Texts.Read(R, ch); sym := null
|
||||
END
|
||||
ELSIF ch < "[" THEN Identifier(sym)
|
||||
ELSIF ch < "a" THEN
|
||||
IF ch = "[" THEN sym := lbrak
|
||||
ELSIF ch = "]" THEN sym := rbrak
|
||||
ELSIF ch = "^" THEN sym := arrow
|
||||
ELSE (* _ ` *) sym := null
|
||||
END ;
|
||||
Texts.Read(R, ch)
|
||||
ELSIF ch < "{" THEN Identifier(sym) ELSE
|
||||
IF ch = "{" THEN sym := lbrace
|
||||
ELSIF ch = "}" THEN sym := rbrace
|
||||
ELSIF ch = "|" THEN sym := bar
|
||||
ELSIF ch = "~" THEN sym := not
|
||||
ELSIF ch = 7FX THEN sym := upto
|
||||
ELSE sym := null
|
||||
END ;
|
||||
Texts.Read(R, ch)
|
||||
END
|
||||
UNTIL sym # null
|
||||
END Get;
|
||||
|
||||
PROCEDURE Init*(T: Texts.Text; pos: LONGINT);
|
||||
BEGIN errpos := pos; errcnt := 0; Texts.OpenReader(R, T, pos); Texts.Read(R, ch)
|
||||
END Init;
|
||||
|
||||
PROCEDURE EnterKW(sym: INTEGER; name: ARRAY OF CHAR);
|
||||
BEGIN
|
||||
(*keyTab[k].id := name; *)
|
||||
COPY(name, keyTab[k].id); (* voc adaptation by noch *)
|
||||
keyTab[k].sym := sym;
|
||||
INC(k)
|
||||
END EnterKW;
|
||||
|
||||
BEGIN Texts.OpenWriter(W); k := 0; KWX[0] := 0; KWX[1] := 0;
|
||||
EnterKW(if, "IF");
|
||||
EnterKW(do, "DO");
|
||||
EnterKW(of, "OF");
|
||||
EnterKW(or, "OR");
|
||||
EnterKW(to, "TO");
|
||||
EnterKW(in, "IN");
|
||||
EnterKW(is, "IS");
|
||||
EnterKW(by, "BY");
|
||||
KWX[2] := k;
|
||||
EnterKW(end, "END");
|
||||
EnterKW(nil, "NIL");
|
||||
EnterKW(var, "VAR");
|
||||
EnterKW(div, "DIV");
|
||||
EnterKW(mod, "MOD");
|
||||
EnterKW(for, "FOR");
|
||||
KWX[3] := k;
|
||||
EnterKW(else, "ELSE");
|
||||
EnterKW(then, "THEN");
|
||||
EnterKW(true, "TRUE");
|
||||
EnterKW(type, "TYPE");
|
||||
EnterKW(case, "CASE");
|
||||
KWX[4] := k;
|
||||
EnterKW(elsif, "ELSIF");
|
||||
EnterKW(false, "FALSE");
|
||||
EnterKW(array, "ARRAY");
|
||||
EnterKW(begin, "BEGIN");
|
||||
EnterKW(const, "CONST");
|
||||
EnterKW(until, "UNTIL");
|
||||
EnterKW(while, "WHILE");
|
||||
KWX[5] := k;
|
||||
EnterKW(record, "RECORD");
|
||||
EnterKW(repeat, "REPEAT");
|
||||
EnterKW(return, "RETURN");
|
||||
EnterKW(import, "IMPORT");
|
||||
EnterKW(module, "MODULE");
|
||||
KWX[6] := k;
|
||||
EnterKW(pointer, "POINTER");
|
||||
KWX[7] := k; KWX[8] := k;
|
||||
EnterKW(procedure, "PROCEDURE");
|
||||
KWX[9] := k
|
||||
END ORS.
|
||||
|
|
@ -1,251 +0,0 @@
|
|||
MODULE ORTool; (*NW 18.2.2013*)
|
||||
IMPORT SYSTEM, Files, Texts, Oberon, ORB;
|
||||
VAR W: Texts.Writer;
|
||||
Form: INTEGER; (*result of ReadType*)
|
||||
mnemo0, mnemo1: ARRAY 16, 4 OF CHAR; (*mnemonics*)
|
||||
|
||||
PROCEDURE Read(VAR R: Files.Rider; VAR n: INTEGER);
|
||||
VAR b: BYTE;
|
||||
BEGIN Files.ReadByte(R, b);
|
||||
IF b < 80H THEN n := b ELSE n := b - 100H END
|
||||
END Read;
|
||||
|
||||
PROCEDURE ReadType(VAR R: Files.Rider);
|
||||
VAR key, len, lev, size, off: INTEGER;
|
||||
ref, mno, class, form, readonly: INTEGER;
|
||||
name, modname: ARRAY 32 OF CHAR;
|
||||
BEGIN Read(R, ref); Texts.Write(W, " "); Texts.Write(W, "[");
|
||||
IF ref < 0 THEN Texts.Write(W, "^"); Texts.WriteInt(W, -ref, 1)
|
||||
ELSE Texts.WriteInt(W, ref, 1);
|
||||
Read(R, form); Texts.WriteString(W, " form = "); Texts.WriteInt(W, form, 1);
|
||||
IF form = ORB.Pointer THEN ReadType(R)
|
||||
ELSIF form = ORB.Array THEN
|
||||
ReadType(R); Files.ReadNum(R, len); Files.ReadNum(R, size);
|
||||
Texts.WriteString(W, " len = "); Texts.WriteInt(W, len, 1);
|
||||
Texts.WriteString(W, " size = "); Texts.WriteInt(W, size, 1)
|
||||
ELSIF form = ORB.Record THEN
|
||||
ReadType(R); (*base type*)
|
||||
Files.ReadNum(R, off); Texts.WriteString(W, " exno = "); Texts.WriteInt(W, off, 1);
|
||||
Files.ReadNum(R, off); Texts.WriteString(W, " extlev = "); Texts.WriteInt(W, off, 1);
|
||||
Files.ReadNum(R, size); Texts.WriteString(W, " size = "); Texts.WriteInt(W, size, 1);
|
||||
Texts.Write(W, " "); Texts.Write(W, "{"); Read(R, class);
|
||||
WHILE class # 0 DO (*fields*)
|
||||
Files.ReadString(R, name);
|
||||
IF name[0] # 0X THEN Texts.Write(W, " "); Texts.WriteString(W, name); ReadType(R)
|
||||
ELSE Texts.WriteString(W, " --")
|
||||
END ;
|
||||
Files.ReadNum(R, off); Texts.WriteInt(W, off, 4); Read(R, class)
|
||||
END ;
|
||||
Texts.Write(W, "}")
|
||||
ELSIF form = ORB.Proc THEN
|
||||
ReadType(R); Texts.Write(W, "("); Read(R, class);
|
||||
WHILE class # 0 DO
|
||||
Texts.WriteString(W, " class = "); Texts.WriteInt(W, class, 1); Read(R, readonly);
|
||||
IF readonly = 1 THEN Texts.Write(W, "#") END ;
|
||||
ReadType(R); Read(R, class)
|
||||
END ;
|
||||
Texts.Write(W, ")")
|
||||
END ;
|
||||
Files.ReadString(R, modname);
|
||||
IF modname[0] # 0X THEN
|
||||
Files.ReadInt(R, key); Files.ReadString(R, name);
|
||||
Texts.Write(W, " "); Texts.WriteString(W, modname); Texts.Write(W, "."); Texts.WriteString(W, name);
|
||||
Texts.WriteHex(W, key)
|
||||
END
|
||||
END ;
|
||||
Form := form; Texts.Write(W, "]")
|
||||
END ReadType;
|
||||
|
||||
PROCEDURE DecSym*; (*decode symbol file*)
|
||||
VAR class, typno, k: INTEGER;
|
||||
name: ARRAY 32 OF CHAR;
|
||||
F: Files.File; R: Files.Rider;
|
||||
S: Texts.Scanner;
|
||||
BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
|
||||
IF S.class = Texts.Name THEN
|
||||
Texts.WriteString(W, "OR-decode "); Texts.WriteString(W, S.s);
|
||||
Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf);
|
||||
F := Files.Old(S.s);
|
||||
IF F # NIL THEN
|
||||
Files.Set(R, F, 0); Files.ReadInt(R, k); Files.ReadInt(R, k);
|
||||
Files.ReadString(R, name); Texts.WriteString(W, name); Texts.WriteHex(W, k);
|
||||
Read(R, class); Texts.WriteInt(W, class, 3); (*sym file version*)
|
||||
IF class = ORB.versionkey THEN
|
||||
Texts.WriteLn(W); Read(R, class);
|
||||
WHILE class # 0 DO
|
||||
Texts.WriteInt(W, class, 4); Files.ReadString(R, name); Texts.Write(W, " "); Texts.WriteString(W, name);
|
||||
ReadType(R);
|
||||
IF class = ORB.Typ THEN
|
||||
Texts.Write(W, "("); Read(R, class);
|
||||
WHILE class # 0 DO (*pointer base fixup*)
|
||||
Texts.WriteString(W, " ->"); Texts.WriteInt(W, class, 4); Read(R, class)
|
||||
END ;
|
||||
Texts.Write(W, ")")
|
||||
ELSIF (class = ORB.Const) OR (class = ORB.Var) THEN
|
||||
Files.ReadNum(R, k); Texts.WriteInt(W, k, 5); (*Reals, Strings!*)
|
||||
END ;
|
||||
Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf);
|
||||
Read(R, class)
|
||||
END
|
||||
ELSE Texts.WriteString(W, " bad symfile version")
|
||||
END
|
||||
ELSE Texts.WriteString(W, " not found")
|
||||
END ;
|
||||
Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
|
||||
END
|
||||
END DecSym;
|
||||
|
||||
(* ---------------------------------------------------*)
|
||||
|
||||
PROCEDURE WriteReg(r: LONGINT);
|
||||
BEGIN Texts.Write(W, " ");
|
||||
IF r < 12 THEN Texts.WriteString(W, " R"); Texts.WriteInt(W, r MOD 10H, 1)
|
||||
ELSIF r = 12 THEN Texts.WriteString(W, "MT")
|
||||
ELSIF r = 13 THEN Texts.WriteString(W, "SB")
|
||||
ELSIF r = 14 THEN Texts.WriteString(W, "SP")
|
||||
ELSE Texts.WriteString(W, "LNK")
|
||||
END
|
||||
END WriteReg;
|
||||
|
||||
PROCEDURE opcode(w: LONGINT);
|
||||
VAR k, op, u, a, b, c: LONGINT;
|
||||
BEGIN
|
||||
k := w DIV 40000000H MOD 4;
|
||||
a := w DIV 1000000H MOD 10H;
|
||||
b := w DIV 100000H MOD 10H;
|
||||
op := w DIV 10000H MOD 10H;
|
||||
u := w DIV 20000000H MOD 2;
|
||||
IF k = 0 THEN
|
||||
Texts.WriteString(W, mnemo0[op]);
|
||||
IF u = 1 THEN Texts.Write(W, "'") END ;
|
||||
WriteReg(a); WriteReg(b); WriteReg(w MOD 10H)
|
||||
ELSIF k = 1 THEN
|
||||
Texts.WriteString(W, mnemo0[op]);
|
||||
IF u = 1 THEN Texts.Write(W, "'") END ;
|
||||
WriteReg(a); WriteReg(b); w := w MOD 10000H;
|
||||
IF w >= 8000H THEN w := w - 10000H END ;
|
||||
Texts.WriteInt(W, w, 7)
|
||||
ELSIF k = 2 THEN (*LDR/STR*)
|
||||
IF u = 1 THEN Texts.WriteString(W, "STR ") ELSE Texts.WriteString(W, "LDR") END ;
|
||||
WriteReg(a); WriteReg(b); w := w MOD 100000H;
|
||||
IF w >= 80000H THEN w := w - 100000H END ;
|
||||
Texts.WriteInt(W, w, 8)
|
||||
ELSIF k = 3 THEN (*Branch instr*)
|
||||
Texts.Write(W, "B");
|
||||
IF ODD(w DIV 10000000H) THEN Texts.Write(W, "L") END ;
|
||||
Texts.WriteString(W, mnemo1[a]);
|
||||
IF u = 0 THEN WriteReg(w MOD 10H) ELSE
|
||||
w := w MOD 100000H;
|
||||
IF w >= 80000H THEN w := w - 100000H END ;
|
||||
Texts.WriteInt(W, w, 8)
|
||||
END
|
||||
END
|
||||
END opcode;
|
||||
|
||||
PROCEDURE Sync(VAR R: Files.Rider);
|
||||
VAR ch: CHAR;
|
||||
BEGIN Files.Read(R, ch); Texts.WriteString(W, "Sync "); Texts.Write(W, ch); Texts.WriteLn(W)
|
||||
END Sync;
|
||||
|
||||
PROCEDURE Write(VAR R: Files.Rider; x: INTEGER);
|
||||
BEGIN Files.WriteByte(R, x) (* -128 <= x < 128 *)
|
||||
END Write;
|
||||
|
||||
PROCEDURE DecObj*; (*decode object file*)
|
||||
VAR class, i, n, key, size, fix, adr, data, len: INTEGER;
|
||||
ch: CHAR;
|
||||
name: ARRAY 32 OF CHAR;
|
||||
F: Files.File; R: Files.Rider;
|
||||
S: Texts.Scanner;
|
||||
BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
|
||||
IF S.class = Texts.Name THEN
|
||||
Texts.WriteString(W, "decode "); Texts.WriteString(W, S.s); F := Files.Old(S.s);
|
||||
IF F # NIL THEN
|
||||
Files.Set(R, F, 0); Files.ReadString(R, name); Texts.WriteLn(W); Texts.WriteString(W, name);
|
||||
Files.ReadInt(R, key); Texts.WriteHex(W, key); Read(R, class); Texts.WriteInt(W, class, 4); (*version*)
|
||||
Files.ReadInt(R, size); Texts.WriteInt(W, size, 6); Texts.WriteLn(W);
|
||||
Texts.WriteString(W, "imports:"); Texts.WriteLn(W); Files.ReadString(R, name);
|
||||
WHILE name[0] # 0X DO
|
||||
Texts.Write(W, 9X); Texts.WriteString(W, name);
|
||||
Files.ReadInt(R, key); Texts.WriteHex(W, key); Texts.WriteLn(W);
|
||||
Files.ReadString(R, name)
|
||||
END ;
|
||||
(* Sync(R); *)
|
||||
Texts.WriteString(W, "type descriptors"); Texts.WriteLn(W);
|
||||
Files.ReadInt(R, n); n := n DIV 4; i := 0;
|
||||
WHILE i < n DO Files.ReadInt(R, data); Texts.WriteHex(W, data); INC(i) END ;
|
||||
Texts.WriteLn(W);
|
||||
Texts.WriteString(W, "data"); Files.ReadInt(R, data); Texts.WriteInt(W, data, 6); Texts.WriteLn(W);
|
||||
Texts.WriteString(W, "strings"); Texts.WriteLn(W);
|
||||
Files.ReadInt(R, n); i := 0;
|
||||
WHILE i < n DO Files.Read(R, ch); Texts.Write(W, ch); INC(i) END ;
|
||||
Texts.WriteLn(W);
|
||||
Texts.WriteString(W, "code"); Texts.WriteLn(W);
|
||||
Files.ReadInt(R, n); i := 0;
|
||||
WHILE i < n DO
|
||||
Files.ReadInt(R, data); Texts.WriteInt(W, i, 4); Texts.Write(W, 9X); Texts.WriteHex(W, data);
|
||||
Texts.Write(W, 9X); opcode(data); Texts.WriteLn(W); INC(i)
|
||||
END ;
|
||||
(* Sync(R); *)
|
||||
Texts.WriteString(W, "commands:"); Texts.WriteLn(W);
|
||||
Files.ReadString(R, name);
|
||||
WHILE name[0] # 0X DO
|
||||
Texts.Write(W, 9X); Texts.WriteString(W, name);
|
||||
Files.ReadInt(R, adr); Texts.WriteInt(W, adr, 5); Texts.WriteLn(W);
|
||||
Files.ReadString(R, name)
|
||||
END ;
|
||||
(* Sync(R); *)
|
||||
Texts.WriteString(W, "entries"); Texts.WriteLn(W);
|
||||
Files.ReadInt(R, n); i := 0;
|
||||
WHILE i < n DO
|
||||
Files.ReadInt(R, adr); Texts.WriteInt(W, adr, 6); INC(i)
|
||||
END ;
|
||||
Texts.WriteLn(W);
|
||||
(* Sync(R); *)
|
||||
Texts.WriteString(W, "pointer refs"); Texts.WriteLn(W); Files.ReadInt(R, adr);
|
||||
WHILE adr # -1 DO Texts.WriteInt(W, adr, 6); Files.ReadInt(R, adr) END ;
|
||||
Texts.WriteLn(W);
|
||||
(* Sync(R); *)
|
||||
Files.ReadInt(R, data); Texts.WriteString(W, "fixP = "); Texts.WriteInt(W, data, 8); Texts.WriteLn(W);
|
||||
Files.ReadInt(R, data); Texts.WriteString(W, "fixD = "); Texts.WriteInt(W, data, 8); Texts.WriteLn(W);
|
||||
Files.ReadInt(R, data); Texts.WriteString(W, "fixT = "); Texts.WriteInt(W, data, 8); Texts.WriteLn(W);
|
||||
Files.ReadInt(R, data); Texts.WriteString(W, "entry = "); Texts.WriteInt(W, data, 8); Texts.WriteLn(W);
|
||||
Files.Read(R, ch);
|
||||
IF ch # "O" THEN Texts.WriteString(W, "format eror"); Texts.WriteLn(W) END
|
||||
(* Sync(R); *)
|
||||
ELSE Texts.WriteString(W, " not found"); Texts.WriteLn(W)
|
||||
END ;
|
||||
Texts.Append(Oberon.Log, W.buf)
|
||||
END
|
||||
END DecObj;
|
||||
|
||||
BEGIN Texts.OpenWriter(W); Texts.WriteString(W, "ORTool 18.2.2013");
|
||||
Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf);
|
||||
mnemo0[0] := "MOV";
|
||||
mnemo0[1] := "LSL";
|
||||
mnemo0[2] := "ASR";
|
||||
mnemo0[3] := "ROR";
|
||||
mnemo0[4] := "AND";
|
||||
mnemo0[5] := "ANN";
|
||||
mnemo0[6] := "IOR";
|
||||
mnemo0[7] := "XOR";
|
||||
mnemo0[8] := "ADD";
|
||||
mnemo0[9] := "SUB";
|
||||
mnemo0[10] := "MUL";
|
||||
mnemo0[11] := "DIV";
|
||||
mnemo0[12] := "FAD";
|
||||
mnemo0[13] := "FSB";
|
||||
mnemo0[14] := "FML";
|
||||
mnemo0[15] := "FDV";
|
||||
mnemo1[0] := "MI ";
|
||||
mnemo1[8] := "PL";
|
||||
mnemo1[1] := "EQ ";
|
||||
mnemo1[9] := "NE ";
|
||||
mnemo1[2] := "LS ";
|
||||
mnemo1[10] := "HI ";
|
||||
mnemo1[5] := "LT ";
|
||||
mnemo1[13] := "GE ";
|
||||
mnemo1[6] := "LE ";
|
||||
mnemo1[14] := "GT ";
|
||||
mnemo1[15] := "NO ";
|
||||
END ORTool.
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
MODULE Oberon;
|
||||
|
||||
(* this module emulates Oberon.Log and Oberon.Par in order to pass agruments to Oberon programs, as it's in Oberon environment;
|
||||
it creates Oberon.Par from command line arguments;
|
||||
procedure Dump dumps Oberon.Log to standard output.
|
||||
|
||||
-- noch *)
|
||||
|
||||
(* Files are commented out, because it's not necessary for work, but can be very useful for debug. See WriteTextToFile procedure; -- noch *)
|
||||
IMPORT Args, Strings, Texts := CompatTexts, (*Files := CompatFiles,*) Out := Console;
|
||||
|
||||
VAR Log*: Texts.Text;
|
||||
|
||||
Par*: RECORD
|
||||
text*: Texts.Text;
|
||||
pos* : LONGINT;
|
||||
END;
|
||||
|
||||
arguments : ARRAY 2048 OF CHAR;
|
||||
|
||||
PROCEDURE GetSelection* (VAR text: Texts.Text; VAR beg, end, time: LONGINT);
|
||||
(*VAR M: SelectionMsg;*)
|
||||
BEGIN
|
||||
(*M.time := -1; Viewers.Broadcast(M); time := M.time;
|
||||
IF time >= 0 THEN text := M.text; beg := M.beg; end := M.end END*)
|
||||
END GetSelection;
|
||||
|
||||
PROCEDURE Collect*( count : LONGINT);
|
||||
BEGIN
|
||||
|
||||
END Collect;
|
||||
|
||||
PROCEDURE ArgsToString(VAR opts : ARRAY OF CHAR);
|
||||
VAR i : INTEGER;
|
||||
opt : ARRAY 256 OF CHAR;
|
||||
BEGIN
|
||||
|
||||
i := 1;
|
||||
opt := ""; COPY ("", opts);
|
||||
|
||||
WHILE i < Args.argc DO
|
||||
Args.Get(i, opt);
|
||||
Strings.Append(opt, opts);(* Strings.Append (" ", opts);*)
|
||||
(* ORP calls Texts.Scan, which returns filename, and nextCh would be set to " " if we append here " ". However after that ORP will check nextCh, and if it finds that nextCh is not "/" it's not gonna parse options. That's why Strings.Append is commented out; -- noch *)
|
||||
INC(i)
|
||||
END;
|
||||
|
||||
END ArgsToString;
|
||||
|
||||
PROCEDURE StringToText(VAR arguments : ARRAY OF CHAR; VAR T : Texts.Text);
|
||||
VAR
|
||||
W : Texts.Writer;
|
||||
BEGIN
|
||||
Texts.OpenWriter(W);
|
||||
Texts.WriteString(W, arguments);
|
||||
Texts.Append (T, W.buf);
|
||||
END StringToText;
|
||||
(*
|
||||
PROCEDURE WriteTextToFile(VAR T : Texts.Text; filename : ARRAY OF CHAR);
|
||||
VAR f : Files.File; r : Files.Rider;
|
||||
BEGIN
|
||||
f := Files.New(filename);
|
||||
Files.Set(r, f, 0);
|
||||
Texts.Store(r, T);
|
||||
Files.Register(f);
|
||||
END WriteTextToFile;
|
||||
*)
|
||||
PROCEDURE TextToString(VAR T : Texts.Text; VAR string : ARRAY OF CHAR);
|
||||
VAR R : Texts.Reader;
|
||||
ch : CHAR;
|
||||
i : LONGINT;
|
||||
BEGIN
|
||||
COPY("", string);
|
||||
Texts.OpenReader(R, T, 0);
|
||||
i := 0;
|
||||
WHILE Texts.Pos(R) < T.len DO
|
||||
Texts.Read(R, ch);
|
||||
string[i] := ch;
|
||||
INC(i);
|
||||
END;
|
||||
(*string[i] := 0X;*)
|
||||
END TextToString;
|
||||
|
||||
PROCEDURE DumpLog*;
|
||||
VAR s : POINTER TO ARRAY OF CHAR;
|
||||
BEGIN
|
||||
NEW(s, Log.len + 1);
|
||||
COPY("", s^);
|
||||
TextToString(Log, s^);
|
||||
Out.String(s^); Out.Ln;
|
||||
|
||||
NEW(Log);
|
||||
Texts.Open(Log, "");
|
||||
END DumpLog;
|
||||
|
||||
|
||||
BEGIN
|
||||
NEW(Log);
|
||||
Texts.Open(Log, "");
|
||||
|
||||
NEW(Par.text);
|
||||
Texts.Open(Par.text, "");
|
||||
Par.pos := 0;
|
||||
|
||||
COPY("", arguments);
|
||||
ArgsToString(arguments);
|
||||
StringToText(arguments, Par.text);
|
||||
(*WriteTextToFile(Par.text, "params.txt");*)
|
||||
(*WriteTextToFile(Log, "log.txt");*)
|
||||
(*DumpLog;*)
|
||||
END Oberon.
|
||||
Binary file not shown.
|
|
@ -1,29 +0,0 @@
|
|||
|
||||
RISC crosscompiler
|
||||
==================
|
||||
|
||||
This is a version of re re revised Oberon compiler for Wirth's RISC machine which can be compiled and run with VOC (Vishap Oberon Compiler) on supported platforms.
|
||||
|
||||
Files generated can be transferred to RISC machine or emulator and be run there.
|
||||
|
||||
Compile
|
||||
=======
|
||||
|
||||
If you have vishap oberon compiler installed, just type
|
||||
>make
|
||||
|
||||
Run
|
||||
===
|
||||
|
||||
>./ORP test.Mod /s
|
||||
|
||||
like that.
|
||||
|
||||
you may need symbol (.smb) files from RISC Oberon system in order to write programs that import some modules.
|
||||
|
||||
some answers
|
||||
============
|
||||
|
||||
- why Oberon10.Scn.Fnt ?
|
||||
- it's actually not really necessary. because Texts are patched (test for NIL) to not crash if this file does not exist. however, unless I remove dependency from Fonts.Mod I have decided to keep this file here, and thus my added test for NIL is not necessary, and generated output file is completely correct Oberon Text file. Otherwise it would not contain the font name, for instance.
|
||||
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
|
||||
SETPATH = MODULES=".:x86_64"
|
||||
|
||||
VOC0 = $(SETPATH) /opt/voc/bin/voc
|
||||
|
||||
all:
|
||||
#$(VOC0) -s ORS.Mod
|
||||
#$(VOC0) -s ORB.Mod
|
||||
#$(VOC0) -s ORG.Mod
|
||||
$(VOC0) -s CompatFiles.Mod \
|
||||
Fonts.Mod CompatTexts.Mod Oberon.Mod \
|
||||
ORS.Mod ORB.Mod ORG.Mod ORP.Mod -M
|
||||
|
||||
test:
|
||||
./ORP -s test.Mod
|
||||
|
||||
clean:
|
||||
rm *.sym
|
||||
rm *.o
|
||||
rm *.h
|
||||
rm *.c
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,3 +0,0 @@
|
|||
put ORP binary here and run
|
||||
|
||||
> ./ORP Test.Mod
|
||||
|
|
@ -1,677 +0,0 @@
|
|||
MODULE CompatFiles; (* J. Templ 1.12. 89/12.4.95 Oberon files mapped onto Unix files *)
|
||||
(* modified version of Files, which opens only the file provided and does not scan any path in any environment variable, also ReadLine procedure added; -- noch *)
|
||||
IMPORT SYSTEM, Unix, Kernel, Args, Console;
|
||||
|
||||
(* standard data type I/O
|
||||
|
||||
little endian,
|
||||
Sint:1, Int:2, Lint:4
|
||||
ORD({0}) = 1,
|
||||
false = 0, true =1
|
||||
IEEE real format,
|
||||
null terminated strings,
|
||||
compact numbers according to M.Odersky *)
|
||||
|
||||
|
||||
CONST
|
||||
nofbufs = 4;
|
||||
bufsize = 4096;
|
||||
fileTabSize = 64;
|
||||
noDesc = -1;
|
||||
notDone = -1;
|
||||
|
||||
(* file states *)
|
||||
open = 0; create = 1; close = 2;
|
||||
|
||||
|
||||
TYPE
|
||||
FileName = ARRAY 101 OF CHAR;
|
||||
File* = POINTER TO Handle;
|
||||
Buffer = POINTER TO BufDesc;
|
||||
|
||||
Handle = RECORD
|
||||
workName, registerName: FileName;
|
||||
tempFile: BOOLEAN;
|
||||
dev, ino, mtime: LONGINT;
|
||||
fd-, len, pos: LONGINT;
|
||||
bufs: ARRAY nofbufs OF Buffer;
|
||||
swapper, state: INTEGER
|
||||
END ;
|
||||
|
||||
BufDesc = RECORD
|
||||
f: File;
|
||||
chg: BOOLEAN;
|
||||
org, size: LONGINT;
|
||||
data: ARRAY bufsize OF SYSTEM.BYTE
|
||||
END ;
|
||||
|
||||
Rider* = RECORD
|
||||
res*: LONGINT;
|
||||
eof*: BOOLEAN;
|
||||
buf: Buffer;
|
||||
org, offset: LONGINT
|
||||
END ;
|
||||
|
||||
Time = POINTER TO TimeDesc;
|
||||
TimeDesc = RECORD
|
||||
sec*, min*, hour*, mday*, mon*, year*, wday*, isdst*, zone*, gmtoff*: LONGINT;
|
||||
(* sec*, min*, hour*, mday*, mon*, year*, wday*, isdst*, zone*, gmtoff*: INTEGER;*)
|
||||
END ;
|
||||
|
||||
VAR
|
||||
fileTab: ARRAY fileTabSize OF LONGINT (*=File*);
|
||||
tempno: INTEGER;
|
||||
|
||||
(* for localtime *)
|
||||
PROCEDURE -includetime()
|
||||
'#include "time.h"';
|
||||
|
||||
PROCEDURE -localtime(VAR clock: LONGINT): Time
|
||||
"(CompatFiles_Time) localtime(clock)";
|
||||
|
||||
PROCEDURE -getcwd(VAR cwd: Unix.Name)
|
||||
"getcwd(cwd, cwd__len)";
|
||||
|
||||
PROCEDURE -IdxTrap "__HALT(-1)";
|
||||
|
||||
PROCEDURE^ Finalize(o: SYSTEM.PTR);
|
||||
|
||||
PROCEDURE Err(s: ARRAY OF CHAR; f: File; errno: LONGINT);
|
||||
BEGIN
|
||||
Console.Ln; Console.String("-- "); Console.String(s); Console.String(": ");
|
||||
IF f # NIL THEN
|
||||
IF f.registerName # "" THEN Console.String(f.registerName) ELSE Console.String(f.workName) END
|
||||
END ;
|
||||
IF errno # 0 THEN Console.String(" errno = "); Console.Int(errno, 1) END ;
|
||||
Console.Ln;
|
||||
HALT(99)
|
||||
END Err;
|
||||
|
||||
PROCEDURE MakeFileName(dir, name: ARRAY OF CHAR; VAR dest: ARRAY OF CHAR);
|
||||
VAR i, j: INTEGER;
|
||||
BEGIN i := 0; j := 0;
|
||||
WHILE dir[i] # 0X DO dest[i] := dir[i]; INC(i) END ;
|
||||
IF dest[i-1] # "/" THEN dest[i] := "/"; INC(i) END ;
|
||||
WHILE name[j] # 0X DO dest[i] := name[j]; INC(i); INC(j) END ;
|
||||
dest[i] := 0X
|
||||
END MakeFileName;
|
||||
|
||||
PROCEDURE GetTempName(finalName: ARRAY OF CHAR; VAR name: ARRAY OF CHAR);
|
||||
VAR n, i, j: LONGINT;
|
||||
BEGIN
|
||||
INC(tempno); n := tempno; i := 0;
|
||||
IF finalName[0] # "/" THEN (* relative pathname *)
|
||||
WHILE Kernel.CWD[i] # 0X DO name[i] := Kernel.CWD[i]; INC(i) END;
|
||||
IF Kernel.CWD[i-1] # "/" THEN name[i] := "/"; INC(i) END
|
||||
END;
|
||||
j := 0;
|
||||
WHILE finalName[j] # 0X DO name[i] := finalName[j]; INC(i); INC(j) END;
|
||||
DEC(i);
|
||||
WHILE name[i] # "/" DO DEC(i) END;
|
||||
name[i+1] := "."; name[i+2] := "t"; name[i+3] := "m"; name[i+4] := "p"; name[i+5] := "."; INC(i, 6);
|
||||
WHILE n > 0 DO name[i] := CHR(n MOD 10 + ORD("0")); n := n DIV 10; INC(i) END;
|
||||
name[i] := "."; INC(i); n := SHORT(Unix.Getpid());
|
||||
WHILE n > 0 DO name[i] := CHR(n MOD 10 + ORD("0")); n := n DIV 10; INC(i) END;
|
||||
name[i] := 0X
|
||||
END GetTempName;
|
||||
|
||||
PROCEDURE Create(f: File);
|
||||
VAR stat: Unix.Status; done: BOOLEAN;
|
||||
errno: LONGINT; err: ARRAY 32 OF CHAR;
|
||||
BEGIN
|
||||
IF f.fd = noDesc THEN
|
||||
IF f.state = create THEN GetTempName(f.registerName, f.workName); f.tempFile := TRUE
|
||||
ELSIF f.state = close THEN
|
||||
f.workName := f.registerName; f.registerName := ""; f.tempFile := FALSE
|
||||
END ;
|
||||
errno := Unix.Unlink(f.workName); (*unlink first to avoid stale NFS handles and to avoid reuse of inodes*)
|
||||
f.fd := Unix.Open(f.workName, Unix.rdwr + Unix.creat + Unix.trunc, {2, 4,5, 7,8});
|
||||
done := f.fd >= 0; errno := Unix.errno();
|
||||
IF (~done & ((errno = Unix.ENFILE) OR (errno = Unix.EMFILE))) OR (done & (f.fd >= fileTabSize)) THEN
|
||||
IF done & (f.fd >= fileTabSize) THEN errno := Unix.Close(f.fd) END ;
|
||||
Kernel.GC(TRUE);
|
||||
f.fd := Unix.Open(f.workName, Unix.rdwr + Unix.creat + Unix.trunc, {2, 4,5, 7,8});
|
||||
done := f.fd >= 0
|
||||
END ;
|
||||
IF done THEN
|
||||
IF f.fd >= fileTabSize THEN errno := Unix.Close(f.fd); Err("too many files open", f, 0)
|
||||
ELSE fileTab[f.fd] := SYSTEM.VAL(LONGINT, f); INC(Kernel.nofiles); Kernel.RegisterObject(f, Finalize);
|
||||
f.state := open; f.pos := 0; errno := Unix.Fstat(f.fd, stat);
|
||||
f.dev := stat.dev; f.ino := stat.ino; f.mtime := stat.mtime
|
||||
END
|
||||
ELSE errno := Unix.errno();
|
||||
IF errno = Unix.ENOENT THEN err := "no such directory"
|
||||
ELSIF (errno = Unix.ENFILE) OR (errno = Unix.EMFILE) THEN err := "too many files open"
|
||||
ELSE err := "file not created"
|
||||
END ;
|
||||
Err(err, f, errno)
|
||||
END
|
||||
END
|
||||
END Create;
|
||||
|
||||
PROCEDURE Flush(buf: Buffer);
|
||||
VAR res: LONGINT; f: File; stat: Unix.Status;
|
||||
BEGIN
|
||||
IF buf.chg THEN f := buf.f; Create(f);
|
||||
IF buf.org # f.pos THEN res := Unix.Lseek(f.fd, buf.org, 0) END ;
|
||||
res := Unix.Write(f.fd, SYSTEM.ADR(buf.data), buf.size);
|
||||
IF res < 0 THEN Err("error in writing file", f, Unix.errno()) END ;
|
||||
f.pos := buf.org + buf.size;
|
||||
buf.chg := FALSE;
|
||||
res := Unix.Fstat(f.fd, stat);
|
||||
f.mtime := stat.mtime
|
||||
END
|
||||
END Flush;
|
||||
|
||||
PROCEDURE Close* (f: File);
|
||||
VAR i, res: LONGINT;
|
||||
BEGIN
|
||||
IF (f.state # create) OR (f.registerName # "") THEN
|
||||
Create(f); i := 0;
|
||||
WHILE (i < nofbufs) & (f.bufs[i] # NIL) DO Flush(f.bufs[i]); INC(i) END ;
|
||||
res := Unix.Fsync(f.fd);
|
||||
IF res < 0 THEN Err("error in writing file", f, Unix.errno()) END
|
||||
END
|
||||
END Close;
|
||||
|
||||
PROCEDURE Length* (f: File): LONGINT;
|
||||
BEGIN RETURN f.len
|
||||
END Length;
|
||||
|
||||
PROCEDURE New* (name: ARRAY OF CHAR): File;
|
||||
VAR f: File;
|
||||
BEGIN
|
||||
NEW(f); f.workName := ""; COPY(name, f.registerName);
|
||||
f.fd := noDesc; f.state := create; f.len := 0; f.pos := 0; f.swapper := -1; (*all f.buf[i] = NIL*)
|
||||
RETURN f
|
||||
END New;
|
||||
(*
|
||||
PROCEDURE ScanPath(VAR pos: INTEGER; VAR dir: ARRAY OF CHAR); (* supports ~, ~user and blanks inside path *)
|
||||
VAR i: INTEGER; ch: CHAR; home: ARRAY 256 OF CHAR;
|
||||
BEGIN
|
||||
i := 0; ch := Kernel.OBERON[pos];
|
||||
WHILE (ch = " ") OR (ch = ":") DO INC(pos); ch := Kernel.OBERON[pos] END ;
|
||||
IF ch = "~" THEN
|
||||
INC(pos); ch := Kernel.OBERON[pos];
|
||||
home := ""; Args.GetEnv("HOME", home);
|
||||
WHILE home[i] # 0X DO dir[i] := home[i]; INC(i) END ;
|
||||
IF (ch # "/") & (ch # 0X) & (ch # ":") & (ch # " ") THEN
|
||||
WHILE (i > 0) & (dir[i-1] # "/") DO DEC(i) END
|
||||
END
|
||||
END ;
|
||||
WHILE (ch # 0X) & (ch # ":") DO dir[i] := ch; INC(i); INC(pos); ch := Kernel.OBERON[pos] END ;
|
||||
WHILE (i > 0) & (dir[i-1] = " ") DO DEC(i) END ;
|
||||
dir[i] := 0X
|
||||
END ScanPath;
|
||||
*)
|
||||
PROCEDURE HasDir(VAR name: ARRAY OF CHAR): BOOLEAN;
|
||||
VAR i: INTEGER; ch: CHAR;
|
||||
BEGIN i := 0; ch := name[0];
|
||||
WHILE (ch # 0X) & (ch # "/") DO INC(i); ch := name[i] END ;
|
||||
RETURN ch = "/"
|
||||
END HasDir;
|
||||
|
||||
PROCEDURE CacheEntry(dev, ino: LONGINT; mtime: LONGINT): File;
|
||||
VAR f: File; i: INTEGER; stat: Unix.Status; res: LONGINT;
|
||||
BEGIN i := 0;
|
||||
WHILE i < fileTabSize DO
|
||||
f := SYSTEM.VAL(File, fileTab[i]);
|
||||
IF (f # NIL) & (ino = f.ino) & (dev = f.dev) THEN
|
||||
IF mtime # f.mtime THEN i := 0;
|
||||
WHILE i < nofbufs DO
|
||||
IF f.bufs[i] # NIL THEN f.bufs[i].org := -1; f.bufs[i] := NIL END ;
|
||||
INC(i)
|
||||
END ;
|
||||
f.swapper := -1; f.mtime := mtime;
|
||||
res := Unix.Fstat(f.fd, stat); f.len := stat.size
|
||||
END ;
|
||||
RETURN f
|
||||
END ;
|
||||
INC(i)
|
||||
END ;
|
||||
RETURN NIL
|
||||
END CacheEntry;
|
||||
|
||||
PROCEDURE Old* (name: ARRAY OF CHAR): File;
|
||||
VAR f: File; fd, res, errno: LONGINT; pos: INTEGER; done: BOOLEAN;
|
||||
dir, path: ARRAY 256 OF CHAR;
|
||||
stat: Unix.Status;
|
||||
BEGIN
|
||||
IF name # "" THEN
|
||||
IF HasDir(name) THEN dir := ""; COPY(name, path)
|
||||
ELSE
|
||||
pos := 0;
|
||||
COPY(name, path); (* -- noch *)
|
||||
(*ScanPath(pos, dir);*) (*MakeFileName(dir, name, path);*) (*ScanPath(pos, dir)*)
|
||||
END ;
|
||||
LOOP
|
||||
fd := Unix.Open(path, Unix.rdwr, {}); done := fd >= 0; errno := Unix.errno();
|
||||
IF (~done & ((errno = Unix.ENFILE) OR (errno = Unix.EMFILE))) OR (done & (fd >= fileTabSize)) THEN
|
||||
IF done & (fd >= fileTabSize) THEN res := Unix.Close(fd) END ;
|
||||
Kernel.GC(TRUE);
|
||||
fd := Unix.Open(path, Unix.rdwr, {});
|
||||
done := fd >= 0; errno := Unix.errno();
|
||||
IF ~done & ((errno = Unix.ENFILE) OR (errno = Unix.EMFILE)) THEN Err("too many files open", f, errno) END
|
||||
END ;
|
||||
IF ~done & ((errno = Unix.EACCES) OR (errno = Unix.EROFS) OR (errno = Unix.EAGAIN)) THEN
|
||||
(* errno EAGAIN observed on Solaris 2.4 *)
|
||||
fd := Unix.Open(path, Unix.rdonly, {}); done := fd >= 0; errno := Unix.errno()
|
||||
END ;
|
||||
IF (~done) & (errno # Unix.ENOENT) THEN
|
||||
Console.String("warning Files.Old "); Console.String(name);
|
||||
Console.String(" errno = "); Console.Int(errno, 0); Console.Ln;
|
||||
END ;
|
||||
IF done THEN
|
||||
res := Unix.Fstat(fd, stat);
|
||||
f := CacheEntry(stat.dev, stat.ino, stat.mtime);
|
||||
IF f # NIL THEN res := Unix.Close(fd); RETURN f
|
||||
ELSIF fd >= fileTabSize THEN res := Unix.Close(fd); Err("too many files open", f, 0)
|
||||
ELSE NEW(f); fileTab[fd] := SYSTEM.VAL(LONGINT, f); INC(Kernel.nofiles); Kernel.RegisterObject(f, Finalize);
|
||||
f.fd := fd; f.state := open; f.len := stat.size; f.pos := 0; f.swapper := -1; (*all f.buf[i] = NIL*)
|
||||
COPY(name, f.workName); f.registerName := ""; f.tempFile := FALSE;
|
||||
f.dev := stat.dev; f.ino := stat.ino; f.mtime := stat.mtime;
|
||||
RETURN f
|
||||
END
|
||||
ELSIF dir = "" THEN RETURN NIL
|
||||
ELSE (*MakeFileName(dir, name, path);*) (*ScanPath(pos, dir)*)
|
||||
RETURN NIL
|
||||
END
|
||||
END
|
||||
ELSE RETURN NIL
|
||||
END
|
||||
END Old;
|
||||
|
||||
PROCEDURE Purge* (f: File);
|
||||
VAR i: INTEGER; stat: Unix.Status; res: LONGINT;
|
||||
BEGIN i := 0;
|
||||
WHILE i < nofbufs DO
|
||||
IF f.bufs[i] # NIL THEN f.bufs[i].org := -1; f.bufs[i] := NIL END ;
|
||||
INC(i)
|
||||
END ;
|
||||
IF f.fd # noDesc THEN res := Unix.Ftruncate(f.fd, 0); res := Unix.Lseek(f.fd, 0, 0) END ;
|
||||
f.pos := 0; f.len := 0; f.swapper := -1;
|
||||
res := Unix.Fstat(f.fd, stat); f.mtime := stat.mtime
|
||||
END Purge;
|
||||
|
||||
PROCEDURE GetDate* (f: File; VAR t, d: LONGINT);
|
||||
VAR stat: Unix.Status; clock, res: LONGINT; time: Time;
|
||||
BEGIN
|
||||
Create(f); res := Unix.Fstat(f.fd, stat);
|
||||
time := localtime(stat.mtime);
|
||||
t := time.sec + ASH(time.min, 6) + ASH(time.hour, 12);
|
||||
d := time.mday + ASH(time.mon+1, 5) + ASH(time.year MOD 100, 9)
|
||||
END GetDate;
|
||||
|
||||
PROCEDURE Pos* (VAR r: Rider): LONGINT;
|
||||
BEGIN RETURN r.org + r.offset
|
||||
END Pos;
|
||||
|
||||
PROCEDURE Set* (VAR r: Rider; f: File; pos: LONGINT);
|
||||
VAR org, offset, i, n, res: LONGINT; buf: Buffer;
|
||||
BEGIN
|
||||
IF f # NIL THEN
|
||||
IF pos > f.len THEN pos := f.len ELSIF pos < 0 THEN pos := 0 END ;
|
||||
offset := pos MOD bufsize; org := pos - offset; i := 0;
|
||||
WHILE (i < nofbufs) & (f.bufs[i] # NIL) & (org # f.bufs[i].org) DO INC(i) END ;
|
||||
IF i < nofbufs THEN
|
||||
IF f.bufs[i] = NIL THEN NEW(buf); buf.chg := FALSE; buf.org := -1; buf.f := f; f.bufs[i] := buf
|
||||
ELSE buf := f.bufs[i]
|
||||
END
|
||||
ELSE
|
||||
f.swapper := (f.swapper + 1) MOD nofbufs;
|
||||
buf := f.bufs[f.swapper];
|
||||
Flush(buf)
|
||||
END ;
|
||||
IF buf.org # org THEN
|
||||
IF org = f.len THEN buf.size := 0
|
||||
ELSE Create(f);
|
||||
IF f.pos # org THEN res := Unix.Lseek(f.fd, org, 0) END ;
|
||||
n := Unix.ReadBlk(f.fd, buf.data);
|
||||
IF n < 0 THEN Err("read from file not done", f, Unix.errno()) END ;
|
||||
f.pos := org + n;
|
||||
buf.size := n
|
||||
END ;
|
||||
buf.org := org; buf.chg := FALSE
|
||||
END
|
||||
ELSE buf := NIL; org := 0; offset := 0
|
||||
END ;
|
||||
r.buf := buf; r.org := org; r.offset := offset; r.eof := FALSE; r.res := 0
|
||||
END Set;
|
||||
|
||||
PROCEDURE Read* (VAR r: Rider; VAR x: SYSTEM.BYTE);
|
||||
VAR offset: LONGINT; buf: Buffer;
|
||||
BEGIN
|
||||
buf := r.buf; offset := r.offset;
|
||||
IF r.org # buf.org THEN Set(r, buf.f, r.org + offset); buf := r.buf; offset := r.offset END ;
|
||||
IF (offset < buf.size) THEN
|
||||
x := buf.data[offset]; r.offset := offset + 1
|
||||
ELSIF r.org + offset < buf.f.len THEN
|
||||
Set(r, r.buf.f, r.org + offset);
|
||||
x := r.buf.data[0]; r.offset := 1
|
||||
ELSE
|
||||
x := 0X; r.eof := TRUE
|
||||
END
|
||||
END Read;
|
||||
|
||||
PROCEDURE ReadBytes* (VAR r: Rider; VAR x: ARRAY OF SYSTEM.BYTE; n: LONGINT);
|
||||
VAR xpos, min, restInBuf, offset: LONGINT; buf: Buffer;
|
||||
BEGIN
|
||||
IF n > LEN(x) THEN IdxTrap END ;
|
||||
xpos := 0; buf := r.buf; offset := r.offset;
|
||||
WHILE n > 0 DO
|
||||
IF (r.org # buf.org) OR (offset >= bufsize) THEN
|
||||
Set(r, buf.f, r.org + offset);
|
||||
buf := r.buf; offset := r.offset
|
||||
END ;
|
||||
restInBuf := buf.size - offset;
|
||||
IF restInBuf = 0 THEN r.res := n; r.eof := TRUE; RETURN
|
||||
ELSIF n > restInBuf THEN min := restInBuf ELSE min := n END ;
|
||||
SYSTEM.MOVE(SYSTEM.ADR(buf.data) + offset, SYSTEM.ADR(x) + xpos, min);
|
||||
INC(offset, min); r.offset := offset; INC(xpos, min); DEC(n, min)
|
||||
END ;
|
||||
r.res := 0; r.eof := FALSE
|
||||
END ReadBytes;
|
||||
|
||||
PROCEDURE ReadByte* (VAR r : Rider; VAR x : ARRAY OF SYSTEM.BYTE);
|
||||
BEGIN
|
||||
ReadBytes(r, x, 1);
|
||||
END ReadByte;
|
||||
|
||||
PROCEDURE Base* (VAR r: Rider): File;
|
||||
BEGIN RETURN r.buf.f
|
||||
END Base;
|
||||
|
||||
PROCEDURE Write* (VAR r: Rider; x: SYSTEM.BYTE);
|
||||
VAR buf: Buffer; offset: LONGINT;
|
||||
BEGIN
|
||||
buf := r.buf; offset := r.offset;
|
||||
IF (r.org # buf.org) OR (offset >= bufsize) THEN
|
||||
Set(r, buf.f, r.org + offset);
|
||||
buf := r.buf; offset := r.offset
|
||||
END ;
|
||||
buf.data[offset] := x;
|
||||
buf.chg := TRUE;
|
||||
IF offset = buf.size THEN
|
||||
INC(buf.size); INC(buf.f.len)
|
||||
END ;
|
||||
r.offset := offset + 1; r.res := 0
|
||||
END Write;
|
||||
|
||||
PROCEDURE WriteByte* (VAR r : Rider; x : SYSTEM.BYTE); (* added for compatibility with PO 2013, -- noch *)
|
||||
BEGIN
|
||||
Write(r, x);
|
||||
END WriteByte;
|
||||
|
||||
PROCEDURE WriteBytes* (VAR r: Rider; VAR x: ARRAY OF SYSTEM.BYTE; n: LONGINT);
|
||||
VAR xpos, min, restInBuf, offset: LONGINT; buf: Buffer;
|
||||
BEGIN
|
||||
IF n > LEN(x) THEN IdxTrap END ;
|
||||
xpos := 0; buf := r.buf; offset := r.offset;
|
||||
WHILE n > 0 DO
|
||||
IF (r.org # buf.org) OR (offset >= bufsize) THEN
|
||||
Set(r, buf.f, r.org + offset);
|
||||
buf := r.buf; offset := r.offset
|
||||
END ;
|
||||
restInBuf := bufsize - offset;
|
||||
IF n > restInBuf THEN min := restInBuf ELSE min := n END ;
|
||||
SYSTEM.MOVE(SYSTEM.ADR(x) + xpos, SYSTEM.ADR(buf.data) + offset, min);
|
||||
INC(offset, min); r.offset := offset;
|
||||
IF offset > buf.size THEN INC(buf.f.len, offset - buf.size); buf.size := offset END ;
|
||||
INC(xpos, min); DEC(n, min); buf.chg := TRUE
|
||||
END ;
|
||||
r.res := 0
|
||||
END WriteBytes;
|
||||
|
||||
(* another solution would be one that is similar to ReadBytes, WriteBytes.
|
||||
No code duplication, more symmetric, only two ifs for
|
||||
Read and Write in buffer, buf.size replaced by bufsize in Write ops, buf.size and len
|
||||
must be made consistent with offset (if offset > buf.size) in a lazy way.
|
||||
|
||||
PROCEDURE Write* (VAR r: Rider; x: SYSTEM.BYTE);
|
||||
VAR buf: Buffer; offset: LONGINT;
|
||||
BEGIN
|
||||
buf := r.buf; offset := r.offset;
|
||||
IF (offset >= bufsize) OR (r.org # buf.org) THEN
|
||||
Set(r, buf.f, r.org + offset); buf := r.buf; offset := r.offset;
|
||||
END ;
|
||||
buf.data[offset] := x; r.offset := offset + 1; buf.chg := TRUE
|
||||
END Write;
|
||||
|
||||
|
||||
PROCEDURE WriteBytes ...
|
||||
|
||||
PROCEDURE Read* (VAR r: Rider; VAR x: SYSTEM.BYTE);
|
||||
VAR offset: LONGINT; buf: Buffer;
|
||||
BEGIN
|
||||
buf := r.buf; offset := r.offset;
|
||||
IF (offset >= buf.size) OR (r.org # buf.org) THEN
|
||||
IF r.org + offset >= buf.f.len THEN x := 0X; r.eof := TRUE; RETURN
|
||||
ELSE Set(r, buf.f, r.org + offset); buf := r.buf; offset := r.offset
|
||||
END
|
||||
END ;
|
||||
x := buf.data[offset]; r.offset := offset + 1
|
||||
END Read;
|
||||
|
||||
but this would also affect Set, Length, and Flush.
|
||||
Especially Length would become fairly complex.
|
||||
*)
|
||||
|
||||
PROCEDURE Delete* (name: ARRAY OF CHAR; VAR res: INTEGER);
|
||||
BEGIN
|
||||
res := SHORT(Unix.Unlink(name));
|
||||
res := SHORT(Unix.errno())
|
||||
END Delete;
|
||||
|
||||
PROCEDURE Rename* (old, new: ARRAY OF CHAR; VAR res: INTEGER);
|
||||
VAR fdold, fdnew, n, errno, r: LONGINT;
|
||||
ostat, nstat: Unix.Status;
|
||||
buf: ARRAY 4096 OF CHAR;
|
||||
BEGIN
|
||||
r := Unix.Stat(old, ostat);
|
||||
IF r >= 0 THEN
|
||||
r := Unix.Stat(new, nstat);
|
||||
IF (r >= 0) & ((ostat.dev # nstat.dev) OR (ostat.ino # nstat.ino)) THEN
|
||||
Delete(new, res); (* work around stale nfs handles *)
|
||||
END ;
|
||||
r := Unix.Rename(old, new);
|
||||
IF r < 0 THEN res := SHORT(Unix.errno());
|
||||
IF res = Unix.EXDEV THEN (* cross device link, move the file *)
|
||||
fdold := Unix.Open(old, Unix.rdonly, {});
|
||||
IF fdold < 0 THEN res := 2; RETURN END ;
|
||||
fdnew := Unix.Open(new, Unix.rdwr + Unix.creat + Unix.trunc, {2, 4,5, 7,8});
|
||||
IF fdnew < 0 THEN r := Unix.Close(fdold); res := 3; RETURN END ;
|
||||
n := Unix.Read(fdold, SYSTEM.ADR(buf), bufsize);
|
||||
WHILE n > 0 DO
|
||||
r := Unix.Write(fdnew, SYSTEM.ADR(buf), n);
|
||||
IF r < 0 THEN errno := Unix.errno(); r := Unix.Close(fdold); r := Unix.Close(fdnew);
|
||||
Err("cannot move file", NIL, errno)
|
||||
END ;
|
||||
n := Unix.Read(fdold, SYSTEM.ADR(buf), bufsize)
|
||||
END ;
|
||||
errno := Unix.errno();
|
||||
r := Unix.Close(fdold); r := Unix.Close(fdnew);
|
||||
IF n = 0 THEN r := Unix.Unlink(old); res := 0
|
||||
ELSE Err("cannot move file", NIL, errno)
|
||||
END ;
|
||||
ELSE RETURN (* res is Unix.Rename return code *)
|
||||
END
|
||||
END ;
|
||||
res := 0
|
||||
ELSE res := 2 (* old file not found *)
|
||||
END
|
||||
END Rename;
|
||||
|
||||
PROCEDURE Register* (f: File);
|
||||
VAR idx, errno: INTEGER; f1: File; file: ARRAY 104 OF CHAR;
|
||||
BEGIN
|
||||
IF (f.state = create) & (f.registerName # "") THEN f.state := close (* shortcut renaming *) END ;
|
||||
Close(f);
|
||||
IF f.registerName # "" THEN
|
||||
Rename(f.workName, f.registerName, errno);
|
||||
IF errno # 0 THEN COPY(f.registerName, file); HALT(99) END ;
|
||||
f.workName := f.registerName; f.registerName := ""; f.tempFile := FALSE
|
||||
END
|
||||
END Register;
|
||||
|
||||
PROCEDURE ChangeDirectory*(path: ARRAY OF CHAR; VAR res: INTEGER);
|
||||
BEGIN
|
||||
res := SHORT(Unix.Chdir(path));
|
||||
getcwd(Kernel.CWD)
|
||||
END ChangeDirectory;
|
||||
|
||||
PROCEDURE FlipBytes(VAR src, dest: ARRAY OF SYSTEM.BYTE);
|
||||
VAR i, j: LONGINT;
|
||||
BEGIN
|
||||
IF ~Kernel.littleEndian THEN i := LEN(src); j := 0;
|
||||
WHILE i > 0 DO DEC(i); dest[j] := src[i]; INC(j) END
|
||||
ELSE SYSTEM.MOVE(SYSTEM.ADR(src), SYSTEM.ADR(dest), LEN(src))
|
||||
END
|
||||
END FlipBytes;
|
||||
|
||||
PROCEDURE ReadBool* (VAR R: Rider; VAR x: BOOLEAN);
|
||||
BEGIN Read(R, SYSTEM.VAL(CHAR, x))
|
||||
END ReadBool;
|
||||
|
||||
(* PROCEDURE ReadInt* (VAR R: Rider; VAR x: INTEGER);
|
||||
VAR b: ARRAY 2 OF CHAR;
|
||||
BEGIN ReadBytes(R, b, 2);
|
||||
x := ORD(b[0]) + ORD(b[1])*256
|
||||
END ReadInt;
|
||||
*)
|
||||
|
||||
PROCEDURE ReadInt* (VAR R: Rider; VAR x: LONGINT); (* to compile OR compiler; -- noch *)
|
||||
VAR b: ARRAY 4 OF CHAR;
|
||||
BEGIN ReadBytes(R, b, 4);
|
||||
x := ORD(b[0]) + ORD(b[1])*100H + ORD(b[2])*10000H + ORD(b[3])*1000000H
|
||||
END ReadInt;
|
||||
|
||||
PROCEDURE ReadLInt* (VAR R: Rider; VAR x: LONGINT);
|
||||
VAR b: ARRAY 4 OF CHAR;
|
||||
BEGIN ReadBytes(R, b, 4);
|
||||
x := ORD(b[0]) + ORD(b[1])*100H + ORD(b[2])*10000H + ORD(b[3])*1000000H
|
||||
END ReadLInt;
|
||||
|
||||
PROCEDURE ReadSet* (VAR R: Rider; VAR x: SET);
|
||||
VAR b: ARRAY 4 OF CHAR;
|
||||
BEGIN ReadBytes(R, b, 4);
|
||||
x := SYSTEM.VAL(SET, ORD(b[0]) + ORD(b[1])*100H + ORD(b[2])*10000H + ORD(b[3])*1000000H)
|
||||
END ReadSet;
|
||||
|
||||
PROCEDURE ReadReal* (VAR R: Rider; VAR x: REAL);
|
||||
VAR b: ARRAY 4 OF CHAR;
|
||||
BEGIN ReadBytes(R, b, 4); FlipBytes(b, x)
|
||||
END ReadReal;
|
||||
|
||||
PROCEDURE ReadLReal* (VAR R: Rider; VAR x: LONGREAL);
|
||||
VAR b: ARRAY 8 OF CHAR;
|
||||
BEGIN ReadBytes(R, b, 8); FlipBytes(b, x)
|
||||
END ReadLReal;
|
||||
|
||||
PROCEDURE ReadString* (VAR R: Rider; VAR x: ARRAY OF CHAR);
|
||||
VAR i: INTEGER; ch: CHAR;
|
||||
BEGIN i := 0;
|
||||
REPEAT Read(R, ch); x[i] := ch; INC(i) UNTIL ch = 0X
|
||||
END ReadString;
|
||||
|
||||
(* need to read line; -- noch *)
|
||||
PROCEDURE ReadLine* (VAR R: Rider; VAR x: ARRAY OF CHAR);
|
||||
VAR i: INTEGER; ch: CHAR; b : BOOLEAN;
|
||||
BEGIN i := 0;
|
||||
b := FALSE;
|
||||
REPEAT
|
||||
Read(R, ch);
|
||||
IF ((ch = 0X) OR (ch = 0AX) OR (ch = 0DX)) THEN
|
||||
b := TRUE
|
||||
ELSE
|
||||
x[i] := ch;
|
||||
INC(i);
|
||||
END;
|
||||
UNTIL b
|
||||
END ReadLine;
|
||||
|
||||
PROCEDURE ReadNum* (VAR R: Rider; VAR x: LONGINT);
|
||||
VAR s: SHORTINT; ch: CHAR; n: LONGINT;
|
||||
BEGIN s := 0; n := 0; Read(R, ch);
|
||||
WHILE ORD(ch) >= 128 DO INC(n, ASH(ORD(ch) - 128, s) ); INC(s, 7); Read(R, ch) END;
|
||||
INC(n, ASH(ORD(ch) MOD 64 - ORD(ch) DIV 64 * 64, s) );
|
||||
x := n
|
||||
END ReadNum;
|
||||
|
||||
PROCEDURE WriteBool* (VAR R: Rider; x: BOOLEAN);
|
||||
BEGIN Write(R, SYSTEM.VAL(CHAR, x))
|
||||
END WriteBool;
|
||||
|
||||
(* PROCEDURE WriteInt* (VAR R: Rider; x: INTEGER);
|
||||
VAR b: ARRAY 2 OF CHAR;
|
||||
BEGIN b[0] := CHR(x); b[1] := CHR(x DIV 256);
|
||||
WriteBytes(R, b, 2);
|
||||
END WriteInt;
|
||||
*)
|
||||
PROCEDURE WriteInt* (VAR R: Rider; x: LONGINT); (* to compile OR compiler; -- noch *)
|
||||
VAR b: ARRAY 4 OF CHAR;
|
||||
BEGIN
|
||||
b[0] := CHR(x); b[1] := CHR(x DIV 100H); b[2] := CHR(x DIV 10000H); b[3] := CHR(x DIV 1000000H);
|
||||
WriteBytes(R, b, 4);
|
||||
END WriteInt;
|
||||
|
||||
PROCEDURE WriteLInt* (VAR R: Rider; x: LONGINT);
|
||||
VAR b: ARRAY 4 OF CHAR;
|
||||
BEGIN
|
||||
b[0] := CHR(x); b[1] := CHR(x DIV 100H); b[2] := CHR(x DIV 10000H); b[3] := CHR(x DIV 1000000H);
|
||||
WriteBytes(R, b, 4);
|
||||
END WriteLInt;
|
||||
|
||||
PROCEDURE WriteSet* (VAR R: Rider; x: SET);
|
||||
VAR b: ARRAY 4 OF CHAR; i: LONGINT;
|
||||
BEGIN i := SYSTEM.VAL(LONGINT, x);
|
||||
b[0] := CHR(i); b[1] := CHR(i DIV 100H); b[2] := CHR(i DIV 10000H); b[3] := CHR(i DIV 1000000H);
|
||||
WriteBytes(R, b, 4);
|
||||
END WriteSet;
|
||||
|
||||
PROCEDURE WriteReal* (VAR R: Rider; x: REAL);
|
||||
VAR b: ARRAY 4 OF CHAR;
|
||||
BEGIN FlipBytes(x, b); WriteBytes(R, b, 4)
|
||||
END WriteReal;
|
||||
|
||||
PROCEDURE WriteLReal* (VAR R: Rider; x: LONGREAL);
|
||||
VAR b: ARRAY 8 OF CHAR;
|
||||
BEGIN FlipBytes(x, b); WriteBytes(R, b, 8)
|
||||
END WriteLReal;
|
||||
|
||||
PROCEDURE WriteString* (VAR R: Rider; x: ARRAY [1] OF CHAR);
|
||||
VAR i: INTEGER;
|
||||
BEGIN i := 0;
|
||||
WHILE x[i] # 0X DO INC(i) END ;
|
||||
WriteBytes(R, x, i+1)
|
||||
END WriteString;
|
||||
|
||||
PROCEDURE WriteNum* (VAR R: Rider; x: LONGINT);
|
||||
BEGIN
|
||||
WHILE (x < - 64) OR (x > 63) DO Write(R, CHR(x MOD 128 + 128)); x := x DIV 128 END;
|
||||
Write(R, CHR(x MOD 128))
|
||||
END WriteNum;
|
||||
|
||||
PROCEDURE GetName*(f: File; VAR name: ARRAY OF CHAR);
|
||||
BEGIN
|
||||
COPY (f.workName, name);
|
||||
END GetName;
|
||||
|
||||
PROCEDURE Finalize(o: SYSTEM.PTR);
|
||||
VAR f: File; res: LONGINT;
|
||||
BEGIN
|
||||
f := SYSTEM.VAL(File, o);
|
||||
IF f.fd >= 0 THEN
|
||||
fileTab[f.fd] := 0; res := Unix.Close(f.fd); f.fd := -1; DEC(Kernel.nofiles);
|
||||
IF f.tempFile THEN res := Unix.Unlink(f.workName) END
|
||||
END
|
||||
END Finalize;
|
||||
|
||||
PROCEDURE Init;
|
||||
VAR i: LONGINT;
|
||||
BEGIN
|
||||
i := 0; WHILE i < fileTabSize DO fileTab[i] := 0; INC(i) END ;
|
||||
tempno := -1; Kernel.nofiles := 0
|
||||
END Init;
|
||||
|
||||
BEGIN Init
|
||||
END CompatFiles.
|
||||
|
|
@ -1,677 +0,0 @@
|
|||
MODULE CompatFiles; (* J. Templ 1.12. 89/12.4.95 Oberon files mapped onto Unix files *)
|
||||
(* modified version of Files, which opens only the file provided and does not scan any path in any environment variable, also ReadLine procedure added; -- noch *)
|
||||
IMPORT SYSTEM, Unix, Kernel, Args, Console;
|
||||
|
||||
(* standard data type I/O
|
||||
|
||||
little endian,
|
||||
Sint:1, Int:2, Lint:4
|
||||
ORD({0}) = 1,
|
||||
false = 0, true =1
|
||||
IEEE real format,
|
||||
null terminated strings,
|
||||
compact numbers according to M.Odersky *)
|
||||
|
||||
|
||||
CONST
|
||||
nofbufs = 4;
|
||||
bufsize = 4096;
|
||||
fileTabSize = 64;
|
||||
noDesc = -1;
|
||||
notDone = -1;
|
||||
|
||||
(* file states *)
|
||||
open = 0; create = 1; close = 2;
|
||||
|
||||
|
||||
TYPE
|
||||
FileName = ARRAY 101 OF CHAR;
|
||||
File* = POINTER TO Handle;
|
||||
Buffer = POINTER TO BufDesc;
|
||||
|
||||
Handle = RECORD
|
||||
workName, registerName: FileName;
|
||||
tempFile: BOOLEAN;
|
||||
dev, ino, mtime: LONGINT;
|
||||
fd-: INTEGER; len, pos: LONGINT;
|
||||
bufs: ARRAY nofbufs OF Buffer;
|
||||
swapper, state: INTEGER
|
||||
END ;
|
||||
|
||||
BufDesc = RECORD
|
||||
f: File;
|
||||
chg: BOOLEAN;
|
||||
org, size: LONGINT;
|
||||
data: ARRAY bufsize OF SYSTEM.BYTE
|
||||
END ;
|
||||
|
||||
Rider* = RECORD
|
||||
res*: LONGINT;
|
||||
eof*: BOOLEAN;
|
||||
buf: Buffer;
|
||||
org, offset: LONGINT
|
||||
END ;
|
||||
|
||||
Time = POINTER TO TimeDesc;
|
||||
TimeDesc = RECORD
|
||||
sec*, min*, hour*, mday*, mon*, year*, wday*, isdst*, zone*, gmtoff*: LONGINT;
|
||||
(* sec*, min*, hour*, mday*, mon*, year*, wday*, isdst*, zone*, gmtoff*: INTEGER;*)
|
||||
END ;
|
||||
|
||||
VAR
|
||||
fileTab: ARRAY fileTabSize OF LONGINT (*=File*);
|
||||
tempno: INTEGER;
|
||||
|
||||
(* for localtime *)
|
||||
PROCEDURE -includetime()
|
||||
'#include "time.h"';
|
||||
|
||||
PROCEDURE -localtime(VAR clock: LONGINT): Time
|
||||
"(CompatFiles_Time) localtime(clock)";
|
||||
|
||||
PROCEDURE -getcwd(VAR cwd: Unix.Name)
|
||||
"getcwd(cwd, cwd__len)";
|
||||
|
||||
PROCEDURE -IdxTrap "__HALT(-1)";
|
||||
|
||||
PROCEDURE^ Finalize(o: SYSTEM.PTR);
|
||||
|
||||
PROCEDURE Err(s: ARRAY OF CHAR; f: File; errno: LONGINT);
|
||||
BEGIN
|
||||
Console.Ln; Console.String("-- "); Console.String(s); Console.String(": ");
|
||||
IF f # NIL THEN
|
||||
IF f.registerName # "" THEN Console.String(f.registerName) ELSE Console.String(f.workName) END
|
||||
END ;
|
||||
IF errno # 0 THEN Console.String(" errno = "); Console.Int(errno, 1) END ;
|
||||
Console.Ln;
|
||||
HALT(99)
|
||||
END Err;
|
||||
|
||||
PROCEDURE MakeFileName(dir, name: ARRAY OF CHAR; VAR dest: ARRAY OF CHAR);
|
||||
VAR i, j: INTEGER;
|
||||
BEGIN i := 0; j := 0;
|
||||
WHILE dir[i] # 0X DO dest[i] := dir[i]; INC(i) END ;
|
||||
IF dest[i-1] # "/" THEN dest[i] := "/"; INC(i) END ;
|
||||
WHILE name[j] # 0X DO dest[i] := name[j]; INC(i); INC(j) END ;
|
||||
dest[i] := 0X
|
||||
END MakeFileName;
|
||||
|
||||
PROCEDURE GetTempName(finalName: ARRAY OF CHAR; VAR name: ARRAY OF CHAR);
|
||||
VAR n, i, j: LONGINT;
|
||||
BEGIN
|
||||
INC(tempno); n := tempno; i := 0;
|
||||
IF finalName[0] # "/" THEN (* relative pathname *)
|
||||
WHILE Kernel.CWD[i] # 0X DO name[i] := Kernel.CWD[i]; INC(i) END;
|
||||
IF Kernel.CWD[i-1] # "/" THEN name[i] := "/"; INC(i) END
|
||||
END;
|
||||
j := 0;
|
||||
WHILE finalName[j] # 0X DO name[i] := finalName[j]; INC(i); INC(j) END;
|
||||
DEC(i);
|
||||
WHILE name[i] # "/" DO DEC(i) END;
|
||||
name[i+1] := "."; name[i+2] := "t"; name[i+3] := "m"; name[i+4] := "p"; name[i+5] := "."; INC(i, 6);
|
||||
WHILE n > 0 DO name[i] := CHR(n MOD 10 + ORD("0")); n := n DIV 10; INC(i) END;
|
||||
name[i] := "."; INC(i); n := SHORT(Unix.Getpid());
|
||||
WHILE n > 0 DO name[i] := CHR(n MOD 10 + ORD("0")); n := n DIV 10; INC(i) END;
|
||||
name[i] := 0X
|
||||
END GetTempName;
|
||||
|
||||
PROCEDURE Create(f: File);
|
||||
VAR stat: Unix.Status; done: BOOLEAN;
|
||||
errno: LONGINT; err: ARRAY 32 OF CHAR;
|
||||
BEGIN
|
||||
IF f.fd = noDesc THEN
|
||||
IF f.state = create THEN GetTempName(f.registerName, f.workName); f.tempFile := TRUE
|
||||
ELSIF f.state = close THEN
|
||||
f.workName := f.registerName; f.registerName := ""; f.tempFile := FALSE
|
||||
END ;
|
||||
errno := Unix.Unlink(f.workName); (*unlink first to avoid stale NFS handles and to avoid reuse of inodes*)
|
||||
f.fd := Unix.Open(f.workName, SYSTEM.VAL(INTEGER, Unix.rdwr + Unix.creat + Unix.trunc), SYSTEM.VAL(LONGINT, {2, 4,5, 7,8}));
|
||||
done := f.fd >= 0; errno := Unix.errno();
|
||||
IF (~done & ((errno = Unix.ENFILE) OR (errno = Unix.EMFILE))) OR (done & (f.fd >= fileTabSize)) THEN
|
||||
IF done & (f.fd >= fileTabSize) THEN errno := Unix.Close(f.fd) END ;
|
||||
Kernel.GC(TRUE);
|
||||
f.fd := Unix.Open(f.workName, SYSTEM.VAL(INTEGER, Unix.rdwr + Unix.creat + Unix.trunc), SYSTEM.VAL(LONGINT, {2, 4,5, 7,8}));
|
||||
done := f.fd >= 0
|
||||
END ;
|
||||
IF done THEN
|
||||
IF f.fd >= fileTabSize THEN errno := Unix.Close(f.fd); Err("too many files open", f, 0)
|
||||
ELSE fileTab[f.fd] := SYSTEM.VAL(LONGINT, f); INC(Kernel.nofiles); Kernel.RegisterObject(f, Finalize);
|
||||
f.state := open; f.pos := 0; errno := Unix.Fstat(f.fd, stat);
|
||||
f.dev := stat.dev; f.ino := stat.ino; f.mtime := stat.mtime
|
||||
END
|
||||
ELSE errno := Unix.errno();
|
||||
IF errno = Unix.ENOENT THEN err := "no such directory"
|
||||
ELSIF (errno = Unix.ENFILE) OR (errno = Unix.EMFILE) THEN err := "too many files open"
|
||||
ELSE err := "file not created"
|
||||
END ;
|
||||
Err(err, f, errno)
|
||||
END
|
||||
END
|
||||
END Create;
|
||||
|
||||
PROCEDURE Flush(buf: Buffer);
|
||||
VAR res: LONGINT; f: File; stat: Unix.Status;
|
||||
BEGIN
|
||||
IF buf.chg THEN f := buf.f; Create(f);
|
||||
IF buf.org # f.pos THEN res := Unix.Lseek(f.fd, buf.org, 0) END ;
|
||||
res := Unix.Write(f.fd, SYSTEM.ADR(buf.data), buf.size);
|
||||
IF res < 0 THEN Err("error in writing file", f, Unix.errno()) END ;
|
||||
f.pos := buf.org + buf.size;
|
||||
buf.chg := FALSE;
|
||||
res := Unix.Fstat(f.fd, stat);
|
||||
f.mtime := stat.mtime
|
||||
END
|
||||
END Flush;
|
||||
|
||||
PROCEDURE Close* (f: File);
|
||||
VAR i, res: LONGINT;
|
||||
BEGIN
|
||||
IF (f.state # create) OR (f.registerName # "") THEN
|
||||
Create(f); i := 0;
|
||||
WHILE (i < nofbufs) & (f.bufs[i] # NIL) DO Flush(f.bufs[i]); INC(i) END ;
|
||||
res := Unix.Fsync(f.fd);
|
||||
IF res < 0 THEN Err("error in writing file", f, Unix.errno()) END
|
||||
END
|
||||
END Close;
|
||||
|
||||
PROCEDURE Length* (f: File): LONGINT;
|
||||
BEGIN RETURN f.len
|
||||
END Length;
|
||||
|
||||
PROCEDURE New* (name: ARRAY OF CHAR): File;
|
||||
VAR f: File;
|
||||
BEGIN
|
||||
NEW(f); f.workName := ""; COPY(name, f.registerName);
|
||||
f.fd := noDesc; f.state := create; f.len := 0; f.pos := 0; f.swapper := -1; (*all f.buf[i] = NIL*)
|
||||
RETURN f
|
||||
END New;
|
||||
(*
|
||||
PROCEDURE ScanPath(VAR pos: INTEGER; VAR dir: ARRAY OF CHAR); (* supports ~, ~user and blanks inside path *)
|
||||
VAR i: INTEGER; ch: CHAR; home: ARRAY 256 OF CHAR;
|
||||
BEGIN
|
||||
i := 0; ch := Kernel.OBERON[pos];
|
||||
WHILE (ch = " ") OR (ch = ":") DO INC(pos); ch := Kernel.OBERON[pos] END ;
|
||||
IF ch = "~" THEN
|
||||
INC(pos); ch := Kernel.OBERON[pos];
|
||||
home := ""; Args.GetEnv("HOME", home);
|
||||
WHILE home[i] # 0X DO dir[i] := home[i]; INC(i) END ;
|
||||
IF (ch # "/") & (ch # 0X) & (ch # ":") & (ch # " ") THEN
|
||||
WHILE (i > 0) & (dir[i-1] # "/") DO DEC(i) END
|
||||
END
|
||||
END ;
|
||||
WHILE (ch # 0X) & (ch # ":") DO dir[i] := ch; INC(i); INC(pos); ch := Kernel.OBERON[pos] END ;
|
||||
WHILE (i > 0) & (dir[i-1] = " ") DO DEC(i) END ;
|
||||
dir[i] := 0X
|
||||
END ScanPath;
|
||||
*)
|
||||
PROCEDURE HasDir(VAR name: ARRAY OF CHAR): BOOLEAN;
|
||||
VAR i: INTEGER; ch: CHAR;
|
||||
BEGIN i := 0; ch := name[0];
|
||||
WHILE (ch # 0X) & (ch # "/") DO INC(i); ch := name[i] END ;
|
||||
RETURN ch = "/"
|
||||
END HasDir;
|
||||
|
||||
PROCEDURE CacheEntry(dev, ino: LONGINT; mtime: LONGINT): File;
|
||||
VAR f: File; i: INTEGER; stat: Unix.Status; res: LONGINT;
|
||||
BEGIN i := 0;
|
||||
WHILE i < fileTabSize DO
|
||||
f := SYSTEM.VAL(File, fileTab[i]);
|
||||
IF (f # NIL) & (ino = f.ino) & (dev = f.dev) THEN
|
||||
IF mtime # f.mtime THEN i := 0;
|
||||
WHILE i < nofbufs DO
|
||||
IF f.bufs[i] # NIL THEN f.bufs[i].org := -1; f.bufs[i] := NIL END ;
|
||||
INC(i)
|
||||
END ;
|
||||
f.swapper := -1; f.mtime := mtime;
|
||||
res := Unix.Fstat(f.fd, stat); f.len := stat.size
|
||||
END ;
|
||||
RETURN f
|
||||
END ;
|
||||
INC(i)
|
||||
END ;
|
||||
RETURN NIL
|
||||
END CacheEntry;
|
||||
|
||||
PROCEDURE Old* (name: ARRAY OF CHAR): File;
|
||||
VAR f: File; fd, res: INTEGER; errno: LONGINT; pos: INTEGER; done: BOOLEAN;
|
||||
dir, path: ARRAY 256 OF CHAR;
|
||||
stat: Unix.Status;
|
||||
BEGIN
|
||||
IF name # "" THEN
|
||||
IF HasDir(name) THEN dir := ""; COPY(name, path)
|
||||
ELSE
|
||||
pos := 0;
|
||||
COPY(name, path); (* -- noch *)
|
||||
(*ScanPath(pos, dir);*) (*MakeFileName(dir, name, path);*) (*ScanPath(pos, dir)*)
|
||||
END ;
|
||||
LOOP
|
||||
fd := Unix.Open(path, SYSTEM.VAL(INTEGER, Unix.rdwr), (*{}*) 0); done := fd >= 0; errno := Unix.errno();
|
||||
IF (~done & ((errno = Unix.ENFILE) OR (errno = Unix.EMFILE))) OR (done & (fd >= fileTabSize)) THEN
|
||||
IF done & (fd >= fileTabSize) THEN res := Unix.Close(fd) END ;
|
||||
Kernel.GC(TRUE);
|
||||
fd := Unix.Open(path, SYSTEM.VAL(INTEGER, Unix.rdwr), (*{}*)0);
|
||||
done := fd >= 0; errno := Unix.errno();
|
||||
IF ~done & ((errno = Unix.ENFILE) OR (errno = Unix.EMFILE)) THEN Err("too many files open", f, errno) END
|
||||
END ;
|
||||
IF ~done & ((errno = Unix.EACCES) OR (errno = Unix.EROFS) OR (errno = Unix.EAGAIN)) THEN
|
||||
(* errno EAGAIN observed on Solaris 2.4 *)
|
||||
fd := Unix.Open(path, SYSTEM.VAL(INTEGER, Unix.rdonly), (*{}*)0); done := fd >= 0; errno := Unix.errno()
|
||||
END ;
|
||||
IF (~done) & (errno # Unix.ENOENT) THEN
|
||||
Console.String("warning Files.Old "); Console.String(name);
|
||||
Console.String(" errno = "); Console.Int(errno, 0); Console.Ln;
|
||||
END ;
|
||||
IF done THEN
|
||||
res := Unix.Fstat(fd, stat);
|
||||
f := CacheEntry(stat.dev, stat.ino, stat.mtime);
|
||||
IF f # NIL THEN res := Unix.Close(fd); RETURN f
|
||||
ELSIF fd >= fileTabSize THEN res := Unix.Close(fd); Err("too many files open", f, 0)
|
||||
ELSE NEW(f); fileTab[fd] := SYSTEM.VAL(LONGINT, f); INC(Kernel.nofiles); Kernel.RegisterObject(f, Finalize);
|
||||
f.fd := fd; f.state := open; f.len := stat.size; f.pos := 0; f.swapper := -1; (*all f.buf[i] = NIL*)
|
||||
COPY(name, f.workName); f.registerName := ""; f.tempFile := FALSE;
|
||||
f.dev := stat.dev; f.ino := stat.ino; f.mtime := stat.mtime;
|
||||
RETURN f
|
||||
END
|
||||
ELSIF dir = "" THEN RETURN NIL
|
||||
ELSE (*MakeFileName(dir, name, path);*) (*ScanPath(pos, dir)*)
|
||||
RETURN NIL
|
||||
END
|
||||
END
|
||||
ELSE RETURN NIL
|
||||
END
|
||||
END Old;
|
||||
|
||||
PROCEDURE Purge* (f: File);
|
||||
VAR i: INTEGER; stat: Unix.Status; res: LONGINT;
|
||||
BEGIN i := 0;
|
||||
WHILE i < nofbufs DO
|
||||
IF f.bufs[i] # NIL THEN f.bufs[i].org := -1; f.bufs[i] := NIL END ;
|
||||
INC(i)
|
||||
END ;
|
||||
IF f.fd # noDesc THEN res := Unix.Ftruncate(f.fd, 0); res := Unix.Lseek(f.fd, 0, 0) END ;
|
||||
f.pos := 0; f.len := 0; f.swapper := -1;
|
||||
res := Unix.Fstat(f.fd, stat); f.mtime := stat.mtime
|
||||
END Purge;
|
||||
|
||||
PROCEDURE GetDate* (f: File; VAR t, d: LONGINT);
|
||||
VAR stat: Unix.Status; clock, res: LONGINT; time: Time;
|
||||
BEGIN
|
||||
Create(f); res := Unix.Fstat(f.fd, stat);
|
||||
time := localtime(stat.mtime);
|
||||
t := time.sec + ASH(time.min, 6) + ASH(time.hour, 12);
|
||||
d := time.mday + ASH(time.mon+1, 5) + ASH(time.year MOD 100, 9)
|
||||
END GetDate;
|
||||
|
||||
PROCEDURE Pos* (VAR r: Rider): LONGINT;
|
||||
BEGIN RETURN r.org + r.offset
|
||||
END Pos;
|
||||
|
||||
PROCEDURE Set* (VAR r: Rider; f: File; pos: LONGINT);
|
||||
VAR org, offset, i, n, res: LONGINT; buf: Buffer;
|
||||
BEGIN
|
||||
IF f # NIL THEN
|
||||
IF pos > f.len THEN pos := f.len ELSIF pos < 0 THEN pos := 0 END ;
|
||||
offset := pos MOD bufsize; org := pos - offset; i := 0;
|
||||
WHILE (i < nofbufs) & (f.bufs[i] # NIL) & (org # f.bufs[i].org) DO INC(i) END ;
|
||||
IF i < nofbufs THEN
|
||||
IF f.bufs[i] = NIL THEN NEW(buf); buf.chg := FALSE; buf.org := -1; buf.f := f; f.bufs[i] := buf
|
||||
ELSE buf := f.bufs[i]
|
||||
END
|
||||
ELSE
|
||||
f.swapper := (f.swapper + 1) MOD nofbufs;
|
||||
buf := f.bufs[f.swapper];
|
||||
Flush(buf)
|
||||
END ;
|
||||
IF buf.org # org THEN
|
||||
IF org = f.len THEN buf.size := 0
|
||||
ELSE Create(f);
|
||||
IF f.pos # org THEN res := Unix.Lseek(f.fd, org, 0) END ;
|
||||
n := Unix.ReadBlk(f.fd, buf.data);
|
||||
IF n < 0 THEN Err("read from file not done", f, Unix.errno()) END ;
|
||||
f.pos := org + n;
|
||||
buf.size := n
|
||||
END ;
|
||||
buf.org := org; buf.chg := FALSE
|
||||
END
|
||||
ELSE buf := NIL; org := 0; offset := 0
|
||||
END ;
|
||||
r.buf := buf; r.org := org; r.offset := offset; r.eof := FALSE; r.res := 0
|
||||
END Set;
|
||||
|
||||
PROCEDURE Read* (VAR r: Rider; VAR x: SYSTEM.BYTE);
|
||||
VAR offset: LONGINT; buf: Buffer;
|
||||
BEGIN
|
||||
buf := r.buf; offset := r.offset;
|
||||
IF r.org # buf.org THEN Set(r, buf.f, r.org + offset); buf := r.buf; offset := r.offset END ;
|
||||
IF (offset < buf.size) THEN
|
||||
x := buf.data[offset]; r.offset := offset + 1
|
||||
ELSIF r.org + offset < buf.f.len THEN
|
||||
Set(r, r.buf.f, r.org + offset);
|
||||
x := r.buf.data[0]; r.offset := 1
|
||||
ELSE
|
||||
x := 0X; r.eof := TRUE
|
||||
END
|
||||
END Read;
|
||||
|
||||
PROCEDURE ReadBytes* (VAR r: Rider; VAR x: ARRAY OF SYSTEM.BYTE; n: LONGINT);
|
||||
VAR xpos, min, restInBuf, offset: LONGINT; buf: Buffer;
|
||||
BEGIN
|
||||
IF n > LEN(x) THEN IdxTrap END ;
|
||||
xpos := 0; buf := r.buf; offset := r.offset;
|
||||
WHILE n > 0 DO
|
||||
IF (r.org # buf.org) OR (offset >= bufsize) THEN
|
||||
Set(r, buf.f, r.org + offset);
|
||||
buf := r.buf; offset := r.offset
|
||||
END ;
|
||||
restInBuf := buf.size - offset;
|
||||
IF restInBuf = 0 THEN r.res := n; r.eof := TRUE; RETURN
|
||||
ELSIF n > restInBuf THEN min := restInBuf ELSE min := n END ;
|
||||
SYSTEM.MOVE(SYSTEM.ADR(buf.data) + offset, SYSTEM.ADR(x) + xpos, min);
|
||||
INC(offset, min); r.offset := offset; INC(xpos, min); DEC(n, min)
|
||||
END ;
|
||||
r.res := 0; r.eof := FALSE
|
||||
END ReadBytes;
|
||||
|
||||
PROCEDURE ReadByte* (VAR r : Rider; VAR x : ARRAY OF SYSTEM.BYTE);
|
||||
BEGIN
|
||||
ReadBytes(r, x, 1);
|
||||
END ReadByte;
|
||||
|
||||
PROCEDURE Base* (VAR r: Rider): File;
|
||||
BEGIN RETURN r.buf.f
|
||||
END Base;
|
||||
|
||||
PROCEDURE Write* (VAR r: Rider; x: SYSTEM.BYTE);
|
||||
VAR buf: Buffer; offset: LONGINT;
|
||||
BEGIN
|
||||
buf := r.buf; offset := r.offset;
|
||||
IF (r.org # buf.org) OR (offset >= bufsize) THEN
|
||||
Set(r, buf.f, r.org + offset);
|
||||
buf := r.buf; offset := r.offset
|
||||
END ;
|
||||
buf.data[offset] := x;
|
||||
buf.chg := TRUE;
|
||||
IF offset = buf.size THEN
|
||||
INC(buf.size); INC(buf.f.len)
|
||||
END ;
|
||||
r.offset := offset + 1; r.res := 0
|
||||
END Write;
|
||||
|
||||
PROCEDURE WriteByte* (VAR r : Rider; x : SYSTEM.BYTE); (* added for compatibility with PO 2013, -- noch *)
|
||||
BEGIN
|
||||
Write(r, x);
|
||||
END WriteByte;
|
||||
|
||||
PROCEDURE WriteBytes* (VAR r: Rider; VAR x: ARRAY OF SYSTEM.BYTE; n: LONGINT);
|
||||
VAR xpos, min, restInBuf, offset: LONGINT; buf: Buffer;
|
||||
BEGIN
|
||||
IF n > LEN(x) THEN IdxTrap END ;
|
||||
xpos := 0; buf := r.buf; offset := r.offset;
|
||||
WHILE n > 0 DO
|
||||
IF (r.org # buf.org) OR (offset >= bufsize) THEN
|
||||
Set(r, buf.f, r.org + offset);
|
||||
buf := r.buf; offset := r.offset
|
||||
END ;
|
||||
restInBuf := bufsize - offset;
|
||||
IF n > restInBuf THEN min := restInBuf ELSE min := n END ;
|
||||
SYSTEM.MOVE(SYSTEM.ADR(x) + xpos, SYSTEM.ADR(buf.data) + offset, min);
|
||||
INC(offset, min); r.offset := offset;
|
||||
IF offset > buf.size THEN INC(buf.f.len, offset - buf.size); buf.size := offset END ;
|
||||
INC(xpos, min); DEC(n, min); buf.chg := TRUE
|
||||
END ;
|
||||
r.res := 0
|
||||
END WriteBytes;
|
||||
|
||||
(* another solution would be one that is similar to ReadBytes, WriteBytes.
|
||||
No code duplication, more symmetric, only two ifs for
|
||||
Read and Write in buffer, buf.size replaced by bufsize in Write ops, buf.size and len
|
||||
must be made consistent with offset (if offset > buf.size) in a lazy way.
|
||||
|
||||
PROCEDURE Write* (VAR r: Rider; x: SYSTEM.BYTE);
|
||||
VAR buf: Buffer; offset: LONGINT;
|
||||
BEGIN
|
||||
buf := r.buf; offset := r.offset;
|
||||
IF (offset >= bufsize) OR (r.org # buf.org) THEN
|
||||
Set(r, buf.f, r.org + offset); buf := r.buf; offset := r.offset;
|
||||
END ;
|
||||
buf.data[offset] := x; r.offset := offset + 1; buf.chg := TRUE
|
||||
END Write;
|
||||
|
||||
|
||||
PROCEDURE WriteBytes ...
|
||||
|
||||
PROCEDURE Read* (VAR r: Rider; VAR x: SYSTEM.BYTE);
|
||||
VAR offset: LONGINT; buf: Buffer;
|
||||
BEGIN
|
||||
buf := r.buf; offset := r.offset;
|
||||
IF (offset >= buf.size) OR (r.org # buf.org) THEN
|
||||
IF r.org + offset >= buf.f.len THEN x := 0X; r.eof := TRUE; RETURN
|
||||
ELSE Set(r, buf.f, r.org + offset); buf := r.buf; offset := r.offset
|
||||
END
|
||||
END ;
|
||||
x := buf.data[offset]; r.offset := offset + 1
|
||||
END Read;
|
||||
|
||||
but this would also affect Set, Length, and Flush.
|
||||
Especially Length would become fairly complex.
|
||||
*)
|
||||
|
||||
PROCEDURE Delete* (name: ARRAY OF CHAR; VAR res: INTEGER);
|
||||
BEGIN
|
||||
res := SHORT(Unix.Unlink(name));
|
||||
res := SHORT(Unix.errno())
|
||||
END Delete;
|
||||
|
||||
PROCEDURE Rename* (old, new: ARRAY OF CHAR; VAR res: INTEGER);
|
||||
VAR fdold, fdnew: INTEGER; n, errno, r: LONGINT;
|
||||
ostat, nstat: Unix.Status;
|
||||
buf: ARRAY 4096 OF CHAR;
|
||||
BEGIN
|
||||
r := Unix.Stat(old, ostat);
|
||||
IF r >= 0 THEN
|
||||
r := Unix.Stat(new, nstat);
|
||||
IF (r >= 0) & ((ostat.dev # nstat.dev) OR (ostat.ino # nstat.ino)) THEN
|
||||
Delete(new, res); (* work around stale nfs handles *)
|
||||
END ;
|
||||
r := Unix.Rename(old, new);
|
||||
IF r < 0 THEN res := SHORT(Unix.errno());
|
||||
IF res = Unix.EXDEV THEN (* cross device link, move the file *)
|
||||
fdold := Unix.Open(old, SYSTEM.VAL(INTEGER, Unix.rdonly), (*{}*)0);
|
||||
IF fdold < 0 THEN res := 2; RETURN END ;
|
||||
fdnew := Unix.Open(new, SYSTEM.VAL(INTEGER, Unix.rdwr + Unix.creat + Unix.trunc), SYSTEM.VAL(LONGINT, {2, 4,5, 7,8}));
|
||||
IF fdnew < 0 THEN r := Unix.Close(fdold); res := 3; RETURN END ;
|
||||
n := Unix.Read(fdold, SYSTEM.ADR(buf), bufsize);
|
||||
WHILE n > 0 DO
|
||||
r := Unix.Write(fdnew, SYSTEM.ADR(buf), n);
|
||||
IF r < 0 THEN errno := Unix.errno(); r := Unix.Close(fdold); r := Unix.Close(fdnew);
|
||||
Err("cannot move file", NIL, errno)
|
||||
END ;
|
||||
n := Unix.Read(fdold, SYSTEM.ADR(buf), bufsize)
|
||||
END ;
|
||||
errno := Unix.errno();
|
||||
r := Unix.Close(fdold); r := Unix.Close(fdnew);
|
||||
IF n = 0 THEN r := Unix.Unlink(old); res := 0
|
||||
ELSE Err("cannot move file", NIL, errno)
|
||||
END ;
|
||||
ELSE RETURN (* res is Unix.Rename return code *)
|
||||
END
|
||||
END ;
|
||||
res := 0
|
||||
ELSE res := 2 (* old file not found *)
|
||||
END
|
||||
END Rename;
|
||||
|
||||
PROCEDURE Register* (f: File);
|
||||
VAR idx, errno: INTEGER; f1: File; file: ARRAY 104 OF CHAR;
|
||||
BEGIN
|
||||
IF (f.state = create) & (f.registerName # "") THEN f.state := close (* shortcut renaming *) END ;
|
||||
Close(f);
|
||||
IF f.registerName # "" THEN
|
||||
Rename(f.workName, f.registerName, errno);
|
||||
IF errno # 0 THEN COPY(f.registerName, file); HALT(99) END ;
|
||||
f.workName := f.registerName; f.registerName := ""; f.tempFile := FALSE
|
||||
END
|
||||
END Register;
|
||||
|
||||
PROCEDURE ChangeDirectory*(path: ARRAY OF CHAR; VAR res: INTEGER);
|
||||
BEGIN
|
||||
res := SHORT(Unix.Chdir(path));
|
||||
getcwd(Kernel.CWD)
|
||||
END ChangeDirectory;
|
||||
|
||||
PROCEDURE FlipBytes(VAR src, dest: ARRAY OF SYSTEM.BYTE);
|
||||
VAR i, j: LONGINT;
|
||||
BEGIN
|
||||
IF ~Kernel.littleEndian THEN i := LEN(src); j := 0;
|
||||
WHILE i > 0 DO DEC(i); dest[j] := src[i]; INC(j) END
|
||||
ELSE SYSTEM.MOVE(SYSTEM.ADR(src), SYSTEM.ADR(dest), LEN(src))
|
||||
END
|
||||
END FlipBytes;
|
||||
|
||||
PROCEDURE ReadBool* (VAR R: Rider; VAR x: BOOLEAN);
|
||||
BEGIN Read(R, SYSTEM.VAL(CHAR, x))
|
||||
END ReadBool;
|
||||
|
||||
(* PROCEDURE ReadInt* (VAR R: Rider; VAR x: INTEGER);
|
||||
VAR b: ARRAY 2 OF CHAR;
|
||||
BEGIN ReadBytes(R, b, 2);
|
||||
x := ORD(b[0]) + ORD(b[1])*256
|
||||
END ReadInt;
|
||||
*)
|
||||
|
||||
PROCEDURE ReadInt* (VAR R: Rider; VAR x: LONGINT); (* to compile OR compiler; -- noch *)
|
||||
VAR b: ARRAY 4 OF CHAR;
|
||||
BEGIN ReadBytes(R, b, 4);
|
||||
x := ORD(b[0]) + ORD(b[1])*100H + ORD(b[2])*10000H + ORD(b[3])*1000000H
|
||||
END ReadInt;
|
||||
|
||||
PROCEDURE ReadLInt* (VAR R: Rider; VAR x: LONGINT);
|
||||
VAR b: ARRAY 4 OF CHAR;
|
||||
BEGIN ReadBytes(R, b, 4);
|
||||
x := ORD(b[0]) + ORD(b[1])*100H + ORD(b[2])*10000H + ORD(b[3])*1000000H
|
||||
END ReadLInt;
|
||||
|
||||
PROCEDURE ReadSet* (VAR R: Rider; VAR x: SET);
|
||||
VAR b: ARRAY 4 OF CHAR;
|
||||
BEGIN ReadBytes(R, b, 4);
|
||||
x := SYSTEM.VAL(SET, ORD(b[0]) + ORD(b[1])*100H + ORD(b[2])*10000H + ORD(b[3])*1000000H)
|
||||
END ReadSet;
|
||||
|
||||
PROCEDURE ReadReal* (VAR R: Rider; VAR x: REAL);
|
||||
VAR b: ARRAY 4 OF CHAR;
|
||||
BEGIN ReadBytes(R, b, 4); FlipBytes(b, x)
|
||||
END ReadReal;
|
||||
|
||||
PROCEDURE ReadLReal* (VAR R: Rider; VAR x: LONGREAL);
|
||||
VAR b: ARRAY 8 OF CHAR;
|
||||
BEGIN ReadBytes(R, b, 8); FlipBytes(b, x)
|
||||
END ReadLReal;
|
||||
|
||||
PROCEDURE ReadString* (VAR R: Rider; VAR x: ARRAY OF CHAR);
|
||||
VAR i: INTEGER; ch: CHAR;
|
||||
BEGIN i := 0;
|
||||
REPEAT Read(R, ch); x[i] := ch; INC(i) UNTIL ch = 0X
|
||||
END ReadString;
|
||||
|
||||
(* need to read line; -- noch *)
|
||||
PROCEDURE ReadLine* (VAR R: Rider; VAR x: ARRAY OF CHAR);
|
||||
VAR i: INTEGER; ch: CHAR; b : BOOLEAN;
|
||||
BEGIN i := 0;
|
||||
b := FALSE;
|
||||
REPEAT
|
||||
Read(R, ch);
|
||||
IF ((ch = 0X) OR (ch = 0AX) OR (ch = 0DX)) THEN
|
||||
b := TRUE
|
||||
ELSE
|
||||
x[i] := ch;
|
||||
INC(i);
|
||||
END;
|
||||
UNTIL b
|
||||
END ReadLine;
|
||||
|
||||
PROCEDURE ReadNum* (VAR R: Rider; VAR x: LONGINT);
|
||||
VAR s: SHORTINT; ch: CHAR; n: LONGINT;
|
||||
BEGIN s := 0; n := 0; Read(R, ch);
|
||||
WHILE ORD(ch) >= 128 DO INC(n, ASH(ORD(ch) - 128, s) ); INC(s, 7); Read(R, ch) END;
|
||||
INC(n, ASH(ORD(ch) MOD 64 - ORD(ch) DIV 64 * 64, s) );
|
||||
x := n
|
||||
END ReadNum;
|
||||
|
||||
PROCEDURE WriteBool* (VAR R: Rider; x: BOOLEAN);
|
||||
BEGIN Write(R, SYSTEM.VAL(CHAR, x))
|
||||
END WriteBool;
|
||||
|
||||
(* PROCEDURE WriteInt* (VAR R: Rider; x: INTEGER);
|
||||
VAR b: ARRAY 2 OF CHAR;
|
||||
BEGIN b[0] := CHR(x); b[1] := CHR(x DIV 256);
|
||||
WriteBytes(R, b, 2);
|
||||
END WriteInt;
|
||||
*)
|
||||
PROCEDURE WriteInt* (VAR R: Rider; x: LONGINT); (* to compile OR compiler; -- noch *)
|
||||
VAR b: ARRAY 4 OF CHAR;
|
||||
BEGIN
|
||||
b[0] := CHR(x); b[1] := CHR(x DIV 100H); b[2] := CHR(x DIV 10000H); b[3] := CHR(x DIV 1000000H);
|
||||
WriteBytes(R, b, 4);
|
||||
END WriteInt;
|
||||
|
||||
PROCEDURE WriteLInt* (VAR R: Rider; x: LONGINT);
|
||||
VAR b: ARRAY 4 OF CHAR;
|
||||
BEGIN
|
||||
b[0] := CHR(x); b[1] := CHR(x DIV 100H); b[2] := CHR(x DIV 10000H); b[3] := CHR(x DIV 1000000H);
|
||||
WriteBytes(R, b, 4);
|
||||
END WriteLInt;
|
||||
|
||||
PROCEDURE WriteSet* (VAR R: Rider; x: SET);
|
||||
VAR b: ARRAY 4 OF CHAR; i: LONGINT;
|
||||
BEGIN i := SYSTEM.VAL(LONGINT, x);
|
||||
b[0] := CHR(i); b[1] := CHR(i DIV 100H); b[2] := CHR(i DIV 10000H); b[3] := CHR(i DIV 1000000H);
|
||||
WriteBytes(R, b, 4);
|
||||
END WriteSet;
|
||||
|
||||
PROCEDURE WriteReal* (VAR R: Rider; x: REAL);
|
||||
VAR b: ARRAY 4 OF CHAR;
|
||||
BEGIN FlipBytes(x, b); WriteBytes(R, b, 4)
|
||||
END WriteReal;
|
||||
|
||||
PROCEDURE WriteLReal* (VAR R: Rider; x: LONGREAL);
|
||||
VAR b: ARRAY 8 OF CHAR;
|
||||
BEGIN FlipBytes(x, b); WriteBytes(R, b, 8)
|
||||
END WriteLReal;
|
||||
|
||||
PROCEDURE WriteString* (VAR R: Rider; x: ARRAY [1] OF CHAR);
|
||||
VAR i: INTEGER;
|
||||
BEGIN i := 0;
|
||||
WHILE x[i] # 0X DO INC(i) END ;
|
||||
WriteBytes(R, x, i+1)
|
||||
END WriteString;
|
||||
|
||||
PROCEDURE WriteNum* (VAR R: Rider; x: LONGINT);
|
||||
BEGIN
|
||||
WHILE (x < - 64) OR (x > 63) DO Write(R, CHR(x MOD 128 + 128)); x := x DIV 128 END;
|
||||
Write(R, CHR(x MOD 128))
|
||||
END WriteNum;
|
||||
|
||||
PROCEDURE GetName*(f: File; VAR name: ARRAY OF CHAR);
|
||||
BEGIN
|
||||
COPY (f.workName, name);
|
||||
END GetName;
|
||||
|
||||
PROCEDURE Finalize(o: SYSTEM.PTR);
|
||||
VAR f: File; res: LONGINT;
|
||||
BEGIN
|
||||
f := SYSTEM.VAL(File, o);
|
||||
IF f.fd >= 0 THEN
|
||||
fileTab[f.fd] := 0; res := Unix.Close(f.fd); f.fd := -1; DEC(Kernel.nofiles);
|
||||
IF f.tempFile THEN res := Unix.Unlink(f.workName) END
|
||||
END
|
||||
END Finalize;
|
||||
|
||||
PROCEDURE Init;
|
||||
VAR i: LONGINT;
|
||||
BEGIN
|
||||
i := 0; WHILE i < fileTabSize DO fileTab[i] := 0; INC(i) END ;
|
||||
tempno := -1; Kernel.nofiles := 0
|
||||
END Init;
|
||||
|
||||
BEGIN Init
|
||||
END CompatFiles.
|
||||
Loading…
Add table
Add a link
Reference in a new issue