mirror of
https://github.com/vishapoberon/compiler.git
synced 2026-04-05 23:22:25 +00:00
Beginning adding -OC (large model) runtime library
This commit is contained in:
parent
9ffafc59b4
commit
212bcd58b9
23 changed files with 6183 additions and 169 deletions
10
makefile
10
makefile
|
|
@ -156,13 +156,14 @@ full: configuration
|
|||
@printf "\n\n--- Compiler build successfull ---\n\n"
|
||||
@make -f src/tools/make/oberon.mk -s browsercmd MODEL=2
|
||||
@printf "\n\n--- Library build started ---\n\n"
|
||||
@make -f src/tools/make/oberon.mk -s library MODEL=2
|
||||
@make -f src/tools/make/oberon.mk -s O2library
|
||||
@make -f src/tools/make/oberon.mk -s OakwoodLibrary MODEL=C
|
||||
@printf "\n\n--- Library build successfull ---\n\n"
|
||||
@make -f src/tools/make/oberon.mk -s sourcechanges
|
||||
@make -f src/tools/make/oberon.mk -s install MODEL=2
|
||||
@make -f src/tools/make/oberon.mk -s install
|
||||
@printf "\n\n--- Confidence tests started ---\n\n"
|
||||
@make -f src/tools/make/oberon.mk -s confidence MODEL=2
|
||||
@make -f src/tools/make/oberon.mk -s showpath MODEL=2
|
||||
@make -f src/tools/make/oberon.mk -s showpath
|
||||
|
||||
|
||||
assemble:
|
||||
|
|
@ -190,7 +191,8 @@ browsercmd: configuration
|
|||
|
||||
# library: build all directories under src/library
|
||||
library: configuration
|
||||
@make -f src/tools/make/oberon.mk -s library MODEL=2
|
||||
@make -f src/tools/make/oberon.mk -s O2library
|
||||
@make -f src/tools/make/oberon.mk -s OakwoodLibrary MODEL=C
|
||||
|
||||
# Individual library components
|
||||
v4: configuration
|
||||
|
|
|
|||
|
|
@ -66,7 +66,14 @@ MODULE Compiler; (* J. Templ 3.2.95 *)
|
|||
|
||||
OPT.sintobj.typ := OPT.sinttyp;
|
||||
OPT.intobj.typ := OPT.inttyp;
|
||||
OPT.lintobj.typ := OPT.linttyp
|
||||
OPT.lintobj.typ := OPT.linttyp;
|
||||
|
||||
(* Enable or disable (non-system) BYTE type *)
|
||||
IF OPM.Model = "C" THEN
|
||||
OPT.cpbytetyp.strobj.name[4] := 0X (* Enable Component Pascal non-system BYTE type *)
|
||||
ELSE
|
||||
OPT.cpbytetyp.strobj.name[4] := '@' (* Disable Component Pascal non-system BYTE type *)
|
||||
END
|
||||
END PropagateElementaryTypeSizes;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -821,10 +821,11 @@ MODULE OPC; (* copyright (c) J. Templ 12.7.95 / 3.7.96 *)
|
|||
GenHeaderMsg;
|
||||
OPM.WriteLn;
|
||||
|
||||
(* Define adjustable type sizes *)
|
||||
OPM.WriteString("#define INTEGER int"); OPM.WriteInt(OPT.inttyp.size*8); OPM.WriteLn;
|
||||
OPM.WriteString("#define LONGINT int"); OPM.WriteInt(OPT.linttyp.size*8); OPM.WriteLn;
|
||||
OPM.WriteString("#define SET uint"); OPM.WriteInt(OPT.settyp.size*8); OPM.WriteLn;
|
||||
(* Define model dependent type sizes *)
|
||||
OPM.WriteString("#define SHORTINT int"); OPM.WriteInt(OPT.sinttyp.size*8); OPM.WriteLn;
|
||||
OPM.WriteString("#define INTEGER int"); OPM.WriteInt(OPT.inttyp.size*8); OPM.WriteLn;
|
||||
OPM.WriteString("#define LONGINT int"); OPM.WriteInt(OPT.linttyp.size*8); OPM.WriteLn;
|
||||
OPM.WriteString("#define SET uint"); OPM.WriteInt(OPT.settyp.size*8); OPM.WriteLn;
|
||||
OPM.WriteLn;
|
||||
|
||||
Include(BasicIncludeFile);
|
||||
|
|
|
|||
|
|
@ -151,13 +151,12 @@ CONST
|
|||
VAR
|
||||
topScope*: Object;
|
||||
|
||||
undftyp*,
|
||||
bytetyp*, booltyp*, chartyp*,
|
||||
sinttyp*, inttyp*, linttyp*, hinttyp*,
|
||||
adrtyp*,
|
||||
int8typ*, int16typ*, int32typ*, int64typ*,
|
||||
realtyp*, lrltyp*, settyp*, stringtyp*,
|
||||
niltyp*, notyp*, sysptrtyp*: Struct;
|
||||
undftyp*, niltyp*, notyp*,
|
||||
bytetyp*, cpbytetyp*, booltyp*, chartyp*,
|
||||
sinttyp*, inttyp*, linttyp*, hinttyp*,
|
||||
int8typ*, int16typ*, int32typ*, int64typ*,
|
||||
realtyp*, lrltyp*, settyp*, stringtyp*,
|
||||
adrtyp*, sysptrtyp*: Struct;
|
||||
|
||||
sintobj*, intobj*, lintobj*: Object;
|
||||
|
||||
|
|
@ -1295,13 +1294,13 @@ BEGIN topScope := NIL; OpenScope(0, NIL); OPM.errpos := 0;
|
|||
InitStruct(niltyp, NilTyp);
|
||||
|
||||
(*initialization of module SYSTEM*)
|
||||
EnterTyp("BYTE", Byte, 1, bytetyp);
|
||||
EnterTyp("BYTE", Byte, 1, bytetyp);
|
||||
EnterTyp("PTR", Pointer, -1, sysptrtyp); (* Size set in Compiler.PropagateElementaryTypeSize *)
|
||||
EnterTyp("ADDRESS", Int, -1, adrtyp); (* Size set in Compiler.PropagateElementaryTypeSize *)
|
||||
EnterTyp("INT8", Int, 1, int8typ);
|
||||
EnterTyp("INT16", Int, 2, int16typ);
|
||||
EnterTyp("INT32", Int, 4, int32typ);
|
||||
EnterTyp("INT64", Int, 8, int64typ);
|
||||
EnterTyp("INT8", Int, 1, int8typ);
|
||||
EnterTyp("INT16", Int, 2, int16typ);
|
||||
EnterTyp("INT32", Int, 4, int32typ);
|
||||
EnterTyp("INT64", Int, 8, int64typ);
|
||||
|
||||
EnterProc("ADR", adrfn);
|
||||
EnterProc("CC", ccfn);
|
||||
|
|
@ -1320,12 +1319,13 @@ BEGIN topScope := NIL; OpenScope(0, NIL); OPM.errpos := 0;
|
|||
universe := topScope; topScope^.right := NIL;
|
||||
|
||||
|
||||
EnterTyp("BOOLEAN", Bool, 1, booltyp);
|
||||
EnterTyp("CHAR", Char, 1, chartyp);
|
||||
EnterTyp("BOOLEAN", Bool, 1, booltyp);
|
||||
EnterTyp("CHAR", Char, 1, chartyp);
|
||||
EnterTyp("SET", Set, -1, settyp); (* Size set in Compiler.PropagateElementaryTypeSize *)
|
||||
EnterTyp("REAL", Real, 4, realtyp);
|
||||
EnterTyp("LONGREAL", LReal, 8, lrltyp);
|
||||
EnterTyp("HUGEINT", Int, 8, hinttyp);
|
||||
EnterTyp("REAL", Real, 4, realtyp);
|
||||
EnterTyp("LONGREAL", LReal, 8, lrltyp);
|
||||
EnterTyp("HUGEINT", Int, 8, hinttyp);
|
||||
EnterTyp("BYTE@", Int, 1, cpbytetyp); (* Component Pascal byte type, enabled in Compiler.PropagateElementaryTypeSize *)
|
||||
|
||||
EnterTypeAlias("SHORTINT", sintobj);
|
||||
EnterTypeAlias("INTEGER", intobj);
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ MODULE OPV; (* J. Templ 16.2.95 / 3.7.96
|
|||
|
||||
(* mark basic types as predefined, OPC.Ident can avoid qualification*)
|
||||
OPT.chartyp^.strobj^.linkadr := PredefinedType;
|
||||
OPT.cpbytetyp^.strobj^.linkadr := PredefinedType;
|
||||
OPT.settyp^.strobj^.linkadr := PredefinedType;
|
||||
OPT.realtyp^.strobj^.linkadr := PredefinedType;
|
||||
OPT.adrtyp^.strobj^.linkadr := PredefinedType;
|
||||
|
|
|
|||
|
|
@ -76,4 +76,3 @@ PROCEDURE LinkMain*(VAR moduleName: ARRAY OF CHAR; statically: BOOLEAN; addition
|
|||
|
||||
|
||||
END extTools.
|
||||
,
|
||||
764
src/runtime/Files.Mod
Normal file
764
src/runtime/Files.Mod
Normal file
|
|
@ -0,0 +1,764 @@
|
|||
MODULE Files; (* J. Templ 1.12. 89/12.4.95 Oberon files mapped onto Unix files *)
|
||||
|
||||
IMPORT SYSTEM, Platform, Heap, Strings, Out;
|
||||
|
||||
(* 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;
|
||||
noDesc = -1;
|
||||
notDone = -1;
|
||||
|
||||
(* file states *)
|
||||
open = 0; (* OS File has been opened *)
|
||||
create = 1; (* OS file needs to be created *)
|
||||
close = 2; (* Register telling Create to use registerName directly:
|
||||
i.e. since we're closing and all data is still in
|
||||
buffers bypass writing to temp file and then renaming
|
||||
and just write directly to fianl register name *)
|
||||
|
||||
|
||||
TYPE
|
||||
FileName = ARRAY 101 OF CHAR;
|
||||
File* = POINTER TO FileDesc;
|
||||
Buffer = POINTER TO BufDesc;
|
||||
|
||||
FileDesc = RECORD
|
||||
workName: FileName;
|
||||
registerName: FileName;
|
||||
tempFile: BOOLEAN;
|
||||
identity: Platform.FileIdentity;
|
||||
fd-: Platform.FileHandle;
|
||||
len, pos: LONGINT;
|
||||
bufs: ARRAY nofbufs OF Buffer;
|
||||
swapper: INTEGER;
|
||||
state: INTEGER;
|
||||
next: File;
|
||||
END;
|
||||
|
||||
BufDesc = RECORD
|
||||
f: File;
|
||||
chg: BOOLEAN;
|
||||
org: LONGINT;
|
||||
size: LONGINT;
|
||||
data: ARRAY bufsize OF SYSTEM.BYTE
|
||||
END;
|
||||
|
||||
Rider* = RECORD
|
||||
res*: LONGINT;
|
||||
eof*: BOOLEAN;
|
||||
buf: Buffer;
|
||||
org: LONGINT;
|
||||
offset: LONGINT
|
||||
END;
|
||||
|
||||
|
||||
VAR
|
||||
files: File; (* List of files that have an OS file handle/descriptor assigned *)
|
||||
tempno: INTEGER;
|
||||
HOME: ARRAY 1024 OF CHAR;
|
||||
SearchPath: POINTER TO ARRAY OF CHAR;
|
||||
|
||||
|
||||
|
||||
|
||||
PROCEDURE -IdxTrap "__HALT(-1)";
|
||||
|
||||
PROCEDURE^ Finalize(o: SYSTEM.PTR);
|
||||
|
||||
PROCEDURE Err(s: ARRAY OF CHAR; f: File; errcode: Platform.ErrorCode);
|
||||
BEGIN
|
||||
Out.Ln; Out.String("-- "); Out.String(s); Out.String(": ");
|
||||
IF f # NIL THEN
|
||||
IF f.registerName # "" THEN Out.String(f.registerName) ELSE Out.String(f.workName) END;
|
||||
IF f.fd # 0 THEN Out.String("f.fd = "); Out.Int(f.fd,1) END
|
||||
END;
|
||||
IF errcode # 0 THEN Out.String(" errcode = "); Out.Int(errcode, 1) END;
|
||||
Out.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 Platform.CWD[i] # 0X DO name[i] := Platform.CWD[i]; INC(i) END;
|
||||
IF Platform.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 := Platform.PID;
|
||||
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
|
||||
identity: Platform.FileIdentity;
|
||||
done: BOOLEAN;
|
||||
error: Platform.ErrorCode;
|
||||
err: ARRAY 32 OF CHAR;
|
||||
BEGIN
|
||||
(*
|
||||
Out.String("Files.Create fd = "); Out.Int(f.fd,1);
|
||||
Out.String(", registerName = "); Out.String(f.registerName);
|
||||
Out.String(", workName = "); Out.String(f.workName);
|
||||
Out.String(", state = "); Out.Int(f.state,1);
|
||||
Out.Ln;
|
||||
*)
|
||||
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;
|
||||
error := Platform.Unlink(f.workName); (*unlink first to avoid stale NFS handles and to avoid reuse of inodes*)
|
||||
|
||||
error := Platform.New(f.workName, f.fd);
|
||||
done := error = 0;
|
||||
IF done THEN
|
||||
f.next := files; files := f;
|
||||
INC(Heap.FileCount);
|
||||
Heap.RegisterFinalizer(f, Finalize);
|
||||
f.state := open;
|
||||
f.pos := 0;
|
||||
error := Platform.Identify(f.fd, f.identity);
|
||||
ELSE
|
||||
IF Platform.NoSuchDirectory(error) THEN err := "no such directory"
|
||||
ELSIF Platform.TooManyFiles(error) THEN err := "too many files open"
|
||||
ELSE err := "file not created"
|
||||
END;
|
||||
Err(err, f, error)
|
||||
END
|
||||
END
|
||||
END Create;
|
||||
|
||||
PROCEDURE Flush(buf: Buffer);
|
||||
VAR
|
||||
error: Platform.ErrorCode;
|
||||
f: File;
|
||||
(* identity: Platform.FileIdentity; *)
|
||||
BEGIN
|
||||
(*
|
||||
Out.String("Files.Flush buf.f.registername = "); Out.String(buf.f.registerName);
|
||||
Out.String(", buf.f.fd = "); Out.Int(buf.f.fd,1);
|
||||
Out.String(", buffer at $"); Out.Hex(SYSTEM.ADR(buf.data));
|
||||
Out.String(", size "); Out.Int(buf.size,1); Out.Ln;
|
||||
*)
|
||||
IF buf.chg THEN f := buf.f; Create(f);
|
||||
IF buf.org # f.pos THEN
|
||||
error := Platform.Seek(f.fd, buf.org, Platform.SeekSet);
|
||||
(*
|
||||
Out.String("Seeking to "); Out.Int(buf.org,1);
|
||||
Out.String(", error code "); Out.Int(error,1); Out.Ln;
|
||||
*)
|
||||
END;
|
||||
error := Platform.Write(f.fd, SYSTEM.ADR(buf.data), buf.size);
|
||||
IF error # 0 THEN Err("error writing file", f, error) END;
|
||||
f.pos := buf.org + buf.size;
|
||||
buf.chg := FALSE;
|
||||
error := Platform.Identify(f.fd, f.identity);
|
||||
IF error # 0 THEN Err("error identifying file", f, error) END;
|
||||
(*
|
||||
error := Platform.Identify(f.fd, identity);
|
||||
f.identity.mtime := identity.mtime;
|
||||
*)
|
||||
END
|
||||
END Flush;
|
||||
|
||||
|
||||
PROCEDURE CloseOSFile(f: File);
|
||||
(* Close the OS file handle and remove f from 'files' *)
|
||||
VAR prev: File; error: Platform.ErrorCode;
|
||||
BEGIN
|
||||
IF files = f THEN files := f.next
|
||||
ELSE
|
||||
prev := files;
|
||||
WHILE (prev # NIL) & (prev.next # f) DO prev := prev.next END;
|
||||
IF prev.next # NIL THEN prev.next := f.next END
|
||||
END;
|
||||
error := Platform.Close(f.fd);
|
||||
f.fd := noDesc; f.state := create; DEC(Heap.FileCount);
|
||||
END CloseOSFile;
|
||||
|
||||
|
||||
PROCEDURE Close* (f: File);
|
||||
VAR
|
||||
i: LONGINT;
|
||||
error: Platform.ErrorCode;
|
||||
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;
|
||||
error := Platform.Sync(f.fd);
|
||||
IF error # 0 THEN Err("error writing file", f, error) END;
|
||||
CloseOSFile(f);
|
||||
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);
|
||||
(* Extract next individual directory from searchpath starting at pos,
|
||||
updating pos and returning dir.
|
||||
Supports ~, ~user and blanks inside path *)
|
||||
VAR i: INTEGER; ch: CHAR;
|
||||
BEGIN
|
||||
i := 0;
|
||||
IF SearchPath = NIL THEN
|
||||
IF pos = 0 THEN
|
||||
dir[0] := "."; i := 1; INC(pos) (* Default search path is just the current directory *)
|
||||
END
|
||||
ELSE
|
||||
ch := SearchPath[pos];
|
||||
WHILE (ch = " ") OR (ch = ";") DO INC(pos); ch := SearchPath[pos] END;
|
||||
IF ch = "~" THEN
|
||||
INC(pos); ch := SearchPath[pos];
|
||||
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 := SearchPath[pos] END;
|
||||
WHILE (i > 0) & (dir[i-1] = " ") DO DEC(i) END
|
||||
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(identity: Platform.FileIdentity): File;
|
||||
VAR f: File; i: INTEGER; error: Platform.ErrorCode;
|
||||
BEGIN f := files;
|
||||
WHILE f # NIL DO
|
||||
IF Platform.SameFile(identity, f.identity) THEN
|
||||
IF ~Platform.SameFileTime(identity, f.identity) 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.identity := identity;
|
||||
error := Platform.Size(f.fd, f.len);
|
||||
END;
|
||||
RETURN f
|
||||
END;
|
||||
f := f.next
|
||||
END;
|
||||
RETURN NIL
|
||||
END CacheEntry;
|
||||
|
||||
PROCEDURE Old*(name: ARRAY OF CHAR): File;
|
||||
VAR
|
||||
f: File;
|
||||
fd: Platform.FileHandle;
|
||||
pos: INTEGER;
|
||||
done: BOOLEAN;
|
||||
dir, path: ARRAY 256 OF CHAR;
|
||||
error: Platform.ErrorCode;
|
||||
identity: Platform.FileIdentity;
|
||||
BEGIN
|
||||
(* Out.String("Files.Old "); Out.String(name); Out.Ln; *)
|
||||
IF name # "" THEN
|
||||
IF HasDir(name) THEN dir := ""; COPY(name, path)
|
||||
ELSE pos := 0; ScanPath(pos, dir); MakeFileName(dir, name, path); ScanPath(pos, dir)
|
||||
END;
|
||||
LOOP
|
||||
error := Platform.OldRW(path, fd); done := error = 0;
|
||||
IF ~done & Platform.TooManyFiles(error) THEN Err("too many files open", f, error) END;
|
||||
IF ~done & Platform.Inaccessible(error) THEN
|
||||
error := Platform.OldRO(path, fd); done := error = 0;
|
||||
END;
|
||||
IF ~done & ~Platform.Absent(error) THEN
|
||||
Out.String("Warning: Files.Old "); Out.String(name);
|
||||
Out.String(" error = "); Out.Int(error, 0); Out.Ln;
|
||||
END;
|
||||
IF done THEN
|
||||
(* Out.String(" fd = "); Out.Int(fd,1); Out.Ln; *)
|
||||
error := Platform.Identify(fd, identity);
|
||||
f := CacheEntry(identity);
|
||||
IF f # NIL THEN
|
||||
(* error := Platform.Close(fd); DCWB: Either this should be removed or should call CloseOSFile. *)
|
||||
RETURN f
|
||||
ELSE NEW(f); Heap.RegisterFinalizer(f, Finalize);
|
||||
f.fd := fd; f.state := open; f.pos := 0; f.swapper := -1; (*all f.buf[i] = NIL*)
|
||||
error := Platform.Size(fd, f.len);
|
||||
COPY(name, f.workName); f.registerName := ""; f.tempFile := FALSE;
|
||||
f.identity := identity;
|
||||
f.next := files; files := f; INC(Heap.FileCount);
|
||||
RETURN f
|
||||
END
|
||||
ELSIF dir = "" THEN RETURN NIL
|
||||
ELSE MakeFileName(dir, name, path); ScanPath(pos, dir)
|
||||
END
|
||||
END
|
||||
ELSE RETURN NIL
|
||||
END
|
||||
END Old;
|
||||
|
||||
PROCEDURE Purge* (f: File);
|
||||
VAR i: INTEGER; identity: Platform.FileIdentity; error: Platform.ErrorCode;
|
||||
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
|
||||
error := Platform.Truncate(f.fd, 0);
|
||||
error := Platform.Seek(f.fd, 0, Platform.SeekSet)
|
||||
END;
|
||||
f.pos := 0; f.len := 0; f.swapper := -1;
|
||||
error := Platform.Identify(f.fd, identity); Platform.SetMTime(f.identity, identity)
|
||||
END Purge;
|
||||
|
||||
PROCEDURE GetDate* (f: File; VAR t, d: LONGINT);
|
||||
VAR
|
||||
identity: Platform.FileIdentity; error: Platform.ErrorCode;
|
||||
BEGIN
|
||||
Create(f); error := Platform.Identify(f.fd, identity);
|
||||
Platform.MTimeAsClock(identity, t, d)
|
||||
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: LONGINT; buf: Buffer; error: Platform.ErrorCode;
|
||||
BEGIN
|
||||
IF f # NIL THEN
|
||||
(*
|
||||
Out.String("Files.Set rider on fd = "); Out.Int(f.fd,1);
|
||||
Out.String(", registerName = "); Out.String(f.registerName);
|
||||
Out.String(", workName = "); Out.String(f.workName);
|
||||
Out.String(", state = "); Out.Int(f.state,1);
|
||||
Out.Ln;
|
||||
*)
|
||||
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 error := Platform.Seek(f.fd, org, Platform.SeekSet) END;
|
||||
error := Platform.ReadBuf(f.fd, buf.data, n);
|
||||
IF error # 0 THEN Err("read from file not done", f, error) 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 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 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 := Platform.Unlink(name) END Delete;
|
||||
|
||||
PROCEDURE Rename* (old, new: ARRAY OF CHAR; VAR res: INTEGER);
|
||||
VAR
|
||||
fdold, fdnew: Platform.FileHandle;
|
||||
n: LONGINT;
|
||||
error, ignore: Platform.ErrorCode;
|
||||
oldidentity, newidentity: Platform.FileIdentity;
|
||||
buf: ARRAY 4096 OF CHAR;
|
||||
BEGIN
|
||||
(*
|
||||
Out.String("Files.Rename old = "); Out.String(old);
|
||||
Out.String(", new = "); Out.String(new); Out.Ln;
|
||||
*)
|
||||
error := Platform.IdentifyByName(old, oldidentity);
|
||||
IF error = 0 THEN
|
||||
error := Platform.IdentifyByName(new, newidentity);
|
||||
IF (error # 0) & ~Platform.SameFile(oldidentity, newidentity) THEN
|
||||
Delete(new, error); (* work around stale nfs handles *)
|
||||
END;
|
||||
error := Platform.Rename(old, new);
|
||||
(* Out.String("Platform.Rename error code "); Out.Int(error,1); Out.Ln; *)
|
||||
IF ~Platform.DifferentFilesystems(error) THEN
|
||||
res := error; RETURN
|
||||
ELSE
|
||||
(* cross device link, move the file *)
|
||||
error := Platform.OldRO(old, fdold);
|
||||
IF error # 0 THEN res := 2; RETURN END;
|
||||
error := Platform.New(new, fdnew);
|
||||
IF error # 0 THEN error := Platform.Close(fdold); res := 3; RETURN END;
|
||||
error := Platform.Read(fdold, SYSTEM.ADR(buf), bufsize, n);
|
||||
WHILE n > 0 DO
|
||||
error := Platform.Write(fdnew, SYSTEM.ADR(buf), n);
|
||||
IF error # 0 THEN
|
||||
ignore := Platform.Close(fdold);
|
||||
ignore := Platform.Close(fdnew);
|
||||
Err("cannot move file", NIL, error)
|
||||
END;
|
||||
error := Platform.Read(fdold, SYSTEM.ADR(buf), bufsize, n);
|
||||
END;
|
||||
ignore := Platform.Close(fdold);
|
||||
ignore := Platform.Close(fdnew);
|
||||
IF n = 0 THEN
|
||||
error := Platform.Unlink(old); res := 0
|
||||
ELSE
|
||||
Err("cannot move file", NIL, error)
|
||||
END;
|
||||
END
|
||||
ELSE
|
||||
res := 2 (* old file not found *)
|
||||
END
|
||||
END Rename;
|
||||
|
||||
PROCEDURE Register* (f: File);
|
||||
VAR idx, errcode: INTEGER; f1: File; file: ARRAY 104 OF CHAR;
|
||||
BEGIN
|
||||
(*
|
||||
Out.String("Files.Register f.registerName = "); Out.String(f.registerName);
|
||||
Out.String(", fd = "); Out.Int(f.fd,1); Out.Ln;
|
||||
*)
|
||||
IF (f.state = create) & (f.registerName # "") THEN f.state := close (* shortcut renaming *) END;
|
||||
Close(f);
|
||||
IF f.registerName # "" THEN
|
||||
Rename(f.workName, f.registerName, errcode);
|
||||
(*
|
||||
Out.String("Renamed (for register) f.fd = "); Out.Int(f.fd,1);
|
||||
Out.String(" from workname "); Out.String(f.workName);
|
||||
Out.String(" to registerName "); Out.String(f.registerName);
|
||||
Out.String(" errorcode = "); Out.Int(errcode,1); Out.Ln;
|
||||
*)
|
||||
IF errcode # 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 := Platform.Chdir(path);
|
||||
END ChangeDirectory;
|
||||
|
||||
PROCEDURE FlipBytes(VAR src, dest: ARRAY OF SYSTEM.BYTE);
|
||||
VAR i, j: LONGINT;
|
||||
BEGIN
|
||||
IF ~Platform.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 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);
|
||||
(* Reads 32 bits as a SET value (even on 64 bit systems. See Oakwood appendix 1.2.5.4 *)
|
||||
VAR b: ARRAY 4 OF CHAR; l: LONGINT;
|
||||
BEGIN ReadBytes(R, b, 4);
|
||||
(* Need to read via a LONGINT to provide correct behaviour for 64 bit sets. *)
|
||||
l := ORD(b[0]) + ORD(b[1])*100H + ORD(b[2])*10000H + ORD(b[3])*1000000H;
|
||||
x := SYSTEM.VAL(SET, l)
|
||||
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;
|
||||
|
||||
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 ReadNum64* (VAR R: Rider; VAR x: SYSTEM.INT64);
|
||||
(* todo. use proper code when INC/ASH properly support INT64 on 32 bit platforms
|
||||
VAR s: SHORTINT; ch: CHAR; n: SYSTEM.INT64;
|
||||
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
|
||||
*)
|
||||
VAR n: LONGINT;
|
||||
BEGIN ReadNum(R, n); x := n
|
||||
END ReadNum64;
|
||||
|
||||
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 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 WriteNum64* (VAR R: Rider; x: SYSTEM.INT64);
|
||||
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 WriteNum64;
|
||||
|
||||
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);
|
||||
(*
|
||||
Out.String("Files.Finalize f.fd = "); Out.Int(f.fd,1);
|
||||
Out.String(", f.registername = "); Out.String(f.registerName);
|
||||
Out.String(", f.workName = "); Out.String(f.workName); Out.Ln;
|
||||
*)
|
||||
IF f.fd >= 0 THEN
|
||||
CloseOSFile(f);
|
||||
IF f.tempFile THEN res := Platform.Unlink(f.workName) END
|
||||
END
|
||||
END Finalize;
|
||||
|
||||
PROCEDURE SetSearchPath*(path: ARRAY OF CHAR);
|
||||
BEGIN
|
||||
IF Strings.Length(path) # 0 THEN
|
||||
NEW(SearchPath, Strings.Length(path)+1);
|
||||
COPY(path, SearchPath^)
|
||||
ELSE
|
||||
SearchPath := NIL
|
||||
END
|
||||
END SetSearchPath;
|
||||
|
||||
|
||||
BEGIN
|
||||
tempno := -1;
|
||||
Heap.FileCount := 0;
|
||||
HOME := ""; Platform.GetEnv("HOME", HOME);
|
||||
END Files.
|
||||
578
src/runtime/Heap.Mod
Normal file
578
src/runtime/Heap.Mod
Normal file
|
|
@ -0,0 +1,578 @@
|
|||
MODULE Heap;
|
||||
|
||||
IMPORT S := SYSTEM; (* Cannot import anything else as heap initialization must complete
|
||||
before any other modules are initialized. *)
|
||||
|
||||
CONST
|
||||
ModNameLen = 20;
|
||||
CmdNameLen = 24;
|
||||
SZA = SIZE(S.ADDRESS); (* Size of address *)
|
||||
Unit = 4*SZA; (* smallest possible heap block *)
|
||||
nofLists = 9; (* number of free_lists *)
|
||||
heapSize0 = 8000*Unit; (* startup heap size *)
|
||||
|
||||
(* all blocks look the same:
|
||||
free blocks describe themselves: size = Unit
|
||||
tag = &tag++
|
||||
->block size
|
||||
sentinel = -SZA
|
||||
next
|
||||
*)
|
||||
|
||||
(* heap chunks *)
|
||||
nextChnkOff = S.VAL(S.ADDRESS, 0); (* next heap chunk, sorted ascendingly! *)
|
||||
endOff = S.VAL(S.ADDRESS, SZA); (* end of heap chunk *)
|
||||
blkOff = S.VAL(S.ADDRESS, 3*SZA); (* first block in a chunk *)
|
||||
|
||||
(* heap blocks *)
|
||||
tagOff = S.VAL(S.ADDRESS, 0); (* block starts with tag *)
|
||||
sizeOff = S.VAL(S.ADDRESS, SZA); (* block size in free block relative to block start *)
|
||||
sntlOff = S.VAL(S.ADDRESS, 2*SZA); (* pointer offset table sentinel in free block relative to block start *)
|
||||
nextOff = S.VAL(S.ADDRESS, 3*SZA); (* next pointer in free block relative to block start *)
|
||||
NoPtrSntl = S.VAL(S.ADDRESS, -SZA);
|
||||
AddressZero = S.VAL(S.ADDRESS, 0);
|
||||
|
||||
TYPE
|
||||
ModuleName = ARRAY ModNameLen OF CHAR;
|
||||
CmdName = ARRAY CmdNameLen OF CHAR;
|
||||
|
||||
Module = POINTER TO ModuleDesc;
|
||||
Cmd = POINTER TO CmdDesc;
|
||||
|
||||
EnumProc = PROCEDURE(P: PROCEDURE(p: S.PTR));
|
||||
|
||||
ModuleDesc = RECORD
|
||||
next: Module;
|
||||
name: ModuleName;
|
||||
refcnt: LONGINT;
|
||||
cmds: Cmd;
|
||||
types: S.ADDRESS;
|
||||
enumPtrs: EnumProc;
|
||||
reserved1, reserved2: LONGINT
|
||||
END ;
|
||||
|
||||
Command = PROCEDURE;
|
||||
|
||||
CmdDesc = RECORD
|
||||
next: Cmd;
|
||||
name: CmdName;
|
||||
cmd: Command
|
||||
END ;
|
||||
|
||||
Finalizer = PROCEDURE(obj: S.PTR);
|
||||
|
||||
FinNode = POINTER TO FinDesc;
|
||||
FinDesc = RECORD
|
||||
next: FinNode;
|
||||
obj: S.ADDRESS; (* weak pointer *)
|
||||
marked: BOOLEAN;
|
||||
finalize: Finalizer;
|
||||
END ;
|
||||
|
||||
VAR
|
||||
(* the list of loaded (=initialization started) modules *)
|
||||
modules*: S.PTR;
|
||||
|
||||
freeList: ARRAY nofLists + 1 OF S.ADDRESS; (* dummy, 16, 32, 48, 64, 80, 96, 112, 128, sentinel *)
|
||||
bigBlocks: S.ADDRESS;
|
||||
allocated*: S.ADDRESS;
|
||||
firstTry: BOOLEAN;
|
||||
|
||||
(* extensible heap *)
|
||||
heap: S.ADDRESS; (* the sorted list of heap chunks *)
|
||||
heapend: S.ADDRESS; (* max possible pointer value (used for stack collection) *)
|
||||
heapsize*: S.ADDRESS; (* the sum of all heap chunk sizes *)
|
||||
|
||||
(* finalization candidates *)
|
||||
fin: FinNode;
|
||||
|
||||
(* garbage collector locking *)
|
||||
lockdepth: INTEGER;
|
||||
interrupted: BOOLEAN;
|
||||
|
||||
(* File system file count monitor *)
|
||||
FileCount*: INTEGER;
|
||||
|
||||
|
||||
PROCEDURE Lock*;
|
||||
BEGIN
|
||||
INC(lockdepth);
|
||||
END Lock;
|
||||
|
||||
PROCEDURE -PlatformHalt(code: LONGINT) "Platform_Halt(code)";
|
||||
|
||||
PROCEDURE Unlock*;
|
||||
BEGIN
|
||||
DEC(lockdepth);
|
||||
IF interrupted & (lockdepth = 0) THEN
|
||||
PlatformHalt(-9);
|
||||
END
|
||||
END Unlock;
|
||||
|
||||
|
||||
(*
|
||||
PROCEDURE TAS*(VAR flag:BOOLEAN): BOOLEAN; (* added for compatibility with ulmSYSTEM module; noch *)
|
||||
VAR oldflag : BOOLEAN;
|
||||
BEGIN
|
||||
oldflag := flag;
|
||||
flag := TRUE;
|
||||
RETURN oldflag;
|
||||
END TAS;
|
||||
*)
|
||||
|
||||
PROCEDURE REGMOD*(VAR name: ModuleName; enumPtrs: EnumProc): S.PTR;
|
||||
VAR m: Module;
|
||||
BEGIN
|
||||
(* REGMOD is called at the start of module initialisation code before that modules
|
||||
type descriptors have been set up. 'NEW' depends on the Heap modules type
|
||||
descriptors being ready for use, therefore, just for the Heap module itself, we
|
||||
must use S.NEW. *)
|
||||
IF name = "Heap" THEN
|
||||
S.NEW(m, SIZE(ModuleDesc))
|
||||
ELSE
|
||||
NEW(m)
|
||||
END;
|
||||
m.types := 0; m.cmds := NIL;
|
||||
COPY(name, m.name); m.refcnt := 0; m.enumPtrs := enumPtrs; m.next := S.VAL(Module, modules);
|
||||
modules := m;
|
||||
RETURN m
|
||||
END REGMOD;
|
||||
|
||||
PROCEDURE REGCMD*(m: Module; VAR name: CmdName; cmd: Command);
|
||||
VAR c: Cmd;
|
||||
BEGIN
|
||||
(* REGCMD is called during module initialisation code before that modules
|
||||
type descriptors have been set up. 'NEW' depends on the Heap modules type
|
||||
descriptors being ready for use, therefore, just for the commands registered
|
||||
by the Heap module itself, we must use S.NEW. *)
|
||||
IF m.name = "Heap" THEN
|
||||
S.NEW(c, SIZE(CmdDesc))
|
||||
ELSE
|
||||
NEW(c)
|
||||
END;
|
||||
COPY(name, c.name); c.cmd := cmd; c.next := m.cmds; m.cmds := c
|
||||
END REGCMD;
|
||||
|
||||
PROCEDURE REGTYP*(m: Module; typ: S.ADDRESS);
|
||||
BEGIN S.PUT(typ, m.types); m.types := typ
|
||||
END REGTYP;
|
||||
|
||||
PROCEDURE INCREF*(m: Module);
|
||||
BEGIN INC(m.refcnt)
|
||||
END INCREF;
|
||||
|
||||
|
||||
PROCEDURE -ExternPlatformOSAllocate "extern address Platform_OSAllocate(address size);";
|
||||
PROCEDURE -OSAllocate(size: S.ADDRESS): S.ADDRESS "Platform_OSAllocate(size)";
|
||||
|
||||
PROCEDURE NewChunk(blksz: S.ADDRESS): S.ADDRESS;
|
||||
VAR chnk: S.ADDRESS;
|
||||
BEGIN
|
||||
chnk := OSAllocate(blksz + blkOff);
|
||||
IF chnk # 0 THEN
|
||||
S.PUT(chnk + endOff, chnk + (blkOff + blksz));
|
||||
S.PUT(chnk + blkOff, chnk + (blkOff + sizeOff));
|
||||
S.PUT(chnk + (blkOff + sizeOff), blksz);
|
||||
S.PUT(chnk + (blkOff + sntlOff), NoPtrSntl);
|
||||
S.PUT(chnk + (blkOff + nextOff), bigBlocks);
|
||||
bigBlocks := chnk + blkOff;
|
||||
INC(heapsize, blksz)
|
||||
END ;
|
||||
RETURN chnk
|
||||
END NewChunk;
|
||||
|
||||
PROCEDURE ExtendHeap(blksz: S.ADDRESS);
|
||||
VAR size, chnk, j, next: S.ADDRESS;
|
||||
BEGIN
|
||||
IF blksz > 10000*Unit THEN size := blksz
|
||||
ELSE size := 10000*Unit (* additional heuristics *)
|
||||
END ;
|
||||
chnk := NewChunk(size);
|
||||
IF chnk # 0 THEN
|
||||
(*sorted insertion*)
|
||||
IF chnk < heap THEN
|
||||
S.PUT(chnk, heap); heap := chnk
|
||||
ELSE
|
||||
j := heap; S.GET(j, next);
|
||||
WHILE (next # 0) & (chnk > next) DO
|
||||
j := next;
|
||||
S.GET(j, next)
|
||||
END;
|
||||
S.PUT(chnk, next); S.PUT(j, chnk)
|
||||
END ;
|
||||
IF next = 0 THEN S.GET(chnk+endOff, heapend) END
|
||||
END
|
||||
END ExtendHeap;
|
||||
|
||||
PROCEDURE ^GC*(markStack: BOOLEAN);
|
||||
|
||||
PROCEDURE NEWREC*(tag: S.ADDRESS): S.PTR;
|
||||
VAR
|
||||
i, i0, di, blksz, restsize, t, adr, end, next, prev: S.ADDRESS;
|
||||
new: S.PTR;
|
||||
BEGIN
|
||||
Lock();
|
||||
S.GET(tag, blksz);
|
||||
|
||||
ASSERT((Unit = 16) OR (Unit = 32));
|
||||
ASSERT(SIZE(S.PTR) = SIZE(S.ADDRESS));
|
||||
ASSERT(blksz MOD Unit = 0);
|
||||
|
||||
i0 := blksz DIV Unit; i := i0;
|
||||
IF i < nofLists THEN adr := freeList[i];
|
||||
WHILE adr = 0 DO INC(i); adr := freeList[i] END
|
||||
END ;
|
||||
IF i < nofLists THEN (* unlink *)
|
||||
S.GET(adr + nextOff, next);
|
||||
freeList[i] := next;
|
||||
IF i # i0 THEN (* split *)
|
||||
di := i - i0; restsize := di * Unit; end := adr + restsize;
|
||||
S.PUT(end + sizeOff, blksz);
|
||||
S.PUT(end + sntlOff, NoPtrSntl);
|
||||
S.PUT(end, end + sizeOff);
|
||||
S.PUT(adr + sizeOff, restsize);
|
||||
S.PUT(adr + nextOff, freeList[di]);
|
||||
freeList[di] := adr;
|
||||
INC(adr, restsize)
|
||||
END
|
||||
ELSE
|
||||
adr := bigBlocks; prev := 0;
|
||||
LOOP
|
||||
IF adr = 0 THEN
|
||||
IF firstTry THEN
|
||||
GC(TRUE); INC(blksz, Unit);
|
||||
IF (heapsize - allocated - blksz) * 4 < heapsize THEN
|
||||
(* heap is still almost full; expand to avoid thrashing *)
|
||||
ExtendHeap((allocated + blksz) DIV (3*Unit) * (4*Unit) - heapsize)
|
||||
END ;
|
||||
firstTry := FALSE; new := NEWREC(tag); firstTry := TRUE;
|
||||
IF new = NIL THEN
|
||||
(* depending on the fragmentation, the heap may not have been extended by
|
||||
the anti-thrashing heuristics above *)
|
||||
ExtendHeap((allocated + blksz) DIV (3*Unit) * (4*Unit) - heapsize);
|
||||
new := NEWREC(tag); (* will find a free block if heap has been expanded properly *)
|
||||
END ;
|
||||
Unlock(); RETURN new
|
||||
ELSE
|
||||
Unlock(); RETURN NIL
|
||||
END
|
||||
END ;
|
||||
S.GET(adr+sizeOff, t);
|
||||
IF t >= blksz THEN EXIT END ;
|
||||
prev := adr; S.GET(adr + nextOff, adr)
|
||||
END ;
|
||||
restsize := t - blksz; end := adr + restsize;
|
||||
S.PUT(end + sizeOff, blksz);
|
||||
S.PUT(end + sntlOff, NoPtrSntl);
|
||||
S.PUT(end, end + sizeOff);
|
||||
IF restsize > nofLists * Unit THEN (*resize*)
|
||||
S.PUT(adr + sizeOff, restsize)
|
||||
ELSE (*unlink*)
|
||||
S.GET(adr + nextOff, next);
|
||||
IF prev = 0 THEN bigBlocks := next
|
||||
ELSE S.PUT(prev + nextOff, next);
|
||||
END ;
|
||||
IF restsize > 0 THEN (*move*)
|
||||
di := restsize DIV Unit;
|
||||
S.PUT(adr + sizeOff, restsize);
|
||||
S.PUT(adr + nextOff, freeList[di]);
|
||||
freeList[di] := adr
|
||||
END
|
||||
END ;
|
||||
INC(adr, restsize)
|
||||
END ;
|
||||
i := adr + 4*SZA; end := adr + blksz;
|
||||
WHILE i < end DO (*deliberately unrolled*)
|
||||
S.PUT(i, AddressZero);
|
||||
S.PUT(i + SZA, AddressZero);
|
||||
S.PUT(i + 2*SZA, AddressZero);
|
||||
S.PUT(i + 3*SZA, AddressZero);
|
||||
INC(i, 4*SZA)
|
||||
END ;
|
||||
S.PUT(adr + nextOff, AddressZero);
|
||||
S.PUT(adr, tag);
|
||||
S.PUT(adr + sizeOff, AddressZero);
|
||||
S.PUT(adr + sntlOff, AddressZero);
|
||||
INC(allocated, blksz);
|
||||
Unlock();
|
||||
RETURN S.VAL(S.PTR, adr + SZA)
|
||||
END NEWREC;
|
||||
|
||||
PROCEDURE NEWBLK*(size: S.ADDRESS): S.PTR;
|
||||
VAR blksz, tag: S.ADDRESS; new: S.PTR;
|
||||
BEGIN
|
||||
Lock();
|
||||
blksz := (size + (4*SZA + Unit - 1)) DIV Unit * Unit; (*size + tag + meta + blksz + sntnl + UnitAlignment*)
|
||||
new := NEWREC(S.ADR(blksz));
|
||||
tag := S.VAL(S.ADDRESS, new) + blksz - 3*SZA;
|
||||
S.PUT(tag - SZA, AddressZero); (*reserved for meta info*)
|
||||
S.PUT(tag, blksz);
|
||||
S.PUT(tag + SZA, NoPtrSntl);
|
||||
S.PUT(S.VAL(S.ADDRESS, new) - SZA, tag);
|
||||
Unlock();
|
||||
RETURN new
|
||||
END NEWBLK;
|
||||
|
||||
PROCEDURE Mark(q: S.ADDRESS);
|
||||
VAR p, tag, offset, fld, n, tagbits: S.ADDRESS;
|
||||
BEGIN
|
||||
IF q # 0 THEN
|
||||
S.GET(q - SZA, tagbits); (* Load the tag for the record at q *)
|
||||
IF ~ODD(tagbits) THEN (* If it has not already been marked *)
|
||||
S.PUT(q - SZA, tagbits + 1); (* Mark it *)
|
||||
p := 0;
|
||||
tag := tagbits + SZA; (* Tag addresses first offset *)
|
||||
LOOP
|
||||
S.GET(tag, offset); (* Get next ptr field offset *)
|
||||
IF offset < 0 THEN (* Sentinel reached: Value is -8*(#fields+1) *)
|
||||
S.PUT(q - SZA, tag + offset + 1); (* Rotate base ptr into tag *)
|
||||
IF p = 0 THEN EXIT END ;
|
||||
n := q; q := p;
|
||||
S.GET(q - SZA, tag); DEC(tag, 1);
|
||||
S.GET(tag, offset); fld := q + offset;
|
||||
S.GET(fld, p); S.PUT(fld, S.VAL(S.PTR, n))
|
||||
ELSE (* offset references a ptr field *)
|
||||
fld := q + offset; (* S.ADDRESS the pointer *)
|
||||
S.GET(fld, n); (* Load the pointer *)
|
||||
IF n # 0 THEN (* If pointer is not NIL *)
|
||||
S.GET(n - SZA, tagbits); (* Consider record pointed to by this field *)
|
||||
IF ~ODD(tagbits) THEN
|
||||
S.PUT(n - SZA, tagbits + 1);
|
||||
S.PUT(q - SZA, tag + 1);
|
||||
S.PUT(fld, S.VAL(S.PTR, p));
|
||||
p := q; q := n;
|
||||
tag := tagbits
|
||||
END
|
||||
END
|
||||
END ;
|
||||
INC(tag, SZA)
|
||||
END
|
||||
END
|
||||
END
|
||||
END Mark;
|
||||
|
||||
PROCEDURE MarkP(p: S.PTR); (* for compatibility with EnumPtrs in ANSI mode *)
|
||||
BEGIN
|
||||
Mark(S.VAL(S.ADDRESS, p))
|
||||
END MarkP;
|
||||
|
||||
PROCEDURE Scan;
|
||||
VAR chnk, adr, end, start, tag, i, size, freesize: S.ADDRESS;
|
||||
BEGIN bigBlocks := 0; i := 1;
|
||||
WHILE i < nofLists DO freeList[i] := 0; INC(i) END ;
|
||||
freesize := 0; allocated := 0; chnk := heap;
|
||||
WHILE chnk # 0 DO
|
||||
adr := chnk + blkOff;
|
||||
S.GET(chnk + endOff, end);
|
||||
WHILE adr < end DO
|
||||
S.GET(adr, tag);
|
||||
IF ODD(tag) THEN (*marked*)
|
||||
IF freesize > 0 THEN
|
||||
start := adr - freesize;
|
||||
S.PUT(start, start+SZA);
|
||||
S.PUT(start+sizeOff, freesize);
|
||||
S.PUT(start+sntlOff, NoPtrSntl);
|
||||
i := freesize DIV Unit; freesize := 0;
|
||||
IF i < nofLists THEN S.PUT(start + nextOff, freeList[i]); freeList[i] := start
|
||||
ELSE S.PUT(start + nextOff, bigBlocks); bigBlocks := start
|
||||
END
|
||||
END ;
|
||||
DEC(tag, 1);
|
||||
S.PUT(adr, tag);
|
||||
S.GET(tag, size);
|
||||
INC(allocated, size);
|
||||
INC(adr, size)
|
||||
ELSE (*unmarked*)
|
||||
S.GET(tag, size);
|
||||
INC(freesize, size);
|
||||
INC(adr, size)
|
||||
END
|
||||
END ;
|
||||
IF freesize > 0 THEN (*collect last block*)
|
||||
start := adr - freesize;
|
||||
S.PUT(start, start+SZA);
|
||||
S.PUT(start+sizeOff, freesize);
|
||||
S.PUT(start+sntlOff, NoPtrSntl);
|
||||
i := freesize DIV Unit; freesize := 0;
|
||||
IF i < nofLists THEN S.PUT(start + nextOff, freeList[i]); freeList[i] := start
|
||||
ELSE S.PUT(start + nextOff, bigBlocks); bigBlocks := start
|
||||
END
|
||||
END ;
|
||||
S.GET(chnk, chnk)
|
||||
END
|
||||
END Scan;
|
||||
|
||||
PROCEDURE Sift (l, r: S.ADDRESS; VAR a: ARRAY OF S.ADDRESS);
|
||||
VAR i, j, x: S.ADDRESS;
|
||||
BEGIN j := l; x := a[j];
|
||||
LOOP i := j; j := 2*j + 1;
|
||||
IF (j < r) & (a[j] < a[j+1]) THEN INC(j) END;
|
||||
IF (j > r) OR (a[j] <= x) THEN EXIT END;
|
||||
a[i] := a[j]
|
||||
END;
|
||||
a[i] := x
|
||||
END Sift;
|
||||
|
||||
PROCEDURE HeapSort (n: S.ADDRESS; VAR a: ARRAY OF S.ADDRESS);
|
||||
VAR l, r, x: S.ADDRESS;
|
||||
BEGIN l := n DIV 2; r := n - 1;
|
||||
WHILE l > 0 DO DEC(l); Sift(l, r, a) END;
|
||||
WHILE r > 0 DO x := a[0]; a[0] := a[r]; a[r] := x; DEC(r); Sift(l, r, a) END
|
||||
END HeapSort;
|
||||
|
||||
PROCEDURE MarkCandidates(n: S.ADDRESS; VAR cand: ARRAY OF S.ADDRESS);
|
||||
VAR chnk, adr, tag, next, lim, lim1, i, ptr, size: S.ADDRESS;
|
||||
BEGIN
|
||||
chnk := heap; i := 0; lim := cand[n-1];
|
||||
WHILE (chnk # 0 ) & (chnk < lim) DO
|
||||
adr := chnk + blkOff;
|
||||
S.GET(chnk + endOff, lim1);
|
||||
IF lim < lim1 THEN lim1 := lim END ;
|
||||
WHILE adr < lim1 DO
|
||||
S.GET(adr, tag);
|
||||
IF ODD(tag) THEN (*already marked*)
|
||||
S.GET(tag-1, size); INC(adr, size)
|
||||
ELSE
|
||||
S.GET(tag, size);
|
||||
ptr := adr + SZA;
|
||||
WHILE cand[i] < ptr DO INC(i) END ;
|
||||
IF i = n THEN RETURN END ;
|
||||
next := adr + size;
|
||||
IF cand[i] < next THEN Mark(ptr) END ;
|
||||
adr := next
|
||||
END
|
||||
END ;
|
||||
S.GET(chnk, chnk)
|
||||
END
|
||||
END MarkCandidates;
|
||||
|
||||
PROCEDURE CheckFin;
|
||||
VAR n: FinNode; tag: S.ADDRESS;
|
||||
BEGIN
|
||||
n := fin;
|
||||
WHILE n # NIL DO
|
||||
S.GET(n.obj - SZA, tag);
|
||||
IF ~ODD(tag) THEN n.marked := FALSE; Mark(n.obj)
|
||||
ELSE n.marked := TRUE
|
||||
END ;
|
||||
n := n.next
|
||||
END
|
||||
END CheckFin;
|
||||
|
||||
PROCEDURE Finalize;
|
||||
VAR n, prev: FinNode;
|
||||
BEGIN n := fin; prev := NIL;
|
||||
WHILE n # NIL DO
|
||||
IF ~n.marked THEN
|
||||
IF n = fin THEN fin := fin.next ELSE prev.next := n.next END ;
|
||||
n.finalize(S.VAL(S.PTR, n.obj));
|
||||
(* new nodes may have been pushed in n.finalize, therefore: *)
|
||||
IF prev = NIL THEN n := fin ELSE n := n.next END
|
||||
ELSE
|
||||
prev := n; n := n.next
|
||||
END
|
||||
END
|
||||
END Finalize;
|
||||
|
||||
PROCEDURE FINALL*;
|
||||
VAR n: FinNode;
|
||||
BEGIN
|
||||
WHILE fin # NIL DO
|
||||
n := fin; fin := fin.next;
|
||||
n.finalize(S.VAL(S.PTR, n.obj))
|
||||
END
|
||||
END FINALL;
|
||||
|
||||
PROCEDURE -ExternMainStackFrame "extern address Platform_MainStackFrame;";
|
||||
PROCEDURE -PlatformMainStackFrame(): S.ADDRESS "Platform_MainStackFrame";
|
||||
|
||||
PROCEDURE MarkStack(n: S.ADDRESS; VAR cand: ARRAY OF S.ADDRESS);
|
||||
VAR
|
||||
frame: S.PTR;
|
||||
inc, nofcand: S.ADDRESS;
|
||||
sp, p, stack0: S.ADDRESS;
|
||||
align: RECORD ch: CHAR; p: S.PTR END ;
|
||||
BEGIN
|
||||
IF n > 0 THEN MarkStack(n-1, cand); (* flush register windows by means of recursive calls *)
|
||||
IF n > 100 THEN RETURN END (* prevent tail recursion optimization *)
|
||||
END ;
|
||||
IF n = 0 THEN
|
||||
nofcand := 0; sp := S.ADR(frame);
|
||||
stack0 := PlatformMainStackFrame();
|
||||
(* check for minimum alignment of pointers *)
|
||||
inc := S.ADR(align.p) - S.ADR(align);
|
||||
IF sp > stack0 THEN inc := -inc END ;
|
||||
WHILE sp # stack0 DO
|
||||
S.GET(sp, p);
|
||||
IF (p > heap) & (p < heapend) THEN
|
||||
IF nofcand = LEN(cand) THEN HeapSort(nofcand, cand); MarkCandidates(nofcand, cand); nofcand := 0 END ;
|
||||
cand[nofcand] := p; INC(nofcand)
|
||||
END ;
|
||||
INC(sp, inc)
|
||||
END ;
|
||||
IF nofcand > 0 THEN HeapSort(nofcand, cand); MarkCandidates(nofcand, cand) END
|
||||
END
|
||||
END MarkStack;
|
||||
|
||||
PROCEDURE GC*(markStack: BOOLEAN);
|
||||
VAR
|
||||
m: Module;
|
||||
i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23: S.ADDRESS;
|
||||
cand: ARRAY 10000 OF S.ADDRESS;
|
||||
BEGIN
|
||||
IF (lockdepth = 0) OR (lockdepth = 1) & ~markStack THEN
|
||||
Lock();
|
||||
m := S.VAL(Module, modules);
|
||||
WHILE m # NIL DO
|
||||
IF m.enumPtrs # NIL THEN m.enumPtrs(MarkP) END ;
|
||||
m := m^.next
|
||||
END ;
|
||||
IF markStack THEN
|
||||
(* generate register pressure to force callee saved registers to memory;
|
||||
may be simplified by inlining OS calls or processor specific instructions
|
||||
*)
|
||||
i0 := -100; i1 := -101; i2 := -102; i3 := -103; i4 := -104; i5 := -105; i6 := -106; i7 := -107;
|
||||
i8 := 1; i9 := 2; i10 := 3; i11 := 4; i12 := 5; i13 := 6; i14 := 7; i15 := 8;
|
||||
i16 := 9; i17 := 10; i18 := 11; i19 := 12; i20 := 13; i21 := 14; i22 := 15; i23 := 16;
|
||||
LOOP INC(i0, 1); INC(i1, 2); INC(i2, 3); INC(i3, 4); INC(i4, 5); INC(i5, 6); INC(i6, 7); INC(i7, 8);
|
||||
INC(i8, 9); INC(i9, 10); INC(i10, 11); INC(i11, 12); INC(i12, 13); INC(i13, 14); INC(i14, 15); INC(i15, 16);
|
||||
INC(i16, 17); INC(i17, 18); INC(i18, 19); INC(i19, 20); INC(i20, 21); INC(i21, 22); INC(i22, 23); INC(i23, 24);
|
||||
IF (i0 = -99) & (i15 = 24) THEN MarkStack(32, cand); EXIT END
|
||||
END ;
|
||||
IF i0 + i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11 + i12 + i13 + i14 + i15
|
||||
+ i16 + i17 + i18 + i19 + i20 + i21 + i22 + i23 > 10000 THEN RETURN (* use all variables *)
|
||||
END ;
|
||||
END;
|
||||
CheckFin;
|
||||
Scan;
|
||||
Finalize;
|
||||
Unlock()
|
||||
END
|
||||
END GC;
|
||||
|
||||
PROCEDURE RegisterFinalizer*(obj: S.PTR; finalize: Finalizer);
|
||||
VAR f: FinNode;
|
||||
BEGIN NEW(f);
|
||||
f.obj := S.VAL(S.ADDRESS, obj); f.finalize := finalize; f.marked := TRUE;
|
||||
f.next := fin; fin := f;
|
||||
END RegisterFinalizer;
|
||||
|
||||
|
||||
PROCEDURE -ExternHeapInit "extern void *Heap__init();";
|
||||
PROCEDURE -HeapModuleInit 'Heap__init()';
|
||||
|
||||
PROCEDURE InitHeap*;
|
||||
(* InitHeap is called by Platform.init before any module bodies have been
|
||||
initialised, to enable NEW, S.NEW *)
|
||||
BEGIN
|
||||
heap := NewChunk(heapSize0);
|
||||
S.GET(heap + endOff, heapend);
|
||||
S.PUT(heap, AddressZero);
|
||||
allocated := 0; firstTry := TRUE; freeList[nofLists] := 1; lockdepth := 0;
|
||||
FileCount := 0; modules := NIL; heapsize := 0; bigBlocks := 0; fin := NIL;
|
||||
interrupted := FALSE;
|
||||
|
||||
HeapModuleInit;
|
||||
END InitHeap;
|
||||
|
||||
END Heap.
|
||||
0
src/runtime/In.Mod
Normal file
0
src/runtime/In.Mod
Normal file
486
src/runtime/LowLReal.Mod
Normal file
486
src/runtime/LowLReal.Mod
Normal file
|
|
@ -0,0 +1,486 @@
|
|||
(* $Id: LowLReal.Mod,v 1.6 1999/09/02 13:15:35 acken Exp $ *)
|
||||
MODULE oocLowLReal;
|
||||
|
||||
(* ToDo. support 64 bit builds *)
|
||||
|
||||
(*
|
||||
LowLReal - Gives access to the underlying properties of the type LONGREAL
|
||||
for IEEE double-precision numbers.
|
||||
Copyright (C) 1996 Michael Griebling
|
||||
|
||||
This module is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This module is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*)
|
||||
|
||||
|
||||
IMPORT Low := LowReal, S := SYSTEM;
|
||||
|
||||
(*
|
||||
|
||||
Real number properties are defined as follows:
|
||||
|
||||
radix--The whole number value of the radix used to represent the
|
||||
corresponding read number values.
|
||||
|
||||
places--The whole number value of the number of radix places used
|
||||
to store values of the corresponding real number type.
|
||||
|
||||
expoMin--The whole number value of the exponent minimum.
|
||||
|
||||
expoMax--The whole number value of the exponent maximum.
|
||||
|
||||
large--The largest value of the corresponding real number type.
|
||||
|
||||
small--The smallest positive value of the corresponding real number
|
||||
type, represented to maximal precision.
|
||||
|
||||
IEC559--A Boolean value that is TRUE if and only if the implementation
|
||||
of the corresponding real number type conforms to IEC 559:1989
|
||||
(IEEE 754:1987) in all regards.
|
||||
|
||||
NOTES
|
||||
6 -- If `IEC559' is TRUE, the value of `radix' is 2.
|
||||
7 -- If LowReal.IEC559 is TRUE, the 32-bit format of IEC 559:1989
|
||||
is used for the type REAL.
|
||||
7 -- If LowLong.IEC559 is TRUE, the 64-bit format of IEC 559:1989
|
||||
is used for the type REAL.
|
||||
|
||||
LIA1--A Boolean value that is TRUE if and only if the implementation of
|
||||
the corresponding real number type conforms to ISO/IEC 10967-1:199x
|
||||
(LIA-1) in all regards: parameters, arithmetic, exceptions, and
|
||||
notification.
|
||||
|
||||
rounds--A Boolean value that is TRUE if and only if each operation produces
|
||||
a result that is one of the values of the corresponding real number
|
||||
type nearest to the mathematical result.
|
||||
|
||||
gUnderflow--A Boolean value that is TRUE if and only if there are values of
|
||||
the corresponding real number type between 0.0 and `small'.
|
||||
|
||||
exception--A Boolean value that is TRUE if and only if every operation that
|
||||
attempts to produce a real value out of range raises an exception.
|
||||
|
||||
extend--A Boolean value that is TRUE if and only if expressions of the
|
||||
corresponding real number type are computed to higher precision than
|
||||
the stored values.
|
||||
|
||||
nModes--The whole number value giving the number of bit positions needed for
|
||||
the status flags for mode control.
|
||||
|
||||
*)
|
||||
|
||||
CONST
|
||||
radix*= 2;
|
||||
places*= 53;
|
||||
expoMax*= 1023;
|
||||
expoMin*= 1-expoMax;
|
||||
large*= MAX(LONGREAL); (*1.7976931348623157D+308;*) (* MAX(LONGREAL) *)
|
||||
(*small*= 2.2250738585072014D-308;*)
|
||||
small*= 2.2250738585072014/9.9999999999999981D307(*/10^308)*);
|
||||
IEC559*= TRUE;
|
||||
LIA1*= FALSE;
|
||||
rounds*= FALSE;
|
||||
gUnderflow*= TRUE; (* there are IEEE numbers smaller than `small' *)
|
||||
exception*= FALSE; (* at least in the default implementation *)
|
||||
extend*= FALSE;
|
||||
nModes*= 0;
|
||||
ONE=1.0D0; (* some commonly-used constants *)
|
||||
ZERO=0.0D0;
|
||||
TEN=1.0D1;
|
||||
|
||||
DEBUG = TRUE;
|
||||
|
||||
expOffset=expoMax;
|
||||
hiBit=19;
|
||||
expBit=hiBit+1;
|
||||
nMask={0..hiBit,31}; (* number mask *)
|
||||
expMask={expBit..30}; (* exponent mask *)
|
||||
|
||||
TYPE
|
||||
Modes*= SET;
|
||||
LongInt=ARRAY 2 OF LONGINT;
|
||||
LongSet=ARRAY 2 OF SET;
|
||||
|
||||
VAR
|
||||
(*sml* : LONGREAL; tmp: LONGREAL;*) (* this was a test to get small as a variable at runtime. obviously, compile time preferred; -- noch *)
|
||||
isBigEndian-: BOOLEAN; (* set when target is big endian *)
|
||||
(*
|
||||
PROCEDURE power0(i, j : INTEGER) : LONGREAL; (* used to calculate sml at runtime; -- noch *)
|
||||
VAR k : INTEGER;
|
||||
p : LONGREAL;
|
||||
BEGIN
|
||||
k := 1;
|
||||
p := i;
|
||||
REPEAT
|
||||
p := p * i;
|
||||
INC(k);
|
||||
UNTIL k=j;
|
||||
RETURN p;
|
||||
END power0;
|
||||
*)
|
||||
|
||||
(* Errors are handled through the LowReal module *)
|
||||
|
||||
PROCEDURE err*(): INTEGER;
|
||||
BEGIN
|
||||
RETURN Low.err
|
||||
END err;
|
||||
|
||||
PROCEDURE ClearError*;
|
||||
BEGIN
|
||||
Low.ClearError
|
||||
END ClearError;
|
||||
|
||||
PROCEDURE ErrorHandler*(err: INTEGER);
|
||||
BEGIN
|
||||
Low.ErrorHandler(err)
|
||||
END ErrorHandler;
|
||||
|
||||
(* type-casting utilities *)
|
||||
|
||||
PROCEDURE Move (VAR x: LONGREAL; VAR ra: ARRAY OF LONGINT);
|
||||
(* typecast a LONGREAL to an array of LONGINTs *)
|
||||
VAR t: LONGINT;
|
||||
BEGIN
|
||||
S.MOVE(S.ADR(x),S.ADR(ra),SIZE(LONGREAL));
|
||||
IF ~isBigEndian THEN t:=ra[0]; ra[0]:=ra[1]; ra[1]:=t END
|
||||
END Move;
|
||||
|
||||
PROCEDURE MoveSet (VAR x: LONGREAL; VAR ra: ARRAY OF SET);
|
||||
(* typecast a LONGREAL to an array of LONGINTs *)
|
||||
VAR t: SET;
|
||||
BEGIN
|
||||
S.MOVE(S.ADR(x),S.ADR(ra),SIZE(LONGREAL));
|
||||
IF ~isBigEndian THEN t:=ra[0]; ra[0]:=ra[1]; ra[1]:=t END
|
||||
END MoveSet;
|
||||
|
||||
(* Note: The below should be done with a type cast --
|
||||
once the compiler supports such things. *)
|
||||
(*<* PUSH; Warnings := FALSE *>*)
|
||||
PROCEDURE Real * (ra: ARRAY OF LONGINT): LONGREAL;
|
||||
(* typecast an array of big endian LONGINTs to a LONGREAL *)
|
||||
VAR t: LONGINT; x: LONGREAL;
|
||||
BEGIN
|
||||
IF ~isBigEndian THEN t:=ra[0]; ra[0]:=ra[1]; ra[1]:=t END;
|
||||
S.MOVE(S.ADR(ra),S.ADR(x),SIZE(LONGREAL));
|
||||
RETURN x
|
||||
END Real;
|
||||
|
||||
PROCEDURE ToReal (ra: ARRAY OF SET): LONGREAL;
|
||||
(* typecast an array of LONGINTs to a LONGREAL *)
|
||||
VAR t: SET; x: LONGREAL;
|
||||
BEGIN
|
||||
IF ~isBigEndian THEN t:=ra[0]; ra[0]:=ra[1]; ra[1]:=t END;
|
||||
S.MOVE(S.ADR(ra),S.ADR(x),SIZE(LONGREAL));
|
||||
RETURN x
|
||||
END ToReal;
|
||||
(*<* POP *> *)
|
||||
|
||||
PROCEDURE exponent*(x: LONGREAL): INTEGER;
|
||||
(*
|
||||
The value of the call exponent(x) shall be the exponent value of `x'
|
||||
that lies between `expoMin' and `expoMax'. An exception shall occur
|
||||
and may be raised if `x' is equal to 0.0.
|
||||
*)
|
||||
VAR ra: LongInt;
|
||||
BEGIN
|
||||
(* NOTE: x=0.0 should raise exception *)
|
||||
IF x=ZERO THEN RETURN 0
|
||||
ELSE Move(x, ra);
|
||||
RETURN SHORT(S.LSH(ra[0],-expBit) MOD 2048)-expOffset
|
||||
END
|
||||
END exponent;
|
||||
|
||||
PROCEDURE exponent10*(x: LONGREAL): INTEGER;
|
||||
(*
|
||||
The value of the call exponent10(x) shall be the base 10 exponent
|
||||
value of `x'. An exception shall occur and may be raised if `x' is
|
||||
equal to 0.0.
|
||||
*)
|
||||
VAR exp: INTEGER;
|
||||
BEGIN
|
||||
IF x=ZERO THEN RETURN 0 END; (* exception could be raised here *)
|
||||
exp:=0; x:=ABS(x);
|
||||
WHILE x>=TEN DO x:=x/TEN; INC(exp) END;
|
||||
WHILE x<1 DO x:=x*TEN; DEC(exp) END;
|
||||
RETURN exp
|
||||
END exponent10;
|
||||
|
||||
PROCEDURE fraction*(x: LONGREAL): LONGREAL;
|
||||
(*
|
||||
The value of the call fraction(x) shall be the significand (or
|
||||
significant) part of `x'. Hence the following relationship shall
|
||||
hold: x = scale(fraction(x), exponent(x)).
|
||||
*)
|
||||
CONST eZero={(hiBit+2)..29};
|
||||
VAR ra: LongInt;
|
||||
BEGIN
|
||||
IF x=ZERO THEN RETURN ZERO
|
||||
ELSE Move(x, ra);
|
||||
ra[0]:=S.VAL(LONGINT, S.VAL(SET,ra[0])*nMask+eZero);
|
||||
RETURN Real(ra)*2.0D0
|
||||
END
|
||||
END fraction;
|
||||
|
||||
PROCEDURE IsInfinity * (real: LONGREAL) : BOOLEAN;
|
||||
CONST signMask={0..30};
|
||||
VAR ra: LongSet;
|
||||
BEGIN
|
||||
MoveSet(real, ra);
|
||||
RETURN (ra[0]*signMask=expMask) & (ra[1]={})
|
||||
END IsInfinity;
|
||||
|
||||
PROCEDURE IsNaN * (real: LONGREAL) : BOOLEAN;
|
||||
CONST fracMask={0..hiBit};
|
||||
VAR ra: LongSet;
|
||||
BEGIN
|
||||
MoveSet(real, ra);
|
||||
RETURN (ra[0]*expMask=expMask) & ((ra[1]#{}) OR (ra[0]*fracMask#{}))
|
||||
END IsNaN;
|
||||
|
||||
PROCEDURE sign*(x: LONGREAL): LONGREAL;
|
||||
(*
|
||||
The value of the call sign(x) shall be 1.0 if `x' is greater than 0.0,
|
||||
or shall be -1.0 if `x' is less than 0.0, or shall be either 1.0 or
|
||||
-1.0 if `x' is equal to 0.0.
|
||||
*)
|
||||
BEGIN
|
||||
IF x<ZERO THEN RETURN -ONE ELSE RETURN ONE END
|
||||
END sign;
|
||||
|
||||
PROCEDURE scale*(x: LONGREAL; n: INTEGER): LONGREAL;
|
||||
(*
|
||||
The value of the call scale(x,n) shall be the value x*radix^n if such
|
||||
a value exists; otherwise an exception shall occur and may be raised.
|
||||
*)
|
||||
VAR exp: LONGINT; lexp: SET; ra: LongInt;
|
||||
BEGIN
|
||||
IF x=ZERO THEN RETURN ZERO END; (* can't scale zero *)
|
||||
exp:= exponent(x)+n; (* new exponent *)
|
||||
IF exp>expoMax THEN RETURN large*sign(x) (* exception raised here *)
|
||||
ELSIF exp<expoMin THEN RETURN small*sign(x) (* exception here as well *)
|
||||
END;
|
||||
lexp:=S.VAL(SET,S.LSH(exp+expOffset,expBit)); (* shifted exponent bits *)
|
||||
Move(x, ra);
|
||||
ra[0]:=S.VAL(LONGINT, S.VAL(SET,ra[0])*nMask+lexp); (* insert new exponent *)
|
||||
RETURN Real(ra)
|
||||
END scale;
|
||||
|
||||
PROCEDURE ulp*(x: LONGREAL): LONGREAL;
|
||||
(*
|
||||
The value of the call ulp(x) shall be the value of the corresponding
|
||||
real number type equal to a unit in the last place of `x', if such a
|
||||
value exists; otherwise an exception shall occur and may be raised.
|
||||
*)
|
||||
BEGIN
|
||||
RETURN scale(ONE, exponent(x)-places+1)
|
||||
END ulp;
|
||||
|
||||
PROCEDURE succ*(x: LONGREAL): LONGREAL;
|
||||
(*
|
||||
The value of the call succ(x) shall be the next value of the
|
||||
corresponding real number type greater than `x', if such a type
|
||||
exists; otherwise an exception shall occur and may be raised.
|
||||
*)
|
||||
BEGIN
|
||||
RETURN x+ulp(x)*sign(x)
|
||||
END succ;
|
||||
|
||||
PROCEDURE pred*(x: LONGREAL): LONGREAL;
|
||||
(*
|
||||
The value of the call pred(x) shall be the next value of the
|
||||
corresponding real number type less than `x', if such a type exists;
|
||||
otherwise an exception shall occur and may be raised.
|
||||
*)
|
||||
BEGIN
|
||||
RETURN x-ulp(x)*sign(x)
|
||||
END pred;
|
||||
|
||||
PROCEDURE MaskReal(x: LONGREAL; lo: INTEGER): LONGREAL;
|
||||
VAR ra: LongSet;
|
||||
BEGIN
|
||||
MoveSet(x, ra); (* type-cast into sets for masking *)
|
||||
IF lo<32 THEN ra[1]:=ra[1]*{lo..31} (* just need to mask lower word *)
|
||||
ELSE ra[0]:=ra[0]*{lo-32..31}; ra[1]:={} (* mask upper word & clear lower word *)
|
||||
END;
|
||||
RETURN ToReal(ra)
|
||||
END MaskReal;
|
||||
|
||||
PROCEDURE intpart*(x: LONGREAL): LONGREAL;
|
||||
(*
|
||||
The value of the call intpart(x) shall be the integral part of `x'.
|
||||
For negative values, this shall be -intpart(abs(x)).
|
||||
*)
|
||||
VAR lo, hi: INTEGER;
|
||||
BEGIN hi:=hiBit+32; (* account for low 32-bits as well *)
|
||||
lo:=(hi+1)-exponent(x);
|
||||
IF lo<=0 THEN RETURN x (* no fractional part *)
|
||||
ELSIF lo<=hi+1 THEN RETURN MaskReal(x, lo) (* integer part is extracted *)
|
||||
ELSE RETURN 0 (* no whole part *)
|
||||
END
|
||||
END intpart;
|
||||
|
||||
PROCEDURE fractpart*(x: LONGREAL): LONGREAL;
|
||||
(*
|
||||
The value of the call fractpart(x) shall be the fractional part of
|
||||
`x'. This satifies the relationship fractpart(x)+intpart(x)=x.
|
||||
*)
|
||||
BEGIN
|
||||
RETURN x-intpart(x)
|
||||
END fractpart;
|
||||
|
||||
PROCEDURE trunc*(x: LONGREAL; n: INTEGER): LONGREAL;
|
||||
(*
|
||||
The value of the call trunc(x,n) shall be the value of the most
|
||||
significant `n' places of `x'. An exception shall occur and may be
|
||||
raised if `n' is less than or equal to zero.
|
||||
*)
|
||||
VAR loBit: INTEGER;
|
||||
BEGIN loBit:=places-n;
|
||||
IF n<=0 THEN RETURN ZERO (* exception should be raised *)
|
||||
ELSIF loBit<=0 THEN RETURN x (* nothing was truncated *)
|
||||
ELSE RETURN MaskReal(x, loBit) (* clear all lower bits *)
|
||||
END
|
||||
END trunc;
|
||||
|
||||
PROCEDURE In (bit: INTEGER; x: LONGREAL): BOOLEAN;
|
||||
VAR ra: LongSet;
|
||||
BEGIN
|
||||
MoveSet(x, ra); (* type-cast into sets for masking *)
|
||||
IF bit<32 THEN RETURN bit IN ra[1] (* check bit in lower word *)
|
||||
ELSE RETURN bit-32 IN ra[0] (* check bit in upper word *)
|
||||
END
|
||||
END In;
|
||||
|
||||
PROCEDURE round*(x: LONGREAL; n: INTEGER): LONGREAL;
|
||||
(*
|
||||
The value of the call round(x,n) shall be the value of `x' rounded to
|
||||
the most significant `n' places. An exception shall occur and may be
|
||||
raised if such a value does not exist, or if `n' is less than or equal
|
||||
to zero.
|
||||
*)
|
||||
VAR loBit: INTEGER; t, r: LONGREAL;
|
||||
BEGIN loBit:=places-n;
|
||||
IF n<=0 THEN RETURN ZERO (* exception should be raised *)
|
||||
ELSIF loBit<=0 THEN RETURN x (* nothing was rounded *)
|
||||
ELSE t:=MaskReal(x, loBit); (* truncated result *)
|
||||
IF In(loBit-1, x) THEN (* check if result should be rounded *)
|
||||
r:=scale(ONE,exponent(x)-n+1); (* rounding fraction *)
|
||||
IF In(31+32, x) THEN RETURN t-r (* negative rounding toward -infinity *)
|
||||
ELSE RETURN t+r (* positive rounding toward +infinity *)
|
||||
END
|
||||
ELSE RETURN t (* return truncated result *)
|
||||
END
|
||||
END
|
||||
END round;
|
||||
|
||||
PROCEDURE synthesize*(expart: INTEGER; frapart: LONGREAL): LONGREAL;
|
||||
(*
|
||||
The value of the call synthesize(expart,frapart) shall be a value of
|
||||
the corresponding real number type contructed from the value of
|
||||
`expart' and `frapart'. This value shall satisfy the relationship
|
||||
synthesize(exponent(x),fraction(x)) = x.
|
||||
*)
|
||||
BEGIN
|
||||
RETURN scale(frapart, expart)
|
||||
END synthesize;
|
||||
|
||||
PROCEDURE setMode*(m: Modes);
|
||||
(*
|
||||
The call setMode(m) shall set status flags from the value of `m',
|
||||
appropriate to the underlying implementation of the corresponding real
|
||||
number type.
|
||||
|
||||
NOTES
|
||||
3 -- Many implementations of floating point provide options for
|
||||
setting flags within the system which control details of the handling
|
||||
of the type. Although two procedures are provided, one for each real
|
||||
number type, the effect may be the same. Typical effects that can be
|
||||
obtained by this means are:
|
||||
a) Ensuring that overflow will raise an exception;
|
||||
b) Allowing underflow to raise an exception;
|
||||
c) Controlling the rounding;
|
||||
d) Allowing special values to be produced (e.g. NaNs in
|
||||
implementations conforming to IEC 559:1989 (IEEE 754:1987));
|
||||
e) Ensuring that special valu access will raise an exception;
|
||||
Since these effects are so varied, the values of type `Modes' that may
|
||||
be used are not specified by this International Standard.
|
||||
4 -- The effects of `setMode' on operation on values of the
|
||||
corresponding real number type in coroutines other than the calling
|
||||
coroutine is not defined. Implementations are not require to preserve
|
||||
the status flags (if any) with the coroutine state.
|
||||
*)
|
||||
BEGIN
|
||||
(* hardware dependent mode setting of coprocessor *)
|
||||
END setMode;
|
||||
|
||||
PROCEDURE currentMode*(): Modes;
|
||||
(*
|
||||
The value of the call currentMode() shall be the current status flags
|
||||
(in the form set by `setMode'), or the default status flags (if
|
||||
`setMode' is not used).
|
||||
|
||||
NOTE 5 -- The value of the call currentMode() is not necessarily the
|
||||
value of set by `setMode', since a call of `setMode' might attempt to
|
||||
set flags that cannot be set by the program.
|
||||
*)
|
||||
BEGIN
|
||||
RETURN {}
|
||||
END currentMode;
|
||||
|
||||
PROCEDURE IsLowException*(): BOOLEAN;
|
||||
(* Returns TRUE if the current coroutine is in the exceptional execution state
|
||||
because of the raising of the LowReal exception; otherwise returns FALSE.
|
||||
*)
|
||||
BEGIN
|
||||
RETURN FALSE
|
||||
END IsLowException;
|
||||
|
||||
PROCEDURE InitEndian;
|
||||
VAR endianTest: INTEGER; c: CHAR;
|
||||
BEGIN
|
||||
endianTest:=1;
|
||||
S.GET(S.ADR(endianTest), c);
|
||||
isBigEndian:=c#1X
|
||||
END InitEndian;
|
||||
|
||||
PROCEDURE Test;
|
||||
CONST n1=1.234D39; n2=-1.23343D-20; n3=123.456;
|
||||
VAR n: LONGREAL; exp: INTEGER;
|
||||
BEGIN
|
||||
exp:=exponent(n1); exp:=exponent(n2);
|
||||
n:=fraction(n1); n:=fraction(n2);
|
||||
n:=scale(ONE, -8); n:=scale(ONE, 8);
|
||||
n:=succ(10);
|
||||
n:=intpart(n3);
|
||||
n:=trunc(n3, 5); (* n=120 *)
|
||||
n:=trunc(n3, 7); (* n=123 *)
|
||||
n:=trunc(n3, 12); (* n=123.4375 *)
|
||||
n:=round(n3, 5); (* n=124 *)
|
||||
n:=round(n3, 7); (* n=123 *)
|
||||
n:=round(n3, 12); (* n=123.46875 *)
|
||||
END Test;
|
||||
|
||||
BEGIN
|
||||
InitEndian; (* check whether target is big endian *)
|
||||
(*
|
||||
tmp := power0(10,308); (* this is test to calculate small as a variable at runtime; -- noch *)
|
||||
sml := 2.2250738585072014/tmp;
|
||||
sml := 2.2250738585072014/power0(10, 308);
|
||||
*)
|
||||
|
||||
|
||||
IF DEBUG THEN Test END
|
||||
END oocLowLReal.
|
||||
408
src/runtime/LowReal.Mod
Normal file
408
src/runtime/LowReal.Mod
Normal file
|
|
@ -0,0 +1,408 @@
|
|||
(* $Id: LowReal.Mod,v 1.5 1999/09/02 13:17:38 acken Exp $ *)
|
||||
MODULE LowReal;
|
||||
|
||||
(*
|
||||
LowReal - Gives access to the underlying properties of the type REAL
|
||||
for IEEE single-precision numbers.
|
||||
Copyright (C) 1995 Michael Griebling
|
||||
|
||||
This module is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This module is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*)
|
||||
|
||||
|
||||
IMPORT S := SYSTEM, Reals;
|
||||
|
||||
(*
|
||||
|
||||
Real number properties are defined as follows:
|
||||
|
||||
radix--The whole number value of the radix used to represent the
|
||||
corresponding read number values.
|
||||
|
||||
places--The whole number value of the number of radix places used
|
||||
to store values of the corresponding real number type.
|
||||
|
||||
expoMin--The whole number value of the exponent minimum.
|
||||
|
||||
expoMax--The whole number value of the exponent maximum.
|
||||
|
||||
large--The largest value of the corresponding real number type.
|
||||
|
||||
small--The smallest positive value of the corresponding real number
|
||||
type, represented to maximal precision.
|
||||
|
||||
IEC559--A Boolean value that is TRUE if and only if the implementation
|
||||
of the corresponding real number type conforms to IEC 559:1989
|
||||
(IEEE 754:1987) in all regards.
|
||||
|
||||
NOTES
|
||||
6 -- If `IEC559' is TRUE, the value of `radix' is 2.
|
||||
7 -- If LowReal.IEC559 is TRUE, the 32-bit format of IEC 559:1989
|
||||
is used for the type REAL.
|
||||
7 -- If LowLong.IEC559 is TRUE, the 64-bit format of IEC 559:1989
|
||||
is used for the type REAL.
|
||||
|
||||
LIA1--A Boolean value that is TRUE if and only if the implementation of
|
||||
the corresponding real number type conforms to ISO/IEC 10967-1:199x
|
||||
(LIA-1) in all regards: parameters, arithmetic, exceptions, and
|
||||
notification.
|
||||
|
||||
rounds--A Boolean value that is TRUE if and only if each operation produces
|
||||
a result that is one of the values of the corresponding real number
|
||||
type nearest to the mathematical result.
|
||||
|
||||
gUnderflow--A Boolean value that is TRUE if and only if there are values of
|
||||
the corresponding real number type between 0.0 and `small'.
|
||||
|
||||
exception--A Boolean value that is TRUE if and only if every operation that
|
||||
attempts to produce a real value out of range raises an exception.
|
||||
|
||||
extend--A Boolean value that is TRUE if and only if expressions of the
|
||||
corresponding real number type are computed to higher precision than
|
||||
the stored values.
|
||||
|
||||
nModes--The whole number value giving the number of bit positions needed for
|
||||
the status flags for mode control.
|
||||
|
||||
*)
|
||||
CONST
|
||||
radix* = 2;
|
||||
places* = 24;
|
||||
expoMax* = 127;
|
||||
expoMin* = 1-expoMax;
|
||||
large* = MAX(REAL); (*3.40282347E+38;*)
|
||||
(*small* = 1.17549435E-38; (* 2^(-126) *)*)
|
||||
small* = 1/8.50705917E37; (* don't know better way; -- noch *)
|
||||
IEC559* = TRUE;
|
||||
LIA1* = FALSE;
|
||||
rounds* = FALSE;
|
||||
gUnderflow* = TRUE; (* there are IEEE numbers smaller than `small' *)
|
||||
exception* = FALSE; (* at least in the default implementation *)
|
||||
extend* = FALSE;
|
||||
nModes* = 0;
|
||||
|
||||
TEN = 10.0; (* some commonly-used constants *)
|
||||
ONE = 1.0;
|
||||
ZERO = 0.0;
|
||||
|
||||
expOffset = expoMax;
|
||||
hiBit = 22;
|
||||
expBit = hiBit+1;
|
||||
nMask = {0..hiBit,31}; (* number mask *)
|
||||
expMask = {expBit..30}; (* exponent mask *)
|
||||
|
||||
TYPE
|
||||
Modes*= SET;
|
||||
|
||||
VAR
|
||||
(*small* : REAL; tmp: REAL;*) (* this was a test to get small as a variable at runtime. obviously, compile time preferred; -- noch *)
|
||||
ErrorHandler*: PROCEDURE (errno : INTEGER);
|
||||
err-: INTEGER;
|
||||
|
||||
(* Error handler default stub which can be replaced *)
|
||||
|
||||
PROCEDURE DefaultHandler (errno : INTEGER);
|
||||
BEGIN
|
||||
err:=errno
|
||||
END DefaultHandler;
|
||||
|
||||
PROCEDURE ClearError*;
|
||||
BEGIN
|
||||
err:=0
|
||||
END ClearError;
|
||||
|
||||
|
||||
PROCEDURE exponent*(x: REAL): INTEGER;
|
||||
(*
|
||||
The value of the call exponent(x) shall be the exponent value of `x'
|
||||
that lies between `expoMin' and `expoMax'. An exception shall occur
|
||||
and may be raised if `x' is equal to 0.0.
|
||||
*)
|
||||
BEGIN
|
||||
(* NOTE: x=0.0 should raise exception *)
|
||||
IF x = ZERO THEN RETURN 0
|
||||
ELSE RETURN Reals.Expo(x) - expOffset
|
||||
END
|
||||
END exponent;
|
||||
|
||||
PROCEDURE SetExponent(VAR x: REAL; ex: INTEGER);
|
||||
BEGIN Reals.SetExpo(x, ex + expOffset)
|
||||
END SetExponent;
|
||||
|
||||
PROCEDURE exponent10*(x: REAL): INTEGER;
|
||||
(*
|
||||
The value of the call exponent10(x) shall be the base 10 exponent
|
||||
value of `x'. An exception shall occur and may be raised if `x' is
|
||||
equal to 0.0.
|
||||
*)
|
||||
VAR exp: INTEGER;
|
||||
BEGIN
|
||||
exp := 0; x := ABS(x);
|
||||
IF x = ZERO THEN RETURN exp END; (* exception could be raised here *)
|
||||
WHILE x >= TEN DO x := x/TEN; INC(exp) END;
|
||||
WHILE (x > ZERO) & (x < 1.0) DO x := x*TEN; DEC(exp) END;
|
||||
RETURN exp
|
||||
END exponent10;
|
||||
|
||||
(* TYPE REAL: 1/sign, 8/exponent, 23/significand *)
|
||||
|
||||
PROCEDURE fraction*(x: REAL): REAL;
|
||||
(*
|
||||
The value of the call fraction(x) shall be the significand (or
|
||||
significant) part of `x'. Hence the following relationship shall
|
||||
hold: x = scale(fraction(x), exponent(x)).
|
||||
*)
|
||||
VAR c: CHAR;
|
||||
BEGIN
|
||||
IF x=ZERO THEN RETURN ZERO
|
||||
ELSE
|
||||
(* Set top 7 bits of exponent to 0111111 *)
|
||||
S.GET(S.ADR(x)+3, c);
|
||||
c := CHR(((ORD(c) DIV 128) * 128) + 63); (* Set X0111111 (X unchanged) *)
|
||||
S.PUT(S.ADR(x)+3, c);
|
||||
(* Set bottom bit of exponent to 0 *)
|
||||
S.GET(S.ADR(x)+2, c);
|
||||
c := CHR(ORD(c) MOD 128); (* Set 0XXXXXXX (X unchanged) *)
|
||||
S.PUT(S.ADR(x)+2, c);
|
||||
RETURN x * 2.0;
|
||||
END
|
||||
(*
|
||||
CONST eZero={(hiBit+2)..29};
|
||||
BEGIN
|
||||
IF x=ZERO THEN RETURN ZERO
|
||||
ELSE RETURN S.VAL(REAL,(S.VAL(SET,x)*nMask)+eZero)*2.0 (* set the mantissa's exponent to zero *)
|
||||
END
|
||||
*)
|
||||
END fraction;
|
||||
|
||||
PROCEDURE IsInfinity * (real: REAL) : BOOLEAN;
|
||||
VAR c0, c1, c2, c3: CHAR;
|
||||
BEGIN
|
||||
S.GET(S.ADR(real)+0, c3);
|
||||
S.GET(S.ADR(real)+1, c2);
|
||||
S.GET(S.ADR(real)+2, c1);
|
||||
S.GET(S.ADR(real)+3, c0);
|
||||
RETURN (ORD(c0) MOD 128 = 127) & (ORD(c1) = 128) & (ORD(c2) = 0) & (ORD(c3) = 0)
|
||||
END IsInfinity;
|
||||
|
||||
PROCEDURE IsNaN * (real: REAL) : BOOLEAN;
|
||||
VAR c0, c1, c2, c3: CHAR;
|
||||
BEGIN
|
||||
S.GET(S.ADR(real)+0, c3);
|
||||
S.GET(S.ADR(real)+1, c2);
|
||||
S.GET(S.ADR(real)+2, c1);
|
||||
S.GET(S.ADR(real)+3, c0);
|
||||
RETURN (ORD(c0) MOD 128 = 127)
|
||||
& (ORD(c1) DIV 128 = 1)
|
||||
& ((ORD(c1) MOD 128 # 0) OR (ORD(c2) # 0) OR (ORD(c3) # 0))
|
||||
END IsNaN;
|
||||
|
||||
PROCEDURE sign*(x: REAL): REAL;
|
||||
(*
|
||||
The value of the call sign(x) shall be 1.0 if `x' is greater than 0.0,
|
||||
or shall be -1.0 if `x' is less than 0.0, or shall be either 1.0 or
|
||||
-1.0 if `x' is equal to 0.0.
|
||||
*)
|
||||
BEGIN
|
||||
IF x<ZERO THEN RETURN -ONE ELSE RETURN ONE END
|
||||
END sign;
|
||||
|
||||
|
||||
PROCEDURE scale*(x: REAL; n: INTEGER): REAL;
|
||||
(*
|
||||
The value of the call scale(x,n) shall be the value x*radix^n if such
|
||||
a value exists; otherwise an execption shall occur and may be raised.
|
||||
*)
|
||||
VAR exp: LONGINT; lexp: SET;
|
||||
BEGIN
|
||||
IF x = ZERO THEN RETURN ZERO END;
|
||||
exp := exponent(x) + n; (* new exponent *)
|
||||
IF exp > expoMax THEN RETURN large * sign(x) (* exception raised here *)
|
||||
ELSIF exp < expoMin THEN RETURN small * sign(x) (* exception here as well *)
|
||||
END;
|
||||
SetExponent(x, SHORT(exp));
|
||||
(* SetExponent replaces these 2 lines:
|
||||
lexp := S.VAL(SET, S.LSH(exp + expOffset, expBit)); (* shifted exponent bits *)
|
||||
RETURN S.VAL(REAL, (S.VAL(SET, x) * nMask) + lexp) (* insert new exponent *)
|
||||
*)
|
||||
END scale;
|
||||
|
||||
PROCEDURE ulp*(x: REAL): REAL;
|
||||
(*
|
||||
The value of the call ulp(x) shall be the value of the corresponding
|
||||
real number type equal to a unit in the last place of `x', if such a
|
||||
value exists; otherwise an exception shall occur and may be raised.
|
||||
*)
|
||||
BEGIN
|
||||
RETURN scale(ONE, exponent(x)-places+1)
|
||||
END ulp;
|
||||
|
||||
PROCEDURE succ*(x: REAL): REAL;
|
||||
(*
|
||||
The value of the call succ(x) shall be the next value of the
|
||||
corresponding real number type greater than `x', if such a type
|
||||
exists; otherwise an exception shall occur and may be raised.
|
||||
*)
|
||||
BEGIN
|
||||
RETURN x+ulp(x)*sign(x)
|
||||
END succ;
|
||||
|
||||
PROCEDURE pred*(x: REAL): REAL;
|
||||
(*
|
||||
The value of the call pred(x) shall be the next value of the
|
||||
corresponding real number type less than `x', if such a type exists;
|
||||
otherwise an exception shall occur and may be raised.
|
||||
*)
|
||||
BEGIN
|
||||
RETURN x-ulp(x)*sign(x)
|
||||
END pred;
|
||||
|
||||
PROCEDURE intpart*(x: REAL): REAL;
|
||||
(*
|
||||
The value of the call intpart(x) shall be the integral part of `x'.
|
||||
For negative values, this shall be -intpart(abs(x)).
|
||||
*)
|
||||
VAR loBit: INTEGER;
|
||||
BEGIN
|
||||
loBit := (hiBit+1) - exponent(x);
|
||||
IF loBit <= 0 THEN RETURN x (* no fractional part *)
|
||||
ELSIF loBit <= hiBit+1 THEN
|
||||
RETURN S.VAL(REAL,S.VAL(SET,x)*{loBit..31}) (* integer part is extracted *)
|
||||
ELSE RETURN ZERO (* no whole part *)
|
||||
END
|
||||
END intpart;
|
||||
|
||||
PROCEDURE fractpart*(x: REAL): REAL;
|
||||
(*
|
||||
The value of the call fractpart(x) shall be the fractional part of
|
||||
`x'. This satifies the relationship fractpart(x)+intpart(x)=x.
|
||||
*)
|
||||
BEGIN
|
||||
RETURN x-intpart(x)
|
||||
END fractpart;
|
||||
|
||||
PROCEDURE trunc*(x: REAL; n: INTEGER): REAL;
|
||||
(*
|
||||
The value of the call trunc(x,n) shall be the value of the most
|
||||
significant `n' places of `x'. An exception shall occur and may be
|
||||
raised if `n' is less than or equal to zero.
|
||||
*)
|
||||
VAR loBit: INTEGER; mask: SET;
|
||||
BEGIN loBit:=places-n;
|
||||
IF n<=0 THEN RETURN ZERO (* exception should be raised *)
|
||||
ELSIF loBit<=0 THEN RETURN x (* nothing was truncated *)
|
||||
ELSE mask:={loBit..31}; (* truncation bit mask *)
|
||||
RETURN S.VAL(REAL,S.VAL(SET,x)*mask)
|
||||
END
|
||||
END trunc;
|
||||
|
||||
PROCEDURE round*(x: REAL; n: INTEGER): REAL;
|
||||
(*
|
||||
The value of the call round(x,n) shall be the value of `x' rounded to
|
||||
the most significant `n' places. An exception shall occur and may be
|
||||
raised if such a value does not exist, or if `n' is less than or equal
|
||||
to zero.
|
||||
*)
|
||||
VAR loBit: INTEGER; num, mask: SET; r: REAL;
|
||||
BEGIN loBit:=places-n;
|
||||
IF n<=0 THEN RETURN ZERO (* exception should be raised *)
|
||||
ELSIF loBit<=0 THEN RETURN x (* nothing was rounded *)
|
||||
ELSE mask:={loBit..31}; num:=S.VAL(SET,x); (* truncation bit mask and number as SET *)
|
||||
x:=S.VAL(REAL,num*mask); (* truncated result *)
|
||||
IF loBit-1 IN num THEN (* check if result should be rounded *)
|
||||
r:=scale(ONE,exponent(x)-n+1); (* rounding fraction *)
|
||||
IF 31 IN num THEN RETURN x-r (* negative rounding toward -infinity *)
|
||||
ELSE RETURN x+r (* positive rounding toward +infinity *)
|
||||
END
|
||||
ELSE RETURN x (* return truncated result *)
|
||||
END
|
||||
END
|
||||
END round;
|
||||
|
||||
PROCEDURE synthesize*(expart: INTEGER; frapart: REAL): REAL;
|
||||
(*
|
||||
The value of the call synthesize(expart,frapart) shall be a value of
|
||||
the corresponding real number type contructed from the value of
|
||||
`expart' and `frapart'. This value shall satisfy the relationship
|
||||
synthesize(exponent(x),fraction(x)) = x.
|
||||
*)
|
||||
BEGIN
|
||||
RETURN scale(frapart, expart)
|
||||
END synthesize;
|
||||
|
||||
|
||||
PROCEDURE setMode*(m: Modes);
|
||||
(*
|
||||
The call setMode(m) shall set status flags from the value of `m',
|
||||
appropriate to the underlying implementation of the corresponding real
|
||||
number type.
|
||||
|
||||
NOTES
|
||||
3 -- Many implementations of floating point provide options for
|
||||
setting flags within the system which control details of the handling
|
||||
of the type. Although two procedures are provided, one for each real
|
||||
number type, the effect may be the same. Typical effects that can be
|
||||
obtained by this means are:
|
||||
a) Ensuring that overflow will raise an exception;
|
||||
b) Allowing underflow to raise an exception;
|
||||
c) Controlling the rounding;
|
||||
d) Allowing special values to be produced (e.g. NaNs in
|
||||
implementations conforming to IEC 559:1989 (IEEE 754:1987));
|
||||
e) Ensuring that special valu access will raise an exception;
|
||||
Since these effects are so varied, the values of type `Modes' that may
|
||||
be used are not specified by this International Standard.
|
||||
4 -- The effects of `setMode' on operation on values of the
|
||||
corresponding real number type in coroutines other than the calling
|
||||
coroutine is not defined. Implementations are not require to preserve
|
||||
the status flags (if any) with the coroutine state.
|
||||
*)
|
||||
BEGIN
|
||||
(* hardware dependent mode setting of coprocessor *)
|
||||
END setMode;
|
||||
|
||||
PROCEDURE currentMode*(): Modes;
|
||||
(*
|
||||
The value of the call currentMode() shall be the current status flags
|
||||
(in the form set by `setMode'), or the default status flags (if
|
||||
`setMode' is not used).
|
||||
|
||||
NOTE 5 -- The value of the call currentMode() is not necessarily the
|
||||
value of set by `setMode', since a call of `setMode' might attempt to
|
||||
set flags that cannot be set by the program.
|
||||
*)
|
||||
BEGIN
|
||||
RETURN {}
|
||||
END currentMode;
|
||||
|
||||
PROCEDURE IsLowException*(): BOOLEAN;
|
||||
(*
|
||||
Returns TRUE if the current coroutine is in the exceptional execution state
|
||||
because of the raising of the LowReal exception; otherwise returns FALSE.
|
||||
*)
|
||||
BEGIN
|
||||
RETURN FALSE
|
||||
END IsLowException;
|
||||
|
||||
BEGIN
|
||||
(* install the default error handler -- just sets err variable *)
|
||||
ErrorHandler:=DefaultHandler;
|
||||
(* tmp := power0(2,126); (* this is test to calculate small as a variable at runtime; -- noch *)
|
||||
small := sml;
|
||||
small := 1/power0(2,126);
|
||||
*)
|
||||
END LowReal.
|
||||
|
||||
|
||||
612
src/runtime/Math.Mod
Normal file
612
src/runtime/Math.Mod
Normal file
|
|
@ -0,0 +1,612 @@
|
|||
(* $Id: RealMath.Mod,v 1.6 1999/09/02 13:19:17 acken Exp $ *)
|
||||
MODULE oocRealMath;
|
||||
|
||||
(* MathL - Oakwood REAL Mathematics.
|
||||
Adapted (with minimal changes) from OOC RealMath.Mod *)
|
||||
|
||||
(*
|
||||
RealMath - Target independent mathematical functions for REAL
|
||||
(IEEE single-precision) numbers.
|
||||
|
||||
Numerical approximations are taken from "Software Manual for the
|
||||
Elementary Functions" by Cody & Waite and "Computer Approximations"
|
||||
by Hart et al.
|
||||
|
||||
Copyright (C) 1995 Michael Griebling
|
||||
|
||||
This module is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This module is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*)
|
||||
|
||||
IMPORT l := LowReal, S := SYSTEM;
|
||||
|
||||
CONST
|
||||
pi* = 3.1415926535897932384626433832795028841972;
|
||||
e* = 2.7182818284590452353602874713526624977572;
|
||||
|
||||
ZERO=0.0; ONE=1.0; HALF=0.5; TWO=2.0; (* local constants *)
|
||||
|
||||
(* internally-used constants *)
|
||||
huge = l.large; (* largest number this package accepts *)
|
||||
miny = ONE/huge; (* smallest number this package accepts *)
|
||||
sqrtHalf = 0.70710678118654752440;
|
||||
Limit = 2.4414062E-4; (* 2**(-MantBits/2) *)
|
||||
eps = 2.9802322E-8; (* 2**(-MantBits-1) *)
|
||||
piInv = 0.31830988618379067154; (* 1/pi *)
|
||||
piByTwo = 1.57079632679489661923132;
|
||||
piByFour = 0.78539816339744830962;
|
||||
lnv = 0.6931610107421875; (* should be exact *)
|
||||
vbytwo = 0.13830277879601902638E-4; (* used in sinh/cosh *)
|
||||
ln2Inv = 1.44269504088896340735992468100189213;
|
||||
|
||||
(* error/exception codes *)
|
||||
NoError*=0; IllegalRoot*=1; IllegalLog*=2; Overflow*=3; IllegalPower*=4; IllegalLogBase*=5;
|
||||
IllegalTrig*=6; IllegalInvTrig*=7; HypInvTrigClipped*=8; IllegalHypInvTrig*=9;
|
||||
LossOfAccuracy*=10; Underflow*=11;
|
||||
|
||||
VAR
|
||||
a1: ARRAY 18 OF REAL; (* lookup table for power function *)
|
||||
a2: ARRAY 9 OF REAL; (* lookup table for power function *)
|
||||
em: REAL; (* largest number such that 1+epsilon > 1.0 *)
|
||||
LnInfinity: REAL; (* natural log of infinity *)
|
||||
LnSmall: REAL; (* natural log of very small number *)
|
||||
SqrtInfinity: REAL; (* square root of infinity *)
|
||||
TanhMax: REAL; (* maximum Tanh value *)
|
||||
t: REAL; (* internal variables *)
|
||||
|
||||
(* internally used support routines *)
|
||||
|
||||
PROCEDURE SinCos (x, y, sign: REAL): REAL;
|
||||
CONST
|
||||
ymax=9099; (* ENTIER(pi*2**(MantBits/2)) *)
|
||||
r1=-0.1666665668E+0;
|
||||
r2= 0.8333025139E-2;
|
||||
r3=-0.1980741872E-3;
|
||||
r4= 0.2601903036E-5;
|
||||
VAR
|
||||
n: LONGINT; xn, f, g: REAL;
|
||||
BEGIN
|
||||
IF y>=ymax THEN l.ErrorHandler(LossOfAccuracy); RETURN ZERO END;
|
||||
|
||||
(* determine the reduced number *)
|
||||
n:=ENTIER(y*piInv+HALF); xn:=n;
|
||||
IF ODD(n) THEN sign:=-sign END;
|
||||
x:=ABS(x);
|
||||
IF x#y THEN xn:=xn-HALF END;
|
||||
|
||||
(* fractional part of reduced number *)
|
||||
f:=SHORT(ABS(LONG(x)) - LONG(xn)*pi);
|
||||
|
||||
(* Pre: |f| <= pi/2 *)
|
||||
IF ABS(f)<Limit THEN RETURN sign*f END;
|
||||
|
||||
(* evaluate polynomial approximation of sin *)
|
||||
g:=f*f; g:=(((r4*g+r3)*g+r2)*g+r1)*g;
|
||||
g:=f+f*g; (* don't use less accurate f(1+g) *)
|
||||
RETURN sign*g
|
||||
END SinCos;
|
||||
|
||||
PROCEDURE div (x, y : LONGINT) : LONGINT;
|
||||
(* corrected MOD function *)
|
||||
BEGIN
|
||||
IF x < 0 THEN RETURN -ABS(x) DIV y ELSE RETURN x DIV y END
|
||||
END div;
|
||||
|
||||
|
||||
(* forward declarations *)
|
||||
PROCEDURE^ arctan2* (xn, xd: REAL): REAL;
|
||||
PROCEDURE^ sincos* (x: REAL; VAR Sin, Cos: REAL);
|
||||
|
||||
PROCEDURE round*(x: REAL): LONGINT;
|
||||
(* Returns the value of x rounded to the nearest integer *)
|
||||
BEGIN
|
||||
IF x<ZERO THEN RETURN -ENTIER(HALF-x)
|
||||
ELSE RETURN ENTIER(x+HALF)
|
||||
END
|
||||
END round;
|
||||
|
||||
PROCEDURE sqrt*(x: REAL): REAL;
|
||||
(* Returns the positive square root of x where x >= 0 *)
|
||||
CONST
|
||||
P0=0.41731; P1=0.59016;
|
||||
VAR
|
||||
xMant, yEst, z: REAL; xExp: INTEGER;
|
||||
BEGIN
|
||||
(* optimize zeros and check for illegal negative roots *)
|
||||
IF x=ZERO THEN RETURN ZERO END;
|
||||
IF x<ZERO THEN l.ErrorHandler(IllegalRoot); x:=-x END;
|
||||
|
||||
(* reduce the input number to the range 0.5 <= x <= 1.0 *)
|
||||
xMant:=l.fraction(x)*HALF; xExp:=l.exponent(x)+1;
|
||||
|
||||
(* initial estimate of the square root *)
|
||||
yEst:=P0+P1*xMant;
|
||||
|
||||
(* perform two newtonian iterations *)
|
||||
z:=(yEst+xMant/yEst); yEst:=0.25*z+xMant/z;
|
||||
|
||||
(* adjust for odd exponents *)
|
||||
IF ODD(xExp) THEN yEst:=yEst*sqrtHalf; INC(xExp) END;
|
||||
|
||||
(* single Newtonian iteration to produce real number accuracy *)
|
||||
RETURN l.scale(yEst, xExp DIV 2)
|
||||
END sqrt;
|
||||
|
||||
PROCEDURE exp*(x: REAL): REAL;
|
||||
(* Returns the exponential of x for x < Ln(MAX(REAL)) *)
|
||||
CONST
|
||||
ln2=0.6931471805599453094172321D0;
|
||||
P0=0.24999999950E+0; P1=0.41602886268E-2; Q1=0.49987178778E-1;
|
||||
VAR xn, g, p, q, z: REAL; n: LONGINT;
|
||||
BEGIN
|
||||
(* Ensure we detect overflows and return 0 for underflows *)
|
||||
IF x>=LnInfinity THEN l.ErrorHandler(Overflow); RETURN huge
|
||||
ELSIF x<LnSmall THEN l.ErrorHandler(Underflow); RETURN ZERO
|
||||
ELSIF ABS(x)<eps THEN RETURN ONE
|
||||
END;
|
||||
|
||||
(* Decompose and scale the number *)
|
||||
n:=round(ln2Inv*x);
|
||||
xn:=n; g:=SHORT(LONG(x)-LONG(xn)*ln2);
|
||||
|
||||
(* Calculate exp(g)/2 from "Software Manual for the Elementary Functions" *)
|
||||
z:=g*g; p:=(P1*z+P0)*g; q:=Q1*z+HALF;
|
||||
RETURN l.scale(HALF+p/(q-p), SHORT(n+1))
|
||||
END exp;
|
||||
|
||||
PROCEDURE ln*(x: REAL): REAL;
|
||||
(* Returns the natural logarithm of x for x > 0 *)
|
||||
CONST
|
||||
c1=355.0/512.0; c2=-2.121944400546905827679E-4;
|
||||
A0=-0.5527074855E+0; B0=-0.6632718214E+1;
|
||||
VAR f, zn, zd, r, z, w, xn: REAL; n: INTEGER;
|
||||
BEGIN
|
||||
(* ensure illegal inputs are trapped and handled *)
|
||||
IF x<=ZERO THEN l.ErrorHandler(IllegalLog); RETURN -huge END;
|
||||
|
||||
(* reduce the range of the input *)
|
||||
f:=l.fraction(x)*HALF; n:=l.exponent(x)+1;
|
||||
IF f>sqrtHalf THEN zn:=(f-HALF)-HALF; zd:=f*HALF+HALF
|
||||
ELSE zn:=f-HALF; zd:=zn*HALF+HALF; DEC(n)
|
||||
END;
|
||||
|
||||
(* evaluate rational approximation from "Software Manual for the Elementary Functions" *)
|
||||
z:=zn/zd; w:=z*z; r:=z+z*(w*A0/(w+B0));
|
||||
|
||||
(* scale the output *)
|
||||
xn:=n;
|
||||
RETURN (xn*c2+r)+xn*c1
|
||||
END ln;
|
||||
|
||||
(* The angle in all trigonometric functions is measured in radians *)
|
||||
|
||||
PROCEDURE sin*(x: REAL): REAL;
|
||||
(* Returns the sine of x for all x *)
|
||||
BEGIN
|
||||
IF x<ZERO THEN RETURN SinCos(x, -x, -ONE)
|
||||
ELSE RETURN SinCos(x, x, ONE)
|
||||
END
|
||||
END sin;
|
||||
|
||||
PROCEDURE cos*(x: REAL): REAL;
|
||||
(* Returns the cosine of x for all x *)
|
||||
BEGIN
|
||||
RETURN SinCos(x, ABS(x)+piByTwo, ONE)
|
||||
END cos;
|
||||
|
||||
PROCEDURE tan*(x: REAL): REAL;
|
||||
(* Returns the tangent of x where x cannot be an odd multiple of pi/2 *)
|
||||
CONST
|
||||
ymax = 6434; (* ENTIER(2**(MantBits/2)*pi/2) *)
|
||||
twoByPi = 0.63661977236758134308;
|
||||
P1=-0.958017723E-1; Q1=-0.429135777E+0; Q2=0.971685835E-2;
|
||||
VAR
|
||||
n: LONGINT;
|
||||
y, xn, f, xnum, xden, g: REAL;
|
||||
BEGIN
|
||||
(* check for error limits *)
|
||||
y:=ABS(x);
|
||||
IF y>ymax THEN l.ErrorHandler(LossOfAccuracy); RETURN ZERO END;
|
||||
|
||||
(* determine n and the fraction f *)
|
||||
n:=round(x*twoByPi); xn:=n;
|
||||
f:=SHORT(LONG(x)-LONG(xn)*piByTwo);
|
||||
|
||||
(* check for underflow *)
|
||||
IF ABS(f)<Limit THEN xnum:=f; xden:=ONE
|
||||
ELSE g:=f*f; xnum:=P1*g*f+f; xden:=(Q2*g+Q1)*g+HALF+HALF
|
||||
END;
|
||||
|
||||
(* find the final result *)
|
||||
IF ODD(n) THEN RETURN xden/(-xnum)
|
||||
ELSE RETURN xnum/xden
|
||||
END
|
||||
END tan;
|
||||
|
||||
PROCEDURE asincos (x: REAL; flag: LONGINT; VAR i: LONGINT; VAR res: REAL);
|
||||
CONST
|
||||
P1=0.933935835E+0; P2=-0.504400557E+0;
|
||||
Q0=0.560363004E+1; Q1=-0.554846723E+1;
|
||||
VAR
|
||||
y, g, r: REAL;
|
||||
BEGIN
|
||||
y:=ABS(x);
|
||||
IF y>HALF THEN
|
||||
i:=1-flag;
|
||||
IF y>ONE THEN l.ErrorHandler(IllegalInvTrig); res:=huge; RETURN END;
|
||||
|
||||
(* reduce the input argument *)
|
||||
g:=(ONE-y)*HALF; r:=-sqrt(g); y:=r+r;
|
||||
|
||||
(* compute approximation *)
|
||||
r:=((P2*g+P1)*g)/((g+Q1)*g+Q0);
|
||||
res:=y+(y*r)
|
||||
ELSE
|
||||
i:=flag;
|
||||
IF y<Limit THEN res:=y
|
||||
ELSE
|
||||
g:=y*y;
|
||||
|
||||
(* compute approximation *)
|
||||
g:=((P2*g+P1)*g)/((g+Q1)*g+Q0);
|
||||
res:=y+y*g
|
||||
END
|
||||
END
|
||||
END asincos;
|
||||
|
||||
PROCEDURE arcsin*(x: REAL): REAL;
|
||||
(* Returns the arcsine of x, in the range [-pi/2, pi/2] where -1 <= x <= 1 *)
|
||||
VAR
|
||||
res: REAL; i: LONGINT;
|
||||
BEGIN
|
||||
asincos(x, 0, i, res);
|
||||
IF l.err#0 THEN RETURN res END;
|
||||
|
||||
(* adjust result for the correct quadrant *)
|
||||
IF i=1 THEN res:=piByFour+(piByFour+res) END;
|
||||
IF x<0 THEN res:=-res END;
|
||||
RETURN res
|
||||
END arcsin;
|
||||
|
||||
PROCEDURE arccos*(x: REAL): REAL;
|
||||
(* Returns the arccosine of x, in the range [0, pi] where -1 <= x <= 1 *)
|
||||
VAR
|
||||
res: REAL; i: LONGINT;
|
||||
BEGIN
|
||||
asincos(x, 1, i, res);
|
||||
IF l.err#0 THEN RETURN res END;
|
||||
|
||||
(* adjust result for the correct quadrant *)
|
||||
IF x<0 THEN
|
||||
IF i=0 THEN res:=piByTwo+(piByTwo+res)
|
||||
ELSE res:=piByFour+(piByFour+res)
|
||||
END
|
||||
ELSE
|
||||
IF i=1 THEN res:=piByFour+(piByFour-res)
|
||||
ELSE res:=-res
|
||||
END;
|
||||
END;
|
||||
RETURN res
|
||||
END arccos;
|
||||
|
||||
PROCEDURE atan(f: REAL): REAL;
|
||||
(* internal arctan algorithm *)
|
||||
CONST
|
||||
rt32=0.26794919243112270647;
|
||||
rt3=1.73205080756887729353;
|
||||
a=rt3-ONE;
|
||||
P0=-0.4708325141E+0; P1=-0.5090958253E-1; Q0=0.1412500740E+1;
|
||||
piByThree=1.04719755119659774615;
|
||||
piBySix=0.52359877559829887308;
|
||||
VAR
|
||||
n: LONGINT; res, g: REAL;
|
||||
BEGIN
|
||||
IF f>ONE THEN f:=ONE/f; n:=2
|
||||
ELSE n:=0
|
||||
END;
|
||||
|
||||
(* check if f should be scaled *)
|
||||
IF f>rt32 THEN f:=(((a*f-HALF)-HALF)+f)/(rt3+f); INC(n) END;
|
||||
|
||||
(* check for underflow *)
|
||||
IF ABS(f)<Limit THEN res:=f
|
||||
ELSE
|
||||
g:=f*f; res:=(P1*g+P0)*g/(g+Q0); res:=f+f*res
|
||||
END;
|
||||
IF n>1 THEN res:=-res END;
|
||||
CASE n OF
|
||||
| 1: res:=res+piBySix
|
||||
| 2: res:=res+piByTwo
|
||||
| 3: res:=res+piByThree
|
||||
| ELSE (* do nothing *)
|
||||
END;
|
||||
RETURN res
|
||||
END atan;
|
||||
|
||||
PROCEDURE arctan*(x: REAL): REAL;
|
||||
(* Returns the arctangent of x, in the range [-pi/2, pi/2] for all x *)
|
||||
BEGIN
|
||||
IF x<0 THEN RETURN -atan(-x)
|
||||
ELSE RETURN atan(x)
|
||||
END
|
||||
END arctan;
|
||||
|
||||
PROCEDURE power*(base, exponent: REAL): REAL;
|
||||
(* Returns the value of the number base raised to the power exponent
|
||||
for base > 0 *)
|
||||
CONST P1=0.83357541E-1; K=0.4426950409;
|
||||
Q1=0.69314675; Q2=0.24018510; Q3=0.54360383E-1;
|
||||
OneOver16=0.0625; XMAX=16*(l.expoMax+1)-1; (*XMIN=16*l.expoMin;*) XMIN=-2016; (* to make it easier for voc; -- noch *)
|
||||
VAR z, g, R, v, u2, u1, w1, w2: REAL; w: LONGREAL;
|
||||
m, p, i: INTEGER; mp, pp, iw1: LONGINT;
|
||||
BEGIN
|
||||
(* handle all possible error conditions *)
|
||||
IF base<=ZERO THEN
|
||||
IF base#ZERO THEN l.ErrorHandler(IllegalPower); base:=-base
|
||||
ELSIF exponent>ZERO THEN RETURN ZERO
|
||||
ELSE l.ErrorHandler(IllegalPower); RETURN huge
|
||||
END
|
||||
END;
|
||||
|
||||
(* extract the exponent of base to m and clear exponent of base in g *)
|
||||
g:=l.fraction(base)*HALF; m:=l.exponent(base)+1;
|
||||
|
||||
(* determine p table offset with an unrolled binary search *)
|
||||
p:=1;
|
||||
IF g<=a1[9] THEN p:=9 END;
|
||||
IF g<=a1[p+4] THEN INC(p, 4) END;
|
||||
IF g<=a1[p+2] THEN INC(p, 2) END;
|
||||
|
||||
(* compute scaled z so that |z| <= 0.044 *)
|
||||
z:=((g-a1[p+1])-a2[(p+1) DIV 2])/(g+a1[p+1]); z:=z+z;
|
||||
|
||||
(* approximation for log2(z) from "Software Manual for the Elementary Functions" *)
|
||||
v:=z*z; R:=P1*v*z; R:=R+K*R; u2:=(R+z*K)+z;
|
||||
u1:=(m*16-p)*OneOver16; w:=LONG(exponent)*(LONG(u1)+LONG(u2)); (* need extra precision *)
|
||||
|
||||
(* calculations below were modified to work properly -- incorrect in cited reference? *)
|
||||
iw1:=ENTIER(16*w); w1:=iw1*OneOver16; w2:=SHORT(w-w1);
|
||||
|
||||
(* check for overflow/underflow *)
|
||||
IF iw1>XMAX THEN l.ErrorHandler(Overflow); RETURN huge
|
||||
ELSIF iw1<XMIN THEN l.ErrorHandler(Underflow); RETURN ZERO
|
||||
END;
|
||||
|
||||
(* final approximation 2**w2-1 where -0.0625 <= w2 <= 0 *)
|
||||
IF w2>ZERO THEN INC(iw1); w2:=w2-OneOver16 END; IF iw1<0 THEN i:=0 ELSE i:=1 END;
|
||||
mp:=div(iw1, 16)+i; pp:=16*mp-iw1; z:=((Q3*w2+Q2)*w2+Q1)*w2; z:=a1[pp+1]+a1[pp+1]*z;
|
||||
RETURN l.scale(z, SHORT(mp))
|
||||
END power;
|
||||
|
||||
PROCEDURE IsRMathException*(): BOOLEAN;
|
||||
(* Returns TRUE if the current coroutine is in the exceptional execution state
|
||||
because of the raising of the RealMath exception; otherwise returns FALSE.
|
||||
*)
|
||||
BEGIN
|
||||
RETURN FALSE
|
||||
END IsRMathException;
|
||||
|
||||
|
||||
(*
|
||||
Following routines are provided as extensions to the ISO standard.
|
||||
They are either used as the basis of other functions or provide
|
||||
useful functions which are not part of the ISO standard.
|
||||
*)
|
||||
|
||||
PROCEDURE log* (x, base: REAL): REAL;
|
||||
(* log(x,base) is the logarithm of x base 'base'. All positive arguments are
|
||||
allowed but base > 0 and base # 1 *)
|
||||
BEGIN
|
||||
(* log(x, base) = ln(x) / ln(base) *)
|
||||
IF base<=ZERO THEN l.ErrorHandler(IllegalLogBase); RETURN -huge
|
||||
ELSE RETURN ln(x)/ln(base)
|
||||
END
|
||||
END log;
|
||||
|
||||
PROCEDURE ipower* (x: REAL; base: INTEGER): REAL;
|
||||
(* ipower(x, base) returns the x to the integer power base where Log2(x) < expoMax *)
|
||||
VAR Exp: INTEGER; y: REAL; neg: BOOLEAN;
|
||||
|
||||
PROCEDURE Adjust(xadj: REAL): REAL;
|
||||
BEGIN
|
||||
IF (x<ZERO)&ODD(base) THEN RETURN -xadj ELSE RETURN xadj END
|
||||
END Adjust;
|
||||
|
||||
BEGIN
|
||||
(* handle all possible error conditions *)
|
||||
IF base=0 THEN RETURN ONE (* x**0 = 1 *)
|
||||
ELSIF ABS(x)<miny THEN
|
||||
IF base>0 THEN RETURN ZERO ELSE l.ErrorHandler(Overflow); RETURN Adjust(huge) END
|
||||
END;
|
||||
|
||||
(* trap potential overflows and underflows *)
|
||||
Exp:=(l.exponent(x)+1)*base; y:=LnInfinity*ln2Inv;
|
||||
IF Exp>y THEN l.ErrorHandler(Overflow); RETURN Adjust(huge)
|
||||
ELSIF Exp<-y THEN RETURN ZERO
|
||||
END;
|
||||
|
||||
(* compute x**base using an optimised algorithm from Knuth, slightly
|
||||
altered : p442, The Art Of Computer Programming, Vol 2 *)
|
||||
y:=ONE; IF base<0 THEN neg:=TRUE; base := -base ELSE neg:= FALSE END;
|
||||
LOOP
|
||||
IF ODD(base) THEN y:=y*x END;
|
||||
base:=base DIV 2; IF base=0 THEN EXIT END;
|
||||
x:=x*x;
|
||||
END;
|
||||
IF neg THEN RETURN ONE/y ELSE RETURN y END
|
||||
END ipower;
|
||||
|
||||
PROCEDURE sincos* (x: REAL; VAR Sin, Cos: REAL);
|
||||
(* More efficient sin/cos implementation if both values are needed. *)
|
||||
BEGIN
|
||||
Sin:=sin(x); Cos:=sqrt(ONE-Sin*Sin)
|
||||
END sincos;
|
||||
|
||||
PROCEDURE arctan2* (xn, xd: REAL): REAL;
|
||||
(* arctan2(xn,xd) is the quadrant-correct arc tangent atan(xn/xd). If the
|
||||
denominator xd is zero, then the numerator xn must not be zero. All
|
||||
arguments are legal except xn = xd = 0. *)
|
||||
VAR
|
||||
res: REAL; xpdiff: LONGINT;
|
||||
BEGIN
|
||||
(* check for error conditions *)
|
||||
IF xd=ZERO THEN
|
||||
IF xn=ZERO THEN l.ErrorHandler(IllegalTrig); RETURN ZERO
|
||||
ELSIF xn<0 THEN RETURN -piByTwo
|
||||
ELSE RETURN piByTwo
|
||||
END;
|
||||
ELSE
|
||||
xpdiff:=l.exponent(xn)-l.exponent(xd);
|
||||
IF ABS(xpdiff)>=l.expoMax-3 THEN
|
||||
(* overflow detected *)
|
||||
IF xn<0 THEN RETURN -piByTwo
|
||||
ELSE RETURN piByTwo
|
||||
END
|
||||
ELSE
|
||||
res:=ABS(xn/xd);
|
||||
IF res#ZERO THEN res:=atan(res) END;
|
||||
IF xd<ZERO THEN res:=pi-res END;
|
||||
IF xn<ZERO THEN RETURN -res
|
||||
ELSE RETURN res
|
||||
END
|
||||
END
|
||||
END
|
||||
END arctan2;
|
||||
|
||||
PROCEDURE sinh* (x: REAL): REAL;
|
||||
(* sinh(x) is the hyperbolic sine of x. The argument x must not be so large
|
||||
that exp(|x|) overflows. *)
|
||||
CONST P0=-7.13793159; P1=-0.190333399; Q0=-42.8277109;
|
||||
VAR y, f: REAL;
|
||||
BEGIN y:=ABS(x);
|
||||
IF y<=ONE THEN (* handle small arguments *)
|
||||
IF y<Limit THEN RETURN x END;
|
||||
|
||||
(* use approximation from "Software Manual for the Elementary Functions" *)
|
||||
f:=y*y; y:=f*((f*P1+P0)/(f+Q0)); RETURN x+x*y
|
||||
ELSIF y>LnInfinity THEN (* handle exp overflows *)
|
||||
y:=y-lnv;
|
||||
IF y>LnInfinity-lnv+0.69 THEN l.ErrorHandler(Overflow);
|
||||
IF x>ZERO THEN RETURN huge ELSE RETURN -huge END
|
||||
ELSE f:=exp(y); f:=f+f*vbytwo (* don't change to f(1+vbytwo) *)
|
||||
END
|
||||
ELSE f:=exp(y); f:=(f-ONE/f)*HALF
|
||||
END;
|
||||
|
||||
(* reach here when 1 < ABS(x) < LnInfinity-lnv+0.69 *)
|
||||
IF x>ZERO THEN RETURN f ELSE RETURN -f END
|
||||
END sinh;
|
||||
|
||||
PROCEDURE cosh* (x: REAL): REAL;
|
||||
(* cosh(x) is the hyperbolic cosine of x. The argument x must not be so large
|
||||
that exp(|x|) overflows. *)
|
||||
VAR y, f: REAL;
|
||||
BEGIN y:=ABS(x);
|
||||
IF y>LnInfinity THEN (* handle exp overflows *)
|
||||
y:=y-lnv;
|
||||
IF y>LnInfinity-lnv+0.69 THEN l.ErrorHandler(Overflow);
|
||||
IF x>ZERO THEN RETURN huge ELSE RETURN -huge END
|
||||
ELSE f:=exp(y); RETURN f+f*vbytwo (* don't change to f(1+vbytwo) *)
|
||||
END
|
||||
ELSE f:=exp(y); RETURN (f+ONE/f)*HALF
|
||||
END
|
||||
END cosh;
|
||||
|
||||
PROCEDURE tanh* (x: REAL): REAL;
|
||||
(* tanh(x) is the hyperbolic tangent of x. All arguments are legal. *)
|
||||
CONST P0=-0.8237728127; P1=-0.3831010665E-2; Q0=2.471319654; ln3over2=0.5493061443;
|
||||
BIG=9.010913347; (* (ln(2)+(t+1)*ln(B))/2 where t=mantissa bits, B=base *)
|
||||
VAR f, t: REAL;
|
||||
BEGIN f:=ABS(x);
|
||||
IF f>BIG THEN t:=ONE
|
||||
ELSIF f>ln3over2 THEN t:=ONE-TWO/(exp(TWO*f)+ONE)
|
||||
ELSIF f<Limit THEN t:=f
|
||||
ELSE (* approximation from "Software Manual for the Elementary Functions" *)
|
||||
t:=f*f; t:=t*(P1*t+P0)/(t+Q0); t:=f+f*t
|
||||
END;
|
||||
IF x<ZERO THEN RETURN -t ELSE RETURN t END
|
||||
END tanh;
|
||||
|
||||
PROCEDURE arcsinh* (x: REAL): REAL;
|
||||
(* arcsinh(x) is the arc hyperbolic sine of x. All arguments are legal. *)
|
||||
BEGIN
|
||||
IF ABS(x)>SqrtInfinity*HALF THEN l.ErrorHandler(HypInvTrigClipped);
|
||||
IF x>ZERO THEN RETURN ln(SqrtInfinity) ELSE RETURN -ln(SqrtInfinity) END;
|
||||
ELSIF x<ZERO THEN RETURN -ln(-x+sqrt(x*x+ONE))
|
||||
ELSE RETURN ln(x+sqrt(x*x+ONE))
|
||||
END
|
||||
END arcsinh;
|
||||
|
||||
PROCEDURE arccosh* (x: REAL): REAL;
|
||||
(* arccosh(x) is the arc hyperbolic cosine of x. All arguments greater than
|
||||
or equal to 1 are legal. *)
|
||||
BEGIN
|
||||
IF x<ONE THEN l.ErrorHandler(IllegalHypInvTrig); RETURN ZERO
|
||||
ELSIF x>SqrtInfinity*HALF THEN l.ErrorHandler(HypInvTrigClipped); RETURN ln(SqrtInfinity)
|
||||
ELSE RETURN ln(x+sqrt(x*x-ONE))
|
||||
END
|
||||
END arccosh;
|
||||
|
||||
PROCEDURE arctanh* (x: REAL): REAL;
|
||||
(* arctanh(x) is the arc hyperbolic tangent of x. |x| < 1 - sqrt(em), where
|
||||
em is machine epsilon. Note that |x| must not be so close to 1 that the
|
||||
result is less accurate than half precision. *)
|
||||
CONST TanhLimit=0.999984991; (* Tanh(5.9) *)
|
||||
VAR t: REAL;
|
||||
BEGIN t:=ABS(x);
|
||||
IF (t>=ONE) OR (t>(ONE-TWO*em)) THEN l.ErrorHandler(IllegalHypInvTrig);
|
||||
IF x<ZERO THEN RETURN -TanhMax ELSE RETURN TanhMax END
|
||||
ELSIF t>TanhLimit THEN l.ErrorHandler(LossOfAccuracy)
|
||||
END;
|
||||
RETURN arcsinh(x/sqrt(ONE-x*x))
|
||||
END arctanh;
|
||||
|
||||
BEGIN
|
||||
(* determine some fundamental constants used by hyperbolic trig functions *)
|
||||
em:=l.ulp(ONE);
|
||||
LnInfinity:=ln(huge);
|
||||
LnSmall:=ln(miny);
|
||||
SqrtInfinity:=sqrt(huge);
|
||||
t:=l.pred(ONE)/sqrt(em); TanhMax:=ln(t+sqrt(t*t+ONE));
|
||||
|
||||
(* initialize some tables for the power() function a1[i]=2**((1-i)/16) *)
|
||||
a1[1] :=ONE;
|
||||
a1[2] :=S.VAL(REAL, 3F75257DH);
|
||||
a1[3] :=S.VAL(REAL, 3F6AC0C7H);
|
||||
a1[4] :=S.VAL(REAL, 3F60CCDFH);
|
||||
a1[5] :=S.VAL(REAL, 3F5744FDH);
|
||||
a1[6] :=S.VAL(REAL, 3F4E248CH);
|
||||
a1[7] :=S.VAL(REAL, 3F45672AH);
|
||||
a1[8] :=S.VAL(REAL, 3F3D08A4H);
|
||||
a1[9] :=S.VAL(REAL, 3F3504F3H);
|
||||
a1[10]:=S.VAL(REAL, 3F2D583FH);
|
||||
a1[11]:=S.VAL(REAL, 3F25FED7H);
|
||||
a1[12]:=S.VAL(REAL, 3F1EF532H);
|
||||
a1[13]:=S.VAL(REAL, 3F1837F0H);
|
||||
a1[14]:=S.VAL(REAL, 3F11C3D3H);
|
||||
a1[15]:=S.VAL(REAL, 3F0B95C2H);
|
||||
a1[16]:=S.VAL(REAL, 3F05AAC3H);
|
||||
a1[17]:=HALF;
|
||||
|
||||
(* a2[i]=2**[(1-2i)/16] - a1[2i]; delta resolution *)
|
||||
a2[1]:=S.VAL(REAL, 31A92436H);
|
||||
a2[2]:=S.VAL(REAL, 336C2A95H);
|
||||
a2[3]:=S.VAL(REAL, 31A8FC24H);
|
||||
a2[4]:=S.VAL(REAL, 331F580CH);
|
||||
a2[5]:=S.VAL(REAL, 336A42A1H);
|
||||
a2[6]:=S.VAL(REAL, 32C12342H);
|
||||
a2[7]:=S.VAL(REAL, 32E75624H);
|
||||
a2[8]:=S.VAL(REAL, 32CF9890H)
|
||||
END oocRealMath.
|
||||
562
src/runtime/MathL.Mod
Normal file
562
src/runtime/MathL.Mod
Normal file
|
|
@ -0,0 +1,562 @@
|
|||
MODULE MathL;
|
||||
|
||||
(* MathL - Oakwood LONGREAL Mathematics.
|
||||
Adapted (with minimal changes) from OOC LRealMath.Mod *)
|
||||
|
||||
(*
|
||||
LRealMath - Target independent mathematical functions for LONGREAL
|
||||
(IEEE double-precision) numbers.
|
||||
|
||||
Numerical approximations are taken from "Software Manual for the
|
||||
Elementary Functions" by Cody & Waite and "Computer Approximations"
|
||||
by Hart et al.
|
||||
|
||||
Copyright (C) 1996-1998 Michael Griebling
|
||||
|
||||
This module is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This module is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*)
|
||||
|
||||
IMPORT l := LowLReal, m := Math, SYSTEM;
|
||||
|
||||
CONST
|
||||
pi* = 3.1415926535897932384626433832795028841972D0;
|
||||
e* = 2.7182818284590452353602874713526624977572D0;
|
||||
|
||||
ZERO=0.0D0; ONE=1.0D0; HALF=0.5D0; TWO=2.0D0; (* local constants *)
|
||||
|
||||
(* internally-used constants *)
|
||||
huge = l.large; (* largest number this package accepts *)
|
||||
miny = l.small; (* smallest number this package accepts *)
|
||||
sqrtHalf = 0.70710678118654752440D0;
|
||||
Limit = 1.0536712D-8; (* 2**(-MantBits/2) *)
|
||||
eps = 5.5511151D-17; (* 2**(-MantBits-1) *)
|
||||
piInv = 0.31830988618379067154D0; (* 1/pi *)
|
||||
piByTwo = 1.57079632679489661923D0;
|
||||
lnv = 0.6931610107421875D0; (* should be exact *)
|
||||
vbytwo = 0.13830277879601902638D-4; (* used in sinh/cosh *)
|
||||
ln2Inv = 1.44269504088896340735992468100189213D0;
|
||||
|
||||
(* error/exception codes *)
|
||||
NoError*=m.NoError; IllegalRoot*=m.IllegalRoot; IllegalLog*=m.IllegalLog; Overflow*=m.Overflow;
|
||||
IllegalPower*=m.IllegalPower; IllegalLogBase*=m.IllegalLogBase; IllegalTrig*=m.IllegalTrig;
|
||||
IllegalInvTrig*=m.IllegalInvTrig; HypInvTrigClipped*=m.HypInvTrigClipped;
|
||||
IllegalHypInvTrig*=m.IllegalHypInvTrig; LossOfAccuracy*=m.LossOfAccuracy;
|
||||
|
||||
VAR
|
||||
a1: ARRAY 18 OF LONGREAL; (* lookup table for power function *)
|
||||
a2: ARRAY 9 OF LONGREAL; (* lookup table for power function *)
|
||||
em: LONGREAL; (* largest number such that 1+epsilon > 1.0 *)
|
||||
LnInfinity: LONGREAL; (* natural log of infinity *)
|
||||
LnSmall: LONGREAL; (* natural log of very small number *)
|
||||
SqrtInfinity: LONGREAL; (* square root of infinity *)
|
||||
TanhMax: LONGREAL; (* maximum Tanh value *)
|
||||
t: LONGREAL; (* internal variables *)
|
||||
|
||||
(* internally used support routines *)
|
||||
|
||||
PROCEDURE SinCos (x, y, sign: LONGREAL): LONGREAL;
|
||||
CONST
|
||||
ymax=210828714; (* ENTIER(pi*2**(MantBits/2)) *)
|
||||
c1=3.1416015625D0;
|
||||
c2=-8.908910206761537356617D-6;
|
||||
r1=-0.16666666666666665052D+0;
|
||||
r2= 0.83333333333331650314D-2;
|
||||
r3=-0.19841269841201840457D-3;
|
||||
r4= 0.27557319210152756119D-5;
|
||||
r5=-0.25052106798274584544D-7;
|
||||
r6= 0.16058936490371589114D-9;
|
||||
r7=-0.76429178068910467734D-12;
|
||||
r8= 0.27204790957888846175D-14;
|
||||
VAR
|
||||
n: LONGINT; xn, f, x1, g: LONGREAL;
|
||||
BEGIN
|
||||
IF y>=ymax THEN l.ErrorHandler(LossOfAccuracy); RETURN ZERO END;
|
||||
|
||||
(* determine the reduced number *)
|
||||
n:=ENTIER(y*piInv+HALF); xn:=n;
|
||||
IF ODD(n) THEN sign:=-sign END;
|
||||
x:=ABS(x);
|
||||
IF x#y THEN xn:=xn-HALF END;
|
||||
|
||||
(* fractional part of reduced number *)
|
||||
x1:=ENTIER(x);
|
||||
f:=((x1-xn*c1)+(x-x1))-xn*c2;
|
||||
|
||||
(* Pre: |f| <= pi/2 *)
|
||||
IF ABS(f)<Limit THEN RETURN sign*f END;
|
||||
|
||||
(* evaluate polynomial approximation of sin *)
|
||||
g:=f*f; g:=(((((((r8*g+r7)*g+r6)*g+r5)*g+r4)*g+r3)*g+r2)*g+r1)*g;
|
||||
g:=f+f*g; (* don't use less accurate f(1+g) *)
|
||||
RETURN sign*g
|
||||
END SinCos;
|
||||
|
||||
PROCEDURE div (x, y : LONGINT) : LONGINT;
|
||||
(* corrected MOD function *)
|
||||
BEGIN
|
||||
IF x < 0 THEN RETURN -ABS(x) DIV y ELSE RETURN x DIV y END
|
||||
END div;
|
||||
|
||||
|
||||
(* forward declarations *)
|
||||
PROCEDURE^ arctan2* (xn, xd: LONGREAL): LONGREAL;
|
||||
PROCEDURE^ sincos* (x: LONGREAL; VAR Sin, Cos: LONGREAL);
|
||||
|
||||
PROCEDURE sqrt*(x: LONGREAL): LONGREAL;
|
||||
(* Returns the positive square root of x where x >= 0 *)
|
||||
CONST
|
||||
P0=0.41731; P1=0.59016;
|
||||
VAR
|
||||
xMant, yEst, z: LONGREAL; xExp: INTEGER;
|
||||
BEGIN
|
||||
(* optimize zeros and check for illegal negative roots *)
|
||||
IF x=ZERO THEN RETURN ZERO END;
|
||||
IF x<ZERO THEN l.ErrorHandler(IllegalRoot); x:=-x END;
|
||||
|
||||
(* reduce the input number to the range 0.5 <= x <= 1.0 *)
|
||||
xMant:=l.fraction(x)*HALF; xExp:=l.exponent(x)+1;
|
||||
|
||||
(* initial estimate of the square root *)
|
||||
yEst:=P0+P1*xMant;
|
||||
|
||||
(* perform three newtonian iterations *)
|
||||
z:=(yEst+xMant/yEst); yEst:=0.25*z+xMant/z;
|
||||
yEst:=HALF*(yEst+xMant/yEst);
|
||||
|
||||
(* adjust for odd exponents *)
|
||||
IF ODD(xExp) THEN yEst:=yEst*sqrtHalf; INC(xExp) END;
|
||||
|
||||
(* single Newtonian iteration to produce real number accuracy *)
|
||||
RETURN l.scale(yEst, xExp DIV 2)
|
||||
END sqrt;
|
||||
|
||||
PROCEDURE exp*(x: LONGREAL): LONGREAL;
|
||||
(* Returns the exponential of x for x < Ln(MAX(REAL) *)
|
||||
CONST
|
||||
c1=0.693359375D0; c2=-2.1219444005469058277D-4;
|
||||
P0=0.249999999999999993D+0; P1=0.694360001511792852D-2; P2=0.165203300268279130D-4;
|
||||
Q1=0.555538666969001188D-1; Q2=0.495862884905441294D-3;
|
||||
VAR xn, g, p, q, z: LONGREAL; n: INTEGER;
|
||||
BEGIN
|
||||
(* Ensure we detect overflows and return 0 for underflows *)
|
||||
IF x>LnInfinity THEN l.ErrorHandler(Overflow); RETURN huge
|
||||
ELSIF x<LnSmall THEN RETURN ZERO
|
||||
ELSIF ABS(x)<eps THEN RETURN ONE
|
||||
END;
|
||||
|
||||
(* Decompose and scale the number *)
|
||||
IF x>=ZERO THEN n:=SHORT(ENTIER(ln2Inv*x+HALF))
|
||||
ELSE n:=SHORT(ENTIER(ln2Inv*x-HALF))
|
||||
END;
|
||||
xn:=n; g:=(x-xn*c1)-xn*c2;
|
||||
|
||||
(* Calculate exp(g)/2 from "Software Manual for the Elementary Functions" *)
|
||||
z:=g*g; p:=((P2*z+P1)*z+P0)*g; q:=(Q2*z+Q1)*z+HALF;
|
||||
RETURN l.scale(HALF+p/(q-p), n+1)
|
||||
END exp;
|
||||
|
||||
PROCEDURE ln*(x: LONGREAL): LONGREAL;
|
||||
(* Returns the natural logarithm of x for x > 0 *)
|
||||
CONST
|
||||
c1=355.0D0/512.0D0; c2=-2.121944400546905827679D-4;
|
||||
P0=-0.64124943423745581147D+2; P1=0.16383943563021534222D+2; P2=-0.78956112887491257267D+0;
|
||||
Q0=-0.76949932108494879777D+3; Q1=0.31203222091924532844D+3; Q2=-0.35667977739034646171D+2;
|
||||
VAR f, zn, zd, r, z, w, p, q, xn: LONGREAL; n: INTEGER;
|
||||
BEGIN
|
||||
(* ensure illegal inputs are trapped and handled *)
|
||||
IF x<=ZERO THEN l.ErrorHandler(IllegalLog); RETURN -huge END;
|
||||
|
||||
(* reduce the range of the input *)
|
||||
f:=l.fraction(x)*HALF; n:=l.exponent(x)+1;
|
||||
IF f>sqrtHalf THEN zn:=(f-HALF)-HALF; zd:=f*HALF+HALF
|
||||
ELSE zn:=f-HALF; zd:=zn*HALF+HALF; DEC(n)
|
||||
END;
|
||||
|
||||
(* evaluate rational approximation from "Software Manual for the Elementary Functions" *)
|
||||
z:=zn/zd; w:=z*z; q:=((w+Q2)*w+Q1)*w+Q0; p:=w*((P2*w+P1)*w+P0); r:=z+z*(p/q);
|
||||
|
||||
(* scale the output *)
|
||||
xn:=n;
|
||||
RETURN (xn*c2+r)+xn*c1
|
||||
END ln;
|
||||
|
||||
|
||||
(* The angle in all trigonometric functions is measured in radians *)
|
||||
|
||||
PROCEDURE sin* (x: LONGREAL): LONGREAL;
|
||||
BEGIN
|
||||
IF x<ZERO THEN RETURN SinCos(x, -x, -ONE)
|
||||
ELSE RETURN SinCos(x, x, ONE)
|
||||
END
|
||||
END sin;
|
||||
|
||||
PROCEDURE cos* (x: LONGREAL): LONGREAL;
|
||||
BEGIN
|
||||
RETURN SinCos(x, ABS(x)+piByTwo, ONE)
|
||||
END cos;
|
||||
|
||||
PROCEDURE tan*(x: LONGREAL): LONGREAL;
|
||||
(* Returns the tangent of x where x cannot be an odd multiple of pi/2 *)
|
||||
VAR Sin, Cos: LONGREAL;
|
||||
BEGIN
|
||||
sincos(x, Sin, Cos);
|
||||
IF ABS(Cos)<miny THEN l.ErrorHandler(IllegalTrig); RETURN huge
|
||||
ELSE RETURN Sin/Cos
|
||||
END
|
||||
END tan;
|
||||
|
||||
PROCEDURE arcsin*(x: LONGREAL): LONGREAL;
|
||||
(* Returns the arcsine of x, in the range [-pi/2, pi/2] where -1 <= x <= 1 *)
|
||||
BEGIN
|
||||
IF ABS(x)>ONE THEN l.ErrorHandler(IllegalInvTrig); RETURN huge
|
||||
ELSE RETURN arctan2(x, sqrt(ONE-x*x))
|
||||
END
|
||||
END arcsin;
|
||||
|
||||
PROCEDURE arccos*(x: LONGREAL): LONGREAL;
|
||||
(* Returns the arccosine of x, in the range [0, pi] where -1 <= x <= 1 *)
|
||||
BEGIN
|
||||
IF ABS(x)>ONE THEN l.ErrorHandler(IllegalInvTrig); RETURN huge
|
||||
ELSE RETURN arctan2(sqrt(ONE-x*x), x)
|
||||
END
|
||||
END arccos;
|
||||
|
||||
PROCEDURE arctan*(x: LONGREAL): LONGREAL;
|
||||
(* Returns the arctangent of x, in the range [-pi/2, pi/2] for all x *)
|
||||
BEGIN
|
||||
RETURN arctan2(x, ONE)
|
||||
END arctan;
|
||||
|
||||
PROCEDURE power*(base, exponent: LONGREAL): LONGREAL;
|
||||
(* Returns the value of the number base raised to the power exponent
|
||||
for base > 0 *)
|
||||
CONST
|
||||
P1=0.83333333333333211405D-1; P2=0.12500000000503799174D-1;
|
||||
P3=0.22321421285924258967D-2; P4=0.43445775672163119635D-3;
|
||||
K=0.44269504088896340736D0;
|
||||
Q1=0.69314718055994529629D+0; Q2=0.24022650695909537056D+0;
|
||||
Q3=0.55504108664085595326D-1; Q4=0.96181290595172416964D-2;
|
||||
Q5=0.13333541313585784703D-2; Q6=0.15400290440989764601D-3;
|
||||
Q7=0.14928852680595608186D-4;
|
||||
OneOver16=0.0625D0; XMAX=16*l.expoMax-1; (*XMIN=16*l.expoMin+1;*) XMIN=-16351; (* noch *)
|
||||
VAR z, g, R, v, u2, u1, w1, w2, y1, y2, w: LONGREAL; m, p, i: INTEGER; mp, pp, iw1: LONGINT;
|
||||
BEGIN
|
||||
(* handle all possible error conditions *)
|
||||
IF ABS(exponent)<miny THEN RETURN ONE (* base**0 = 1 *)
|
||||
ELSIF base<ZERO THEN l.ErrorHandler(IllegalPower); RETURN -huge
|
||||
ELSIF ABS(base)<miny THEN
|
||||
IF exponent>ZERO THEN RETURN ZERO ELSE l.ErrorHandler(Overflow); RETURN -huge END
|
||||
END;
|
||||
|
||||
(* extract the exponent of base to m and clear exponent of base in g *)
|
||||
g:=l.fraction(base)*HALF; m:=l.exponent(base)+1;
|
||||
|
||||
(* determine p table offset with an unrolled binary search *)
|
||||
p:=1;
|
||||
IF g<=a1[9] THEN p:=9 END;
|
||||
IF g<=a1[p+4] THEN INC(p, 4) END;
|
||||
IF g<=a1[p+2] THEN INC(p, 2) END;
|
||||
|
||||
(* compute scaled z so that |z| <= 0.044 *)
|
||||
z:=((g-a1[p+1])-a2[(p+1) DIV 2])/(g+a1[p+1]); z:=z+z;
|
||||
|
||||
(* approximation for log2(z) from "Software Manual for the Elementary Functions" *)
|
||||
v:=z*z; R:=(((P4*v+P3)*v+P2)*v+P1)*v*z; R:=R+K*R; u2:=(R+z*K)+z; u1:=(m*16-p)*OneOver16;
|
||||
|
||||
(* generate w with extra precision calculations *)
|
||||
y1:=ENTIER(16*exponent)*OneOver16; y2:=exponent-y1; w:=u2*exponent+u1*y2;
|
||||
w1:=ENTIER(16*w)*OneOver16; w2:=w-w1; w:=w1+u1*y1;
|
||||
w1:=ENTIER(16*w)*OneOver16; w2:=w2+(w-w1); w:=ENTIER(16*w2)*OneOver16;
|
||||
iw1:=ENTIER(16*(w+w1)); w2:=w2-w;
|
||||
|
||||
(* check for overflow/underflow *)
|
||||
IF iw1>XMAX THEN l.ErrorHandler(Overflow); RETURN huge
|
||||
ELSIF iw1<XMIN THEN RETURN ZERO (* underflow *)
|
||||
END;
|
||||
|
||||
(* final approximation 2**w2-1 where -0.0625 <= w2 <= 0 *)
|
||||
IF w2>ZERO THEN INC(iw1); w2:=w2-OneOver16 END; IF iw1<0 THEN i:=0 ELSE i:=1 END;
|
||||
mp:=div(iw1, 16)+i; pp:=16*mp-iw1;
|
||||
z:=((((((Q7*w2+Q6)*w2+Q5)*w2+Q4)*w2+Q3)*w2+Q2)*w2+Q1)*w2; z:=a1[pp+1]+a1[pp+1]*z;
|
||||
RETURN l.scale(z, SHORT(mp))
|
||||
END power;
|
||||
|
||||
PROCEDURE round*(x: LONGREAL): LONGINT;
|
||||
(* Returns the value of x rounded to the nearest integer *)
|
||||
BEGIN
|
||||
IF x<ZERO THEN RETURN -ENTIER(HALF-x)
|
||||
ELSE RETURN ENTIER(x+HALF)
|
||||
END
|
||||
END round;
|
||||
|
||||
PROCEDURE IsRMathException*(): BOOLEAN;
|
||||
(* Returns TRUE if the current coroutine is in the exceptional execution state
|
||||
because of the raising of the RealMath exception; otherwise returns FALSE.
|
||||
*)
|
||||
BEGIN
|
||||
RETURN FALSE
|
||||
END IsRMathException;
|
||||
|
||||
|
||||
(*
|
||||
Following routines are provided as extensions to the ISO standard.
|
||||
They are either used as the basis of other functions or provide
|
||||
useful functions which are not part of the ISO standard.
|
||||
*)
|
||||
|
||||
PROCEDURE log* (x, base: LONGREAL): LONGREAL;
|
||||
(* log(x,base) is the logarithm of x base b. All positive arguments are
|
||||
allowed but base > 0 and base # 1. *)
|
||||
BEGIN
|
||||
(* log(x, base) = log2(x) / log2(base) *)
|
||||
IF base<=ZERO THEN l.ErrorHandler(IllegalLogBase); RETURN -huge
|
||||
ELSE RETURN ln(x)/ln(base)
|
||||
END
|
||||
END log;
|
||||
|
||||
PROCEDURE ipower* (x: LONGREAL; base: INTEGER): LONGREAL;
|
||||
(* ipower(x, base) returns the x to the integer power base where base*Log2(x) < Log2(Max) *)
|
||||
VAR y: LONGREAL; neg: BOOLEAN; Exp: LONGINT;
|
||||
|
||||
PROCEDURE Adjust(xadj: LONGREAL): LONGREAL;
|
||||
BEGIN
|
||||
IF (x<ZERO)&ODD(base) THEN RETURN -xadj ELSE RETURN xadj END
|
||||
END Adjust;
|
||||
|
||||
BEGIN
|
||||
(* handle all possible error conditions *)
|
||||
IF base=0 THEN RETURN ONE (* x**0 = 1 *)
|
||||
ELSIF ABS(x)<miny THEN
|
||||
IF base>0 THEN RETURN ZERO ELSE l.ErrorHandler(Overflow); RETURN Adjust(huge) END
|
||||
END;
|
||||
|
||||
(* trap potential overflows and underflows *)
|
||||
Exp:=(l.exponent(x)+1)*base; y:=LnInfinity*ln2Inv;
|
||||
IF Exp>y THEN l.ErrorHandler(Overflow); RETURN Adjust(huge)
|
||||
ELSIF Exp<-y THEN RETURN ZERO
|
||||
END;
|
||||
|
||||
(* compute x**base using an optimised algorithm from Knuth, slightly
|
||||
altered : p442, The Art Of Computer Programming, Vol 2 *)
|
||||
y:=ONE; IF base<0 THEN neg:=TRUE; base := -base ELSE neg:= FALSE END;
|
||||
LOOP
|
||||
IF ODD(base) THEN y:=y*x END;
|
||||
base:=base DIV 2; IF base=0 THEN EXIT END;
|
||||
x:=x*x;
|
||||
END;
|
||||
IF neg THEN RETURN ONE/y ELSE RETURN y END
|
||||
END ipower;
|
||||
|
||||
PROCEDURE sincos* (x: LONGREAL; VAR Sin, Cos: LONGREAL);
|
||||
(* More efficient sin/cos implementation if both values are needed. *)
|
||||
BEGIN
|
||||
Sin:=sin(x); Cos:=sqrt(ONE-Sin*Sin)
|
||||
END sincos;
|
||||
|
||||
PROCEDURE arctan2* (xn, xd: LONGREAL): LONGREAL;
|
||||
(* arctan2(xn,xd) is the quadrant-correct arc tangent atan(xn/xd). If the
|
||||
denominator xd is zero, then the numerator xn must not be zero. All
|
||||
arguments are legal except xn = xd = 0. *)
|
||||
CONST
|
||||
P0=0.216062307897242551884D+3; P1=0.3226620700132512059245D+3;
|
||||
P2=0.13270239816397674701D+3; P3=0.1288838303415727934D+2;
|
||||
Q0=0.2160623078972426128957D+3; Q1=0.3946828393122829592162D+3;
|
||||
Q2=0.221050883028417680623D+3; Q3=0.3850148650835119501D+2;
|
||||
PiOver2=pi/2; Sqrt3=1.7320508075688772935D0;
|
||||
VAR atan, z, z2, p, q: LONGREAL; xnExp, xdExp: INTEGER; Quadrant: SHORTINT;
|
||||
BEGIN
|
||||
IF ABS(xd)<miny THEN
|
||||
IF ABS(xn)<miny THEN l.ErrorHandler(IllegalInvTrig); atan:=ZERO
|
||||
ELSE l.ErrorHandler(Overflow); atan:=PiOver2
|
||||
END
|
||||
ELSE xnExp:=l.exponent(xn); xdExp:=l.exponent(xd);
|
||||
IF xnExp-xdExp>=l.expoMax-3 THEN l.ErrorHandler(Overflow); atan:=PiOver2
|
||||
ELSIF xnExp-xdExp<l.expoMin+3 THEN atan:=ZERO
|
||||
ELSE
|
||||
(* ensure division of xn/xd always produces a number < 1 & resolve quadrant *)
|
||||
IF ABS(xn)>ABS(xd) THEN z:=ABS(xd/xn); Quadrant:=2
|
||||
ELSE z:=ABS(xn/xd); Quadrant:=0
|
||||
END;
|
||||
|
||||
(* further reduce range to within 0 to 2-sqrt(3) *)
|
||||
IF z>TWO-Sqrt3 THEN z:=(z*Sqrt3-ONE)/(Sqrt3+z); INC(Quadrant) END;
|
||||
|
||||
(* approximation from "Computer Approximations" table ARCTN 5075 *)
|
||||
IF ABS(z)<Limit THEN atan:=z (* for small values of z2, return this value *)
|
||||
ELSE z2:=z*z; p:=(((P3*z2+P2)*z2+P1)*z2+P0)*z; q:=(((z2+Q3)*z2+Q2)*z2+Q1)*z2+Q0; atan:=p/q;
|
||||
END;
|
||||
|
||||
(* adjust for z's quadrant *)
|
||||
IF Quadrant>1 THEN atan:=-atan END;
|
||||
CASE Quadrant OF
|
||||
1: atan:=atan+pi/6
|
||||
| 2: atan:=atan+PiOver2
|
||||
| 3: atan:=atan+pi/3
|
||||
| ELSE (* angle is correct *)
|
||||
END
|
||||
END;
|
||||
|
||||
(* map negative xds into the correct quadrant *)
|
||||
IF xd<ZERO THEN atan:=pi-atan END
|
||||
END;
|
||||
|
||||
(* map negative xns into the correct quadrant *)
|
||||
IF xn<ZERO THEN atan:=-atan END;
|
||||
RETURN atan
|
||||
END arctan2;
|
||||
|
||||
PROCEDURE sinh* (x: LONGREAL): LONGREAL;
|
||||
(* sinh(x) is the hyperbolic sine of x. The argument x must not be so large
|
||||
that exp(|x|) overflows. *)
|
||||
CONST
|
||||
P0=-0.35181283430177117881D+6; P1=-0.11563521196851768270D+5;
|
||||
P2=-0.16375798202630751372D+3; P3=-0.78966127417357099479D+0;
|
||||
Q0=-0.21108770058106271242D+7; Q1= 0.36162723109421836460D+5;
|
||||
Q2=-0.27773523119650701667D+3;
|
||||
VAR y, f, p, q: LONGREAL;
|
||||
BEGIN y:=ABS(x);
|
||||
IF y<=ONE THEN (* handle small arguments *)
|
||||
IF y<Limit THEN RETURN x END;
|
||||
|
||||
(* use approximation from "Software Manual for the Elementary Functions" *)
|
||||
f:=y*y; p:=((P3*f+P2)*f+P1)*f+P0; q:=((f+Q2)*f+Q1)*f+Q0; y:=f*(p/q); RETURN x+x*y
|
||||
ELSIF y>LnInfinity THEN (* handle exp overflows *)
|
||||
y:=y-lnv;
|
||||
IF y>LnInfinity-lnv+0.69 THEN l.ErrorHandler(Overflow);
|
||||
IF x>ZERO THEN RETURN huge ELSE RETURN -huge END
|
||||
ELSE f:=exp(y); f:=f+f*vbytwo (* don't change to f(1+vbytwo) *)
|
||||
END
|
||||
ELSE f:=exp(y); f:=(f-ONE/f)*HALF
|
||||
END;
|
||||
|
||||
(* reach here when 1 < ABS(x) < LnInfinity-lnv+0.69 *)
|
||||
IF x>ZERO THEN RETURN f ELSE RETURN -f END
|
||||
END sinh;
|
||||
|
||||
PROCEDURE cosh* (x: LONGREAL): LONGREAL;
|
||||
(* cosh(x) is the hyperbolic cosine of x. The argument x must not be so large
|
||||
that exp(|x|) overflows. *)
|
||||
VAR y, f: LONGREAL;
|
||||
BEGIN y:=ABS(x);
|
||||
IF y>LnInfinity THEN (* handle exp overflows *)
|
||||
y:=y-lnv;
|
||||
IF y>LnInfinity-lnv+0.69 THEN l.ErrorHandler(Overflow);
|
||||
IF x>ZERO THEN RETURN huge ELSE RETURN -huge END
|
||||
ELSE f:=exp(y); RETURN f+f*vbytwo (* don't change to f(1+vbytwo) *)
|
||||
END
|
||||
ELSE f:=exp(y); RETURN (f+ONE/f)*HALF
|
||||
END
|
||||
END cosh;
|
||||
|
||||
PROCEDURE tanh* (x: LONGREAL): LONGREAL;
|
||||
(* tanh(x) is the hyperbolic tangent of x. All arguments are legal. *)
|
||||
CONST
|
||||
P0=-0.16134119023996228053D+4; P1=-0.99225929672236083313D+2; P2=-0.96437492777225469787D+0;
|
||||
Q0= 0.48402357071988688686D+4; Q1= 0.22337720718962312926D+4; Q2= 0.11274474380534949335D+3;
|
||||
ln3over2=0.54930614433405484570D0;
|
||||
BIG=19.06154747D0; (* (ln(2)+(t+1)*ln(B))/2 where t=mantissa bits, B=base *)
|
||||
VAR f, t: LONGREAL;
|
||||
BEGIN f:=ABS(x);
|
||||
IF f>BIG THEN t:=ONE
|
||||
ELSIF f>ln3over2 THEN t:=ONE-TWO/(exp(TWO*f)+ONE)
|
||||
ELSIF f<Limit THEN t:=f
|
||||
ELSE (* approximation from "Software Manual for the Elementary Functions" *)
|
||||
t:=f*f; t:=t*(((P2*t+P1)*t+P0)/(((t+Q2)*t+Q1)*t+Q0)); t:=f+f*t
|
||||
END;
|
||||
IF x<ZERO THEN RETURN -t ELSE RETURN t END
|
||||
END tanh;
|
||||
|
||||
PROCEDURE arcsinh* (x: LONGREAL): LONGREAL;
|
||||
(* arcsinh(x) is the arc hyperbolic sine of x. All arguments are legal. *)
|
||||
BEGIN
|
||||
IF ABS(x)>SqrtInfinity*HALF THEN l.ErrorHandler(HypInvTrigClipped);
|
||||
IF x>ZERO THEN RETURN ln(SqrtInfinity) ELSE RETURN -ln(SqrtInfinity) END;
|
||||
ELSIF x<ZERO THEN RETURN -ln(-x+sqrt(x*x+ONE))
|
||||
ELSE RETURN ln(x+sqrt(x*x+ONE))
|
||||
END
|
||||
END arcsinh;
|
||||
|
||||
PROCEDURE arccosh* (x: LONGREAL): LONGREAL;
|
||||
(* arccosh(x) is the arc hyperbolic cosine of x. All arguments greater than
|
||||
or equal to 1 are legal. *)
|
||||
BEGIN
|
||||
IF x<ONE THEN l.ErrorHandler(IllegalHypInvTrig); RETURN ZERO
|
||||
ELSIF x>SqrtInfinity*HALF THEN l.ErrorHandler(HypInvTrigClipped); RETURN ln(SqrtInfinity)
|
||||
ELSE RETURN ln(x+sqrt(x*x-ONE))
|
||||
END
|
||||
END arccosh;
|
||||
|
||||
PROCEDURE arctanh* (x: LONGREAL): LONGREAL;
|
||||
(* arctanh(x) is the arc hyperbolic tangent of x. |x| < 1 - sqrt(em), where
|
||||
em is machine epsilon. Note that |x| must not be so close to 1 that the
|
||||
result is less accurate than half precision. *)
|
||||
CONST TanhLimit=0.999984991D0; (* Tanh(5.9) *)
|
||||
VAR t: LONGREAL;
|
||||
BEGIN t:=ABS(x);
|
||||
IF (t>=ONE) OR (t>(ONE-TWO*em)) THEN l.ErrorHandler(IllegalHypInvTrig);
|
||||
IF x<ZERO THEN RETURN -TanhMax ELSE RETURN TanhMax END
|
||||
ELSIF t>TanhLimit THEN l.ErrorHandler(LossOfAccuracy)
|
||||
END;
|
||||
RETURN arcsinh(x/sqrt(ONE-x*x))
|
||||
END arctanh;
|
||||
|
||||
PROCEDURE ToLONGREAL(h: HUGEINT): LONGREAL;
|
||||
BEGIN RETURN SYSTEM.VAL(LONGREAL, h)
|
||||
END ToLONGREAL;
|
||||
|
||||
BEGIN
|
||||
(* determine some fundamental constants used by hyperbolic trig functions *)
|
||||
em:=l.ulp(ONE);
|
||||
LnInfinity:=ln(huge);
|
||||
LnSmall:=ln(miny);
|
||||
SqrtInfinity:=sqrt(huge);
|
||||
t:=l.pred(ONE)/sqrt(em); TanhMax:=ln(t+sqrt(t*t+ONE));
|
||||
|
||||
(* initialize some tables for the power() function a1[i]=2**((1-i)/16) *)
|
||||
(* disable compiler warnings about 32-bit negative integers *)
|
||||
(*<* PUSH; Warnings := FALSE *>*)
|
||||
a1[ 1] := ONE;
|
||||
a1[ 2] := ToLONGREAL(3FEEA4AFA2A490DAH);
|
||||
a1[ 3] := ToLONGREAL(3FED5818DCFBA487H);
|
||||
a1[ 4] := ToLONGREAL(3FEC199BDD85529CH);
|
||||
a1[ 5] := ToLONGREAL(3FEAE89F995AD3ADH);
|
||||
a1[ 6] := ToLONGREAL(3FE9C49182A3F090H);
|
||||
a1[ 7] := ToLONGREAL(3FE8ACE5422AA0DBH);
|
||||
a1[ 8] := ToLONGREAL(3FE7A11473EB0186H);
|
||||
a1[ 9] := ToLONGREAL(3FE6A09E667F3BCCH);
|
||||
a1[10] := ToLONGREAL(3FE5AB07DD485429H);
|
||||
a1[11] := ToLONGREAL(3FE4BFDAD5362A27H);
|
||||
a1[12] := ToLONGREAL(3FE3DEA64C123422H);
|
||||
a1[13] := ToLONGREAL(3FE306FE0A31B715H);
|
||||
a1[14] := ToLONGREAL(3FE2387A6E756238H);
|
||||
a1[15] := ToLONGREAL(3FE172B83C7D517AH);
|
||||
a1[16] := ToLONGREAL(3FE0B5586CF9890FH);
|
||||
a1[17] := HALF;
|
||||
|
||||
(* a2[i]=2**[(1-2i)/16] - a1[2i]; delta resolution *)
|
||||
a2[1] := ToLONGREAL(3C90B1EE74320000H);
|
||||
a2[2] := ToLONGREAL(3C71106589500000H);
|
||||
a2[3] := ToLONGREAL(3C6C7C46B0700000H);
|
||||
a2[4] := ToLONGREAL(3C9AFAA2047F0000H);
|
||||
a2[5] := ToLONGREAL(3C86324C05460000H);
|
||||
a2[6] := ToLONGREAL(3C7ADA0911F00000H);
|
||||
a2[7] := ToLONGREAL(3C89B07EB6C80000H);
|
||||
a2[8] := ToLONGREAL(3C88A62E4ADC0000H);
|
||||
|
||||
(* reenable compiler warnings *)
|
||||
(*<* POP *>*)
|
||||
END MathL.
|
||||
|
||||
96
src/runtime/Modules.Mod
Normal file
96
src/runtime/Modules.Mod
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
MODULE Modules; (* jt 6.1.96 *)
|
||||
|
||||
(* access to list of modules and commands, based on ETH Oberon *)
|
||||
|
||||
|
||||
IMPORT SYSTEM, Heap;
|
||||
|
||||
CONST
|
||||
ModNameLen* = 20;
|
||||
|
||||
TYPE
|
||||
ModuleName* = ARRAY ModNameLen OF CHAR;
|
||||
Module* = POINTER TO ModuleDesc;
|
||||
Cmd* = POINTER TO CmdDesc;
|
||||
ModuleDesc* = RECORD (* cf. SYSTEM.Mod *)
|
||||
next-: Module;
|
||||
name-: ModuleName;
|
||||
refcnt-: LONGINT;
|
||||
cmds-: Cmd;
|
||||
types-: LONGINT;
|
||||
enumPtrs-: PROCEDURE (P: PROCEDURE(p: LONGINT));
|
||||
reserved1, reserved2: LONGINT;
|
||||
END ;
|
||||
|
||||
Command* = PROCEDURE;
|
||||
|
||||
CmdDesc* = RECORD
|
||||
next-: Cmd;
|
||||
name-: ARRAY 24 OF CHAR;
|
||||
cmd-: Command
|
||||
END ;
|
||||
|
||||
VAR
|
||||
res*: INTEGER;
|
||||
resMsg*: ARRAY 256 OF CHAR;
|
||||
imported*, importing*: ModuleName;
|
||||
|
||||
|
||||
PROCEDURE -modules*(): Module
|
||||
"(Modules_Module)Heap_modules";
|
||||
|
||||
PROCEDURE -setmodules*(m: Module)
|
||||
"Heap_modules = m";
|
||||
|
||||
|
||||
PROCEDURE Append(VAR a: ARRAY OF CHAR; b: ARRAY OF CHAR);
|
||||
VAR i, j: INTEGER;
|
||||
BEGIN
|
||||
i := 0; WHILE a[i] # 0X DO INC(i) END;
|
||||
j := 0; WHILE b[j] # 0X DO a[i] := b[j]; INC(i); INC(j) END;
|
||||
a[i] := 0X
|
||||
END Append;
|
||||
|
||||
PROCEDURE ThisMod* (name: ARRAY OF CHAR): Module;
|
||||
VAR m: Module; bodyname: ARRAY 64 OF CHAR; body: Command;
|
||||
BEGIN m := modules();
|
||||
WHILE (m # NIL) & (m.name # name) DO m := m.next END ;
|
||||
IF m # NIL THEN res := 0; resMsg := ""
|
||||
ELSE res := 1; COPY(name, importing);
|
||||
resMsg := ' module "'; Append(resMsg, name); Append(resMsg, '" not found');
|
||||
END ;
|
||||
RETURN m
|
||||
END ThisMod;
|
||||
|
||||
PROCEDURE ThisCommand* (mod: Module; name: ARRAY OF CHAR): Command;
|
||||
VAR c: Cmd;
|
||||
BEGIN c := mod.cmds;
|
||||
WHILE (c # NIL) & (c.name # name) DO c := c.next END ;
|
||||
IF c # NIL THEN res := 0; resMsg := ""; RETURN c.cmd
|
||||
ELSE res := 2; resMsg := ' command "'; COPY(name, importing);
|
||||
Append(resMsg, mod.name); Append(resMsg, "."); Append(resMsg, name); Append(resMsg, '" not found');
|
||||
RETURN NIL
|
||||
END
|
||||
END ThisCommand;
|
||||
|
||||
PROCEDURE Free*(name: ARRAY OF CHAR; all: BOOLEAN);
|
||||
VAR m, p: Module;
|
||||
BEGIN m := modules();
|
||||
IF all THEN
|
||||
res := 1; resMsg := 'unloading "all" not yet supported'
|
||||
ELSE
|
||||
WHILE (m # NIL) & (m.name # name) DO p := m; m := m.next END ;
|
||||
IF (m # NIL) & (m.refcnt = 0) THEN
|
||||
IF m = modules() THEN setmodules(m.next)
|
||||
ELSE p.next := m.next
|
||||
END ;
|
||||
res := 0
|
||||
ELSE res := 1;
|
||||
IF m = NIL THEN resMsg := "module not found"
|
||||
ELSE resMsg := "clients of this module exist"
|
||||
END
|
||||
END
|
||||
END
|
||||
END Free;
|
||||
|
||||
END Modules.
|
||||
74
src/runtime/Oberon.Mod
Normal file
74
src/runtime/Oberon.Mod
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
MODULE Oberon;
|
||||
|
||||
(* this version should not have dependency on graphics -- noch *)
|
||||
|
||||
IMPORT Platform, Texts, Out;
|
||||
|
||||
TYPE
|
||||
ParList* = POINTER TO ParRec;
|
||||
ParRec* = RECORD
|
||||
(*
|
||||
vwr*: Viewers.Viewer;
|
||||
frame*: Display.Frame;
|
||||
*)
|
||||
text*: Texts.Text;
|
||||
pos*: LONGINT
|
||||
END;
|
||||
|
||||
VAR
|
||||
Log*: Texts.Text;
|
||||
Par*: ParList; (*actual parameters*)
|
||||
OptionChar*: CHAR;
|
||||
|
||||
R: Texts.Reader;
|
||||
W: Texts.Writer;
|
||||
|
||||
(*clocks*)
|
||||
|
||||
PROCEDURE GetClock* (VAR t, d: LONGINT);
|
||||
BEGIN Platform.GetClock(t, d)
|
||||
END GetClock;
|
||||
|
||||
PROCEDURE Time* (): LONGINT;
|
||||
BEGIN RETURN Platform.Time()
|
||||
END Time;
|
||||
|
||||
PROCEDURE PopulateParams;
|
||||
VAR W: Texts.Writer; i: INTEGER; str: ARRAY 256 OF CHAR;
|
||||
BEGIN
|
||||
Texts.OpenWriter(W);
|
||||
i := 1; (* skip program name *)
|
||||
WHILE i < Platform.ArgCount DO
|
||||
Platform.GetArg(i, str); Texts.WriteString(W, str); Texts.Write(W, " ");
|
||||
INC(i)
|
||||
END;
|
||||
Texts.Append (Par^.text, W.buf);
|
||||
END PopulateParams;
|
||||
|
||||
PROCEDURE GetSelection*(VAR text: Texts.Text; VAR beg, end, time: LONGINT);
|
||||
BEGIN text := NIL; beg := 0; end := 0; time := 0
|
||||
END GetSelection;
|
||||
|
||||
(* --- Notifier for echoing to the comsole all text appended to the log. --- *)
|
||||
PROCEDURE LogNotifier(Log: Texts.Text; op: INTEGER; beg, end: LONGINT);
|
||||
VAR ch: CHAR;
|
||||
BEGIN
|
||||
Texts.OpenReader(R, Log, beg);
|
||||
WHILE ~R.eot & (beg < end) DO
|
||||
Texts.Read(R, ch);
|
||||
IF ch = 0DX THEN Out.Ln ELSE Out.Char(ch) END;
|
||||
INC(beg)
|
||||
END
|
||||
END LogNotifier;
|
||||
|
||||
BEGIN
|
||||
NEW(Par);
|
||||
NEW(Par.text);
|
||||
Par.pos := 0;
|
||||
OptionChar := '-';
|
||||
Texts.Open(Par.text, "");
|
||||
PopulateParams;
|
||||
NEW(Log);
|
||||
Texts.Open(Log, "");
|
||||
Log.notify := LogNotifier;
|
||||
END Oberon.
|
||||
55
src/runtime/Out.Mod
Normal file
55
src/runtime/Out.Mod
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
MODULE Out; (* D C W Brown. 2016-09-27 *)
|
||||
|
||||
IMPORT SYSTEM, Platform;
|
||||
|
||||
PROCEDURE Open*;
|
||||
BEGIN
|
||||
END Open;
|
||||
|
||||
PROCEDURE Char*(ch: CHAR);
|
||||
VAR error: Platform.ErrorCode;
|
||||
BEGIN
|
||||
error := Platform.Write(Platform.StdOut, SYSTEM.ADR(ch), 1)
|
||||
END Char;
|
||||
|
||||
PROCEDURE String*(str: ARRAY OF CHAR);
|
||||
VAR l: LONGINT; error: Platform.ErrorCode;
|
||||
BEGIN
|
||||
l := 0; WHILE (l < LEN(str)) & (str[l] # 0X) DO INC(l) END;
|
||||
error := Platform.Write(Platform.StdOut, SYSTEM.ADR(str), l)
|
||||
END String;
|
||||
|
||||
PROCEDURE Int*(x: HUGEINT; n: LONGINT);
|
||||
CONST zero = ORD('0');
|
||||
VAR s: ARRAY 22 OF CHAR; i: INTEGER; negative: BOOLEAN;
|
||||
BEGIN
|
||||
negative := x < 0;
|
||||
IF x = MIN(HUGEINT) THEN
|
||||
s := "8085774586302733229"; i := 19
|
||||
ELSE
|
||||
IF x < 0 THEN x := - x END;
|
||||
s[0] := CHR(zero + (x MOD 10)); x := x DIV 10;
|
||||
i := 1; WHILE x # 0 DO
|
||||
s[i] := CHR(zero + (x MOD 10));
|
||||
x := x DIV 10;
|
||||
INC(i)
|
||||
END
|
||||
END;
|
||||
IF negative THEN s[i] := '-'; INC(i) END;
|
||||
WHILE n > i DO Char(' '); DEC(n) END;
|
||||
WHILE i > 0 DO DEC(i); Char(s[i]) END
|
||||
END Int;
|
||||
|
||||
PROCEDURE Real*(x: REAL; n: INTEGER);
|
||||
BEGIN
|
||||
END Real;
|
||||
|
||||
PROCEDURE LongReal*(x: LONGREAL; n: INTEGER);
|
||||
BEGIN
|
||||
END LongReal;
|
||||
|
||||
PROCEDURE Ln*;
|
||||
BEGIN String(Platform.NL)
|
||||
END Ln;
|
||||
|
||||
END Out.
|
||||
552
src/runtime/Platformunix.Mod
Normal file
552
src/runtime/Platformunix.Mod
Normal file
|
|
@ -0,0 +1,552 @@
|
|||
MODULE Platform;
|
||||
IMPORT SYSTEM;
|
||||
|
||||
CONST
|
||||
StdIn- = 0;
|
||||
StdOut- = 1;
|
||||
StdErr- = 2;
|
||||
|
||||
TYPE
|
||||
HaltProcedure = PROCEDURE(n: LONGINT);
|
||||
SignalHandler = PROCEDURE(signal: INTEGER);
|
||||
|
||||
ErrorCode* = INTEGER;
|
||||
FileHandle* = LONGINT;
|
||||
|
||||
FileIdentity* = RECORD
|
||||
volume: LONGINT; (* dev on Unix filesystems, volume serial number on NTFS *)
|
||||
index: LONGINT; (* inode on Unix filesystems, file id on NTFS *)
|
||||
mtime: LONGINT; (* File modification time, value is system dependent *)
|
||||
END;
|
||||
|
||||
EnvPtr = POINTER TO ARRAY 1024 OF CHAR;
|
||||
ArgPtr = POINTER TO ARRAY 1024 OF CHAR;
|
||||
ArgVec = POINTER TO ARRAY 1024 OF ArgPtr;
|
||||
ArgVecPtr = POINTER TO ARRAY 1 OF SYSTEM.ADDRESS;
|
||||
|
||||
|
||||
VAR
|
||||
LittleEndian-: BOOLEAN;
|
||||
MainStackFrame-: SYSTEM.ADDRESS;
|
||||
HaltCode-: LONGINT;
|
||||
PID-: INTEGER; (* Note: Must be updated by Fork implementation *)
|
||||
CWD-: ARRAY 256 OF CHAR;
|
||||
ArgCount-: INTEGER;
|
||||
|
||||
ArgVector-: SYSTEM.ADDRESS;
|
||||
HaltHandler: HaltProcedure;
|
||||
TimeStart: LONGINT;
|
||||
|
||||
SeekSet-: INTEGER;
|
||||
SeekCur-: INTEGER;
|
||||
SeekEnd-: INTEGER;
|
||||
|
||||
NL-: ARRAY 3 OF CHAR; (* Platform specific newline representation *)
|
||||
|
||||
|
||||
|
||||
(* Unix headers to be included *)
|
||||
|
||||
PROCEDURE -Aincludesystime '#include <sys/time.h>'; (* for gettimeofday *)
|
||||
PROCEDURE -Aincludetime '#include <time.h>'; (* for localtime *)
|
||||
PROCEDURE -Aincludesystypes '#include <sys/types.h>';
|
||||
PROCEDURE -Aincludeunistd '#include <unistd.h>';
|
||||
PROCEDURE -Aincludesysstat '#include <sys/stat.h>';
|
||||
PROCEDURE -Aincludefcntl '#include <fcntl.h>';
|
||||
PROCEDURE -Aincludeerrno '#include <errno.h>';
|
||||
PROCEDURE -Astdlib '#include <stdlib.h>';
|
||||
PROCEDURE -Astdio '#include <stdio.h>';
|
||||
PROCEDURE -Aerrno '#include <errno.h>';
|
||||
|
||||
|
||||
|
||||
|
||||
(* Error code tests *)
|
||||
|
||||
PROCEDURE -EMFILE(): ErrorCode 'EMFILE';
|
||||
PROCEDURE -ENFILE(): ErrorCode 'ENFILE';
|
||||
PROCEDURE -ENOENT(): ErrorCode 'ENOENT';
|
||||
PROCEDURE -EXDEV(): ErrorCode 'EXDEV';
|
||||
PROCEDURE -EACCES(): ErrorCode 'EACCES';
|
||||
PROCEDURE -EROFS(): ErrorCode 'EROFS';
|
||||
PROCEDURE -EAGAIN(): ErrorCode 'EAGAIN';
|
||||
PROCEDURE -ETIMEDOUT(): ErrorCode 'ETIMEDOUT';
|
||||
PROCEDURE -ECONNREFUSED(): ErrorCode 'ECONNREFUSED';
|
||||
PROCEDURE -ECONNABORTED(): ErrorCode 'ECONNABORTED';
|
||||
PROCEDURE -ENETUNREACH(): ErrorCode 'ENETUNREACH';
|
||||
PROCEDURE -EHOSTUNREACH(): ErrorCode 'EHOSTUNREACH';
|
||||
PROCEDURE -EINTR(): ErrorCode 'EINTR';
|
||||
|
||||
|
||||
|
||||
|
||||
PROCEDURE TooManyFiles*(e: ErrorCode): BOOLEAN;
|
||||
BEGIN RETURN (e = EMFILE()) OR (e = ENFILE()) END TooManyFiles;
|
||||
|
||||
PROCEDURE NoSuchDirectory*(e: ErrorCode): BOOLEAN;
|
||||
BEGIN RETURN e = ENOENT() END NoSuchDirectory;
|
||||
|
||||
PROCEDURE DifferentFilesystems*(e: ErrorCode): BOOLEAN;
|
||||
BEGIN RETURN e = EXDEV() END DifferentFilesystems;
|
||||
|
||||
PROCEDURE Inaccessible*(e: ErrorCode): BOOLEAN;
|
||||
BEGIN RETURN (e = EACCES()) OR (e = EROFS()) OR (e = EAGAIN()) END Inaccessible;
|
||||
|
||||
PROCEDURE Absent*(e: ErrorCode): BOOLEAN;
|
||||
BEGIN RETURN e = ENOENT() END Absent;
|
||||
|
||||
PROCEDURE TimedOut*(e: ErrorCode): BOOLEAN;
|
||||
BEGIN RETURN e = ETIMEDOUT() END TimedOut;
|
||||
|
||||
PROCEDURE ConnectionFailed*(e: ErrorCode): BOOLEAN;
|
||||
BEGIN RETURN (e = ECONNREFUSED()) OR (e = ECONNABORTED())
|
||||
OR (e = ENETUNREACH()) OR (e = EHOSTUNREACH()) END ConnectionFailed;
|
||||
|
||||
PROCEDURE Interrupted*(e: ErrorCode): BOOLEAN;
|
||||
BEGIN RETURN e = EINTR() END Interrupted;
|
||||
|
||||
|
||||
|
||||
|
||||
(* OS memory allocaton *)
|
||||
|
||||
PROCEDURE -allocate (size: SYSTEM.ADDRESS): SYSTEM.ADDRESS "(address)((void*)malloc((size_t)size))";
|
||||
PROCEDURE OSAllocate*(size: SYSTEM.ADDRESS): SYSTEM.ADDRESS; BEGIN RETURN allocate(size) END OSAllocate;
|
||||
|
||||
PROCEDURE -free(address: SYSTEM.ADDRESS) "free((void*)address)";
|
||||
PROCEDURE OSFree*(address: SYSTEM.ADDRESS); BEGIN free(address) END OSFree;
|
||||
|
||||
|
||||
|
||||
|
||||
(* Program startup *)
|
||||
|
||||
PROCEDURE -ExternInitHeap "extern void Heap_InitHeap();";
|
||||
PROCEDURE -HeapInitHeap() "Heap_InitHeap()";
|
||||
|
||||
PROCEDURE Init*(argc: INTEGER; argvadr: SYSTEM.ADDRESS);
|
||||
VAR av: ArgVecPtr;
|
||||
BEGIN
|
||||
MainStackFrame := argvadr;
|
||||
ArgCount := argc;
|
||||
av := SYSTEM.VAL(ArgVecPtr, argvadr);
|
||||
ArgVector := av[0];
|
||||
HaltCode := -128;
|
||||
|
||||
(* This function (Platform.Init) is called at program startup BEFORE any
|
||||
modules have been initalised. In turn we must initialise the heap
|
||||
before module startup (xxx__init) code is run. *)
|
||||
HeapInitHeap();
|
||||
END Init;
|
||||
|
||||
|
||||
|
||||
|
||||
(* Program arguments and environment access *)
|
||||
|
||||
PROCEDURE -getenv(var: ARRAY OF CHAR): EnvPtr "(Platform_EnvPtr)getenv((char*)var)";
|
||||
|
||||
PROCEDURE getEnv*(var: ARRAY OF CHAR; VAR val: ARRAY OF CHAR): BOOLEAN;
|
||||
VAR p: EnvPtr;
|
||||
BEGIN
|
||||
p := getenv(var);
|
||||
IF p # NIL THEN COPY(p^, val) END;
|
||||
RETURN p # NIL;
|
||||
END getEnv;
|
||||
|
||||
PROCEDURE GetEnv*(var: ARRAY OF CHAR; VAR val: ARRAY OF CHAR);
|
||||
BEGIN
|
||||
IF ~ getEnv(var, val) THEN val[0] := 0X END;
|
||||
END GetEnv;
|
||||
|
||||
PROCEDURE GetArg*(n: INTEGER; VAR val: ARRAY OF CHAR);
|
||||
VAR av: ArgVec;
|
||||
BEGIN
|
||||
IF n < ArgCount THEN
|
||||
av := SYSTEM.VAL(ArgVec,ArgVector);
|
||||
COPY(av[n]^, val)
|
||||
END
|
||||
END GetArg;
|
||||
|
||||
PROCEDURE GetIntArg*(n: INTEGER; VAR val: LONGINT);
|
||||
VAR s: ARRAY 64 OF CHAR; k, d, i: LONGINT;
|
||||
BEGIN
|
||||
s := ""; GetArg(n, s); i := 0;
|
||||
IF s[0] = "-" THEN i := 1 END ;
|
||||
k := 0; d := ORD(s[i]) - ORD("0");
|
||||
WHILE (d >= 0 ) & (d <= 9) DO k := k*10 + d; INC(i); d := ORD(s[i]) - ORD("0") END ;
|
||||
IF s[0] = "-" THEN k := -k; DEC(i) END ;
|
||||
IF i > 0 THEN val := k END
|
||||
END GetIntArg;
|
||||
|
||||
PROCEDURE ArgPos*(s: ARRAY OF CHAR): INTEGER;
|
||||
VAR i: INTEGER; arg: ARRAY 256 OF CHAR;
|
||||
BEGIN
|
||||
i := 0; GetArg(i, arg);
|
||||
WHILE (i < ArgCount) & (s # arg) DO INC(i); GetArg(i, arg) END ;
|
||||
RETURN i
|
||||
END ArgPos;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(* Signals and traps *)
|
||||
|
||||
PROCEDURE -sethandler(s: INTEGER; h: SignalHandler) "SystemSetHandler(s, (address)h)";
|
||||
|
||||
PROCEDURE SetInterruptHandler*(handler: SignalHandler);
|
||||
BEGIN sethandler(2, handler); END SetInterruptHandler;
|
||||
|
||||
PROCEDURE SetQuitHandler*(handler: SignalHandler);
|
||||
BEGIN sethandler(3, handler); END SetQuitHandler;
|
||||
|
||||
PROCEDURE SetBadInstructionHandler*(handler: SignalHandler);
|
||||
BEGIN sethandler(4, handler); END SetBadInstructionHandler;
|
||||
|
||||
|
||||
|
||||
|
||||
(* Time of day *)
|
||||
|
||||
PROCEDURE -gettimeval "struct timeval tv; gettimeofday(&tv,0)";
|
||||
PROCEDURE -tvsec(): LONGINT "tv.tv_sec";
|
||||
PROCEDURE -tvusec(): LONGINT "tv.tv_usec";
|
||||
PROCEDURE -sectotm(s: LONGINT) "struct tm *time = localtime((time_t*)&s)";
|
||||
PROCEDURE -tmsec(): LONGINT "(LONGINT)time->tm_sec";
|
||||
PROCEDURE -tmmin(): LONGINT "(LONGINT)time->tm_min";
|
||||
PROCEDURE -tmhour(): LONGINT "(LONGINT)time->tm_hour";
|
||||
PROCEDURE -tmmday(): LONGINT "(LONGINT)time->tm_mday";
|
||||
PROCEDURE -tmmon(): LONGINT "(LONGINT)time->tm_mon";
|
||||
PROCEDURE -tmyear(): LONGINT "(LONGINT)time->tm_year";
|
||||
|
||||
PROCEDURE YMDHMStoClock(ye,mo,da,ho,mi,se: LONGINT; VAR t, d: LONGINT);
|
||||
BEGIN
|
||||
d := ASH(ye MOD 100, 9) + ASH(mo+1, 5) + da;
|
||||
t := ASH(ho, 12) + ASH(mi, 6) + se;
|
||||
END YMDHMStoClock;
|
||||
|
||||
PROCEDURE GetClock*(VAR t, d: LONGINT);
|
||||
BEGIN
|
||||
gettimeval; sectotm(tvsec());
|
||||
YMDHMStoClock(tmyear(), tmmon(), tmmday(), tmhour(), tmmin(), tmsec(), t, d);
|
||||
END GetClock;
|
||||
|
||||
PROCEDURE GetTimeOfDay*(VAR sec, usec: LONGINT);
|
||||
BEGIN
|
||||
gettimeval; sec := tvsec(); usec := tvusec();
|
||||
END GetTimeOfDay;
|
||||
|
||||
PROCEDURE Time*(): LONGINT;
|
||||
VAR ms: LONGINT;
|
||||
BEGIN
|
||||
gettimeval;
|
||||
ms := (tvusec() DIV 1000) + (tvsec() * 1000);
|
||||
RETURN (ms - TimeStart) MOD 7FFFFFFFH;
|
||||
END Time;
|
||||
|
||||
|
||||
PROCEDURE -nanosleep(s: LONGINT; ns: LONGINT) "struct timespec req, rem; req.tv_sec = s; req.tv_nsec = ns; nanosleep(&req, &rem)";
|
||||
|
||||
PROCEDURE Delay*(ms: LONGINT);
|
||||
VAR s, ns: LONGINT;
|
||||
BEGIN
|
||||
s := ms DIV 1000;
|
||||
ns := (ms MOD 1000) * 1000000;
|
||||
nanosleep(s, ns);
|
||||
END Delay;
|
||||
|
||||
|
||||
|
||||
|
||||
(* System call *)
|
||||
|
||||
PROCEDURE -system(str: ARRAY OF CHAR): INTEGER "system((char*)str)";
|
||||
PROCEDURE -err(): INTEGER "errno";
|
||||
|
||||
|
||||
PROCEDURE System*(cmd : ARRAY OF CHAR): INTEGER;
|
||||
BEGIN RETURN system(cmd); END System;
|
||||
|
||||
PROCEDURE Error*(): ErrorCode; BEGIN RETURN err() END Error;
|
||||
|
||||
|
||||
|
||||
|
||||
(* File system *)
|
||||
|
||||
(* Note: Consider also using flags O_SYNC and O_DIRECT as we do buffering *)
|
||||
PROCEDURE -openrw (n: ARRAY OF CHAR): INTEGER "open((char*)n, O_RDWR)";
|
||||
PROCEDURE -openro (n: ARRAY OF CHAR): INTEGER "open((char*)n, O_RDONLY)";
|
||||
PROCEDURE -opennew(n: ARRAY OF CHAR): INTEGER "open((char*)n, O_CREAT | O_TRUNC | O_RDWR, 0664)";
|
||||
|
||||
(* File APIs *)
|
||||
|
||||
PROCEDURE OldRO*(VAR n: ARRAY OF CHAR; VAR h: FileHandle): ErrorCode;
|
||||
VAR fd: INTEGER;
|
||||
BEGIN
|
||||
fd := openro(n);
|
||||
IF (fd < 0) THEN RETURN err() ELSE h := fd; RETURN 0 END;
|
||||
END OldRO;
|
||||
|
||||
PROCEDURE OldRW*(VAR n: ARRAY OF CHAR; VAR h: FileHandle): ErrorCode;
|
||||
VAR fd: INTEGER;
|
||||
BEGIN
|
||||
fd := openrw(n);
|
||||
IF (fd < 0) THEN RETURN err() ELSE h := fd; RETURN 0 END;
|
||||
END OldRW;
|
||||
|
||||
PROCEDURE New*(VAR n: ARRAY OF CHAR; VAR h: FileHandle): ErrorCode;
|
||||
VAR fd: INTEGER;
|
||||
BEGIN
|
||||
fd := opennew(n);
|
||||
IF (fd < 0) THEN RETURN err() ELSE h := fd; RETURN 0 END;
|
||||
END New;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -closefile (fd: LONGINT): INTEGER "close(fd)";
|
||||
|
||||
PROCEDURE Close*(h: FileHandle): ErrorCode;
|
||||
BEGIN
|
||||
IF closefile(h) < 0 THEN RETURN err() ELSE RETURN 0 END
|
||||
END Close;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -fstat(fd: LONGINT): INTEGER "fstat(fd, &s)";
|
||||
PROCEDURE -stat(n: ARRAY OF CHAR): INTEGER "stat((char*)n, &s)";
|
||||
PROCEDURE -structstats "struct stat s";
|
||||
PROCEDURE -statdev(): LONGINT "(LONGINT)s.st_dev";
|
||||
PROCEDURE -statino(): LONGINT "(LONGINT)s.st_ino";
|
||||
PROCEDURE -statmtime(): LONGINT "(LONGINT)s.st_mtime";
|
||||
PROCEDURE -statsize(): LONGINT "(address)s.st_size";
|
||||
|
||||
PROCEDURE Identify*(h: FileHandle; VAR identity: FileIdentity): ErrorCode;
|
||||
BEGIN
|
||||
structstats;
|
||||
IF fstat(h) < 0 THEN RETURN err() END;
|
||||
identity.volume := statdev();
|
||||
identity.index := statino();
|
||||
identity.mtime := statmtime();
|
||||
RETURN 0
|
||||
END Identify;
|
||||
|
||||
PROCEDURE IdentifyByName*(n: ARRAY OF CHAR; VAR identity: FileIdentity): ErrorCode;
|
||||
BEGIN
|
||||
structstats;
|
||||
IF stat(n) < 0 THEN RETURN err() END;
|
||||
identity.volume := statdev();
|
||||
identity.index := statino();
|
||||
identity.mtime := statmtime();
|
||||
RETURN 0
|
||||
END IdentifyByName;
|
||||
|
||||
|
||||
PROCEDURE SameFile*(i1, i2: FileIdentity): BOOLEAN;
|
||||
BEGIN RETURN (i1.index = i2.index) & (i1.volume = i2.volume)
|
||||
END SameFile;
|
||||
|
||||
PROCEDURE SameFileTime*(i1, i2: FileIdentity): BOOLEAN;
|
||||
BEGIN RETURN i1.mtime = i2.mtime
|
||||
END SameFileTime;
|
||||
|
||||
PROCEDURE SetMTime*(VAR target: FileIdentity; source: FileIdentity);
|
||||
BEGIN target.mtime := source.mtime;
|
||||
END SetMTime;
|
||||
|
||||
PROCEDURE MTimeAsClock*(i: FileIdentity; VAR t, d: LONGINT);
|
||||
BEGIN
|
||||
sectotm(i.mtime);
|
||||
YMDHMStoClock(tmyear(), tmmon(), tmmday(), tmhour(), tmmin(), tmsec(), t, d);
|
||||
END MTimeAsClock;
|
||||
|
||||
|
||||
PROCEDURE Size*(h: FileHandle; VAR l: LONGINT): ErrorCode;
|
||||
BEGIN
|
||||
structstats;
|
||||
IF fstat(h) < 0 THEN RETURN err() END;
|
||||
l := statsize();
|
||||
RETURN 0;
|
||||
END Size;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -readfile (fd: LONGINT; p: SYSTEM.ADDRESS; l: LONGINT): LONGINT
|
||||
"(LONGINT)read(fd, (void*)(address)(p), l)";
|
||||
|
||||
PROCEDURE Read*(h: FileHandle; p: SYSTEM.ADDRESS; l: LONGINT; VAR n: LONGINT): ErrorCode;
|
||||
BEGIN
|
||||
n := readfile(h, p, l);
|
||||
IF n < 0 THEN n := 0; RETURN err() ELSE RETURN 0 END
|
||||
END Read;
|
||||
|
||||
PROCEDURE ReadBuf*(h: FileHandle; VAR b: ARRAY OF SYSTEM.BYTE; VAR n: LONGINT): ErrorCode;
|
||||
BEGIN
|
||||
n := readfile(h, SYSTEM.ADR(b), LEN(b));
|
||||
IF n < 0 THEN n := 0; RETURN err() ELSE RETURN 0 END
|
||||
END ReadBuf;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -writefile(fd: LONGINT; p: SYSTEM.ADDRESS; l: SYSTEM.ADDRESS): SYSTEM.ADDRESS
|
||||
"write(fd, (void*)(address)(p), l)";
|
||||
|
||||
PROCEDURE Write*(h: FileHandle; p: SYSTEM.ADDRESS; l: LONGINT): ErrorCode;
|
||||
VAR written: SYSTEM.ADDRESS;
|
||||
BEGIN
|
||||
written := writefile(h, p, l);
|
||||
IF written < 0 THEN RETURN err() ELSE RETURN 0 END
|
||||
END Write;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -fsync(fd: LONGINT): INTEGER "fsync(fd)";
|
||||
|
||||
PROCEDURE Sync*(h: FileHandle): ErrorCode;
|
||||
BEGIN
|
||||
IF fsync(h) < 0 THEN RETURN err() ELSE RETURN 0 END
|
||||
END Sync;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -lseek(fd: LONGINT; o: LONGINT; w: INTEGER): INTEGER "lseek(fd, o, w)";
|
||||
PROCEDURE -seekset(): INTEGER "SEEK_SET";
|
||||
PROCEDURE -seekcur(): INTEGER "SEEK_CUR";
|
||||
PROCEDURE -seekend(): INTEGER "SEEK_END";
|
||||
|
||||
PROCEDURE Seek*(h: FileHandle; offset: LONGINT; whence: INTEGER): ErrorCode;
|
||||
BEGIN
|
||||
IF lseek(h, offset, whence) < 0 THEN RETURN err() ELSE RETURN 0 END
|
||||
END Seek;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -ftruncate(fd: LONGINT; l: LONGINT): INTEGER "ftruncate(fd, l)";
|
||||
|
||||
PROCEDURE Truncate*(h: FileHandle; l: LONGINT): ErrorCode;
|
||||
BEGIN
|
||||
IF (ftruncate(h, l) < 0) THEN RETURN err() ELSE RETURN 0 END;
|
||||
END Truncate;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -unlink(n: ARRAY OF CHAR): INTEGER "unlink((char*)n)";
|
||||
|
||||
PROCEDURE Unlink*(VAR n: ARRAY OF CHAR): ErrorCode;
|
||||
BEGIN
|
||||
IF unlink(n) < 0 THEN RETURN err() ELSE RETURN 0 END
|
||||
END Unlink;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -chdir(n: ARRAY OF CHAR): INTEGER "chdir((char*)n)";
|
||||
PROCEDURE -getcwd(VAR cwd: ARRAY OF CHAR): SYSTEM.PTR "getcwd((char*)cwd, cwd__len)";
|
||||
|
||||
PROCEDURE Chdir*(VAR n: ARRAY OF CHAR): ErrorCode;
|
||||
VAR r: INTEGER;
|
||||
BEGIN
|
||||
IF (chdir(n) >= 0) & (getcwd(CWD) # NIL) THEN RETURN 0
|
||||
ELSE RETURN err() END
|
||||
END Chdir;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -rename(o,n: ARRAY OF CHAR): INTEGER "rename((char*)o, (char*)n)";
|
||||
|
||||
PROCEDURE Rename*(VAR o,n: ARRAY OF CHAR): ErrorCode;
|
||||
BEGIN
|
||||
IF rename(o,n) < 0 THEN RETURN err() ELSE RETURN 0 END
|
||||
END Rename;
|
||||
|
||||
|
||||
|
||||
|
||||
(* Process termination *)
|
||||
|
||||
PROCEDURE -exit(code: INTEGER) "exit(code)";
|
||||
PROCEDURE Exit*(code: INTEGER);
|
||||
BEGIN exit(code) END Exit;
|
||||
|
||||
PROCEDURE -errstring(s: ARRAY OF CHAR) 'write(1, s, s__len-1)';
|
||||
PROCEDURE -errc (c: CHAR) 'write(1, &c, 1)';
|
||||
PROCEDURE errch(c: CHAR); BEGIN errc(c) END errch;
|
||||
PROCEDURE errln; BEGIN errch(0AX) END errln;
|
||||
|
||||
PROCEDURE errposint(l: LONGINT);
|
||||
BEGIN IF l>10 THEN errposint(l DIV 10) END; errch(CHR(ORD('0') + (l MOD 10))) END errposint;
|
||||
|
||||
PROCEDURE errint(l: LONGINT);
|
||||
BEGIN IF l<0 THEN errch('-'); l := -l END; errposint(l) END errint;
|
||||
|
||||
PROCEDURE DisplayHaltCode(code: LONGINT);
|
||||
BEGIN
|
||||
CASE code OF
|
||||
| -1: errstring("Assertion failure.")
|
||||
| -2: errstring("Index out of range.")
|
||||
| -3: errstring("Reached end of function without reaching RETURN.")
|
||||
| -4: errstring("CASE statement: no matching label and no ELSE.")
|
||||
| -5: errstring("Type guard failed.")
|
||||
| -6: errstring("Implicit type guard in record assignment failed.")
|
||||
| -7: errstring("Invalid case in WITH statement.")
|
||||
| -8: errstring("Value out of range.")
|
||||
| -9: errstring("Heap interrupted while locked, but lockdepth = 0 at unlock.")
|
||||
|-10: errstring("NIL access.");
|
||||
|-11: errstring("Alignment error.");
|
||||
|-12: errstring("Divide by zero.");
|
||||
|-13: errstring("Arithmetic overflow/underflow.");
|
||||
|-14: errstring("Invalid function argument.");
|
||||
|-15: errstring("Internal error, e.g. Type descriptor size mismatch.")
|
||||
|-20: errstring("Too many, or negative number of, elements in dynamic array.")
|
||||
ELSE
|
||||
END
|
||||
END DisplayHaltCode;
|
||||
|
||||
PROCEDURE Halt*(code: LONGINT);
|
||||
BEGIN
|
||||
HaltCode := code;
|
||||
IF HaltHandler # NIL THEN HaltHandler(code) END;
|
||||
errstring("Terminated by Halt("); errint(code); errstring("). ");
|
||||
IF code < 0 THEN DisplayHaltCode(code) END;
|
||||
errln;
|
||||
exit(SYSTEM.VAL(INTEGER,code));
|
||||
END Halt;
|
||||
|
||||
PROCEDURE AssertFail*(code: LONGINT);
|
||||
BEGIN
|
||||
errstring("Assertion failure.");
|
||||
IF code # 0 THEN errstring(" ASSERT code "); errint(code); errstring("."); END;
|
||||
errln;
|
||||
exit(SYSTEM.VAL(INTEGER,code));
|
||||
END AssertFail;
|
||||
|
||||
PROCEDURE SetHalt*(p: HaltProcedure);
|
||||
BEGIN HaltHandler := p; END SetHalt;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
PROCEDURE TestLittleEndian;
|
||||
VAR i: INTEGER;
|
||||
BEGIN i := 1; SYSTEM.GET(SYSTEM.ADR(i), LittleEndian); END TestLittleEndian;
|
||||
|
||||
|
||||
PROCEDURE -getpid(): INTEGER "(INTEGER)getpid()";
|
||||
|
||||
BEGIN
|
||||
TestLittleEndian;
|
||||
|
||||
HaltCode := -128;
|
||||
HaltHandler := NIL;
|
||||
TimeStart := 0; TimeStart := Time();
|
||||
PID := getpid();
|
||||
IF getcwd(CWD) = NIL THEN CWD := "" END;
|
||||
|
||||
SeekSet := seekset();
|
||||
SeekCur := seekcur();
|
||||
SeekEnd := seekend();
|
||||
|
||||
NL[0] := 0AX; (* LF *)
|
||||
NL[1] := 0X;
|
||||
END Platform.
|
||||
622
src/runtime/Platformwindows.Mod
Normal file
622
src/runtime/Platformwindows.Mod
Normal file
|
|
@ -0,0 +1,622 @@
|
|||
MODULE Platform;
|
||||
IMPORT SYSTEM;
|
||||
|
||||
(* TODO:
|
||||
Use Unicode APIs with manual UTF8 conversion and prepend '\\?\' to
|
||||
file paths in order to get 32768 character path length limit (as
|
||||
opposed to 256 bytes. *)
|
||||
|
||||
|
||||
TYPE
|
||||
HaltProcedure = PROCEDURE(n: LONGINT);
|
||||
SignalHandler = PROCEDURE(signal: INTEGER);
|
||||
|
||||
ErrorCode* = INTEGER;
|
||||
FileHandle* = LONGINT;
|
||||
|
||||
FileIdentity* = RECORD
|
||||
volume: LONGINT; (* dev on Unix filesystems, volume serial number on NTFS *)
|
||||
indexhigh: LONGINT; (* inode on Unix filesystems, file id on NTFS *)
|
||||
indexlow: LONGINT;
|
||||
mtimehigh: LONGINT; (* File modification time, value is system dependent *)
|
||||
mtimelow: LONGINT; (* File modification time, value is system dependent *)
|
||||
END;
|
||||
|
||||
EnvPtr = POINTER TO ARRAY 1024 OF CHAR;
|
||||
ArgPtr = POINTER TO ARRAY 1024 OF CHAR;
|
||||
ArgVec = POINTER TO ARRAY 1024 OF ArgPtr;
|
||||
ArgVecPtr = POINTER TO ARRAY 1 OF SYSTEM.ADDRESS;
|
||||
|
||||
|
||||
VAR
|
||||
LittleEndian-: BOOLEAN;
|
||||
MainStackFrame-: SYSTEM.ADDRESS;
|
||||
HaltCode-: LONGINT;
|
||||
PID-: INTEGER; (* Note: Must be updated by Fork implementation *)
|
||||
CWD-: ARRAY 4096 OF CHAR;
|
||||
ArgCount-: INTEGER;
|
||||
|
||||
ArgVector-: SYSTEM.ADDRESS;
|
||||
HaltHandler: HaltProcedure;
|
||||
TimeStart: LONGINT;
|
||||
|
||||
SeekSet-: INTEGER;
|
||||
SeekCur-: INTEGER;
|
||||
SeekEnd-: INTEGER;
|
||||
|
||||
StdIn-: FileHandle;
|
||||
StdOut-: FileHandle;
|
||||
StdErr-: FileHandle;
|
||||
|
||||
InterruptHandler: SignalHandler;
|
||||
|
||||
nl-: ARRAY 3 OF CHAR; (* Platform specific newline representation *)
|
||||
|
||||
|
||||
|
||||
PROCEDURE -AincludeWindowsWrapper '#include "WindowsWrapper.h"';
|
||||
|
||||
|
||||
(* Error code tests *)
|
||||
|
||||
PROCEDURE -ERRORTOOMANYOPENFILES(): ErrorCode 'ERROR_TOO_MANY_OPEN_FILES';
|
||||
PROCEDURE -ERRORPATHNOTFOUND(): ErrorCode 'ERROR_PATH_NOT_FOUND';
|
||||
PROCEDURE -ERRORFILENOTFOUND(): ErrorCode 'ERROR_FILE_NOT_FOUND';
|
||||
PROCEDURE -ERRORNOTSAMEDEVICE(): ErrorCode 'ERROR_NOT_SAME_DEVICE';
|
||||
PROCEDURE -ERRORACCESSDENIED(): ErrorCode 'ERROR_ACCESS_DENIED';
|
||||
PROCEDURE -ERRORWRITEPROTECT(): ErrorCode 'ERROR_WRITE_PROTECT';
|
||||
PROCEDURE -ERRORSHARINGVIOLATION(): ErrorCode 'ERROR_SHARING_VIOLATION';
|
||||
PROCEDURE -ERRORNOTREADY(): ErrorCode 'ERROR_NOT_READY';
|
||||
PROCEDURE -ETIMEDOUT(): ErrorCode 'WSAETIMEDOUT';
|
||||
PROCEDURE -ECONNREFUSED(): ErrorCode 'WSAECONNREFUSED';
|
||||
PROCEDURE -ECONNABORTED(): ErrorCode 'WSAECONNABORTED';
|
||||
PROCEDURE -ENETUNREACH(): ErrorCode 'WSAENETUNREACH';
|
||||
PROCEDURE -EHOSTUNREACH(): ErrorCode 'WSAEHOSTUNREACH';
|
||||
PROCEDURE -EINTR(): ErrorCode 'WSAEINTR';
|
||||
|
||||
|
||||
|
||||
PROCEDURE TooManyFiles*(e: ErrorCode): BOOLEAN;
|
||||
BEGIN RETURN e = ERRORTOOMANYOPENFILES() END TooManyFiles;
|
||||
|
||||
PROCEDURE NoSuchDirectory*(e: ErrorCode): BOOLEAN;
|
||||
BEGIN RETURN e = ERRORPATHNOTFOUND() END NoSuchDirectory;
|
||||
|
||||
PROCEDURE DifferentFilesystems*(e: ErrorCode): BOOLEAN;
|
||||
BEGIN RETURN e = ERRORNOTSAMEDEVICE() END DifferentFilesystems;
|
||||
|
||||
PROCEDURE Inaccessible*(e: ErrorCode): BOOLEAN;
|
||||
BEGIN
|
||||
RETURN (e = ERRORACCESSDENIED()) OR (e = ERRORWRITEPROTECT())
|
||||
OR (e = ERRORNOTREADY()) OR (e = ERRORSHARINGVIOLATION());
|
||||
END Inaccessible;
|
||||
|
||||
PROCEDURE Absent*(e: ErrorCode): BOOLEAN;
|
||||
BEGIN RETURN (e = ERRORFILENOTFOUND()) OR (e = ERRORPATHNOTFOUND()) END Absent;
|
||||
|
||||
PROCEDURE TimedOut*(e: ErrorCode): BOOLEAN;
|
||||
BEGIN RETURN (e = ETIMEDOUT()) END TimedOut;
|
||||
|
||||
PROCEDURE ConnectionFailed*(e: ErrorCode): BOOLEAN;
|
||||
BEGIN RETURN (e = ECONNREFUSED()) OR (e = ECONNABORTED())
|
||||
OR (e = ENETUNREACH()) OR (e = EHOSTUNREACH()) END ConnectionFailed;
|
||||
|
||||
PROCEDURE Interrupted*(e: ErrorCode): BOOLEAN;
|
||||
BEGIN RETURN e = EINTR() END Interrupted;
|
||||
|
||||
|
||||
|
||||
(* OS memory allocaton *)
|
||||
|
||||
PROCEDURE -allocate(size: SYSTEM.ADDRESS): SYSTEM.ADDRESS "(address)((void*)HeapAlloc(GetProcessHeap(), 0, (size_t)size))";
|
||||
PROCEDURE OSAllocate*(size: SYSTEM.ADDRESS): SYSTEM.ADDRESS; BEGIN RETURN allocate(size) END OSAllocate;
|
||||
|
||||
PROCEDURE -free(address: SYSTEM.ADDRESS) "HeapFree(GetProcessHeap(), 0, (void*)address)";
|
||||
PROCEDURE OSFree*(address: SYSTEM.ADDRESS); BEGIN free(address) END OSFree;
|
||||
|
||||
|
||||
|
||||
|
||||
(* Program startup *)
|
||||
|
||||
PROCEDURE -ExternInitHeap "extern void Heap_InitHeap();";
|
||||
PROCEDURE -HeapInitHeap() "Heap_InitHeap()";
|
||||
|
||||
PROCEDURE Init*(argc: INTEGER; argvadr: SYSTEM.ADDRESS);
|
||||
VAR av: ArgVecPtr;
|
||||
BEGIN
|
||||
MainStackFrame := argvadr;
|
||||
ArgCount := argc;
|
||||
av := SYSTEM.VAL(ArgVecPtr, argvadr);
|
||||
ArgVector := av[0];
|
||||
HaltCode := -128;
|
||||
|
||||
(* This function (Platform.Init) is called at program startup BEFORE any
|
||||
modules have been initalised. In turn we must initialise the heap
|
||||
before module startup (xxx__init) code is run. *)
|
||||
HeapInitHeap();
|
||||
END Init;
|
||||
|
||||
|
||||
|
||||
|
||||
(* Program arguments and environmet access *)
|
||||
|
||||
PROCEDURE -getenv(name: ARRAY OF CHAR; VAR buf: ARRAY OF CHAR): INTEGER
|
||||
"(INTEGER)GetEnvironmentVariable((char*)name, (char*)buf, buf__len)";
|
||||
|
||||
PROCEDURE getEnv*(var: ARRAY OF CHAR; VAR val: ARRAY OF CHAR): BOOLEAN;
|
||||
VAR
|
||||
buf: ARRAY 4096 OF CHAR;
|
||||
res: INTEGER;
|
||||
BEGIN
|
||||
res := getenv(var, buf);
|
||||
IF (res > 0) & (res < LEN(buf)) THEN
|
||||
COPY(buf, val);
|
||||
RETURN TRUE;
|
||||
ELSE
|
||||
RETURN FALSE;
|
||||
END;
|
||||
END getEnv;
|
||||
|
||||
PROCEDURE GetEnv*(var: ARRAY OF CHAR; VAR val: ARRAY OF CHAR);
|
||||
BEGIN
|
||||
IF ~getEnv(var, val) THEN val[0] := 0X END;
|
||||
END GetEnv;
|
||||
|
||||
PROCEDURE GetArg*(n: INTEGER; VAR val: ARRAY OF CHAR);
|
||||
VAR av: ArgVec;
|
||||
BEGIN
|
||||
IF n < ArgCount THEN
|
||||
av := SYSTEM.VAL(ArgVec,ArgVector);
|
||||
COPY(av[n]^, val)
|
||||
END
|
||||
END GetArg;
|
||||
|
||||
PROCEDURE GetIntArg*(n: INTEGER; VAR val: LONGINT);
|
||||
VAR s: ARRAY 64 OF CHAR; k, d, i: LONGINT;
|
||||
BEGIN
|
||||
s := ""; GetArg(n, s); i := 0;
|
||||
IF s[0] = "-" THEN i := 1 END ;
|
||||
k := 0; d := ORD(s[i]) - ORD("0");
|
||||
WHILE (d >= 0 ) & (d <= 9) DO k := k*10 + d; INC(i); d := ORD(s[i]) - ORD("0") END ;
|
||||
IF s[0] = "-" THEN k := -k; DEC(i) END ;
|
||||
IF i > 0 THEN val := k END
|
||||
END GetIntArg;
|
||||
|
||||
PROCEDURE ArgPos*(s: ARRAY OF CHAR): INTEGER;
|
||||
VAR i: INTEGER; arg: ARRAY 256 OF CHAR;
|
||||
BEGIN
|
||||
i := 0; GetArg(i, arg);
|
||||
WHILE (i < ArgCount) & (s # arg) DO INC(i); GetArg(i, arg) END ;
|
||||
RETURN i
|
||||
END ArgPos;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(* Signals and traps *)
|
||||
|
||||
(* PROCEDURE -signal(sig: LONGINT; func: SignalHandler) "signal(sig, func)"; *)
|
||||
|
||||
(* TODO *)
|
||||
|
||||
(* Ctrl/c handling *)
|
||||
|
||||
PROCEDURE -SetInterruptHandler*(h: SignalHandler) "SystemSetInterruptHandler((address)h)";
|
||||
PROCEDURE -SetQuitHandler* (h: SignalHandler) "SystemSetQuitHandler((address)h)";
|
||||
|
||||
PROCEDURE SetBadInstructionHandler*(handler: SignalHandler);
|
||||
BEGIN (* TODO *) END SetBadInstructionHandler;
|
||||
|
||||
|
||||
|
||||
|
||||
(* Time of day *)
|
||||
|
||||
PROCEDURE -getLocalTime "SYSTEMTIME st; GetLocalTime(&st)";
|
||||
PROCEDURE -stmsec(): INTEGER "(INTEGER)st.wMilliseconds";
|
||||
PROCEDURE -stsec(): INTEGER "(INTEGER)st.wSecond";
|
||||
PROCEDURE -stmin(): INTEGER "(INTEGER)st.wMinute";
|
||||
PROCEDURE -sthour(): INTEGER "(INTEGER)st.wHour";
|
||||
PROCEDURE -stmday(): INTEGER "(INTEGER)st.wDay";
|
||||
PROCEDURE -stmon(): INTEGER "(INTEGER)st.wMonth";
|
||||
PROCEDURE -styear(): INTEGER "(INTEGER)st.wYear";
|
||||
|
||||
PROCEDURE YMDHMStoClock(ye,mo,da,ho,mi,se: INTEGER; VAR t, d: LONGINT);
|
||||
BEGIN
|
||||
d := ASH(ye MOD 100, 9) + ASH(mo+1, 5) + da;
|
||||
t := ASH(ho, 12) + ASH(mi, 6) + se;
|
||||
END YMDHMStoClock;
|
||||
|
||||
PROCEDURE GetClock*(VAR t, d: LONGINT);
|
||||
BEGIN
|
||||
getLocalTime;
|
||||
YMDHMStoClock(styear(), stmon(), stmday(), sthour(), stmin(), stsec(), t, d);
|
||||
END GetClock;
|
||||
|
||||
PROCEDURE -GetTickCount(): LONGINT "(LONGINT)(uint32)GetTickCount()";
|
||||
|
||||
PROCEDURE Time*(): LONGINT;
|
||||
VAR ms: LONGINT;
|
||||
BEGIN
|
||||
ms := GetTickCount();
|
||||
RETURN (ms - TimeStart) MOD 7FFFFFFFH;
|
||||
END Time;
|
||||
|
||||
|
||||
PROCEDURE -sleep(ms: LONGINT) "Sleep((DWORD)ms)";
|
||||
|
||||
PROCEDURE Delay*(ms: LONGINT);
|
||||
BEGIN
|
||||
WHILE ms > 30000 DO sleep(30000); ms := ms-30000 END;
|
||||
IF ms > 0 THEN sleep(ms) END;
|
||||
END Delay;
|
||||
|
||||
|
||||
PROCEDURE -stToFt "FILETIME ft; SystemTimeToFileTime(&st, &ft)";
|
||||
PROCEDURE -ftToUli "ULARGE_INTEGER ul; ul.LowPart=ft.dwLowDateTime; ul.HighPart=ft.dwHighDateTime";
|
||||
PROCEDURE -tous1970 "ul.QuadPart = (ul.QuadPart - 116444736000000000ULL)/10LL";
|
||||
PROCEDURE -ulSec(): LONGINT "(LONGINT)(ul.QuadPart / 1000000LL)";
|
||||
PROCEDURE -uluSec(): LONGINT "(LONGINT)(ul.QuadPart % 1000000LL)";
|
||||
|
||||
PROCEDURE GetTimeOfDay*(VAR sec, usec: LONGINT);
|
||||
BEGIN
|
||||
getLocalTime; stToFt; ftToUli; tous1970;
|
||||
sec := ulSec(); usec := uluSec();
|
||||
END GetTimeOfDay;
|
||||
|
||||
|
||||
|
||||
(* System call *)
|
||||
|
||||
PROCEDURE -startupInfo "STARTUPINFO si = {0}; si.cb = sizeof(si);";
|
||||
PROCEDURE -processInfo "PROCESS_INFORMATION pi = {0};";
|
||||
PROCEDURE -createProcess(str: ARRAY OF CHAR): INTEGER "(INTEGER)CreateProcess(0, (char*)str, 0,0,0,0,0,0,&si,&pi)";
|
||||
PROCEDURE -waitForProcess(): INTEGER "(INTEGER)WaitForSingleObject(pi.hProcess, INFINITE)";
|
||||
PROCEDURE -getExitCodeProcess(VAR exitcode: INTEGER) "GetExitCodeProcess(pi.hProcess, (DWORD*)exitcode);";
|
||||
PROCEDURE -cleanupProcess "CloseHandle(pi.hProcess); CloseHandle(pi.hThread);";
|
||||
PROCEDURE -err(): INTEGER "(INTEGER)GetLastError()";
|
||||
|
||||
PROCEDURE System*(cmd : ARRAY OF CHAR): INTEGER;
|
||||
VAR
|
||||
result: INTEGER;
|
||||
BEGIN
|
||||
result := 127;
|
||||
startupInfo; processInfo;
|
||||
IF createProcess(cmd) # 0 THEN
|
||||
IF waitForProcess() = 0 THEN getExitCodeProcess(result) END;
|
||||
cleanupProcess;
|
||||
END;
|
||||
RETURN result * 256;
|
||||
END System;
|
||||
|
||||
PROCEDURE Error*(): ErrorCode; BEGIN RETURN err() END Error;
|
||||
|
||||
|
||||
(* File system *)
|
||||
|
||||
PROCEDURE -invalidHandleValue(): LONGINT "((LONGINT)(address)INVALID_HANDLE_VALUE)";
|
||||
|
||||
PROCEDURE -openrw (n: ARRAY OF CHAR): LONGINT
|
||||
"(LONGINT)(address)CreateFile((char*)n, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)";
|
||||
|
||||
PROCEDURE -openro (n: ARRAY OF CHAR): LONGINT
|
||||
"(LONGINT)(address)CreateFile((char*)n, GENERIC_READ , FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)";
|
||||
|
||||
PROCEDURE -opennew(n: ARRAY OF CHAR): LONGINT
|
||||
"(LONGINT)(address)CreateFile((char*)n, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)";
|
||||
|
||||
|
||||
|
||||
|
||||
(* File APIs *)
|
||||
|
||||
PROCEDURE OldRO*(VAR n: ARRAY OF CHAR; VAR h: FileHandle): ErrorCode;
|
||||
VAR fd: LONGINT;
|
||||
BEGIN
|
||||
fd := openro(n);
|
||||
IF (fd = invalidHandleValue()) THEN RETURN err() ELSE h := fd; RETURN 0 END;
|
||||
END OldRO;
|
||||
|
||||
PROCEDURE OldRW*(VAR n: ARRAY OF CHAR; VAR h: FileHandle): ErrorCode;
|
||||
VAR fd: LONGINT;
|
||||
BEGIN
|
||||
fd := openrw(n);
|
||||
IF (fd = invalidHandleValue()) THEN RETURN err() ELSE h := fd; RETURN 0 END;
|
||||
END OldRW;
|
||||
|
||||
PROCEDURE New*(VAR n: ARRAY OF CHAR; VAR h: FileHandle): ErrorCode;
|
||||
VAR fd: LONGINT;
|
||||
BEGIN
|
||||
fd := opennew(n);
|
||||
IF (fd = invalidHandleValue()) THEN RETURN err() ELSE h := fd; RETURN 0 END;
|
||||
END New;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -closeHandle(h: FileHandle): INTEGER "(INTEGER)CloseHandle((HANDLE)(address)h)";
|
||||
|
||||
PROCEDURE Close*(h: FileHandle): ErrorCode;
|
||||
BEGIN
|
||||
IF closeHandle(h) = 0 THEN RETURN err() ELSE RETURN 0 END
|
||||
END Close;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -byHandleFileInformation "BY_HANDLE_FILE_INFORMATION bhfi";
|
||||
PROCEDURE -getFileInformationByHandle(h: FileHandle): INTEGER "(INTEGER)GetFileInformationByHandle((HANDLE)(address)h, &bhfi)";
|
||||
PROCEDURE -bhfiMtimeHigh(): LONGINT "(LONGINT)bhfi.ftLastWriteTime.dwHighDateTime";
|
||||
PROCEDURE -bhfiMtimeLow(): LONGINT "(LONGINT)bhfi.ftLastWriteTime.dwLowDateTime";
|
||||
PROCEDURE -bhfiVsn(): LONGINT "(LONGINT)bhfi.dwVolumeSerialNumber";
|
||||
PROCEDURE -bhfiIndexHigh(): LONGINT "(LONGINT)bhfi.nFileIndexHigh";
|
||||
PROCEDURE -bhfiIndexLow(): LONGINT "(LONGINT)bhfi.nFileIndexLow";
|
||||
|
||||
|
||||
PROCEDURE Identify*(h: FileHandle; VAR identity: FileIdentity): ErrorCode;
|
||||
BEGIN
|
||||
byHandleFileInformation;
|
||||
IF getFileInformationByHandle(h) = 0 THEN RETURN err() END;
|
||||
identity.volume := bhfiVsn();
|
||||
identity.indexhigh := bhfiIndexHigh();
|
||||
identity.indexlow := bhfiIndexLow();
|
||||
identity.mtimehigh := bhfiMtimeHigh();
|
||||
identity.mtimelow := bhfiMtimeLow();
|
||||
RETURN 0
|
||||
END Identify;
|
||||
|
||||
PROCEDURE IdentifyByName*(n: ARRAY OF CHAR; VAR identity: FileIdentity): ErrorCode;
|
||||
VAR
|
||||
h: FileHandle;
|
||||
e,i: ErrorCode;
|
||||
BEGIN
|
||||
e := OldRO(n, h);
|
||||
IF e # 0 THEN RETURN e END;
|
||||
e := Identify(h, identity);
|
||||
i := Close(h);
|
||||
RETURN e;
|
||||
END IdentifyByName;
|
||||
|
||||
|
||||
PROCEDURE SameFile*(i1, i2: FileIdentity): BOOLEAN;
|
||||
BEGIN RETURN (i1.indexhigh = i2.indexhigh) & (i1.indexlow = i2.indexlow) & (i1.volume = i2.volume)
|
||||
END SameFile;
|
||||
|
||||
PROCEDURE SameFileTime*(i1, i2: FileIdentity): BOOLEAN;
|
||||
BEGIN RETURN (i1.mtimehigh = i2.mtimehigh) & (i1.mtimelow = i2.mtimelow)
|
||||
END SameFileTime;
|
||||
|
||||
PROCEDURE SetMTime*(VAR target: FileIdentity; source: FileIdentity);
|
||||
BEGIN target.mtimehigh := source.mtimehigh; target.mtimelow := source.mtimelow;
|
||||
END SetMTime;
|
||||
|
||||
PROCEDURE -identityToFileTime(i: FileIdentity)
|
||||
"FILETIME ft; ft.dwHighDateTime = i.mtimehigh; ft.dwLowDateTime = i.mtimelow";
|
||||
|
||||
PROCEDURE -fileTimeToSysTime
|
||||
"SYSTEMTIME st; FileTimeToSystemTime(&ft, &st)";
|
||||
|
||||
PROCEDURE MTimeAsClock*(i: FileIdentity; VAR t, d: LONGINT);
|
||||
BEGIN
|
||||
identityToFileTime(i); fileTimeToSysTime;
|
||||
YMDHMStoClock(styear(), stmon(), stmday(), sthour(), stmin(), stsec(), t, d);
|
||||
END MTimeAsClock;
|
||||
|
||||
PROCEDURE -largeInteger "LARGE_INTEGER li";
|
||||
PROCEDURE -liLongint(): LONGINT "(LONGINT)li.QuadPart";
|
||||
PROCEDURE -getFileSize(h: FileHandle): INTEGER "(INTEGER)GetFileSizeEx((HANDLE)(address)h, &li)";
|
||||
|
||||
PROCEDURE Size*(h: FileHandle; VAR l: LONGINT): ErrorCode;
|
||||
BEGIN
|
||||
largeInteger;
|
||||
IF getFileSize(h) = 0 THEN RETURN err() END;
|
||||
l := liLongint();
|
||||
RETURN 0;
|
||||
END Size;
|
||||
|
||||
|
||||
PROCEDURE -readfile (fd: LONGINT; p: SYSTEM.ADDRESS; l: LONGINT; VAR n: SYSTEM.INT32): INTEGER
|
||||
"(INTEGER)ReadFile((HANDLE)fd, (void*)p, (DWORD)l, (DWORD*)n, 0)";
|
||||
|
||||
PROCEDURE Read*(h: FileHandle; p: SYSTEM.ADDRESS; l: LONGINT; VAR n: LONGINT): ErrorCode;
|
||||
VAR result: INTEGER; lengthread: SYSTEM.INT32;
|
||||
BEGIN
|
||||
result := readfile(h, p, l, lengthread);
|
||||
IF result = 0 THEN n := 0; RETURN err() ELSE n := lengthread; RETURN 0 END
|
||||
END Read;
|
||||
|
||||
PROCEDURE ReadBuf*(h: FileHandle; VAR b: ARRAY OF SYSTEM.BYTE; VAR n: LONGINT): ErrorCode;
|
||||
VAR result: INTEGER; lengthread: SYSTEM.INT32;
|
||||
BEGIN
|
||||
result := readfile(h, SYSTEM.ADR(b), LEN(b), lengthread);
|
||||
IF result = 0 THEN n := 0; RETURN err() ELSE n := lengthread; RETURN 0 END
|
||||
END ReadBuf;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -writefile(fd: LONGINT; p: SYSTEM.ADDRESS; l: LONGINT): INTEGER
|
||||
"(INTEGER)WriteFile((HANDLE)fd, (void*)(p), (DWORD)l, 0,0)";
|
||||
|
||||
PROCEDURE Write*(h: FileHandle; p: SYSTEM.ADDRESS; l: LONGINT): ErrorCode;
|
||||
BEGIN
|
||||
IF writefile(h, p, l) = 0 THEN RETURN err() ELSE RETURN 0 END
|
||||
END Write;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -flushFileBuffers(h: FileHandle): INTEGER "(INTEGER)FlushFileBuffers((HANDLE)h)";
|
||||
|
||||
PROCEDURE Sync*(h: FileHandle): ErrorCode;
|
||||
BEGIN
|
||||
IF flushFileBuffers(h) = 0 THEN RETURN err() ELSE RETURN 0 END
|
||||
END Sync;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -setFilePointerEx(h: FileHandle; o: LONGINT; r: INTEGER; VAR rc: INTEGER)
|
||||
"li.QuadPart=o; *rc = (INTEGER)SetFilePointerEx((HANDLE)(address)h, li, 0, (DWORD)r)";
|
||||
|
||||
PROCEDURE -seekset(): INTEGER "FILE_BEGIN";
|
||||
PROCEDURE -seekcur(): INTEGER "FILE_CURRENT";
|
||||
PROCEDURE -seekend(): INTEGER "FILE_END";
|
||||
|
||||
PROCEDURE Seek*(h: FileHandle; o: LONGINT; r: INTEGER): ErrorCode;
|
||||
VAR rc: INTEGER;
|
||||
BEGIN
|
||||
largeInteger;
|
||||
setFilePointerEx(h, o, r, rc);
|
||||
IF rc = 0 THEN RETURN err() ELSE RETURN 0 END
|
||||
END Seek;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -setEndOfFile(h: FileHandle): INTEGER "(INTEGER)SetEndOfFile((HANDLE)(address)h)";
|
||||
PROCEDURE -getFilePos(h: FileHandle; VAR r: LONGINT; VAR rc: INTEGER)
|
||||
"LARGE_INTEGER liz = {0}; *rc = (INTEGER)SetFilePointerEx((HANDLE)(address)h, liz, &li, FILE_CURRENT); *r = (LONGINT)li.QuadPart";
|
||||
|
||||
PROCEDURE Truncate*(h: FileHandle; limit: LONGINT): ErrorCode;
|
||||
VAR rc: INTEGER; oldpos: LONGINT;
|
||||
BEGIN
|
||||
largeInteger;
|
||||
getFilePos(h, oldpos, rc);
|
||||
IF rc = 0 THEN RETURN err() END;
|
||||
setFilePointerEx(h, limit, seekset(), rc);
|
||||
IF rc = 0 THEN RETURN err() END;
|
||||
IF setEndOfFile(h) = 0 THEN RETURN err() END;
|
||||
setFilePointerEx(h, oldpos, seekset(), rc); (* Restore original file position *)
|
||||
IF rc = 0 THEN RETURN err() END;
|
||||
RETURN 0;
|
||||
END Truncate;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -deleteFile(n: ARRAY OF CHAR): INTEGER "(INTEGER)DeleteFile((char*)n)";
|
||||
|
||||
PROCEDURE Unlink*(VAR n: ARRAY OF CHAR): ErrorCode;
|
||||
BEGIN
|
||||
IF deleteFile(n) = 0 THEN RETURN err() ELSE RETURN 0 END
|
||||
END Unlink;
|
||||
|
||||
|
||||
PROCEDURE -setCurrentDirectory(n: ARRAY OF CHAR): INTEGER "(INTEGER)SetCurrentDirectory((char*)n)";
|
||||
PROCEDURE -getCurrentDirectory(VAR n: ARRAY OF CHAR) "GetCurrentDirectory(n__len, (char*)n)";
|
||||
|
||||
PROCEDURE Chdir*(VAR n: ARRAY OF CHAR): ErrorCode;
|
||||
VAR r: INTEGER;
|
||||
BEGIN
|
||||
r := setCurrentDirectory(n);
|
||||
IF r = 0 THEN RETURN err() END;
|
||||
getCurrentDirectory(CWD);
|
||||
RETURN 0;
|
||||
END Chdir;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -moveFile(o,n: ARRAY OF CHAR): INTEGER
|
||||
"(INTEGER)MoveFileEx((char*)o, (char*)n, MOVEFILE_REPLACE_EXISTING)";
|
||||
|
||||
PROCEDURE Rename*(VAR o,n: ARRAY OF CHAR): ErrorCode;
|
||||
BEGIN
|
||||
IF moveFile(o,n) = 0 THEN RETURN err() ELSE RETURN 0 END
|
||||
END Rename;
|
||||
|
||||
|
||||
|
||||
|
||||
(* Process termination *)
|
||||
|
||||
PROCEDURE -exit(code: INTEGER) "ExitProcess((UINT)code)";
|
||||
PROCEDURE Exit*(code: INTEGER);
|
||||
BEGIN exit(code) END Exit;
|
||||
|
||||
|
||||
PROCEDURE -errstring(s: ARRAY OF CHAR) 'WriteFile((HANDLE)(address)Platform_StdOut, s, s__len-1, 0,0)';
|
||||
PROCEDURE -errc (c: CHAR) 'WriteFile((HANDLE)(address)Platform_StdOut, &c, 1, 0,0)';
|
||||
PROCEDURE errch(c: CHAR); BEGIN errc(c) END errch;
|
||||
PROCEDURE errln; BEGIN errch(0DX); errch(0AX) END errln;
|
||||
|
||||
PROCEDURE errposint(l: LONGINT);
|
||||
BEGIN IF l>10 THEN errposint(l DIV 10) END; errch(CHR(ORD('0') + (l MOD 10))) END errposint;
|
||||
|
||||
PROCEDURE errint(l: LONGINT);
|
||||
BEGIN IF l<0 THEN errch('-'); l := -l END; errposint(l) END errint;
|
||||
|
||||
PROCEDURE DisplayHaltCode(code: LONGINT);
|
||||
BEGIN
|
||||
CASE code OF
|
||||
| -1: errstring("Rider ReadBuf/WriteBuf transfer size longer than buffer.")
|
||||
| -2: errstring("Index out of range.")
|
||||
| -3: errstring("Reached end of function without reaching RETURN.")
|
||||
| -4: errstring("CASE statement: no matching label and no ELSE.")
|
||||
| -5: errstring("Type guard failed.")
|
||||
| -6: errstring("Type equality failed.")
|
||||
| -7: errstring("WITH statement type guard failed.")
|
||||
| -8: errstring("SHORT: Value too large for shorter type.")
|
||||
| -9: errstring("Heap interrupted while locked, but lockdepth = 0 at unlock.")
|
||||
|-10: errstring("NIL access.");
|
||||
|-11: errstring("Alignment error.");
|
||||
|-12: errstring("Divide by zero.");
|
||||
|-13: errstring("Arithmetic overflow/underflow.");
|
||||
|-14: errstring("Invalid function argument.");
|
||||
|-15: errstring("Internal error, e.g. Type descriptor size mismatch.")
|
||||
|-20: errstring("Too many, or negative number of, elements in dynamic array.")
|
||||
ELSE
|
||||
END
|
||||
END DisplayHaltCode;
|
||||
|
||||
PROCEDURE Halt*(code: LONGINT);
|
||||
BEGIN
|
||||
HaltCode := code;
|
||||
IF HaltHandler # NIL THEN HaltHandler(code) END;
|
||||
errstring("Terminated by Halt("); errint(code); errstring("). ");
|
||||
IF code < 0 THEN DisplayHaltCode(code) END;
|
||||
errln;
|
||||
exit(SYSTEM.VAL(INTEGER,code));
|
||||
END Halt;
|
||||
|
||||
PROCEDURE AssertFail*(code: LONGINT);
|
||||
BEGIN
|
||||
errstring("Assertion failure.");
|
||||
IF code # 0 THEN errstring(" ASSERT code "); errint(code); errstring("."); END;
|
||||
errln;
|
||||
exit(SYSTEM.VAL(INTEGER,code));
|
||||
END AssertFail;
|
||||
|
||||
PROCEDURE SetHalt*(p: HaltProcedure);
|
||||
BEGIN HaltHandler := p; END SetHalt;
|
||||
|
||||
|
||||
|
||||
|
||||
PROCEDURE TestLittleEndian;
|
||||
VAR i: INTEGER;
|
||||
BEGIN i := 1; SYSTEM.GET(SYSTEM.ADR(i), LittleEndian); END TestLittleEndian;
|
||||
|
||||
|
||||
PROCEDURE -getstdinhandle(): FileHandle "(address)GetStdHandle(STD_INPUT_HANDLE)";
|
||||
PROCEDURE -getstdouthandle(): FileHandle "(address)GetStdHandle(STD_OUTPUT_HANDLE)";
|
||||
PROCEDURE -getstderrhandle(): FileHandle "(address)GetStdHandle(STD_ERROR_HANDLE)";
|
||||
PROCEDURE -getpid(): INTEGER "(INTEGER)GetCurrentProcessId()";
|
||||
|
||||
BEGIN
|
||||
TestLittleEndian;
|
||||
|
||||
HaltCode := -128;
|
||||
HaltHandler := NIL;
|
||||
TimeStart := 0; TimeStart := Time();
|
||||
CWD := ""; getCurrentDirectory(CWD);
|
||||
PID := getpid();
|
||||
|
||||
SeekSet := seekset();
|
||||
SeekCur := seekcur();
|
||||
SeekEnd := seekend();
|
||||
|
||||
StdIn := getstdinhandle();
|
||||
StdOut := getstdouthandle();
|
||||
StdErr := getstderrhandle();
|
||||
|
||||
nl[0] := 0DX; (* CR *)
|
||||
nl[1] := 0AX; (* LF *)
|
||||
nl[2] := 0X;
|
||||
END Platform.
|
||||
136
src/runtime/Reals.Mod
Normal file
136
src/runtime/Reals.Mod
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
MODULE Reals;
|
||||
(* JT, 5.2.90 / RC 9.12.91 conversion between reals and strings for HP-700, MB 9.12.91, JT for Ofront, 16.3. 95*)
|
||||
(* DCWB 20160817 Made independent of INTEGER size *)
|
||||
|
||||
IMPORT SYSTEM;
|
||||
|
||||
PROCEDURE Ten*(e: INTEGER): REAL;
|
||||
VAR r, power: LONGREAL;
|
||||
BEGIN r := 1.0;
|
||||
power := 10.0;
|
||||
WHILE e > 0 DO
|
||||
IF ODD(e) THEN r := r * power END ;
|
||||
power := power * power; e := e DIV 2
|
||||
END ;
|
||||
RETURN SHORT(r)
|
||||
END Ten;
|
||||
|
||||
|
||||
PROCEDURE TenL*(e: INTEGER): LONGREAL;
|
||||
VAR r, power: LONGREAL;
|
||||
BEGIN r := 1.0;
|
||||
power := 10.0;
|
||||
LOOP
|
||||
IF ODD(e) THEN r := r * power END ;
|
||||
e := e DIV 2;
|
||||
IF e <= 0 THEN RETURN r END ;
|
||||
power := power * power
|
||||
END
|
||||
END TenL;
|
||||
|
||||
|
||||
(* Real number format (IEEE 754)
|
||||
|
||||
TYPE REAL - Single precision / binary32:
|
||||
1/sign, 8/exponent, 23/significand
|
||||
|
||||
TYPE LONGREAL - Double precision / binary64:
|
||||
1/sign, 11/exponent, 52/significand
|
||||
|
||||
exponent:
|
||||
stored as exponent value + 127.
|
||||
|
||||
significand (fraction):
|
||||
excludes leading (most significant) bit which is assumed to be 1.
|
||||
*)
|
||||
|
||||
|
||||
PROCEDURE Expo*(x: REAL): INTEGER;
|
||||
VAR i: INTEGER;
|
||||
BEGIN
|
||||
SYSTEM.GET(SYSTEM.ADR(x)+2, i);
|
||||
RETURN (i DIV 128) MOD 256
|
||||
END Expo;
|
||||
|
||||
PROCEDURE SetExpo*(VAR x: REAL; ex: INTEGER);
|
||||
VAR c: CHAR;
|
||||
BEGIN
|
||||
(* Replace exponent bits within top byte of REAL *)
|
||||
SYSTEM.GET(SYSTEM.ADR(x)+3, c);
|
||||
SYSTEM.PUT(SYSTEM.ADR(x)+3, CHR(((ORD(c) DIV 128) * 128) + ((ex DIV 2) MOD 128)));
|
||||
(* Replace exponent bits within 2nd byte of REAL *)
|
||||
SYSTEM.GET(SYSTEM.ADR(x)+2, c);
|
||||
SYSTEM.PUT(SYSTEM.ADR(x)+2, CHR((ORD(c) MOD 128) + ((ex MOD 2) * 128)))
|
||||
END SetExpo;
|
||||
|
||||
PROCEDURE ExpoL*(x: LONGREAL): INTEGER;
|
||||
VAR i: INTEGER;
|
||||
BEGIN
|
||||
SYSTEM.GET(SYSTEM.ADR(x)+6, i);
|
||||
RETURN (i DIV 16) MOD 2048
|
||||
END ExpoL;
|
||||
|
||||
(* Convert LONGREAL: Write positive integer value of x into array d.
|
||||
The value is stored backwards, i.e. least significant digit
|
||||
first. n digits are written, with trailing zeros fill.
|
||||
On entry x has been scaled to the number of digits required. *)
|
||||
PROCEDURE ConvertL*(x: LONGREAL; n: INTEGER; VAR d: ARRAY OF CHAR);
|
||||
VAR i, j, k: LONGINT;
|
||||
BEGIN
|
||||
IF x < 0 THEN x := -x END;
|
||||
k := 0;
|
||||
|
||||
IF (SIZE(LONGINT) < 8) & (n > 9) THEN
|
||||
(* There are more decimal digits than can be held in a single LONGINT *)
|
||||
i := ENTIER(x / 1000000000.0D0); (* The 10th and higher digits *)
|
||||
j := ENTIER(x - (i * 1000000000.0D0)); (* The low 9 digits *)
|
||||
(* First generate the low 9 digits. *)
|
||||
IF j < 0 THEN j := 0 END;
|
||||
WHILE k < 9 DO
|
||||
d[k] := CHR(j MOD 10 + 48); j := j DIV 10; INC(k)
|
||||
END;
|
||||
(* Fall through to generate the upper digits *)
|
||||
ELSE
|
||||
(* We can generate all the digits in one go. *)
|
||||
i := ENTIER(x);
|
||||
END;
|
||||
|
||||
WHILE k < n DO
|
||||
d[k] := CHR(i MOD 10 + 48); i := i DIV 10; INC(k)
|
||||
END
|
||||
END ConvertL;
|
||||
|
||||
|
||||
PROCEDURE Convert*(x: REAL; n: INTEGER; VAR d: ARRAY OF CHAR);
|
||||
BEGIN ConvertL(x, n, d)
|
||||
END Convert;
|
||||
|
||||
PROCEDURE ToHex(i: INTEGER): CHAR;
|
||||
BEGIN
|
||||
IF i < 10 THEN RETURN CHR(i+48)
|
||||
ELSE RETURN CHR(i+55) END
|
||||
END ToHex;
|
||||
|
||||
PROCEDURE BytesToHex(VAR b, d: ARRAY OF SYSTEM.BYTE);
|
||||
VAR i: INTEGER; l: LONGINT; by: CHAR;
|
||||
BEGIN
|
||||
i := 0; l := LEN(b);
|
||||
WHILE i < l DO
|
||||
by := SYSTEM.VAL(CHAR, b[i]);
|
||||
d[i*2] := ToHex(ORD(by) DIV 16);
|
||||
d[i*2+1] := ToHex(ORD(by) MOD 16);
|
||||
INC(i)
|
||||
END
|
||||
END BytesToHex;
|
||||
|
||||
(* Convert Hex *)
|
||||
PROCEDURE ConvertH*(y: REAL; VAR d: ARRAY OF CHAR);
|
||||
BEGIN BytesToHex(y, d)
|
||||
END ConvertH;
|
||||
|
||||
(* Convert Hex Long *)
|
||||
PROCEDURE ConvertHL*(x: LONGREAL; VAR d: ARRAY OF CHAR);
|
||||
BEGIN BytesToHex(x, d)
|
||||
END ConvertHL;
|
||||
|
||||
END Reals.
|
||||
156
src/runtime/Strings.Mod
Normal file
156
src/runtime/Strings.Mod
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
(*-------------------------------------------------------------
|
||||
Strings provides a set of operations on strings (i.e., on string constants and character
|
||||
arrays, both of which contain the character 0X as a terminator). All positions in
|
||||
strings start at 0.
|
||||
Strings.Length(s)
|
||||
returns the number of characters in s up to and excluding the first 0X.
|
||||
Strings.Insert(src, pos, dst)
|
||||
inserts the string src into the string dst at position pos (0 <= pos <= Length(dst)).
|
||||
If pos = Length(dst), src is appended to dst. If the size of dst is not large enough
|
||||
to hold the result of the operation, the result is truncated so that dst is always
|
||||
terminated with a 0X.
|
||||
Strings.Append(s, dst)
|
||||
has the same effect as Insert(s, Length(s), dst).
|
||||
Strings.Delete(s, pos, n)
|
||||
deletes n characters from s starting at position pos (0 <= pos < Length(s)).
|
||||
If n > Length(s) - pos, the new length of s is pos.
|
||||
Strings.Replace(src, pos, dst)
|
||||
has the same effect as Delete(dst, pos, Length(src)) followed by an Insert(src, pos, dst).
|
||||
Strings.Extract(src, pos, n, dst)
|
||||
extracts a substring dst with n characters from position pos (0 <= pos < Length(src)) in src.
|
||||
If n > Length(src) - pos, dst is only the part of src from pos to Length(src) - 1. If the size of
|
||||
dst is not large enough to hold the result of the operation, the result is truncated so that
|
||||
dst is always terminated with a 0X.
|
||||
Strings.Pos(pat, s, pos)
|
||||
returns the position of the first occurrence of pat in s after position pos (inclusive).
|
||||
If pat is not found, -1 is returned.
|
||||
Strings.Cap(s)
|
||||
replaces each lower case letter in s by its upper case equivalent.
|
||||
-------------------------------------------------------------*)
|
||||
(* added from trianus v4 *)
|
||||
MODULE Strings; (*HM 94-06-22 / *)
|
||||
|
||||
|
||||
PROCEDURE Length* (s: ARRAY OF CHAR): INTEGER;
|
||||
VAR i: INTEGER;
|
||||
BEGIN
|
||||
i := 0; WHILE (i < LEN(s)) & (s[i] # 0X) DO INC(i) END ;
|
||||
RETURN i
|
||||
END Length;
|
||||
|
||||
|
||||
PROCEDURE Append* (extra: ARRAY OF CHAR; VAR dest: ARRAY OF CHAR);
|
||||
VAR n1, n2, i: INTEGER;
|
||||
BEGIN
|
||||
n1 := Length(dest); n2 := Length(extra); i := 0;
|
||||
WHILE (i < n2) & (i + n1 < LEN(dest)) DO dest[i + n1] := extra[i]; INC(i) END ;
|
||||
IF i + n1 < LEN(dest) THEN dest[i + n1] := 0X END
|
||||
END Append;
|
||||
|
||||
|
||||
PROCEDURE Insert* (source: ARRAY OF CHAR; pos: INTEGER; VAR dest: ARRAY OF CHAR);
|
||||
VAR n1, n2, i: INTEGER;
|
||||
BEGIN
|
||||
n1 := Length(dest); n2 := Length(source);
|
||||
IF pos < 0 THEN pos := 0 END ;
|
||||
IF pos > n1 THEN Append(dest, source); RETURN END ;
|
||||
IF pos + n2 < LEN(dest) THEN (*make room for source*)
|
||||
i := n1; (*move also 0X if it is there*)
|
||||
WHILE i >= pos DO
|
||||
IF i + n2 < LEN(dest) THEN dest[i + n2] := dest[i] END ;
|
||||
DEC(i)
|
||||
END
|
||||
END ;
|
||||
i := 0; WHILE i < n2 DO dest[pos + i] := source[i]; INC(i) END
|
||||
END Insert;
|
||||
|
||||
|
||||
PROCEDURE Delete* (VAR s: ARRAY OF CHAR; pos, n: INTEGER);
|
||||
VAR len, i: INTEGER;
|
||||
BEGIN
|
||||
len:=Length(s);
|
||||
IF pos < 0 THEN pos:=0 ELSIF pos >= len THEN RETURN END ;
|
||||
IF pos + n < len THEN
|
||||
i:=pos + n; WHILE i < len DO s[i - n]:=s[i]; INC(i) END ;
|
||||
IF i - n < LEN(s) THEN s[i - n]:=0X END
|
||||
ELSE s[pos]:=0X
|
||||
END
|
||||
END Delete;
|
||||
|
||||
|
||||
PROCEDURE Replace* (source: ARRAY OF CHAR; pos: INTEGER; VAR dest: ARRAY OF CHAR);
|
||||
BEGIN
|
||||
Delete(dest, pos, pos + Length(source));
|
||||
Insert(source, pos, dest)
|
||||
END Replace;
|
||||
|
||||
|
||||
PROCEDURE Extract* (source: ARRAY OF CHAR; pos, n: INTEGER; VAR dest: ARRAY OF CHAR);
|
||||
VAR len, destLen, i: INTEGER;
|
||||
BEGIN
|
||||
len := Length(source); destLen := SHORT(LEN(dest)) - 1;
|
||||
IF pos < 0 THEN pos := 0 END ;
|
||||
IF pos >= len THEN dest[0] := 0X; RETURN END ;
|
||||
i := 0;
|
||||
WHILE (pos + i <= LEN(source)) & (source[pos + i] # 0X) & (i < n) DO
|
||||
IF i < destLen THEN dest[i] := source[pos + i] END ;
|
||||
INC(i)
|
||||
END ;
|
||||
dest[i] := 0X
|
||||
END Extract;
|
||||
|
||||
|
||||
PROCEDURE Pos* (pattern, s: ARRAY OF CHAR; pos: INTEGER): INTEGER;
|
||||
VAR n1, n2, i, j: INTEGER;
|
||||
BEGIN
|
||||
n1 := Length(s); n2 := Length(pattern);
|
||||
IF n2 = 0 THEN RETURN 0 END ;
|
||||
i := pos;
|
||||
WHILE i <= n1 - n2 DO
|
||||
IF s[i] = pattern[0] THEN
|
||||
j := 1; WHILE (j < n2) & (s[i + j] = pattern[j]) DO INC(j) END ;
|
||||
IF j = n2 THEN RETURN i END
|
||||
END ;
|
||||
INC(i)
|
||||
END ;
|
||||
RETURN -1
|
||||
END Pos;
|
||||
|
||||
|
||||
PROCEDURE Cap* (VAR s: ARRAY OF CHAR);
|
||||
VAR i: INTEGER;
|
||||
BEGIN
|
||||
i := 0;
|
||||
WHILE s[i] # 0X DO
|
||||
IF ("a" <= s[i]) & (s[i] <= "z") THEN s[i] := CAP(s[i]) END ;
|
||||
INC(i)
|
||||
END
|
||||
END Cap;
|
||||
|
||||
|
||||
PROCEDURE Match* (string, pattern: ARRAY OF CHAR): BOOLEAN;
|
||||
|
||||
PROCEDURE M (VAR name, mask: ARRAY OF CHAR; n, m: INTEGER): BOOLEAN;
|
||||
BEGIN
|
||||
WHILE (n >= 0) & (m >= 0) & (mask[m] # "*") DO
|
||||
IF name[n] # mask[m] THEN RETURN FALSE END ;
|
||||
DEC(n); DEC(m)
|
||||
END ;
|
||||
(* ----- name empty | mask empty | mask ends with "*" *)
|
||||
IF m < 0 THEN RETURN n < 0 END ;
|
||||
(* ----- name empty | mask ends with "*" *)
|
||||
WHILE (m >= 0) & (mask[m] = "*") DO DEC(m) END ;
|
||||
IF m < 0 THEN RETURN TRUE END ;
|
||||
(* ----- name empty | mask still to be matched *)
|
||||
WHILE n >= 0 DO
|
||||
IF M(name, mask, n, m) THEN RETURN TRUE END ;
|
||||
DEC(n)
|
||||
END ;
|
||||
RETURN FALSE
|
||||
END M;
|
||||
|
||||
BEGIN
|
||||
RETURN M(string, pattern, Length(string)-1, Length(pattern)-1)
|
||||
END Match;
|
||||
|
||||
END Strings.
|
||||
881
src/runtime/Texts.Mod
Normal file
881
src/runtime/Texts.Mod
Normal file
|
|
@ -0,0 +1,881 @@
|
|||
MODULE Texts; (** CAS/HM 23.9.93 -- interface based on Texts by JG/NW 6.12.91**) (* << RC, MB, JT *)
|
||||
IMPORT
|
||||
Files, Modules, Reals, SYSTEM;
|
||||
|
||||
(*--- insert field e: Elem into Texts.Scanner and change Texts.Scan to set it in case of class=6 *)
|
||||
|
||||
|
||||
CONST
|
||||
Displaywhite = 15;
|
||||
ElemChar* = 1CX;
|
||||
TAB = 9X; CR = 0DX; maxD = 9;
|
||||
(**FileMsg.id**)
|
||||
load* = 0; store* = 1;
|
||||
(**Notifier op**)
|
||||
replace* = 0; insert* = 1; delete* = 2; unmark* = 3;
|
||||
(**Scanner.class**)
|
||||
Inval* = 0; Name* = 1; String* = 2; Int* = 3; Real* = 4; LongReal* = 5; Char* = 6;
|
||||
|
||||
textTag = 0F0X; DocBlockId = 0F7X; version = 01X;
|
||||
|
||||
TYPE
|
||||
FontsFont = POINTER TO FontDesc;
|
||||
FontDesc = RECORD
|
||||
name: ARRAY 32 OF CHAR;
|
||||
END ;
|
||||
|
||||
Run = POINTER TO RunDesc;
|
||||
RunDesc = RECORD
|
||||
prev, next: Run;
|
||||
len: LONGINT;
|
||||
fnt: FontsFont;
|
||||
col, voff: SYSTEM.INT8;
|
||||
ascii: BOOLEAN (* << *)
|
||||
END;
|
||||
|
||||
Piece = POINTER TO PieceDesc;
|
||||
PieceDesc = RECORD (RunDesc)
|
||||
file: Files.File;
|
||||
org: LONGINT
|
||||
END;
|
||||
|
||||
Elem* = POINTER TO ElemDesc;
|
||||
Buffer* = POINTER TO BufDesc;
|
||||
Text* = POINTER TO TextDesc;
|
||||
|
||||
ElemMsg* = RECORD END;
|
||||
Handler* = PROCEDURE (e: Elem; VAR msg: ElemMsg);
|
||||
|
||||
ElemDesc* = RECORD (RunDesc)
|
||||
W*, H*: LONGINT;
|
||||
handle*: Handler;
|
||||
base: Text
|
||||
END;
|
||||
|
||||
FileMsg* = RECORD (ElemMsg)
|
||||
id*: INTEGER;
|
||||
pos*: LONGINT;
|
||||
r*: Files.Rider
|
||||
END;
|
||||
|
||||
CopyMsg* = RECORD (ElemMsg)
|
||||
e*: Elem
|
||||
END;
|
||||
|
||||
IdentifyMsg* = RECORD (ElemMsg)
|
||||
mod*, proc*: ARRAY 32 OF CHAR
|
||||
END;
|
||||
|
||||
|
||||
BufDesc* = RECORD
|
||||
len*: LONGINT;
|
||||
head: Run
|
||||
END;
|
||||
|
||||
Notifier* = PROCEDURE (T: Text; op: INTEGER; beg, end: LONGINT);
|
||||
TextDesc* = RECORD
|
||||
len*: LONGINT;
|
||||
notify*: Notifier;
|
||||
head, cache: Run;
|
||||
corg: LONGINT
|
||||
END;
|
||||
|
||||
Reader* = RECORD
|
||||
eot*: BOOLEAN;
|
||||
fnt*: FontsFont;
|
||||
col*, voff*: SYSTEM.INT8;
|
||||
elem*: Elem;
|
||||
rider: Files.Rider;
|
||||
run: Run;
|
||||
org, off: LONGINT
|
||||
END;
|
||||
|
||||
Scanner* = RECORD (Reader)
|
||||
nextCh*: CHAR;
|
||||
line*, class*: INTEGER;
|
||||
i*: LONGINT;
|
||||
x*: REAL;
|
||||
y*: LONGREAL;
|
||||
c*: CHAR;
|
||||
len*: SHORTINT;
|
||||
s*: ARRAY 64 OF CHAR (* << *)
|
||||
END;
|
||||
|
||||
Writer* = RECORD
|
||||
buf*: Buffer;
|
||||
fnt*: FontsFont;
|
||||
col*, voff*: SYSTEM.INT8;
|
||||
rider: Files.Rider;
|
||||
file: Files.File
|
||||
END;
|
||||
|
||||
Alien = POINTER TO RECORD (ElemDesc)
|
||||
file: Files.File;
|
||||
org, span: LONGINT;
|
||||
mod, proc: ARRAY 32 OF CHAR
|
||||
END;
|
||||
|
||||
VAR
|
||||
new*: Elem;
|
||||
del: Buffer;
|
||||
FontsDefault: FontsFont;
|
||||
|
||||
|
||||
PROCEDURE FontsThis(VAR name: ARRAY OF CHAR): FontsFont;
|
||||
VAR F: FontsFont;
|
||||
BEGIN
|
||||
NEW(F); COPY(name, F.name); RETURN F
|
||||
END FontsThis;
|
||||
|
||||
(* run primitives *)
|
||||
|
||||
PROCEDURE Find (T: Text; VAR pos: LONGINT; VAR u: Run; VAR org, off: LONGINT);
|
||||
VAR v: Run; m: LONGINT;
|
||||
BEGIN
|
||||
IF pos >= T.len THEN pos := T.len; u := T.head; org := T.len; off := 0; T.cache := T.head; T.corg := 0
|
||||
ELSE v := T.cache.next; m := pos - T.corg;
|
||||
IF pos >= T.corg THEN
|
||||
WHILE m >= v.len DO DEC(m, v.len); v := v.next END
|
||||
ELSE
|
||||
WHILE m < 0 DO v := v.prev; INC(m, v.len) END;
|
||||
END;
|
||||
u := v; org := pos - m; off := m; T.cache := v.prev; T.corg := org
|
||||
END
|
||||
END Find;
|
||||
|
||||
PROCEDURE Split (off: LONGINT; VAR u, un: Run);
|
||||
VAR p, U: Piece;
|
||||
BEGIN
|
||||
IF off = 0 THEN un := u; u := un.prev
|
||||
ELSIF off >= u.len THEN un := u.next
|
||||
ELSE NEW(p); un := p; U := u(Piece);
|
||||
p^ := U^; INC(p.org, off); DEC(p.len, off); DEC(U.len, p.len);
|
||||
p.ascii := u.ascii; p.prev := U; p.next := U.next; p.next.prev := p; U.next := p (* << *)
|
||||
END
|
||||
END Split;
|
||||
|
||||
PROCEDURE Merge (T: Text; u: Run; VAR v: Run);
|
||||
VAR p, q: Piece;
|
||||
BEGIN
|
||||
IF (u IS Piece) & (v IS Piece) & (u.fnt.name = v.fnt.name) & (u.col = v.col) & (u.voff = v.voff)
|
||||
& (u(Piece).ascii = v(Piece).ascii) THEN (* << *)
|
||||
p := u(Piece); q := v(Piece);
|
||||
IF (p.file = q.file) & (p.org + p.len = q.org) THEN
|
||||
IF T.cache = u THEN INC(T.corg, q.len)
|
||||
ELSIF T.cache = v THEN T.cache := T.head; T.corg := 0
|
||||
END;
|
||||
INC(p.len, q.len); v := v.next
|
||||
END
|
||||
END
|
||||
END Merge;
|
||||
|
||||
PROCEDURE Splice (un, v, w: Run; base: Text); (* (u, un) -> (u, v, w, un) *)
|
||||
VAR u: Run;
|
||||
BEGIN
|
||||
IF v # w.next THEN u := un.prev;
|
||||
u.next := v; v.prev := u; un.prev := w; w.next := un;
|
||||
REPEAT
|
||||
IF v IS Elem THEN v(Elem).base := base END;
|
||||
v := v.next
|
||||
UNTIL v = un
|
||||
END
|
||||
END Splice;
|
||||
|
||||
PROCEDURE ClonePiece (p: Piece): Piece;
|
||||
VAR q: Piece;
|
||||
BEGIN NEW(q); q^ := p^; RETURN q
|
||||
END ClonePiece;
|
||||
|
||||
PROCEDURE CloneElem (e: Elem): Elem;
|
||||
VAR msg: CopyMsg;
|
||||
BEGIN msg.e := NIL; e.handle(e, msg); RETURN msg.e
|
||||
END CloneElem;
|
||||
|
||||
|
||||
(** Elements **)
|
||||
|
||||
PROCEDURE CopyElem* (SE, DE: Elem);
|
||||
BEGIN DE.len := SE.len; DE.fnt := SE.fnt; DE.col := SE.col; DE.voff := SE.voff;
|
||||
DE.W := SE.W; DE.H := SE.H; DE.handle := SE.handle
|
||||
END CopyElem;
|
||||
|
||||
PROCEDURE ElemBase* (E: Elem): Text;
|
||||
BEGIN RETURN E.base
|
||||
END ElemBase;
|
||||
|
||||
PROCEDURE ElemPos* (E: Elem): LONGINT;
|
||||
VAR u: Run; pos: LONGINT;
|
||||
BEGIN u := E.base.head.next; pos := 0;
|
||||
WHILE u # E DO pos := pos + u.len; u := u.next END;
|
||||
RETURN pos
|
||||
END ElemPos;
|
||||
|
||||
|
||||
PROCEDURE HandleAlien (E: Elem; VAR msg: ElemMsg);
|
||||
VAR e: Alien; r: Files.Rider; i: LONGINT; ch: CHAR;
|
||||
BEGIN
|
||||
WITH E: Alien DO
|
||||
IF msg IS CopyMsg THEN
|
||||
WITH msg: CopyMsg DO NEW(e); CopyElem(E, e);
|
||||
e.file := E.file; e.org := E.org; e.span := E.span; e.mod := E.mod; e.proc := E.proc;
|
||||
msg.e := e
|
||||
END
|
||||
ELSIF msg IS IdentifyMsg THEN
|
||||
WITH msg: IdentifyMsg DO
|
||||
COPY(E.mod, msg.mod); COPY(E.proc, msg.proc); msg.mod[31] := 1X (*alien*)
|
||||
END
|
||||
ELSIF msg IS FileMsg THEN
|
||||
WITH msg: FileMsg DO
|
||||
IF msg.id = store THEN Files.Set(r, E.file, E.org); i := E.span;
|
||||
WHILE i > 0 DO Files.Read(r, ch); Files.Write(msg.r, ch); DEC(i) END
|
||||
END
|
||||
END
|
||||
END
|
||||
END
|
||||
END HandleAlien;
|
||||
|
||||
|
||||
(** Buffers **)
|
||||
|
||||
PROCEDURE OpenBuf* (B: Buffer);
|
||||
VAR u: Run;
|
||||
BEGIN NEW(u); u.next := u; u.prev := u; B.head := u; B.len := 0
|
||||
END OpenBuf;
|
||||
|
||||
PROCEDURE Copy* (SB, DB: Buffer);
|
||||
VAR u, v, vn: Run;
|
||||
BEGIN u := SB.head.next; v := DB.head.prev;
|
||||
WHILE u # SB.head DO
|
||||
IF u IS Piece THEN vn := ClonePiece(u(Piece)) ELSE vn := CloneElem(u(Elem)) END;
|
||||
v.next := vn; vn.prev := v; v := vn; u := u.next
|
||||
END;
|
||||
v.next := DB.head; DB.head.prev := v;
|
||||
INC(DB.len, SB.len)
|
||||
END Copy;
|
||||
|
||||
PROCEDURE Recall* (VAR B: Buffer);
|
||||
BEGIN B := del; del := NIL
|
||||
END Recall;
|
||||
|
||||
|
||||
(** Texts **)
|
||||
|
||||
PROCEDURE Save* (T: Text; beg, end: LONGINT; B: Buffer);
|
||||
VAR u, v, w, wn: Run; uo, ud, vo, vd: LONGINT;
|
||||
BEGIN Find(T, beg, u, uo, ud); Find(T, end, v, vo, vd);
|
||||
w := B.head.prev;
|
||||
WHILE u # v DO
|
||||
IF u IS Piece THEN wn := ClonePiece(u(Piece)); DEC(wn.len, ud); INC(wn(Piece).org, ud)
|
||||
ELSE wn := CloneElem(u(Elem))
|
||||
END;
|
||||
w.next := wn; wn.prev := w; w := wn; u := u.next; ud := 0
|
||||
END;
|
||||
IF vd > 0 THEN (*v IS Piece*) wn := ClonePiece(v(Piece)); wn.len := vd - ud; INC(wn(Piece).org, ud);
|
||||
w.next := wn; wn.prev := w; w := wn
|
||||
END;
|
||||
w.next := B.head; B.head.prev := w;
|
||||
INC(B.len, end - beg)
|
||||
END Save;
|
||||
|
||||
PROCEDURE Insert* (T: Text; pos: LONGINT; B: Buffer);
|
||||
VAR u, un, v: Run; p, q: Piece; uo, ud, len: LONGINT;
|
||||
BEGIN Find(T, pos, u, uo, ud); Split(ud, u, un);
|
||||
len := B.len; v := B.head.next;
|
||||
Merge(T, u, v); Splice(un, v, B.head.prev, T);
|
||||
INC(T.len, len); B.head.next := B.head; B.head.prev := B.head; B.len := 0;
|
||||
IF T.notify # NIL THEN T.notify(T, insert, pos, pos+len) END
|
||||
END Insert;
|
||||
|
||||
PROCEDURE Append* (T: Text; B: Buffer);
|
||||
VAR v: Run; pos, len: LONGINT;
|
||||
BEGIN pos := T.len; len := B.len; v := B.head.next;
|
||||
Merge(T, T.head.prev, v); Splice(T.head, v, B.head.prev, T);
|
||||
INC(T.len, len); B.head.next := B.head; B.head.prev := B.head; B.len := 0;
|
||||
IF T.notify # NIL THEN T.notify(T, insert, pos, pos+len) END
|
||||
END Append;
|
||||
|
||||
PROCEDURE Delete* (T: Text; beg, end: LONGINT);
|
||||
VAR c, u, un, v, vn: Run; co, uo, ud, vo, vd: LONGINT;
|
||||
BEGIN
|
||||
Find(T, beg, u, uo, ud); Split(ud, u, un); c := T.cache; co := T.corg;
|
||||
Find(T, end, v, vo, vd); Split(vd, v, vn); T.cache := c; T.corg := co;
|
||||
NEW(del); OpenBuf(del); del.len := end - beg;
|
||||
Splice(del.head, un, v, NIL);
|
||||
Merge(T, u, vn); u.next := vn; vn.prev := u;
|
||||
DEC(T.len, end - beg);
|
||||
IF T.notify # NIL THEN T.notify(T, delete, beg, end) END
|
||||
END Delete;
|
||||
|
||||
PROCEDURE ChangeLooks* (T: Text; beg, end: LONGINT; sel: SET; fnt: FontsFont; col, voff: SYSTEM.INT8);
|
||||
VAR c, u, un, v, vn: Run; co, uo, ud, vo, vd: LONGINT;
|
||||
BEGIN Find(T, beg, u, uo, ud); Split(ud, u, un); c := T.cache; co := T.corg;
|
||||
Find(T, end, v, vo, vd); Split(vd, v, vn); T.cache := c; T.corg := co;
|
||||
WHILE un # vn DO
|
||||
IF (0 IN sel) & (fnt # NIL) THEN un.fnt := fnt END;
|
||||
IF 1 IN sel THEN un.col := col END;
|
||||
IF 2 IN sel THEN un.voff := voff END;
|
||||
Merge(T, u, un);
|
||||
IF u.next = un THEN u := un; un := un.next ELSE u.next := un; un.prev := u END
|
||||
END;
|
||||
Merge(T, u, un); u.next := un; un.prev := u;
|
||||
IF T.notify # NIL THEN T.notify(T, replace, beg, end) END
|
||||
END ChangeLooks;
|
||||
|
||||
|
||||
(** Readers **)
|
||||
|
||||
PROCEDURE OpenReader* (VAR R: Reader; T: Text; pos: LONGINT);
|
||||
VAR u: Run;
|
||||
BEGIN
|
||||
IF pos >= T.len THEN pos := T.len END;
|
||||
Find(T, pos, u, R.org, R.off); R.run := u; R.eot := FALSE;
|
||||
IF u IS Piece THEN
|
||||
Files.Set(R.rider, u(Piece).file, u(Piece).org + R.off)
|
||||
END
|
||||
END OpenReader;
|
||||
|
||||
PROCEDURE Read* (VAR R: Reader; VAR ch: CHAR);
|
||||
VAR u: Run; pos: LONGINT; nextch: CHAR;
|
||||
BEGIN u := R.run; R.fnt := u.fnt; R.col := u.col; R.voff := u.voff; INC(R.off);
|
||||
IF u IS Piece THEN Files.Read(R.rider, ch); R.elem := NIL;
|
||||
IF (ch = 0AX) & u(Piece).ascii THEN ch := CR (* << LF to CR *)
|
||||
ELSIF (ch = CR) & u(Piece).ascii THEN (* << CR LF to CR *)
|
||||
pos := Files.Pos(R.rider); Files.Read(R.rider, nextch);
|
||||
IF nextch = 0AX THEN INC(R.off) ELSE Files.Set(R.rider, u(Piece).file, pos) END
|
||||
END
|
||||
ELSIF u IS Elem THEN ch := ElemChar; R.elem := u(Elem)
|
||||
ELSE ch := 0X; R.elem := NIL; R.eot := TRUE
|
||||
END;
|
||||
IF R.off = u.len THEN INC(R.org, u.len); u := u.next;
|
||||
IF u IS Piece THEN
|
||||
WITH u: Piece DO Files.Set(R.rider, u.file, u.org) END
|
||||
END;
|
||||
R.run := u; R.off := 0
|
||||
END
|
||||
END Read;
|
||||
|
||||
PROCEDURE ReadElem* (VAR R: Reader);
|
||||
VAR u, un: Run;
|
||||
BEGIN u := R.run;
|
||||
WHILE u IS Piece DO INC(R.org, u.len); u := u.next END;
|
||||
IF u IS Elem THEN un := u.next; R.run := un; INC(R.org); R.off := 0;
|
||||
R.fnt := u.fnt; R.col := u.col; R.voff := u.voff; R.elem := u(Elem);
|
||||
IF un IS Piece THEN
|
||||
WITH un: Piece DO Files.Set(R.rider, un.file, un.org) END
|
||||
END
|
||||
ELSE R.eot := TRUE; R.elem := NIL
|
||||
END
|
||||
END ReadElem;
|
||||
|
||||
PROCEDURE ReadPrevElem* (VAR R: Reader);
|
||||
VAR u: Run;
|
||||
BEGIN u := R.run.prev;
|
||||
WHILE u IS Piece DO DEC(R.org, u.len); u := u.prev END;
|
||||
IF u IS Elem THEN R.run := u; DEC(R.org); R.off := 0;
|
||||
R.fnt := u.fnt; R.col := u.col; R.voff := u.voff; R.elem := u(Elem)
|
||||
ELSE R.eot := TRUE; R.elem := NIL
|
||||
END
|
||||
END ReadPrevElem;
|
||||
|
||||
PROCEDURE Pos* (VAR R: Reader): LONGINT;
|
||||
BEGIN RETURN R.org + R.off
|
||||
END Pos;
|
||||
|
||||
|
||||
(** Scanners --------------- NW --------------- **)
|
||||
|
||||
PROCEDURE OpenScanner* (VAR S: Scanner; T: Text; pos: LONGINT);
|
||||
BEGIN OpenReader(S, T, pos); S.line := 0; S.nextCh := " "
|
||||
END OpenScanner;
|
||||
|
||||
(*IEEE floating point formats:
|
||||
x = 2^(e-127) * 1.m bit 0: sign, bits 1- 8: e, bits 9-31: m
|
||||
x = 2^(e-1023) * 1.m bit 0: sign, bits 1-11: e, bits 12-63: m *)
|
||||
|
||||
PROCEDURE Scan* (VAR S: Scanner);
|
||||
CONST maxD = 32;
|
||||
VAR ch, term: CHAR;
|
||||
neg, negE, hex: BOOLEAN;
|
||||
i, j, h: SHORTINT;
|
||||
e: INTEGER; k: LONGINT;
|
||||
x, f: REAL; y, g: LONGREAL;
|
||||
d: ARRAY maxD OF CHAR;
|
||||
|
||||
PROCEDURE ReadScaleFactor;
|
||||
BEGIN 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
|
||||
e := e*10 + ORD(ch) - 30H; Read(S, ch)
|
||||
END
|
||||
END ReadScaleFactor;
|
||||
|
||||
BEGIN ch := S.nextCh; i := 0;
|
||||
LOOP
|
||||
IF ch = CR THEN INC(S.line)
|
||||
ELSIF (ch # " ") & (ch # TAB) THEN EXIT
|
||||
END ;
|
||||
Read(S, ch)
|
||||
END;
|
||||
IF ("A" <= CAP(ch)) & (CAP(ch) <= "Z") OR (ch = "/") OR (ch = ".") THEN (*name*) (* << *)
|
||||
REPEAT S.s[i] := ch; INC(i); Read(S, ch)
|
||||
UNTIL (CAP(ch) > "Z") & (ch # "_") (* << *)
|
||||
OR ("A" > CAP(ch)) & (ch > "9")
|
||||
OR ("0" > ch) & (ch # ".") & (ch # "/") (* << *)
|
||||
OR (i = 63); (* << *)
|
||||
S.s[i] := 0X; S.len := i; S.class := 1
|
||||
ELSIF ch = 22X THEN (*literal string*)
|
||||
Read(S, ch);
|
||||
WHILE (ch # 22X) & (ch >= " ") & (i # 63) DO (* << *)
|
||||
S.s[i] := ch; INC(i); Read(S, ch)
|
||||
END;
|
||||
S.s[i] := 0X; S.len := i+1; Read(S, ch); S.class := 2
|
||||
ELSE
|
||||
IF ch = "-" THEN neg := TRUE; Read(S, ch) ELSE neg := FALSE END ;
|
||||
IF ("0" <= ch) & (ch <= "9") THEN (*number*)
|
||||
hex := FALSE; j := 0;
|
||||
LOOP d[i] := ch; INC(i); Read(S, ch);
|
||||
IF ch < "0" THEN EXIT END;
|
||||
IF "9" < ch THEN
|
||||
IF ("A" <= ch) & (ch <= "F") THEN hex := TRUE; ch := CHR(ORD(ch)-7)
|
||||
ELSIF ("a" <= ch) & (ch <= "f") THEN hex := TRUE; ch := CHR(ORD(ch)-27H)
|
||||
ELSE EXIT
|
||||
END
|
||||
END
|
||||
END;
|
||||
IF ch = "H" THEN (*hex number*)
|
||||
Read(S, ch); S.class := 3;
|
||||
IF i-j > 8 THEN j := i-8 END ;
|
||||
k := ORD(d[j]) - 30H; INC(j);
|
||||
IF (i-j = 7) & (k >= 8) THEN DEC(k, 16) END ;
|
||||
WHILE j < i DO k := k*10H + (ORD(d[j]) - 30H); INC(j) END ;
|
||||
IF neg THEN S.i := -k ELSE S.i := k END
|
||||
ELSIF ch = "." THEN (*read real*)
|
||||
Read(S, ch); h := i;
|
||||
WHILE ("0" <= ch) & (ch <= "9") DO d[i] := ch; INC(i); Read(S, ch) END ;
|
||||
IF ch = "D" THEN
|
||||
e := 0; y := 0; g := 1;
|
||||
REPEAT y := y*10 + (ORD(d[j]) - 30H); INC(j) UNTIL j = h;
|
||||
WHILE j < i DO g := g/10; y := (ORD(d[j]) - 30H)*g + y; INC(j) END ;
|
||||
ReadScaleFactor;
|
||||
IF negE THEN
|
||||
IF e <= 308 THEN y := y / Reals.TenL(e) ELSE y := 0 END
|
||||
ELSIF e > 0 THEN
|
||||
IF e <= 308 THEN y := Reals.TenL(e) * y ELSE HALT(40) END
|
||||
END ;
|
||||
IF neg THEN y := -y END ;
|
||||
S.class := 5; S.y := y
|
||||
ELSE e := 0; x := 0; f := 1;
|
||||
REPEAT x := x*10 + (ORD(d[j]) - 30H); INC(j) UNTIL j = h;
|
||||
WHILE j < i DO f := f/10; x := (ORD(d[j])-30H)*f + x; INC(j) END;
|
||||
IF ch = "E" THEN ReadScaleFactor END ;
|
||||
IF negE THEN
|
||||
IF e <= 38 THEN x := x / Reals.Ten(e) ELSE x := 0 END
|
||||
ELSIF e > 0 THEN
|
||||
IF e <= 38 THEN x := Reals.Ten(e) * x ELSE HALT(40) END
|
||||
END ;
|
||||
IF neg THEN x := -x END ;
|
||||
S.class := 4; S.x := x
|
||||
END ;
|
||||
IF hex THEN S.class := 0 END
|
||||
ELSE (*decimal integer*)
|
||||
S.class := 3; k := 0;
|
||||
REPEAT k := k*10 + (ORD(d[j]) - 30H); INC(j) UNTIL j = i;
|
||||
IF neg THEN S.i := -k ELSE S.i := k END;
|
||||
IF hex THEN S.class := 0 ELSE S.class := 3 END
|
||||
END
|
||||
ELSE S.class := 6;
|
||||
IF neg THEN S.c := "-" ELSE S.c := ch; Read(S, ch) END
|
||||
END
|
||||
END;
|
||||
S.nextCh := ch
|
||||
END Scan;
|
||||
|
||||
|
||||
(** Writers **)
|
||||
|
||||
PROCEDURE OpenWriter* (VAR W: Writer);
|
||||
BEGIN NEW(W.buf); OpenBuf(W.buf);
|
||||
W.fnt := FontsDefault; W.col := Displaywhite; W.voff := 0;
|
||||
W.file := Files.New(""); Files.Set(W.rider, W.file, 0)
|
||||
END OpenWriter;
|
||||
|
||||
PROCEDURE SetFont* (VAR W: Writer; fnt: FontsFont);
|
||||
BEGIN W.fnt := fnt
|
||||
END SetFont;
|
||||
|
||||
PROCEDURE SetColor* (VAR W: Writer; col: SYSTEM.INT8);
|
||||
BEGIN W.col := col
|
||||
END SetColor;
|
||||
|
||||
PROCEDURE SetOffset* (VAR W: Writer; voff: SYSTEM.INT8);
|
||||
BEGIN W.voff := voff
|
||||
END SetOffset;
|
||||
|
||||
|
||||
PROCEDURE Write* (VAR W: Writer; ch: CHAR);
|
||||
VAR u, un: Run; p: Piece;
|
||||
BEGIN Files.Write(W.rider, ch); INC(W.buf.len); un := W.buf.head; u := un.prev;
|
||||
IF (u IS Piece) & (u(Piece).file = W.file) & (u.fnt.name = W.fnt.name) & (u.col = W.col) & (u.voff = W.voff)
|
||||
& ~u(Piece).ascii THEN (* << *)
|
||||
INC(u.len)
|
||||
ELSE NEW(p); u.next := p; p.prev := u; p.next := un; un.prev := p;
|
||||
p.len := 1; p.fnt := W.fnt; p.col := W.col; p.voff := W.voff;
|
||||
p.file := W.file; p.org := Files.Length(W.file) - 1; p.ascii := FALSE (* << *)
|
||||
END
|
||||
END Write;
|
||||
|
||||
PROCEDURE WriteElem* (VAR W: Writer; e: Elem);
|
||||
VAR u, un: Run;
|
||||
BEGIN
|
||||
IF e.base # NIL THEN HALT(99) END;
|
||||
INC(W.buf.len); e.len := 1; e.fnt := W.fnt; e.col := W.col; e.voff := W.voff;
|
||||
un := W.buf.head; u := un.prev; u.next := e; e.prev := u; e.next := un; un.prev := e
|
||||
END WriteElem;
|
||||
|
||||
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: SYSTEM.INT64);
|
||||
VAR
|
||||
i: INTEGER; x0: SYSTEM.INT64;
|
||||
a: ARRAY 24 OF CHAR;
|
||||
BEGIN i := 0;
|
||||
IF x < 0 THEN
|
||||
IF x = MIN(SYSTEM.INT64) THEN WriteString(W, " -9223372036854775808"); RETURN
|
||||
ELSE DEC(n); x0 := -x
|
||||
END
|
||||
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 WriteInt;
|
||||
|
||||
PROCEDURE WriteHex* (VAR W: Writer; x: LONGINT);
|
||||
VAR i: INTEGER; y: LONGINT;
|
||||
a: ARRAY 20 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;
|
||||
|
||||
PROCEDURE WriteReal* (VAR W: Writer; x: REAL; n: INTEGER);
|
||||
VAR e: INTEGER; x0: REAL;
|
||||
d: ARRAY maxD OF CHAR;
|
||||
BEGIN e := Reals.Expo(x);
|
||||
IF e = 0 THEN
|
||||
WriteString(W, " 0");
|
||||
REPEAT Write(W, " "); DEC(n) UNTIL n <= 3
|
||||
ELSIF e = 255 THEN
|
||||
WriteString(W, " NaN");
|
||||
WHILE n > 4 DO Write(W, " "); DEC(n) END
|
||||
ELSE
|
||||
IF n <= 9 THEN n := 3 ELSE DEC(n, 6) END;
|
||||
REPEAT Write(W, " "); DEC(n) UNTIL n <= 8;
|
||||
(*there are 2 < n <= 8 digits to be written*)
|
||||
IF x < 0.0 THEN Write(W, "-"); x := -x ELSE Write(W, " ") END;
|
||||
e := (e - 127) * 77 DIV 256;
|
||||
IF e >= 0 THEN x := x / Reals.Ten(e) ELSE x := Reals.Ten(-e) * x END;
|
||||
IF x >= 10.0 THEN x := 0.1*x; INC(e) END;
|
||||
x0 := Reals.Ten(n-1); x := x0*x + 0.5;
|
||||
IF x >= 10.0*x0 THEN x := x*0.1; INC(e) END;
|
||||
Reals.Convert(x, n, d);
|
||||
DEC(n); Write(W, d[n]); Write(W, ".");
|
||||
REPEAT DEC(n); Write(W, d[n]) UNTIL n = 0;
|
||||
Write(W, "E");
|
||||
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 WriteReal;
|
||||
|
||||
PROCEDURE WriteRealFix* (VAR W: Writer; x: REAL; n, k: INTEGER);
|
||||
VAR e, i: INTEGER; sign: CHAR; x0: REAL;
|
||||
d: ARRAY maxD OF CHAR;
|
||||
|
||||
PROCEDURE seq(ch: CHAR; n: INTEGER);
|
||||
BEGIN WHILE n > 0 DO Write(W, ch); DEC(n) END
|
||||
END seq;
|
||||
|
||||
PROCEDURE dig(n: INTEGER);
|
||||
BEGIN
|
||||
WHILE n > 0 DO
|
||||
DEC(i); Write(W, d[i]); DEC(n)
|
||||
END
|
||||
END dig;
|
||||
|
||||
BEGIN e := Reals.Expo(x);
|
||||
IF k < 0 THEN k := 0 END;
|
||||
IF e = 0 THEN seq(" ", n-k-2); Write(W, "0"); seq(" ", k+1)
|
||||
ELSIF e = 255 THEN WriteString(W, " NaN"); seq(" ", n-4)
|
||||
ELSE e := (e - 127) * 77 DIV 256;
|
||||
IF x < 0 THEN sign := "-"; x := -x ELSE sign := " " END;
|
||||
IF e >= 0 THEN (*x >= 1.0, 77/256 = log 2*) x := x/Reals.Ten(e)
|
||||
ELSE (*x < 1.0*) x := Reals.Ten(-e) * x
|
||||
END;
|
||||
IF x >= 10.0 THEN x := 0.1*x; INC(e) END;
|
||||
(* 1 <= x < 10 *)
|
||||
IF k+e >= maxD-1 THEN k := maxD-1-e
|
||||
ELSIF k+e < 0 THEN k := -e; x := 0.0
|
||||
END;
|
||||
x0 := Reals.Ten(k+e); x := x0*x + 0.5;
|
||||
IF x >= 10.0*x0 THEN INC(e) END;
|
||||
(*e = no. of digits before decimal point*)
|
||||
INC(e); i := k+e; Reals.Convert(x, i, d);
|
||||
IF e > 0 THEN
|
||||
seq(" ", n-e-k-2); Write(W, sign); dig(e);
|
||||
Write(W, "."); dig(k)
|
||||
ELSE seq(" ", n-k-3);
|
||||
Write(W, sign); Write(W, "0"); Write(W, ".");
|
||||
seq("0", -e); dig(k+e)
|
||||
END
|
||||
END
|
||||
END WriteRealFix;
|
||||
|
||||
PROCEDURE WriteRealHex* (VAR W: Writer; x: REAL);
|
||||
VAR i: INTEGER;
|
||||
d: ARRAY 8 OF CHAR;
|
||||
BEGIN Reals.ConvertH(x, d); i := 0;
|
||||
REPEAT Write(W, d[i]); INC(i) UNTIL i = 8
|
||||
END WriteRealHex;
|
||||
|
||||
PROCEDURE WriteLongReal* (VAR W: Writer; x: LONGREAL; n: INTEGER);
|
||||
CONST maxD = 16;
|
||||
VAR e: INTEGER; x0: LONGREAL;
|
||||
d: ARRAY maxD OF CHAR;
|
||||
BEGIN e := Reals.ExpoL(x);
|
||||
IF e = 0 THEN
|
||||
WriteString(W, " 0");
|
||||
REPEAT Write(W, " "); DEC(n) UNTIL n <= 3
|
||||
ELSIF e = 2047 THEN
|
||||
WriteString(W, " NaN");
|
||||
WHILE n > 4 DO Write(W, " "); DEC(n) END
|
||||
ELSE
|
||||
IF n <= 10 THEN n := 3 ELSE DEC(n, 7) END;
|
||||
REPEAT Write(W, " "); DEC(n) UNTIL n <= maxD;
|
||||
(*there are 2 <= n <= maxD digits to be written*)
|
||||
IF x < 0 THEN Write(W, "-"); x := -x ELSE Write(W, " ") END;
|
||||
|
||||
(* Scale e to be an exponent of 10 rather than 2 *)
|
||||
e := SHORT(LONG(e - 1023) * 77 DIV 256);
|
||||
IF e >= 0 THEN x := x / Reals.TenL(e) ELSE x := Reals.TenL(-e) * x END ;
|
||||
IF x >= 10.0D0 THEN x := 0.1D0 * x; INC(e) END;
|
||||
|
||||
(* Scale x to the number of digits requested *)
|
||||
x0 := Reals.TenL(n-1); x := x0*x + 0.5D0;
|
||||
IF x >= 10.0D0*x0 THEN x := 0.1D0 * x; INC(e) END ;
|
||||
|
||||
(* Generate the mantissa digits of x *)
|
||||
Reals.ConvertL(x, n, d);
|
||||
|
||||
DEC(n); Write(W, d[n]); Write(W, ".");
|
||||
REPEAT DEC(n); Write(W, d[n]) UNTIL n = 0;
|
||||
|
||||
Write(W, "D");
|
||||
IF e < 0 THEN Write(W, "-"); e := -e ELSE Write(W, "+") END;
|
||||
Write(W, CHR(e DIV 100 + 30H)); e := e MOD 100;
|
||||
Write(W, CHR(e DIV 10 + 30H));
|
||||
Write(W, CHR(e MOD 10 + 30H))
|
||||
END
|
||||
END WriteLongReal;
|
||||
|
||||
PROCEDURE WriteLongRealHex* (VAR W: Writer; x: LONGREAL);
|
||||
VAR i: INTEGER;
|
||||
d: ARRAY 16 OF CHAR;
|
||||
BEGIN Reals.ConvertHL(x, d); i := 0;
|
||||
REPEAT Write(W, d[i]); INC(i) UNTIL i = 16
|
||||
END WriteLongRealHex;
|
||||
|
||||
PROCEDURE WriteDate* (VAR W: Writer; t, d: LONGINT);
|
||||
|
||||
PROCEDURE WritePair(ch: CHAR; x: LONGINT);
|
||||
BEGIN Write(W, ch);
|
||||
Write(W, CHR(x DIV 10 + 30H)); Write(W, CHR(x MOD 10 + 30H))
|
||||
END WritePair;
|
||||
|
||||
BEGIN
|
||||
WritePair(" ", d MOD 32); WritePair(".", d DIV 32 MOD 16); WritePair(".", d DIV 512 MOD 128);
|
||||
WritePair(" ", t DIV 4096 MOD 32); WritePair(":", t DIV 64 MOD 64); WritePair(":", t MOD 64)
|
||||
END WriteDate;
|
||||
|
||||
|
||||
(** Text Filing **)
|
||||
|
||||
PROCEDURE Load0 (VAR r: Files.Rider; T: Text);
|
||||
VAR u, un: Run; p: Piece; e: Elem;
|
||||
org, pos, hlen, plen: LONGINT; ecnt, fcnt: SHORTINT;
|
||||
fno, col, voff: SYSTEM.INT8;
|
||||
f: Files.File;
|
||||
msg: FileMsg;
|
||||
mods, procs: ARRAY 64, 32 OF CHAR;
|
||||
name: ARRAY 32 OF CHAR;
|
||||
fnts: ARRAY 32 OF FontsFont;
|
||||
|
||||
PROCEDURE LoadElem (VAR r: Files.Rider; pos, span: LONGINT; VAR e: Elem);
|
||||
VAR M: Modules.Module; Cmd: Modules.Command; a: Alien;
|
||||
org, ew, eh: LONGINT; eno: SYSTEM.INT8;
|
||||
BEGIN new := NIL;
|
||||
Files.ReadLInt(r, ew); Files.ReadLInt(r, eh); Files.Read(r, eno);
|
||||
IF eno > ecnt THEN ecnt := eno; Files.ReadString(r, mods[eno]); Files.ReadString(r, procs[eno]) END;
|
||||
org := Files.Pos(r); M := Modules.ThisMod(mods[eno]);
|
||||
IF M # NIL THEN Cmd := Modules.ThisCommand(M, procs[eno]);
|
||||
IF Cmd # NIL THEN Cmd END
|
||||
END;
|
||||
e := new;
|
||||
IF e # NIL THEN e.W := ew; e.H := eh; e.base := T;
|
||||
msg.pos := pos; e.handle(e, msg);
|
||||
IF Files.Pos(r) # org + span THEN e := NIL END
|
||||
END;
|
||||
IF e = NIL THEN Files.Set(r, f, org + span);
|
||||
NEW(a); a.W := ew; a.H := eh; a.handle := HandleAlien; a.base := T;
|
||||
a.file := f; a.org := org; a.span := span;
|
||||
COPY(mods[eno], a.mod); COPY(procs[eno], a.proc);
|
||||
e := a
|
||||
END
|
||||
END LoadElem;
|
||||
|
||||
BEGIN pos := Files.Pos(r); f := Files.Base(r);
|
||||
NEW(u); u.len := MAX(LONGINT); (*u.fnt := FontsDefault;*)u.fnt := NIL; u.col := Displaywhite;
|
||||
T.head := u; ecnt := 0; fcnt := 0;
|
||||
msg.id := load; msg.r := r;
|
||||
Files.ReadLInt(msg.r, hlen); (*!!!org := pos + hlen;*) org := pos -2 + hlen; pos := org; Files.Read(msg.r, fno);
|
||||
WHILE fno # 0 DO
|
||||
IF fno > fcnt THEN fcnt := fno; Files.ReadString(msg.r, name); fnts[fno] := FontsThis(name) END;
|
||||
Files.Read(msg.r, col); Files.Read(msg.r, voff); Files.ReadLInt(msg.r, plen);
|
||||
IF plen > 0 THEN NEW(p); p.file := f; p.org := pos; p.ascii := FALSE; un := p; un.len := plen
|
||||
ELSE LoadElem(msg.r, pos - org, -plen, e); un := e; un.len := 1
|
||||
END;
|
||||
(*un.fnt := fnts[fno];*) un.col := col; un.voff := voff;
|
||||
INC(pos, un.len); u.next := un; un.prev := u; u := un; Files.Read(msg.r, fno)
|
||||
END;
|
||||
u.next := T.head; T.head.prev := u; T.cache := T.head; T.corg := 0;
|
||||
Files.ReadLInt(msg.r, T.len); Files.Set(r, f, Files.Pos(msg.r) + T.len)
|
||||
END Load0;
|
||||
|
||||
PROCEDURE Load* (VAR r: Files.Rider; T: Text);
|
||||
CONST oldTag = -4095;
|
||||
VAR tag: INTEGER;
|
||||
BEGIN
|
||||
(* for compatibility inner text tags are checked and skipped; remove this in a later version *)
|
||||
Files.ReadInt(r, tag); IF tag # oldTag THEN Files.Set(r, Files.Base(r), Files.Pos(r)-2) END;
|
||||
Load0(r, T)
|
||||
END Load;
|
||||
|
||||
PROCEDURE Open* (T: Text; name: ARRAY OF CHAR);
|
||||
VAR f: Files.File; r: Files.Rider; u: Run; p: Piece; tag, version: CHAR; hlen: LONGINT;
|
||||
BEGIN f := Files.Old(name);
|
||||
IF f = NIL THEN f := Files.New("") END;
|
||||
Files.Set(r, f, 0); Files.Read(r, tag); Files.Read(r, version);
|
||||
IF (tag = textTag) OR (tag = 01X) & (version = textTag) THEN Load0(r, T)
|
||||
ELSE (*ascii*)
|
||||
NEW(u); u.len := MAX(LONGINT); u.fnt := NIL; u.col := Displaywhite;
|
||||
NEW(p);
|
||||
IF (tag = DocBlockId) & (version = 07X) THEN (* extract ascii text from System 3 text document *)
|
||||
Files.Set(r, f, 28); Files.ReadLInt(r, hlen);
|
||||
Files.Set(r, f, 22 + hlen); Files.ReadLInt(r, T.len); p.org := 26 + hlen
|
||||
ELSE
|
||||
T.len := Files.Length(f); p.org := 0
|
||||
END ;
|
||||
IF T.len > 0 THEN p.len := T.len; p.fnt := FontsDefault;
|
||||
p.col := Displaywhite; p.voff := 0; p.file := f; p.ascii := TRUE;
|
||||
u.next := p; u.prev := p; p.next := u; p.prev := u
|
||||
ELSE u.next := u; u.prev := u
|
||||
END;
|
||||
T.head := u; T.cache := T.head; T.corg := 0
|
||||
END
|
||||
END Open;
|
||||
|
||||
PROCEDURE Store* (VAR r: Files.Rider; T: Text);
|
||||
VAR r1: Files.Rider; u, un: Run; e: Elem; org, pos, delta, hlen, rlen: LONGINT; ecnt, fcnt: SHORTINT; ch: CHAR; (* << *)
|
||||
fno: SYSTEM.INT8;
|
||||
msg: FileMsg; iden: IdentifyMsg;
|
||||
mods, procs: ARRAY 64, 32 OF CHAR;
|
||||
fnts: ARRAY 32 OF FontsFont;
|
||||
block: ARRAY 1024 OF CHAR;
|
||||
|
||||
PROCEDURE StoreElem (VAR r: Files.Rider; pos: LONGINT; e: Elem);
|
||||
VAR r1: Files.Rider; org, span: LONGINT; eno: SYSTEM.INT8;
|
||||
BEGIN COPY(iden.mod, mods[ecnt]); COPY(iden.proc, procs[ecnt]); eno := 1;
|
||||
WHILE (mods[eno] # iden.mod) OR (procs[eno] # iden.proc) DO INC(eno) END;
|
||||
Files.Set(r1, Files.Base(r), Files.Pos(r));
|
||||
Files.WriteLInt(r, 0); Files.WriteLInt(r, 0); Files.WriteLInt(r, 0); (*fixup slot*)
|
||||
Files.Write(r, eno);
|
||||
IF eno = ecnt THEN INC(ecnt); Files.WriteString(r, iden.mod); Files.WriteString(r, iden.proc) END;
|
||||
msg.pos := pos; org := Files.Pos(r); e.handle(e, msg); span := Files.Pos(r) - org;
|
||||
Files.WriteLInt(r1, -span); Files.WriteLInt(r1, e.W); Files.WriteLInt(r1, e.H) (*fixup*)
|
||||
END StoreElem;
|
||||
|
||||
BEGIN
|
||||
org := Files.Pos(r); msg.id := store; msg.r := r; Files.WriteLInt(msg.r, 0); (*fixup slot*)
|
||||
u := T.head.next; pos := 0; delta := 0; fcnt := 1; ecnt := 1;
|
||||
WHILE u # T.head DO
|
||||
IF u IS Elem THEN iden.mod[0] := 0X; u(Elem).handle(u(Elem), iden) ELSE iden.mod[0] := 1X END;
|
||||
IF iden.mod[0] # 0X THEN
|
||||
fnts[fcnt] := u.fnt; fno := 1;
|
||||
WHILE fnts[fno].name # u.fnt.name DO INC(fno) END;
|
||||
Files.Write(msg.r, fno);
|
||||
IF fno = fcnt THEN INC(fcnt); Files.WriteString(msg.r, u.fnt.name) END;
|
||||
Files.Write(msg.r, u.col); Files.Write(msg.r, u.voff)
|
||||
END;
|
||||
IF u IS Piece THEN rlen := u.len; un := u.next;
|
||||
WHILE (un IS Piece) & (un.fnt = u.fnt) & (un.col = u.col) & (un.voff = u.voff) DO
|
||||
INC(rlen, un.len); un := un.next
|
||||
END;
|
||||
Files.WriteLInt(msg.r, rlen); INC(pos, rlen); u := un
|
||||
ELSIF iden.mod[0] # 0X THEN StoreElem(msg.r, pos, u(Elem)); INC(pos); u := u.next
|
||||
ELSE INC(delta); u := u.next
|
||||
END
|
||||
END;
|
||||
Files.Write(msg.r, 0); Files.WriteLInt(msg.r, T.len - delta);
|
||||
(*!!!hlen := Files.Pos(msg.r) - org;*) hlen := Files.Pos(msg.r) - org + 2;
|
||||
Files.Set(r1, Files.Base(msg.r), org); Files.WriteLInt(r1, hlen); (*fixup*)
|
||||
u := T.head.next;
|
||||
WHILE u # T.head DO
|
||||
IF u IS Piece THEN
|
||||
WITH u: Piece DO
|
||||
IF u.ascii THEN Files.Set(r1, u.file, u.org); delta := u.len; (* << LF to CR *)
|
||||
WHILE delta > 0 DO Files.Read(r1, ch); DEC(delta);
|
||||
IF ch = 0AX THEN Files.Write(msg.r, CR) ELSE Files.Write(msg.r, ch) END
|
||||
END
|
||||
ELSE Files.Set(r1, u.file, u.org); delta := u.len;
|
||||
WHILE delta > LEN(block) DO Files.ReadBytes(r1, block, LEN(block));
|
||||
Files.WriteBytes(msg.r, block, LEN(block)); DEC(delta, LEN(block))
|
||||
END;
|
||||
Files.ReadBytes(r1, block, delta); Files.WriteBytes(msg.r, block, delta)
|
||||
END
|
||||
END
|
||||
ELSE iden.mod[0] := 0X; u(Elem).handle(u(Elem), iden);
|
||||
IF iden.mod[0] # 0X THEN Files.Write(msg.r, ElemChar) END
|
||||
END;
|
||||
u := u.next
|
||||
END;
|
||||
r := msg.r;
|
||||
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; r: Files.Rider; i, res: INTEGER; bak: ARRAY 64 OF CHAR;
|
||||
BEGIN
|
||||
f := Files.New(name); Files.Set(r, f, 0); Files.Write(r, textTag); Files.Write(r, version); Store(r, T);
|
||||
i := 0; WHILE name[i] # 0X DO INC(i) END;
|
||||
COPY(name, bak); bak[i] := "."; bak[i+1] := "B"; bak[i+2] := "a"; bak[i+3] := "k"; bak[i+4] := 0X;
|
||||
Files.Rename(name, bak, res); Files.Register(f)
|
||||
END Close;
|
||||
|
||||
BEGIN del := NIL; NEW(FontsDefault); FontsDefault.name := "Syntax10.Scn.Fnt"
|
||||
END Texts.
|
||||
|
|
@ -41,7 +41,7 @@ VAR
|
|||
SeekCur-: INTEGER;
|
||||
SeekEnd-: INTEGER;
|
||||
|
||||
nl-: ARRAY 3 OF CHAR; (* Platform specific newline representation *)
|
||||
NL-: ARRAY 3 OF CHAR; (* Platform specific newline representation *)
|
||||
|
||||
|
||||
|
||||
|
|
@ -547,6 +547,6 @@ BEGIN
|
|||
SeekCur := seekcur();
|
||||
SeekEnd := seekend();
|
||||
|
||||
nl[0] := 0AX; (* LF *)
|
||||
nl[1] := 0X;
|
||||
NL[0] := 0AX; (* LF *)
|
||||
NL[1] := 0X;
|
||||
END Platform.
|
||||
|
|
|
|||
|
|
@ -155,16 +155,20 @@ installable:
|
|||
# May require root access.
|
||||
install:
|
||||
@printf "\nInstalling into \"$(INSTALLDIR)\"\n"
|
||||
@rm -rf "$(INSTALLDIR)/bin" "$(INSTALLDIR)/$(MODEL)"
|
||||
@rm -rf "$(INSTALLDIR)/bin" "$(INSTALLDIR)/2 "$(INSTALLDIR)/C
|
||||
|
||||
@mkdir -p "$(INSTALLDIR)/bin"
|
||||
@cp $(OBECOMP) "$(INSTALLDIR)/bin/$(OBECOMP)"
|
||||
@-cp $(BUILDDIR)/showdef$(BINEXT) "$(INSTALLDIR)/bin"
|
||||
|
||||
@mkdir -p "$(INSTALLDIR)/2/include" && cp $(BUILDDIR)/*.h "$(INSTALLDIR)/2/include/"
|
||||
@mkdir -p "$(INSTALLDIR)/2/sym" && cp $(BUILDDIR)/*.sym "$(INSTALLDIR)/2/sym/"
|
||||
@mkdir -p "$(INSTALLDIR)/C/include" && cp $(BUILDDIR)/C/*.h "$(INSTALLDIR)/C/include/"
|
||||
@mkdir -p "$(INSTALLDIR)/C/sym" && cp $(BUILDDIR)/C/*.sym "$(INSTALLDIR)/C/sym/"
|
||||
|
||||
@mkdir -p "$(INSTALLDIR)/lib"
|
||||
@mkdir -p "$(INSTALLDIR)/$(MODEL)/include"
|
||||
@mkdir -p "$(INSTALLDIR)/$(MODEL)/sym"
|
||||
@cp $(BUILDDIR)/*.h "$(INSTALLDIR)/$(MODEL)/include/"
|
||||
@cp $(BUILDDIR)/*.sym "$(INSTALLDIR)/$(MODEL)/sym/"
|
||||
@cp $(OBECOMP) "$(INSTALLDIR)/bin/$(OBECOMP)"
|
||||
@-cp $(BUILDDIR)/showdef$(BINEXT) "$(INSTALLDIR)/bin"
|
||||
@cp $(BUILDDIR)/lib$(ONAME)* "$(INSTALLDIR)/lib/"
|
||||
@cp $(BUILDDIR)/lib$(ONAME)* "$(INSTALLDIR)/lib/"
|
||||
@cp $(BUILDDIR)/C/lib$(ONAME)* "$(INSTALLDIR)/lib/"
|
||||
@if which ldconfig >/dev/null 2>&1; then $(LDCONFIG); fi
|
||||
|
||||
|
||||
|
|
@ -184,176 +188,194 @@ uninstall:
|
|||
if which ldconfig >/dev/null 2>&1; then ldconfig; fi
|
||||
|
||||
|
||||
runtime:
|
||||
@printf "\nMaking v4 library for -O$(MODEL)\n"
|
||||
cd $(BUILDDIR)/$(MODEL) && $(COMPILE) -c SYSTEM.c
|
||||
cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/Platform$(PLATFORM).Mod
|
||||
cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/Heap.Mod
|
||||
cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/Out.Mod
|
||||
cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/Modules.Mod
|
||||
cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/Strings.Mod
|
||||
cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/Files.Mod
|
||||
cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/Reals.Mod
|
||||
# cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/LowReal.Mod
|
||||
# cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/Math.Mod
|
||||
# cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/LowLReal.Mod
|
||||
# cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/MathL.Mod
|
||||
cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/Texts.Mod
|
||||
cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/Oberon.Mod
|
||||
|
||||
|
||||
v4:
|
||||
@printf "\nMaking v4 library\n"
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/v4/Args.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/v4/Printer.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/v4/Sets.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/v4/Args.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/v4/Printer.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/v4/Sets.Mod
|
||||
|
||||
ooc2:
|
||||
@printf "\nMaking ooc2 library\n"
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc2/ooc2Strings.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc2/ooc2Ascii.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc2/ooc2CharClass.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc2/ooc2ConvTypes.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc2/ooc2IntConv.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc2/ooc2IntStr.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc2/ooc2Real0.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc2/ooc2Strings.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc2/ooc2Ascii.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc2/ooc2CharClass.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc2/ooc2ConvTypes.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc2/ooc2IntConv.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc2/ooc2IntStr.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc2/ooc2Real0.Mod
|
||||
|
||||
|
||||
TODO: Comment disabled lines contain use of VAL that reads beyond source variable
|
||||
|
||||
ooc:
|
||||
@printf "\nMaking ooc library\n"
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocLowReal.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocLowLReal.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocRealMath.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocOakMath.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocLRealMath.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocLongInts.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocComplexMath.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocLComplexMath.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocAscii.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocCharClass.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocStrings.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocConvTypes.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocLRealConv.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocLRealStr.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocRealConv.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocRealStr.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocIntConv.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocIntStr.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocMsg.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocSysClock.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocTime.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocChannel.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocStrings2.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocRts.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocFilenames.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocTextRider.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocBinaryRider.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocJulianDay.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocFilenames.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocwrapperlibc.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ooc/oocC$(DATAMODEL).Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocLowReal.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocLowLReal.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocRealMath.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocOakMath.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocLRealMath.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocLongInts.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocComplexMath.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocLComplexMath.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocAscii.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocCharClass.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocStrings.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocConvTypes.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocLRealConv.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocLRealStr.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocRealConv.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocRealStr.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocIntConv.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocIntStr.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocMsg.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocSysClock.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocTime.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocChannel.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocStrings2.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocRts.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocFilenames.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocTextRider.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocBinaryRider.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocJulianDay.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocFilenames.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocwrapperlibc.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ooc/oocC$(DATAMODEL).Mod
|
||||
|
||||
oocX11:
|
||||
@printf "\nMaking oocX11 library\n"
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/oocX11/oocX11.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/oocX11/oocXutil.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/oocX11/oocXYplane.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/oocX11/oocX11.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/oocX11/oocXutil.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/oocX11/oocXYplane.Mod
|
||||
|
||||
ulm:
|
||||
@printf "\nMaking ulm library\n"
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmObjects.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmPriorities.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmDisciplines.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmServices.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmSys.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmSYSTEM.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmEvents.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmProcess.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmResources.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmForwarders.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmRelatedEvents.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmTypes.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmStreams.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmStrings.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmSysTypes.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmTexts.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmSysConversions.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmErrors.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmSysErrors.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmSysStat.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmASCII.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmSets.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmIO.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmAssertions.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmIndirectDisciplines.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmStreamDisciplines.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmIEEE.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmMC68881.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmReals.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmPrint.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmWrite.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmConstStrings.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmPlotters.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmSysIO.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmLoader.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmNetIO.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmPersistentObjects.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmPersistentDisciplines.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmOperations.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmScales.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmTimes.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmClocks.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmTimers.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmConditions.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmStreamConditions.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmTimeConditions.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmCiphers.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmCipherOps.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmBlockCiphers.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmAsymmetricCiphers.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmConclusions.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmRandomGenerators.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmTCrypt.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/ulm/ulmIntOperations.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmObjects.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmPriorities.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmDisciplines.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmServices.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmSys.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmSYSTEM.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmEvents.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmProcess.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmResources.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmForwarders.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmRelatedEvents.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmTypes.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmStreams.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmStrings.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmSysTypes.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmTexts.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmSysConversions.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmErrors.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmSysErrors.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmSysStat.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmASCII.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmSets.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmIO.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmAssertions.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmIndirectDisciplines.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmStreamDisciplines.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmIEEE.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmMC68881.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmReals.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmPrint.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmWrite.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmConstStrings.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmPlotters.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmSysIO.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmLoader.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmNetIO.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmPersistentObjects.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmPersistentDisciplines.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmOperations.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmScales.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmTimes.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmClocks.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmTimers.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmConditions.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmStreamConditions.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmTimeConditions.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmCiphers.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmCipherOps.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmBlockCiphers.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmAsymmetricCiphers.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmConclusions.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmRandomGenerators.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmTCrypt.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/ulm/ulmIntOperations.Mod
|
||||
|
||||
pow32:
|
||||
@printf "\nMaking pow library\n"
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/pow/powStrings.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/pow/powStrings.Mod
|
||||
|
||||
misc:
|
||||
@printf "\nMaking misc library\n"
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/system/Oberon.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/misc/crt.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/misc/Listen.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/misc/MersenneTwister.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/misc/MultiArrays.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/misc/MultiArrayRiders.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/system/Oberon.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/misc/crt.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/misc/Listen.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/misc/MersenneTwister.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/misc/MultiArrays.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/misc/MultiArrayRiders.Mod
|
||||
|
||||
s3:
|
||||
@printf "\nMaking s3 library\n"
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethBTrees.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethMD5.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethSets.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethZlib.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethZlibBuffers.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethZlibInflate.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethZlibDeflate.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethZlibReaders.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethZlibWriters.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethZip.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethRandomNumbers.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethGZReaders.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethGZWriters.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethUnicode.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethDates.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethReals.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../src/library/s3/ethStrings.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethBTrees.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethMD5.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethSets.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethZlib.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethZlibBuffers.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethZlibInflate.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethZlibDeflate.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethZlibReaders.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethZlibWriters.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethZip.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethRandomNumbers.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethGZReaders.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethGZWriters.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethUnicode.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethDates.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethReals.Mod
|
||||
cd $(BUILDDIR); $(ROOTDIR)/$(OBECOMP) -Ffs -O2 ../../src/library/s3/ethStrings.Mod
|
||||
|
||||
librarybinary:
|
||||
@printf "\nMaking lib$(ONAME)\n"
|
||||
|
||||
# Remove objects that should not be part of the library
|
||||
O2library: v4 ooc2 ooc ulm pow32 misc s3
|
||||
@printf "\nMaking lib$(ONAME)2\n"
|
||||
rm -f $(BUILDDIR)/Compiler.o
|
||||
|
||||
# Note: remining compiler files are retained in the library allowing the building
|
||||
# of utilities like BrowserCmd.Mod (aka showdef).
|
||||
|
||||
# Make static library
|
||||
ar rcs "$(BUILDDIR)/lib$(ONAME)$(MODEL).a" $(BUILDDIR)/*.o
|
||||
|
||||
ar rcs "$(BUILDDIR)/lib$(ONAME)2.a" $(BUILDDIR)/*.o
|
||||
# Make shared library
|
||||
@cd $(BUILDDIR) && $(COMPILE) -shared -o lib$(ONAME)$(MODEL).so *.o
|
||||
@cd $(BUILDDIR) && $(COMPILE) -shared -o lib$(ONAME)2.so *.o
|
||||
|
||||
|
||||
|
||||
|
||||
library: v4 ooc2 ooc ulm pow32 misc s3 librarybinary
|
||||
OakwoodLibrary:
|
||||
@printf "\nMaking lib$(ONAME)$(MODEL)\n"
|
||||
mkdir -p $(BUILDDIR)/$(MODEL)
|
||||
cp src/system/*.[ch] $(BUILDDIR)/$(MODEL)
|
||||
@make -f src/tools/make/oberon.mk -s runtime MODEL=$(MODEL)
|
||||
ar rcs "$(BUILDDIR)/$(MODEL)/lib$(ONAME)$(MODEL).a" $(BUILDDIR)/$(MODEL)/*.o
|
||||
@cd $(BUILDDIR)/$(MODEL) && $(COMPILE) -shared -o lib$(ONAME)$(MODEL).so *.o
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue