O7B.Mod 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. MODULE O7B; (*NW 25.6.2014 / 1.3.2019 in Oberon-07*)
  2. IMPORT SYSTEM, Files, ORS := O7S;
  3. (*Definition of data types Object and Type, which together form the data structure
  4. called "symbol table". Contains procedures for creation of Objects, and for search:
  5. NewObj, this, thisimport, thisfield (and OpenScope, CloseScope).
  6. Handling of import and export, i.e. reading and writing of "symbol files" is done by procedures
  7. Import and Export. This module contains the list of standard identifiers, with which
  8. the symbol table (universe), and that of the pseudo-module SYSTEM are initialized. *)
  9. TYPE
  10. LONGINT = INTEGER;
  11. BYTE = CHAR;
  12. CONST versionkey* = 1; maxTypTab = 64;
  13. (* class values*) Head* = 0;
  14. Const* = 1; Var* = 2; Par* = 3; Fld* = 4; Typ* = 5;
  15. SProc* = 6; SFunc* = 7; Mod* = 8;
  16. (* form values*)
  17. Byte* = 1; Bool* = 2; Char* = 3; Int* = 4; Real* = 5; Set* = 6;
  18. Pointer* = 7; NilTyp* = 8; NoTyp* = 9; Proc* = 10;
  19. String* = 11; Array* = 12; Record* = 13;
  20. TYPE Object* = POINTER TO ObjDesc;
  21. Module* = POINTER TO ModDesc;
  22. Type* = POINTER TO TypeDesc;
  23. ObjDesc*= (*EXTENSIBLE*) RECORD
  24. class*, exno*: INTEGER;
  25. expo*, rdo*: BOOLEAN; (*exported / read-only*)
  26. lev*: INTEGER;
  27. next*, dsc*: Object;
  28. type*: Type;
  29. name*: ORS.Ident;
  30. val*: LONGINT
  31. END ;
  32. ModDesc* = RECORD (ObjDesc) orgname-: ORS.Ident END ;
  33. TypeDesc* = RECORD
  34. form*, ref*, mno*: INTEGER; (*ref is only used for import/export*)
  35. nofpar*: INTEGER; (*for procedures, extension level for records*)
  36. len*: LONGINT; (*for arrays, len < 0 => open array; for records: adr of descriptor*)
  37. dsc*, typobj*: Object;
  38. base*: Type; (*for arrays, records, pointers*)
  39. size*: LONGINT; (*in bytes; always multiple of 4, except for Byte, Bool and Char*)
  40. END ;
  41. (* Object classes and the meaning of "val":
  42. class val
  43. ----------
  44. Var address
  45. Par address
  46. Const value
  47. Fld offset
  48. Typ type descriptor (TD) address
  49. SProc inline code number
  50. SFunc inline code number
  51. Mod key
  52. Type forms and the meaning of "dsc" and "base":
  53. form dsc base
  54. ------------------------
  55. Pointer - type of dereferenced object
  56. Proc params result type
  57. Array - type of elements
  58. Record fields extension *)
  59. VAR topScope-, universe, system-: Object;
  60. byteType-, boolType-, charType-: Type;
  61. intType-, realType-, setType-, nilType-, noType-, strType-: Type;
  62. nofmod, Ref: INTEGER;
  63. typtab: ARRAY maxTypTab OF Type;
  64. PROCEDURE NewObj* (VAR obj: Object; (*IN*) id: ORS.Ident; class: INTEGER); (*insert new Object with name id*)
  65. VAR new, x: Object;
  66. BEGIN x := topScope;
  67. WHILE (x.next # NIL) & (x.next.name # id) DO x := x.next END ;
  68. IF x.next = NIL THEN
  69. NEW(new); new.name := id; new.class := class; new.next := NIL; new.rdo := FALSE; new.dsc := NIL;
  70. x.next := new; obj := new
  71. ELSE obj := x.next; ORS.Mark("mult def")
  72. END
  73. END NewObj;
  74. PROCEDURE thisObj* (): Object;
  75. VAR s, x: Object;
  76. BEGIN s := topScope;
  77. REPEAT x := s.next;
  78. WHILE (x # NIL) & (x.name # ORS.id) DO x := x.next END ;
  79. s := s.dsc
  80. UNTIL (x # NIL) OR (s = NIL);
  81. RETURN x
  82. END thisObj;
  83. PROCEDURE thisimport* (mod: Object): Object;
  84. VAR obj: Object;
  85. BEGIN
  86. IF mod.rdo THEN
  87. IF mod.name[0] # 0X THEN
  88. obj := mod.dsc;
  89. WHILE (obj # NIL) & (obj.name # ORS.id) DO obj := obj.next END
  90. ELSE obj := NIL
  91. END
  92. ELSE obj := NIL
  93. END ;
  94. RETURN obj
  95. END thisimport;
  96. PROCEDURE thisfield* (rec: Type): Object;
  97. VAR fld: Object;
  98. BEGIN fld := rec.dsc;
  99. WHILE (fld # NIL) & (fld.name # ORS.id) DO fld := fld.next END ;
  100. RETURN fld
  101. END thisfield;
  102. PROCEDURE OpenScope*;
  103. VAR s: Object;
  104. BEGIN NEW(s); s.class := Head; s.dsc := topScope; s.next := NIL; topScope := s
  105. END OpenScope;
  106. PROCEDURE CloseScope*;
  107. BEGIN topScope := topScope.dsc
  108. END CloseScope;
  109. (*------------------------------- Import ---------------------------------*)
  110. PROCEDURE MakeFileName* (VAR FName: ORS.Ident; (*IN*) name, ext: ARRAY OF CHAR);
  111. VAR i, j: INTEGER;
  112. BEGIN i := 0; j := 0; (*assume name suffix less than 4 characters*)
  113. WHILE (i < ORS.IdLen-5) & (name[i] > 0X) DO FName[i] := name[i]; INC(i) END ;
  114. REPEAT FName[i]:= ext[j]; INC(i); INC(j) UNTIL ext[j] = 0X;
  115. FName[i] := 0X
  116. END MakeFileName;
  117. PROCEDURE ThisModule ((*IN*) name, orgname: ORS.Ident; non: BOOLEAN; key: LONGINT): Object;
  118. VAR mod: Module; obj, obj1: Object;
  119. BEGIN obj1 := topScope; obj := obj1.next; (*search for module*)
  120. WHILE (obj # NIL) & (obj(Module).orgname # name) DO obj1 := obj; obj := obj1.next END ;
  121. IF obj = NIL THEN (*insert new module*)
  122. NEW(mod); mod.class := Mod; mod.rdo := FALSE;
  123. mod.name := name; mod.orgname := orgname; mod.val := key;
  124. mod.lev := nofmod; INC(nofmod); mod.type := noType; mod.dsc := NIL; mod.next := NIL;
  125. obj1.next := mod; obj := mod
  126. ELSE (*module already present*)
  127. IF non THEN ORS.Mark("invalid import order") END
  128. END ;
  129. RETURN obj
  130. END ThisModule;
  131. PROCEDURE Read (VAR R: Files.Rider; VAR x: INTEGER);
  132. VAR b: BYTE;
  133. BEGIN Files.Read(*Byte*)(R, b);
  134. IF ORD(b) < 80H THEN x := ORD(b) ELSE x := ORD(b) - 100H END
  135. END Read;
  136. PROCEDURE ReadInt (VAR R: Files.Rider; VAR x: INTEGER);
  137. VAR y: SYSTEM.INT64;
  138. BEGIN
  139. Files.ReadLInt(R, y);
  140. IF R.eof THEN x := -1
  141. ELSE x := SHORT(y)
  142. END
  143. END ReadInt;
  144. PROCEDURE InType (VAR R: Files.Rider; thismod: Object; VAR T: Type);
  145. VAR key: LONGINT;
  146. ref, class, form, np, readonly: INTEGER;
  147. fld, par, obj, mod, last: Object;
  148. t: Type;
  149. name, modname: ORS.Ident;
  150. BEGIN Read(R, ref);
  151. IF ref < 0 THEN T := typtab[-ref] (*already read*)
  152. ELSE NEW(t); T := t; typtab[ref] := t; t.mno := thismod.lev;
  153. Read(R, form); t.form := form;
  154. IF form = Pointer THEN InType(R, thismod, t.base); t.size := 4
  155. ELSIF form = Array THEN
  156. InType(R, thismod, t.base); Files.ReadNum(R, t.len); Files.ReadNum(R, t.size)
  157. ELSIF form = Record THEN
  158. InType(R, thismod, t.base);
  159. IF t.base.form = NoTyp THEN t.base := NIL; obj := NIL ELSE obj := t.base.dsc END ;
  160. Files.ReadNum(R, t.len); (*TD adr/exno*)
  161. Files.ReadNum(R, t.nofpar); (*ext level*)
  162. Files.ReadNum(R, t.size);
  163. Read(R, class); last := NIL;
  164. WHILE class # 0 DO (*fields*)
  165. NEW(fld); fld.class := class; Files.ReadString(R, fld.name);
  166. IF last = NIL THEN t.dsc := fld ELSE last.next := fld END ;
  167. last := fld;
  168. IF fld.name[0] # 0X THEN fld.expo := TRUE; InType(R, thismod, fld.type) ELSE fld.expo := FALSE; fld.type := nilType END ;
  169. Files.ReadNum(R, fld.val); Read(R, class)
  170. END ;
  171. IF last = NIL THEN t.dsc := obj ELSE last.next := obj END
  172. ELSIF form = Proc THEN
  173. InType(R, thismod, t.base);
  174. obj := NIL; np := 0; Read(R, class);
  175. WHILE class # 0 DO (*parameters*)
  176. NEW(par); par.class := class; Read(R, readonly); par.rdo := readonly = 1;
  177. InType(R, thismod, par.type); par.next := obj; obj := par; INC(np); Read(R, class)
  178. END ;
  179. t.dsc := obj; t.nofpar := np; t.size := 4
  180. END ;
  181. Files.ReadString(R, modname);
  182. IF modname[0] # 0X THEN (*re-import*)
  183. ReadInt(R, key); Files.ReadString(R, name);
  184. mod := ThisModule(modname, modname, FALSE, key);
  185. obj := mod.dsc; (*search type*)
  186. WHILE (obj # NIL) & (obj.name # name) DO obj := obj.next END ;
  187. IF obj # NIL THEN T := obj.type (*type object found in object list of mod*)
  188. ELSE (*insert new type object in object list of mod*)
  189. NEW(obj); obj.name := name; obj.class := Typ; obj.next := mod.dsc; mod.dsc := obj; obj.type := t;
  190. t.mno := mod.lev; t.typobj := obj; T := t
  191. END ;
  192. typtab[ref] := T
  193. END
  194. END
  195. END InType;
  196. PROCEDURE Import* (VAR modid, modid1: ORS.Ident);
  197. VAR key: LONGINT; class, k: INTEGER;
  198. obj: Object; t: Type;
  199. thismod: Object;
  200. modname, fname: ORS.Ident;
  201. F: Files.File; R: Files.Rider;
  202. BEGIN
  203. IF modid1 = "SYSTEM" THEN
  204. thismod := ThisModule(modid, modid1, TRUE, key); DEC(nofmod);
  205. thismod.lev := 0; thismod.dsc := system; thismod.rdo := TRUE
  206. ELSE MakeFileName(fname, modid1, ".smb"); F := Files.Old(fname);
  207. IF F # NIL THEN
  208. Files.Set(R, F, 0); ReadInt(R, key); ReadInt(R, key); Files.ReadString(R, modname);
  209. thismod := ThisModule(modid, modid1, TRUE, key); thismod.rdo := TRUE;
  210. Read(R, class); (*version key*)
  211. IF class # versionkey THEN ORS.Mark("wrong version") END ;
  212. Read(R, class);
  213. WHILE class # 0 DO
  214. NEW(obj); obj.class := class; Files.ReadString(R, obj.name);
  215. InType(R, thismod, obj.type); obj.lev := -thismod.lev;
  216. IF class = Typ THEN
  217. t := obj.type; t.typobj := obj; Read(R, k); (*fixup bases of previously declared pointer types*)
  218. WHILE k # 0 DO typtab[k].base := t; Read(R, k) END
  219. ELSE
  220. IF class = Const THEN
  221. IF obj.type.form = Real THEN ReadInt(R, obj.val) ELSE Files.ReadNum(R, obj.val) END
  222. ELSIF class = Var THEN Files.ReadNum(R, obj.val); obj.rdo := TRUE
  223. END
  224. END;
  225. obj.next := thismod.dsc; thismod.dsc := obj; Read(R, class)
  226. END;
  227. ELSE ORS.Mark("import not available")
  228. END
  229. END
  230. END Import;
  231. (*-------------------------------- Export ---------------------------------*)
  232. PROCEDURE Write (VAR R: Files.Rider; x: INTEGER);
  233. BEGIN Files.Write(*Byte*)(R, CHR(x))
  234. END Write;
  235. PROCEDURE OutType (VAR R: Files.Rider; t: Type);
  236. VAR obj, mod, fld, bot: Object;
  237. PROCEDURE OutPar (VAR R: Files.Rider; par: Object; n: INTEGER);
  238. VAR cl: INTEGER;
  239. BEGIN
  240. IF n > 0 THEN
  241. OutPar(R, par.next, n-1); cl := par.class;
  242. Write(R, cl);
  243. IF par.rdo THEN Write(R, 1) ELSE Write(R, 0) END ;
  244. OutType(R, par.type)
  245. END
  246. END OutPar;
  247. PROCEDURE FindHiddenPointers (VAR R: Files.Rider; typ: Type; offset: LONGINT);
  248. VAR fld: Object; i, n: LONGINT;
  249. BEGIN
  250. IF (typ.form = Pointer) OR (typ.form = NilTyp) THEN Write(R, Fld); Write(R, 0); Files.WriteNum(R, offset)
  251. ELSIF typ.form = Record THEN fld := typ.dsc;
  252. WHILE fld # NIL DO FindHiddenPointers(R, fld.type, fld.val + offset); fld := fld.next END
  253. ELSIF typ.form = Array THEN i := 0; n := typ.len;
  254. WHILE i < n DO FindHiddenPointers(R, typ.base, typ.base.size * i + offset); INC(i) END
  255. END
  256. END FindHiddenPointers;
  257. BEGIN
  258. IF t.ref > 0 THEN (*type was already output*) Write(R, -t.ref)
  259. ELSE obj := t.typobj;
  260. IF obj # NIL THEN Write(R, Ref); t.ref := Ref; INC(Ref) ELSE (*anonymous*) Write(R, 0) END ;
  261. Write(R, t.form);
  262. IF t.form = Pointer THEN OutType(R, t.base)
  263. ELSIF t.form = Array THEN OutType(R, t.base); Files.WriteNum(R, t.len); Files.WriteNum(R, t.size)
  264. ELSIF t.form = Record THEN
  265. IF t.base # NIL THEN OutType(R, t.base); bot := t.base.dsc ELSE OutType(R, noType); bot := NIL END ;
  266. IF obj # NIL THEN Files.WriteNum(R, obj.exno) ELSE Write(R, 0) END;
  267. Files.WriteNum(R, t.nofpar); Files.WriteNum(R, t.size);
  268. fld := t.dsc;
  269. WHILE fld # bot DO (*fields*)
  270. IF fld.expo THEN
  271. Write(R, Fld); Files.WriteString(R, fld.name); OutType(R, fld.type); Files.WriteNum(R, fld.val) (*offset*)
  272. ELSE FindHiddenPointers(R, fld.type, fld.val)
  273. END ;
  274. fld := fld.next
  275. END ;
  276. Write(R, 0)
  277. ELSIF t.form = Proc THEN OutType(R, t.base); OutPar(R, t.dsc, t.nofpar); Write(R, 0)
  278. END ;
  279. IF (t.mno > 0) & (obj # NIL) THEN (*re-export, output name*)
  280. mod := topScope.next;
  281. WHILE (mod # NIL) & (mod.lev # t.mno) DO mod := mod.next END ;
  282. IF mod # NIL THEN Files.WriteString(R, mod(Module).orgname); Files.WriteLInt(R, mod.val); Files.WriteString(R, obj.name)
  283. ELSE ORS.Mark("re-export not found"); Write(R, 0)
  284. END
  285. ELSE Write(R, 0)
  286. END
  287. END
  288. END OutType;
  289. PROCEDURE Export* (VAR modid: ORS.Ident; VAR newSF: BOOLEAN; VAR key: LONGINT);
  290. VAR x, sum, oldkey: LONGINT;
  291. obj, obj0: Object;
  292. filename: ORS.Ident;
  293. F, F1: Files.File; R, R1: Files.Rider;
  294. BEGIN Ref := Record + 1; MakeFileName(filename, modid, ".smb");
  295. F := Files.New(filename);
  296. IF F # NIL THEN
  297. Files.Set(R, F, 0);
  298. Files.WriteLInt(R, 0); (*placeholder*)
  299. Files.WriteLInt(R, 0); (*placeholder for key to be inserted at the end*)
  300. Files.WriteString(R, modid); Write(R, versionkey);
  301. obj := topScope.next;
  302. WHILE obj # NIL DO
  303. IF obj.expo THEN
  304. Write(R, obj.class); Files.WriteString(R, obj.name);
  305. OutType(R, obj.type);
  306. IF obj.class = Typ THEN
  307. IF obj.type.form = Record THEN
  308. obj0 := topScope.next; (*check whether this is base of previously declared pointer types*)
  309. WHILE obj0 # obj DO
  310. IF (obj0.type.form = Pointer) & (obj0.type.base = obj.type) & (obj0.type.ref > 0) THEN Write(R, obj0.type.ref) END;
  311. obj0 := obj0.next
  312. END
  313. END;
  314. Write(R, 0)
  315. ELSIF obj.class = Const THEN
  316. IF obj.type.form = Proc THEN Files.WriteNum(R, obj.exno)
  317. ELSIF obj.type.form = Real THEN Files.WriteLInt(R, obj.val)
  318. ELSE Files.WriteNum(R, obj.val)
  319. END
  320. ELSIF obj.class = Var THEN Files.WriteNum(R, obj.exno)
  321. END
  322. END;
  323. obj := obj.next
  324. END;
  325. REPEAT Write(R, 0) UNTIL Files.Length(F) MOD 4 = 0;
  326. FOR Ref := Record+1 TO maxTypTab-1 DO typtab[Ref] := NIL END ;
  327. Files.Set(R, F, 0); sum := 0; ReadInt(R, x); (* compute key (checksum) *)
  328. WHILE ~R.eof DO sum := sum + x; ReadInt(R, x) END ;
  329. F1 := Files.Old(filename); (*sum is new key*)
  330. IF F1 # NIL THEN Files.Set(R1, F1, 4); ReadInt(R1, oldkey) ELSE oldkey := sum+1 END ;
  331. IF sum # oldkey THEN
  332. IF newSF OR (F1 = NIL) THEN
  333. key := sum; newSF := TRUE; Files.Set(R, F, 4); Files.WriteLInt(R, sum); Files.Register(F) (*insert checksum*)
  334. ELSE ORS.Mark("new symbol file inhibited")
  335. END
  336. ELSE newSF := FALSE; key := sum
  337. END
  338. ELSE newSF := FALSE; ORS.Mark("symbol file not opened")
  339. END
  340. END Export;
  341. PROCEDURE Init*;
  342. BEGIN topScope := universe; nofmod := 1
  343. END Init;
  344. PROCEDURE type (ref, form: INTEGER; size: LONGINT): Type;
  345. VAR tp: Type;
  346. BEGIN NEW(tp); tp.form := form; tp.size := size; tp.ref := ref; tp.base := NIL;
  347. typtab[ref] := tp; RETURN tp
  348. END type;
  349. PROCEDURE enter ((*IN*) name: ARRAY OF CHAR; cl: INTEGER; type: Type; n: LONGINT);
  350. VAR obj: Object;
  351. BEGIN NEW(obj);
  352. (* obj.name := name; *) COPY(name, obj.name);
  353. obj.class := cl; obj.type := type; obj.val := n; obj.dsc := NIL;
  354. IF cl = Typ THEN type.typobj := obj END ;
  355. obj.next := system; system := obj
  356. END enter;
  357. BEGIN
  358. byteType := type(Byte, Int, 1);
  359. boolType := type(Bool, Bool, 1);
  360. charType := type(Char, Char,1);
  361. intType := type(Int, Int, 4);
  362. realType := type(Real, Real, 4);
  363. setType := type(Set, Set,4);
  364. nilType := type(NilTyp, NilTyp, 4);
  365. noType := type(NoTyp, NoTyp, 4);
  366. strType := type(String, String, 8);
  367. (*initialize universe with data types and in-line procedures;
  368. LONGINT is synonym to INTEGER, LONGREAL to REAL.
  369. LED, ADC, SBC; LDPSR, LDREG, REG, COND are not in language definition*)
  370. system := NIL; (*n = procno*10 + nofpar*)
  371. enter("UML", SFunc, intType, 132); (*functions*)
  372. enter("SBC", SFunc, intType, 122);
  373. enter("ADC", SFunc, intType, 112);
  374. enter("ROR", SFunc, intType, 92);
  375. enter("ASR", SFunc, intType, 82);
  376. enter("LSL", SFunc, intType, 72);
  377. enter("LEN", SFunc, intType, 61);
  378. enter("CHR", SFunc, charType, 51);
  379. enter("ORD", SFunc, intType, 41);
  380. enter("FLT", SFunc, realType, 31);
  381. enter("FLOOR", SFunc, intType, 21);
  382. enter("ODD", SFunc, boolType, 11);
  383. enter("ABS", SFunc, intType, 1);
  384. enter("LED", SProc, noType, 81); (*procedures*)
  385. enter("UNPK", SProc, noType, 72);
  386. enter("PACK", SProc, noType, 62);
  387. enter("NEW", SProc, noType, 51);
  388. enter("ASSERT", SProc, noType, 41);
  389. enter("EXCL", SProc, noType, 32);
  390. enter("INCL", SProc, noType, 22);
  391. enter("DEC", SProc, noType, 11);
  392. enter("INC", SProc, noType, 1);
  393. enter("SET", Typ, setType, 0); (*types*)
  394. enter("BOOLEAN", Typ, boolType, 0);
  395. enter("BYTE", Typ, byteType, 0);
  396. enter("CHAR", Typ, charType, 0);
  397. enter("LONGREAL", Typ, realType, 0);
  398. enter("REAL", Typ, realType, 0);
  399. enter("LONGINT", Typ, intType, 0);
  400. enter("INTEGER", Typ, intType, 0);
  401. topScope := NIL; OpenScope; topScope.next := system; universe := topScope;
  402. system := NIL; (* initialize "unsafe" pseudo-module SYSTEM*)
  403. enter("H", SFunc, intType, 201); (*functions*)
  404. enter("COND", SFunc, boolType, 191);
  405. enter("SIZE", SFunc, intType, 181);
  406. enter("ADR", SFunc, intType, 171);
  407. enter("VAL", SFunc, intType, 162);
  408. enter("REG", SFunc, intType, 151);
  409. enter("BIT", SFunc, boolType, 142);
  410. enter("LDREG", SProc, noType, 142); (*procedures*)
  411. enter("LDPSR", SProc, noType, 131);
  412. enter("COPY", SProc, noType, 123);
  413. enter("PUT", SProc, noType, 112);
  414. enter("GET", SProc, noType, 102);
  415. END O7B.