lspker.pas 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270
  1. (* include following two lines for terak *)
  2. (* [$s+] *) (* swapping mode to manage this large file *)
  3. (* [$g+] *) (* goto is legal *)
  4. PROGRAM Paslsp(symin, input, output);
  5. (************************************************************)
  6. (* this file contains global data declarations and *)
  7. (* function definitions to support a sub-standard lisp *)
  8. (* system. it is used with a compiler which compiles lisp *)
  9. (* to pascal source code. this file is divided into the *)
  10. (* following sections: *)
  11. (* 1. constant, type & global variable declarations. *)
  12. (* 2. lisp item selectors & constructors - these are *)
  13. (* the functions which know about the internal *)
  14. (* (pascal) representation of lisp data primitives. *)
  15. (* currently these are: integers (-4096..4095), *)
  16. (* characters, dotted pairs, identifiers, *)
  17. (* code pointers, error conditions, large integers & *)
  18. (* floating point numbers (most hooks exist). *)
  19. (* 3. stack allocation - variables local to a function *)
  20. (* are kept on a stack. *)
  21. (* 4. the garbage collector. *)
  22. (* 5. identifier lookup & entry - symbol table *)
  23. (* management. *)
  24. (* 6. standard lisp functions - pascal implementations *)
  25. (* taking lisp items as arguments and returning a *)
  26. (* lisp item. more standard lisp functions are found *)
  27. (* in lspfns.red. *)
  28. (* 7. i/o primitives (not callable from lisp functions).*)
  29. (* 8. a lisp callable token scanner. *)
  30. (* 9. initialization. *)
  31. (* 10. apply *)
  32. (************************************************************)
  33. (* symin is input channel one--used to initialize "symbol *)
  34. (* table". input is input channel two--standard input. *)
  35. (* output is output channel one--the standard output. *)
  36. (************************************************************)
  37. (* written by martin l. griss, william f. galway and *)
  38. (* ralph ottenheimer. *)
  39. (* last changed 16 june 1981 *)
  40. (************************************************************)
  41. CONST
  42. (* constants relating to input / output *)
  43. sp = ' ';
  44. nul = 0; (* ascii codes *)
  45. ht = 9;
  46. lf = 10;
  47. cr = 13;
  48. inchns = 2; (* number of input channels. *)
  49. outchns = 1; (* number of output channels. *)
  50. eofcode = 26; (* magic character code for eof, ascii for *)
  51. (* cntrl-z. kludge, see note in rdtok. *)
  52. choffset = 1; (* add choffset to ascii code to get address *)
  53. (* in id space for corresponding identifier. *)
  54. eos = nul; (* terminator character for strings. *)
  55. (* constants relating to the token scanner *)
  56. toktype = 129; (* slot in idspace for toktype. *)
  57. chartype = 3; (* various token types *)
  58. inttype = 1;
  59. idtype = 2;
  60. (* constants relating to lisp data types and their representations. *)
  61. shift_const = 8192; (* tags and info are packed into an integer *)
  62. (* assumed to be at least 16 bits long. low order 13 bits *)
  63. (* are the info, top 3 are the tag. *)
  64. int_offset = 4096; (* small integers are stored 0..8191 *)
  65. (* instead of -4096..4095 because it will pack smaller *)
  66. (* under ucsd pascal. *)
  67. end_flag = -1; (* marks end of fixnum free list. *)
  68. (* the various tags - can't use a defined scalar type *)
  69. (* because of the lack of convertion functions. *)
  70. inttag = 0; (* info is an integer *)
  71. chartag = 1; (* info is a character code *)
  72. pairtag = 2; (* info points to pair *)
  73. idtag = 3; (* info points to identifier *)
  74. codetag = 4; (* info is index into a case statement *)
  75. (* that calls appropriate function. *)
  76. errtag = 5; (* info is an error code - see below. *)
  77. fixtag = 6; (* info points to a full word (or *)
  78. (* longer) integer. *)
  79. flotag = 7; (* info points to a float number. *)
  80. (* error codes. corresponding to tag = errtag. *)
  81. noprspace = 1; (* no more "pair space"--can't cons. *)
  82. notpair = 2; (* a pair operation attempted on a non-pair. *)
  83. noidspace = 3; (* no more free identifiers *)
  84. undefined = 4; (* used to mark undefined function cells (etc?) *)
  85. (* constants relating to data space *)
  86. maxpair = 2500; (* max number of pairs allowed. *)
  87. maxident = 400; (* max number of identifiers *)
  88. maxstrsp = 2000; (* size of string (literal) storage space. *)
  89. maxintsp = 50; (* max number of long integers allowed *)
  90. maxflosp = 2; (* max number of floating numbers allowed *)
  91. maxgcstk = 100; (* size of garbage collection stack. *)
  92. stksize = 500; (* stack size *)
  93. (* constants relating to the symbol table. *)
  94. hidmax = 50; (* number of hash values for identifiers *)
  95. nillnk = 0; (* when integers are used as pointers. *)
  96. TYPE
  97. onechar = char;
  98. (* note we allow zero for id_ptr, allowing a "nil" link. *)
  99. stringp = 1..maxstrsp; (* pointer into string space. *)
  100. id_ptr = 0..maxident; (* pointer into id space. *)
  101. any = integer; (* your basic lisp item *)
  102. itemtype = 0..7; (* the tags *)
  103. pair = PACKED RECORD
  104. prcar: any;
  105. prcdr: any;
  106. markflg: boolean; (* for garbage collection *)
  107. END;
  108. ascfile = PACKED FILE OF onechar;
  109. ident = PACKED RECORD (* identifier *)
  110. idname: stringp;
  111. val: any; (* value *)
  112. plist: any; (* property list *)
  113. funcell: any; (* function cell *)
  114. idhlink: id_ptr; (* hash link *)
  115. END;
  116. longint = integer; (* use integer[n] on terak *)
  117. VAR
  118. (* global information *)
  119. xnil, t: any; (* refers to identifiers "nil", and "t". *)
  120. junk: any; (* global to hold uneeded function results *)
  121. old_binds: any; (* saved fluid bindings *)
  122. (* "st" is the stack pointer into "stk". it counts the number of *)
  123. (* items on the stack, so it runs from zero while the stack starts *)
  124. (* at one. *)
  125. st: 0..stksize;
  126. stk: ARRAY[1..stksize] OF any;
  127. (* pair space *)
  128. prspace: PACKED ARRAY[1..maxpair] OF pair; (* all pairs stored here. *)
  129. freepair: integer; (* pointer to next free pair in prspace. *)
  130. (* identifier space *)
  131. idhead: ARRAY[0..hidmax] OF id_ptr;
  132. idspace: PACKED ARRAY[1..maxident] OF ident;
  133. freeident: integer;
  134. (* string space *)
  135. strspace: PACKED ARRAY[1..maxstrsp] OF onechar;
  136. freestr: stringp;
  137. (* large integer space *)
  138. intspace: ARRAY[1..maxintsp] OF longint;
  139. freeint: 1..maxintsp;
  140. (* floating point number space *)
  141. flospace: ARRAY[1..maxflosp] OF real;
  142. freefloat: 1..maxflosp;
  143. (* i/o channels *)
  144. symin: ascfile;
  145. input: ascfile; (* comment out for terak. *)
  146. inchnl: 1..inchns; (* current input channel number *)
  147. outchnl: 1..outchns; (* current output channel number *)
  148. (* "current character" for each input channel. *)
  149. (* may want to include more than one character at some later date *)
  150. (* (for more lookahead). *)
  151. ichrbuf: ARRAY[1..inchns] OF onechar;
  152. (* for collecting statistics. *)
  153. gccount: integer; (* counts garbage collections *)
  154. (* counts from last garbage collection. *)
  155. consknt: integer; (* number of times "cons" called *)
  156. pairknt: integer; (* number of pairs created *)
  157. (********************************************************)
  158. (* *)
  159. (* item selectors & constructors *)
  160. (* *)
  161. (********************************************************)
  162. FUNCTION Truep(predicate: any): boolean;
  163. BEGIN (* truep *)
  164. Truep := predicate <> xnil
  165. END (* truep *);
  166. FUNCTION Falsep(predicate: any): boolean;
  167. BEGIN (* Falsep *)
  168. Falsep := predicate = xnil
  169. END (* Falsep *);
  170. FUNCTION Tag_of(item: any): itemtype;
  171. BEGIN (* tag_of *)
  172. Tag_of := item DIV shift_const;
  173. END;
  174. (* tag_of *)
  175. FUNCTION Info_of(item: any): integer;
  176. BEGIN (* info_of *)
  177. IF item DIV shift_const = inttag THEN
  178. Info_of := item MOD shift_const - int_offset
  179. ELSE
  180. Info_of := item MOD shift_const
  181. END;
  182. (* info_of *)
  183. FUNCTION Mkitem(tag: itemtype; info: longint): any;
  184. (* do range checking on info. ints run from -4096 to +4095 *)
  185. (* everything else runs from 0 to 8191. ints & chars *)
  186. (* contain their info, all others points into an *)
  187. (* appropriate space. *)
  188. BEGIN (* mkitem *)
  189. IF info < 0 THEN (* this check probably not necessary *)
  190. Writeln('*****MKITEM: BAD NEG');
  191. (* pack tag and info into 16-bit item. *)
  192. Mkitem := tag * shift_const + info
  193. END (* mkitem *);
  194. PROCEDURE Set_info(VAR item: any; newinfo: longint);
  195. BEGIN (* set_info *)
  196. item := Mkitem(Tag_of(item), newinfo)
  197. END;
  198. (* set_info *)
  199. PROCEDURE Set_tag(VAR item: any; newtag: itemtype);
  200. BEGIN (* set_tag *)
  201. item := Mkitem(newtag, Info_of(item))
  202. END;
  203. (* set_tag *)
  204. FUNCTION Mkident(id: integer): any;
  205. BEGIN (* mkident *)
  206. Mkident := Mkitem(idtag, id);
  207. END;
  208. (* mkident *)
  209. FUNCTION Car(u: any): any; FORWARD;
  210. FUNCTION Cdr(u: any): any; FORWARD;
  211. FUNCTION Pairp(item: any): any; FORWARD;
  212. FUNCTION Mkfixint(fixint: longint): any;
  213. VAR p: integer;
  214. PROCEDURE Gc_int; (* Garbage collect large integer space. *)
  215. VAR i: integer;
  216. mark_flag: PACKED ARRAY[1..maxintsp] OF boolean;
  217. PROCEDURE Mark(u: any);
  218. BEGIN (* mark *)
  219. IF Truep(Pairp(u)) THEN
  220. BEGIN
  221. Mark(Car(u));
  222. Mark(Cdr(u))
  223. END
  224. ELSE IF Tag_of(u) = fixtag THEN
  225. mark_flag[Info_of(u)] := true
  226. END; (* mark *)
  227. BEGIN (* gc_int *)
  228. FOR i := 1 TO maxintsp DO (* clear mark flags *)
  229. mark_flag[i] := false;
  230. FOR i := 1 TO st DO (* mark from the stack *)
  231. Mark(stk[i]);
  232. FOR i := 1 TO maxident DO (* mark from the symbol table *)
  233. BEGIN
  234. Mark(idspace[i].val);
  235. Mark(idspace[i].plist);
  236. Mark(idspace[i].funcell)
  237. END;
  238. (* reconstruct free list *)
  239. FOR i := 1 TO maxintsp - 1 DO
  240. IF NOT mark_flag[i] THEN
  241. BEGIN
  242. intspace[i] := freeint;
  243. freeint := i
  244. END
  245. END; (* gc_int *)
  246. BEGIN (* mkfixint *)
  247. IF intspace[freeint] = end_flag THEN Gc_int;
  248. IF intspace[freeint] <> end_flag THEN (* convert to fixnum *)
  249. BEGIN
  250. p := freeint;
  251. freeint := intspace[freeint];
  252. Mkfixint := Mkitem(fixtag, p);
  253. intspace[p] := fixint
  254. END
  255. ELSE Writeln('*****FIXNUM SPACE EXHAUSTED')
  256. END (* mkfixint *);
  257. FUNCTION Mkint(int: longint): any;
  258. BEGIN (* mkint *)
  259. IF (int < -int_offset) OR (int > int_offset - 1) THEN
  260. Mkint := Mkfixint(int)
  261. ELSE
  262. Mkint := Mkitem(inttag, int + int_offset)
  263. (* int was in range so add offset *)
  264. END (* mkint *);
  265. FUNCTION Mkpair(pr: integer): any;
  266. BEGIN (* mkpair *)
  267. Mkpair := Mkitem(pairtag, pr)
  268. END;
  269. (* mkpair *)
  270. PROCEDURE Int_val(item: any; VAR number: longint);
  271. (* returns integer value of item (int or fixnum). *)
  272. (* must return 'number' in var parameter instead *)
  273. (* of function value since long integers are not *)
  274. (* a legal function type in ucsd pascal. *)
  275. BEGIN (* int_val *)
  276. IF Tag_of(item) = inttag THEN
  277. number := Info_of(item)
  278. ELSE IF Tag_of(item) = fixtag THEN
  279. number := intspace[Info_of(item)]
  280. ELSE Writeln('***** ILLEGAL DATA TYPE FOR NUMERIC OPERATION')
  281. END (* int_val *);
  282. (********************************************************)
  283. (* *)
  284. (* stack allocation *)
  285. (* *)
  286. (********************************************************)
  287. PROCEDURE Alloc(n: integer);
  288. BEGIN
  289. IF n + st <= stksize THEN
  290. st := n+st
  291. ELSE
  292. BEGIN
  293. Writeln('*****LISP STACK OVERFLOW');
  294. Writeln(' TRIED TO ALLOCATE ',n);
  295. Writeln(' CURRENT STACK TOP IS ',st);
  296. END;
  297. END;
  298. PROCEDURE Dealloc(n: integer);
  299. BEGIN
  300. IF st - n >= 0 THEN
  301. st := st - n
  302. ELSE
  303. Writeln('*****LISP STACK UNDERFLOW');
  304. END;
  305. (* optimized allocs *)
  306. PROCEDURE Alloc1;
  307. BEGIN Alloc(1) END;
  308. PROCEDURE Dealloc1;
  309. BEGIN Dealloc(1) END;
  310. PROCEDURE Alloc2;
  311. BEGIN Alloc(2) END;
  312. PROCEDURE Dealloc2;
  313. BEGIN Dealloc(2) END;
  314. PROCEDURE Alloc3;
  315. BEGIN Alloc(3) END;
  316. PROCEDURE Dealloc3;
  317. BEGIN Dealloc(3) END;
  318. (********************************************************)
  319. (* *)
  320. (* the garbage collector *)
  321. (* *)
  322. (********************************************************)
  323. PROCEDURE Faststat;
  324. (* give quick summary of statistics gathered *)
  325. BEGIN
  326. Writeln('CONSES:',consknt);
  327. Writeln('PAIRS :',pairknt);
  328. Writeln('CONSES/PAIRS: ',consknt/pairknt);
  329. Writeln('ST :',st);
  330. END;
  331. PROCEDURE Gcollect;
  332. VAR
  333. i: integer;
  334. markedk: integer; (* counts the number of pairs marked *)
  335. freedk: integer; (* counts the number of pairs freed. *)
  336. gcstkp: 0..maxgcstk; (* note the garbage collection stack *)
  337. mxgcstk: 0..maxgcstk; (* is local to this procedure. *)
  338. gcstk: ARRAY[1..maxgcstk] OF integer;
  339. PROCEDURE Pushref(pr: any);
  340. (* push the address of an unmarked pair, if that's what it is. *)
  341. BEGIN
  342. IF Tag_of(pr) = pairtag THEN
  343. IF NOT prspace[Info_of(pr)].markflg THEN
  344. BEGIN
  345. IF gcstkp < maxgcstk THEN
  346. BEGIN
  347. gcstkp := gcstkp + 1;
  348. gcstk[gcstkp] := Info_of(pr);
  349. IF gcstkp > mxgcstk THEN
  350. mxgcstk := gcstkp;
  351. END
  352. ELSE
  353. Writeln('*****GARBAGE STACK OVERFLOW');
  354. (* fatal error *)
  355. END;
  356. END;
  357. PROCEDURE Mark;
  358. (* "recursively" mark pairs referred to from gcstk. gcstk is used to *)
  359. (* simulate recursion. *)
  360. VAR
  361. prloc: integer;
  362. BEGIN
  363. WHILE gcstkp > 0 DO
  364. BEGIN
  365. prloc := gcstk[gcstkp];
  366. gcstkp := gcstkp - 1;
  367. prspace[prloc].markflg := true;
  368. Pushref(prspace[prloc].prcdr);
  369. Pushref(prspace[prloc].prcar); (* trace the car first. *)
  370. END;
  371. END;
  372. BEGIN (* gcollect *)
  373. Writeln('***GARBAGE COLLECTOR CALLED');
  374. gccount := gccount + 1; (* count garbage collections. *)
  375. Faststat; (* give summary of statistics collected *)
  376. consknt := 0; (* clear out the cons/pair counters *)
  377. pairknt := 0;
  378. gcstkp := 0; (* initialize the garbage stack pointer. *)
  379. mxgcstk := 0; (* keeps track of max stack depth. *)
  380. (* mark things from the "computation" stack. *)
  381. FOR i := 1 TO st DO
  382. BEGIN
  383. Pushref(stk[i]);
  384. Mark;
  385. END;
  386. (* mark things from identifier space. *)
  387. FOR i := 1 TO maxident DO
  388. BEGIN
  389. Pushref(idspace[i].val);
  390. Mark;
  391. Pushref(idspace[i].plist);
  392. Mark;
  393. Pushref(idspace[i].funcell);
  394. Mark;
  395. END;
  396. (* reconstruct free list by adding things to the head. *)
  397. freedk := 0;
  398. markedk := 0;
  399. FOR i:= 1 TO maxpair - 1 DO
  400. BEGIN
  401. IF prspace[i].markflg THEN
  402. BEGIN
  403. markedk := markedk + 1;
  404. prspace[i].markflg := false
  405. END
  406. ELSE
  407. BEGIN
  408. prspace[i].prcar := xnil;
  409. prspace[i].prcdr := Mkitem(pairtag, freepair);
  410. freepair := i;
  411. freedk := freedk + 1
  412. END
  413. END (* for *);
  414. Writeln(freedk,' PAIRS FREED.');
  415. Writeln(markedk,' PAIRS IN USE.');
  416. Writeln('MAX GC STACK WAS ',mxgcstk);
  417. END (* gcollect *);
  418. (********************************************************)
  419. (* *)
  420. (* identifier lookup & entry *)
  421. (* *)
  422. (********************************************************)
  423. FUNCTION Nmhash(nm: stringp): integer;
  424. CONST
  425. hashc = 256;
  426. VAR
  427. i,tmp: integer;
  428. BEGIN
  429. tmp := 0;
  430. i := 1; (* get hash code from first three chars of string. *)
  431. WHILE (i <= 3) AND (strspace[nm+i] <> Chr(eos)) DO
  432. BEGIN
  433. tmp := Ord(strspace[nm+i]) + hashc*tmp;
  434. i := i + 1;
  435. END;
  436. Nmhash := Abs(tmp) MOD hidmax; (* abs because mod is screwy. *)
  437. END;
  438. FUNCTION Eqstr(s1,s2: stringp): boolean;
  439. BEGIN
  440. WHILE (strspace[s1] = strspace[s2]) AND (strspace[s1] <> Chr(eos)) DO
  441. BEGIN
  442. s1 := s1 + 1;
  443. s2 := s2 + 1;
  444. END;
  445. Eqstr := (strspace[s1] = strspace[s2]);
  446. END;
  447. PROCEDURE Nmlookup(nm: stringp; VAR found: boolean; VAR hash: integer;
  448. VAR loc: any);
  449. (* lookup a name in "identifier space". *)
  450. (* "hash" returns the hash value for the name. *)
  451. (* "loc" returns the location in the space for the (possibly new) *)
  452. (* identifier. *)
  453. BEGIN
  454. hash := Nmhash(nm);
  455. loc := Mkitem(idtag, idhead[hash]);
  456. (* default is identifier, but may be "error". *)
  457. (* start at appropriate hash chain. *)
  458. found := false;
  459. WHILE (Info_of(loc) <> nillnk) AND (NOT found) DO
  460. BEGIN
  461. found := Eqstr(nm, idspace[Info_of(loc)].idname);
  462. IF NOT found THEN
  463. Set_info(loc, idspace[Info_of(loc)].idhlink);
  464. (* next id in chain *)
  465. END;
  466. IF NOT found THEN (* find spot for new identifier *)
  467. BEGIN
  468. IF freeident=nillnk THEN (* no more free identifiers. *)
  469. loc := Mkitem(errtag, noidspace)
  470. ELSE
  471. BEGIN
  472. Set_info(loc, freeident);
  473. freeident := idspace[freeident].idhlink;
  474. END;
  475. END;
  476. END;
  477. PROCEDURE Putnm(nm: stringp; VAR z: any; VAR found: boolean);
  478. (* put a new name into identifier space, or return old location *)
  479. (* if it's already there. *)
  480. VAR
  481. tmp: ident;
  482. hash: integer;
  483. BEGIN
  484. Nmlookup(nm, found, hash, z);
  485. IF (NOT found) AND (Tag_of(z) = idtag) THEN
  486. BEGIN
  487. tmp.idname := nm;
  488. tmp.idhlink := idhead[hash]; (* put new ident at head of chain *)
  489. tmp.val := xnil; (* initialize value and property list *)
  490. tmp.plist := xnil;
  491. tmp.funcell := xnil; (* also, the function cell *)
  492. idhead[hash] := Info_of(z);
  493. idspace[Info_of(z)] := tmp;
  494. END;
  495. END;
  496. (********************************************************)
  497. (* *)
  498. (* standard lisp functions *)
  499. (* *)
  500. (********************************************************)
  501. (* the following standard lisp functions appear in *)
  502. (* lspfns.red: reverse, append, memq, atsoc, get, *)
  503. (* put, remprop, eq, null, equal, error, errorset, *)
  504. (* abs, idp, numberp, atom, minusp, eval, apply, *)
  505. (* evlis, prin1, print, prin2t, list2 ... list5. *)
  506. FUNCTION Setq(VAR u: any; v: any): any;
  507. BEGIN (* setq *)
  508. (* should check to make sure u not t or nil. *)
  509. u := v;
  510. Setq := v
  511. END (* setq *);
  512. FUNCTION Atom(item : any): any;
  513. BEGIN (* atom *)
  514. IF Tag_of(item) <> pairtag THEN Atom := t
  515. ELSE Atom := xnil
  516. END (* atom *);
  517. FUNCTION Codep(item: any): any;
  518. BEGIN (* codep *)
  519. IF Tag_of(item) = codetag THEN Codep := t
  520. ELSE Codep := xnil
  521. END (* codep *);
  522. FUNCTION Idp(item: any): any;
  523. BEGIN (* idp *)
  524. IF Tag_of(item) = idtag THEN Idp := t
  525. ELSE Idp := xnil
  526. END (* idp *);
  527. FUNCTION Pairp(*item: any): any*);
  528. BEGIN (* pairp *)
  529. IF Tag_of(item) = pairtag THEN Pairp := t
  530. ELSE Pairp := xnil
  531. END (* pairp *);
  532. FUNCTION Constantp(item: any): any;
  533. BEGIN (* constantp *)
  534. IF NOT((Pairp(item) = t) OR (Idp(item) = t)) THEN
  535. Constantp := t
  536. ELSE Constantp := xnil
  537. END (* constantp *);
  538. FUNCTION Eq(u, v: any): any;
  539. BEGIN (* eq *)
  540. IF u = v THEN Eq := t
  541. ELSE Eq := xnil
  542. END (* eq *);
  543. FUNCTION Eqn(u, v: any): any;
  544. VAR i, j: longint;
  545. BEGIN (* eqn *)
  546. Int_val(u, i);
  547. Int_val(v, j);
  548. IF i = j THEN Eqn := t
  549. ELSE Eqn := xnil
  550. END (* eqn *);
  551. FUNCTION Fixp(item: any): any;
  552. BEGIN (* fixp *)
  553. IF (Tag_of(item) = inttag) OR (Tag_of(item) = fixtag) THEN
  554. Fixp := t
  555. ELSE Fixp := xnil
  556. END (* fixp *);
  557. FUNCTION Floatp(item: any): any;
  558. BEGIN (* floatp *)
  559. IF Tag_of(item) = flotag THEN Floatp := t
  560. ELSE Floatp := xnil
  561. END (* floatp *);
  562. FUNCTION Numberp(item: any): any;
  563. BEGIN (* numberp *)
  564. Numberp := Fixp(item) (* will have to fix for floats *)
  565. END (* numberp *);
  566. FUNCTION Cons(u, v: any): any;
  567. VAR p: integer;
  568. BEGIN (* cons *)
  569. (* push args onto stack, in case we need to garbage collect the *)
  570. (* references will be detected. *)
  571. Alloc(2);
  572. stk[st] := u;
  573. stk[st-1] := v;
  574. IF prspace[freepair].prcdr = xnil THEN Gcollect;
  575. p := freepair;
  576. freepair := Info_of(prspace[p].prcdr);
  577. prspace[p].prcar := u;
  578. prspace[p].prcdr := v;
  579. Cons := Mkpair(p); (* return new pair. *)
  580. consknt := consknt + 1;
  581. Dealloc(2);
  582. END (* cons *);
  583. FUNCTION Ncons(u: any): any;
  584. BEGIN
  585. Ncons := Cons(u, xnil)
  586. END;
  587. FUNCTION Xcons(u, v: any): any;
  588. BEGIN
  589. Xcons := Cons(v, u)
  590. END;
  591. FUNCTION Car(*u: any): any*);
  592. BEGIN
  593. IF Tag_of(u) = pairtag THEN
  594. Car := prspace[Info_of(u)].prcar
  595. ELSE
  596. Car := Mkitem(errtag, notpair);
  597. END;
  598. FUNCTION Cdr(*u: any): any*);
  599. BEGIN
  600. IF Tag_of(u) = pairtag THEN
  601. Cdr := prspace[Info_of(u)].prcdr
  602. ELSE
  603. Cdr := Mkitem(errtag, notpair);
  604. END;
  605. (* fluid binding *)
  606. FUNCTION Push_bind(bind: any): any;
  607. BEGIN (* push_bind *)
  608. old_binds := cons(bind, old_binds);
  609. push_bind := xnil
  610. END (* push_bind *);
  611. FUNCTION Lam_bind(alist: any): any;
  612. VAR bind: any;
  613. BEGIN (* lam_bind *)
  614. WHILE Truep(Pairp(alist)) DO
  615. BEGIN
  616. bind := Car(alist);
  617. alist := Cdr(alist);
  618. push_bind(bind);
  619. setvalue(Car(bind), Cdr(bind))
  620. END;
  621. Lam_bind := xnil
  622. END (* lam_bind *);
  623. FUNCTION Prog_bind(id: any): any;
  624. BEGIN (* prog_bind *)
  625. Prog_bind := Lam_bind(cons(id, xnil))
  626. END (* prog_bind *);
  627. FUNCTION Unbind(id: any): any;
  628. BEGIN (* unbind *)
  629. setvalue(id, cdr(atsoc(id, old_binds)))
  630. Unbind := xnil
  631. END (* unbind *);
  632. (* arithmetic functions *)
  633. FUNCTION Add1(i: any): any;
  634. VAR j: longint;
  635. BEGIN
  636. Int_val(i, j);
  637. Add1 := Mkint(j + 1)
  638. END;
  639. FUNCTION Difference(i, j: any): any;
  640. VAR i1, i2: longint;
  641. BEGIN
  642. Int_val(i, i1);
  643. Int_val(j, i2);
  644. Difference := Mkint(i1 - i2)
  645. END;
  646. FUNCTION Divide(i, j: any): any;
  647. (* returns dotted pair (quotient . remainder). *)
  648. VAR i1, i2: longint;
  649. BEGIN
  650. Int_val(i, i1);
  651. Int_val(j, i2);
  652. IF i2 = 0 THEN Writeln('***** ATTEMPT TO DIVIDE BY 0 IN DIVIDE');
  653. Divide := Cons(Mkint(i1 DIV i2), Mkint(i1 MOD i2))
  654. END;
  655. FUNCTION Greaterp(i, j: any): any;
  656. VAR i1, i2: longint;
  657. BEGIN
  658. Int_val(i, i1);
  659. Int_val(j, i2);
  660. IF i1 > i2 THEN
  661. Greaterp := t
  662. ELSE
  663. Greaterp := xnil;
  664. END;
  665. FUNCTION Lessp(i, j: any): any;
  666. VAR i1, i2: longint;
  667. BEGIN
  668. Int_val(i, i1);
  669. Int_val(j, i2);
  670. IF i1 < i2 THEN
  671. Lessp := t
  672. ELSE
  673. Lessp := xnil;
  674. END;
  675. FUNCTION Minus(i: any): any;
  676. VAR j: longint;
  677. BEGIN
  678. Int_val(i, j);
  679. Minus := Mkint(-j)
  680. END;
  681. FUNCTION Plus2(i, j: any): any;
  682. VAR i1, i2: longint;
  683. BEGIN
  684. Int_val(i, i1);
  685. Int_val(j, i2);
  686. Plus2 := Mkint(i1 + i2)
  687. END;
  688. FUNCTION Quotient(i, j: any): any;
  689. VAR i1, i2: longint;
  690. BEGIN
  691. Int_val(i, i1);
  692. Int_val(j, i2);
  693. IF i2 = 0 THEN Writeln('***** ATTEMPT TO DIVIDE BY 0 IN QUOTIENT');
  694. Quotient := Mkint(i1 DIV i2)
  695. END;
  696. FUNCTION Remainder(i, j: any): any;
  697. VAR i1, i2: longint;
  698. BEGIN
  699. Int_val(i, i1);
  700. Int_val(j, i2);
  701. IF i2 = 0 THEN Writeln('***** ATTEMPT TO DIVIDE BY 0 IN REMAINDER');
  702. Remainder := Mkint(i1 MOD i2)
  703. END;
  704. FUNCTION Times2(i, j: any): any;
  705. VAR i1, i2: longint;
  706. BEGIN
  707. Int_val(i, i1);
  708. Int_val(j, i2);
  709. Times2 := Mkint(i1 * i2)
  710. END;
  711. (* times2 *)
  712. (* symbol table support *)
  713. FUNCTION Value(u: any): any;
  714. BEGIN (* value *)
  715. Value := idspace[Info_of(u)].val
  716. END (* value *);
  717. FUNCTION Plist(u: any): any;
  718. BEGIN (* plist *)
  719. Plist := idspace[Info_of(u)].plist
  720. END (* plist *);
  721. FUNCTION Funcell(u: any): any;
  722. BEGIN (* funcell *)
  723. Funcell := idspace[Info_of(u)].funcell
  724. END (* funcell *);
  725. FUNCTION Setplist(u, v: any): any;
  726. BEGIN (* setplist *)
  727. END (* setplist *);
  728. (* also need setvalue, setfuncell, setplist. *)
  729. FUNCTION Xnot(u: any): any;
  730. BEGIN (* xnot *)
  731. Xnot := Eq(u, xnil)
  732. END (* xnot *);
  733. (********************************************************)
  734. (* *)
  735. (* i/o primitives *)
  736. (* *)
  737. (********************************************************)
  738. PROCEDURE Terpri;
  739. (* need to change for multiple output channels. *)
  740. BEGIN
  741. Writeln(output);
  742. END;
  743. PROCEDURE Wrtok(u: any);
  744. (* doesn't expand escaped characters in identifier names *)
  745. VAR i: integer;
  746. BEGIN
  747. IF Tag_of(u) = inttag THEN
  748. IF Info_of(u) = 0 THEN
  749. Write('0')
  750. ELSE
  751. Write(Info_of(u): 2+Trunc(Log(Abs(Info_of(u)))))
  752. ELSE IF Tag_of(u) = fixtag THEN
  753. Write(intspace[Info_of(u)])
  754. ELSE IF Tag_of(u) = flotag THEN
  755. Write(flospace[Info_of(u)])
  756. ELSE IF Tag_of(u) = idtag THEN
  757. BEGIN
  758. i := idspace[Info_of(u)].idname;
  759. WHILE (i <= maxstrsp) AND (strspace[i] <> Chr(eos)) DO
  760. BEGIN
  761. Write(strspace[i]);
  762. i:= i + 1;
  763. END;
  764. END
  765. ELSE IF Tag_of(u) = chartag THEN
  766. Write(Chr(Info_of(u) - choffset))
  767. ELSE
  768. Writeln('WRTOK GIVEN ',Tag_of(u), Info_of(u));
  769. END;
  770. PROCEDURE Rdchnl(chnlnum: integer; VAR ch: onechar);
  771. BEGIN
  772. IF (chnlnum < 1) OR (chnlnum > inchns) THEN
  773. Writeln('*****BAD INPUT CHANNEL FOR RDCHNL')
  774. ELSE
  775. CASE chnlnum OF
  776. 1: BEGIN
  777. ch := symin^; (* a little strange, but avoids *)
  778. Get(symin); (* initialization problems *)
  779. ichrbuf[inchnl] := symin^;
  780. END;
  781. 2: BEGIN
  782. ch := input^;
  783. Get(input);
  784. ichrbuf[inchnl] := input^;
  785. END;
  786. END;
  787. (* case *)
  788. END;
  789. (* rdchnl *)
  790. FUNCTION Eofchnl(chnlnum: integer): boolean;
  791. BEGIN
  792. IF (chnlnum < 1) OR (chnlnum > inchns) THEN
  793. Writeln('*****BAD INPUT CHANNEL FOR EOFCHNL')
  794. ELSE
  795. CASE chnlnum OF
  796. 1: Eofchnl := Eof(symin);
  797. 2: Eofchnl := Eof(input);
  798. END;
  799. END;
  800. (********************************************************)
  801. (* *)
  802. (* token scanner *)
  803. (* *)
  804. (********************************************************)
  805. FUNCTION Rdtok: any;
  806. VAR
  807. ch: onechar;
  808. i: integer;
  809. anint: longint;
  810. moreid: boolean;
  811. found: boolean;
  812. token: any; (* the token read *)
  813. FUNCTION Digit(ch: onechar): boolean;
  814. BEGIN
  815. Digit := ( '0' <= ch ) AND ( ch <= '9')
  816. END;
  817. FUNCTION Escalpha(VAR ch: onechar): boolean;
  818. (* test for alphabetic or escaped character. *)
  819. (* note possible side effect. *)
  820. BEGIN (* escalpha *)
  821. IF ( 'A' <= ch ) AND ( ch <= 'Z') THEN
  822. Escalpha := true
  823. ELSE IF ( Ord('A')+32 <= Ord(ch)) AND ( Ord(ch) <= Ord('Z')+32) THEN
  824. Escalpha := true (* lower case alphabetics *)
  825. ELSE IF ch='!' THEN
  826. BEGIN
  827. Rdchnl(inchnl,ch);
  828. Escalpha := true;
  829. END
  830. ELSE
  831. Escalpha := false;
  832. END (* escalpha *);
  833. FUNCTION Alphanum(VAR ch: onechar): boolean;
  834. (* test if escalfa or digit *)
  835. VAR b: boolean;
  836. BEGIN
  837. b := Digit(ch);
  838. IF NOT b THEN b := Escalpha(ch);
  839. Alphanum := b;
  840. END;
  841. FUNCTION Whitesp(ch: onechar): boolean;
  842. BEGIN
  843. (* may want a faster test *)
  844. Whitesp := (ch = sp) OR (Ord(ch) = cr) OR (Ord(ch) = lf)
  845. OR (Ord(ch) = ht) OR (Ord(ch) = nul)
  846. END;
  847. (* reads fixnums...need to read flonums too *)
  848. BEGIN (* rdtok *)
  849. IF NOT Eofchnl(inchnl) THEN
  850. REPEAT (* skip leading white space. *)
  851. Rdchnl(inchnl,ch)
  852. UNTIL (NOT Whitesp(ch)) OR Eofchnl(inchnl);
  853. IF Eofchnl(inchnl) THEN
  854. token := Mkitem(chartag, eofcode + choffset)
  855. (* should really return !$eof!$ *)
  856. ELSE
  857. BEGIN
  858. token := xnil; (* init to something *)
  859. IF Digit(ch) THEN
  860. Set_tag(token, inttag)
  861. ELSE IF Escalpha(ch) THEN
  862. Set_tag(token, idtag)
  863. ELSE
  864. Set_tag(token, chartag);
  865. CASE Tag_of(token) OF
  866. chartag: BEGIN
  867. Set_tag(token, idtag);
  868. idspace[toktype].val := Mkitem(inttag, chartype);
  869. Set_info(token, Ord(ch) + choffset);
  870. END;
  871. inttag: BEGIN
  872. idspace[toktype].val := Mkitem(inttag, inttype);
  873. anint := Ord(ch) - Ord('0');
  874. WHILE Digit(ichrbuf[inchnl]) DO
  875. BEGIN
  876. Rdchnl(inchnl,ch);
  877. anint := 10 * anint + (Ord(ch) - Ord('0'))
  878. END;
  879. Set_info(token, anint)
  880. END;
  881. idtag: BEGIN
  882. idspace[toktype].val := Mkitem(inttag, idtype);
  883. i := freestr; (* point to possible new string *)
  884. moreid := true;
  885. WHILE (i < maxstrsp) AND moreid DO
  886. BEGIN
  887. strspace[i] := ch;
  888. i := i + 1;
  889. moreid := Alphanum(ichrbuf[inchnl]);
  890. IF moreid THEN
  891. Rdchnl(inchnl,ch);
  892. END;
  893. strspace[i] := Chr(eos); (* terminate string *)
  894. IF (i >= maxstrsp) THEN
  895. Writeln('*****STRING SPACE EXHAUSTED')
  896. ELSE (* look the name up, return item for it *)
  897. BEGIN
  898. Putnm(freestr, token, found);
  899. IF NOT found THEN
  900. freestr := i + 1;
  901. END;
  902. END;
  903. (* of case idtag *)
  904. END;
  905. (* of case *)
  906. END;
  907. Rdtok := token
  908. END;
  909. (* rdtok *)
  910. (********************************************************)
  911. (* *)
  912. (* initialization *)
  913. (* *)
  914. (********************************************************)
  915. FUNCTION Read: any; FORWARD;
  916. PROCEDURE Init;
  917. (* initialization procedure depends on *)
  918. (* ability to load stack with constants *)
  919. (* from a file. *)
  920. VAR
  921. strptr: stringp;
  922. nam: PACKED ARRAY[1..3] OF onechar;
  923. (* holds 'nil', other strings? *)
  924. i, n: integer;
  925. idref: any;
  926. found: boolean;
  927. (* init is divided into two parts so it can compile on terak *)
  928. PROCEDURE Init1;
  929. BEGIN
  930. (* initialize top of stack *)
  931. st := 0;
  932. freefloat := 1;
  933. (* define nil - the id, nil, is defined a little later. *)
  934. freeident := 1;
  935. xnil := Mkitem(idtag, freeident);
  936. (* initialize pair space. *)
  937. FOR i := 1 TO maxpair - 1 DO (* initialize free list. *)
  938. BEGIN
  939. prspace[i].markflg := false; (* redundant? *)
  940. prspace[i].prcar := xnil; (* just for fun *)
  941. prspace[i].prcdr := Mkitem(pairtag, i + 1)
  942. END;
  943. prspace[maxpair].prcar := xnil;
  944. prspace[maxpair].prcdr := xnil; (* end flag *)
  945. freepair := 1; (* point to first free pair *)
  946. (* initialize identifier space and string space. *)
  947. freestr := 1;
  948. FOR i := 0 TO hidmax - 1 DO
  949. idhead[i] := nillnk;
  950. FOR i := 1 TO maxident DO
  951. BEGIN
  952. IF i < maxident THEN
  953. idspace[i].idhlink := i + 1
  954. ELSE (* nil to mark the final identifier in the table. *)
  955. idspace[i].idhlink := nillnk;
  956. (* set function cells to undefined *)
  957. idspace[i].funcell := Mkitem(errtag, undefined)
  958. END;
  959. (* nil must be the first identifier in the table--id #1 *)
  960. (* must fill in fields by hand for nil.*)
  961. (* putnm can handle any later additions. *)
  962. nam := 'NIL';
  963. strptr := freestr;
  964. FOR i := 1 TO 3 DO
  965. BEGIN
  966. strspace[strptr] := nam[i];
  967. strptr:= strptr + 1;
  968. END;
  969. strspace[strptr] := Chr(eos);
  970. Putnm(freestr, xnil, found);
  971. IF NOT found THEN
  972. freestr := strptr + 1;
  973. (* make the single character ascii identifiers, except nul(=eos). *)
  974. FOR i := 1 TO 127 DO
  975. BEGIN
  976. strspace[freestr] := Chr(i);
  977. strspace[freestr + 1] := Chr(eos);
  978. Putnm(freestr, idref, found);
  979. IF NOT found THEN
  980. freestr := freestr + 2;
  981. IF i = Ord('T') THEN
  982. t := idref;
  983. (* returns location for 't. *)
  984. END;
  985. (* init fixnum free list. *)
  986. FOR i := 1 TO maxintsp - 1 DO
  987. intspace[i] := i + 1;
  988. intspace[maxintsp] := end_flag;
  989. freeint := 1;
  990. (* clear the counters *)
  991. gccount := 0;
  992. consknt := 0;
  993. pairknt := 0;
  994. END (* init1 *);
  995. PROCEDURE Init2;
  996. VAR token: any;
  997. BEGIN
  998. (* load "symbol table" with identifiers, constants, and functions. *)
  999. inchnl := 1; (* select symbol input file. *)
  1000. (* reset(symin,'#5:poly.data'); *) (* for terak *)
  1001. token := Rdtok; (* get count of identifiers. *)
  1002. IF Tag_of(token) <> inttag THEN
  1003. Writeln('*****BAD SYMBOL TABLE, INTEGER EXPECTED AT START');
  1004. n := Info_of(token);
  1005. FOR i := 1 TO n DO
  1006. token := Rdtok;
  1007. (* reading token magically loads it into id space. *)
  1008. token := Rdtok; (* look for zero terminator. *)
  1009. IF (Tag_of(token) <> inttag) OR (Info_of(token) <> 0) THEN
  1010. Writeln('*****BAD SYMBOL TABLE, ZERO EXPECTED AFTER IDENTIFIERS');
  1011. token := Rdtok; (* count of constants *)
  1012. IF Tag_of(token) <> inttag THEN
  1013. Writeln('*****BAD SYMBOL TABLE, INTEGER EXPECTED BEFORE CONSTANTS');
  1014. n := Info_of(token);
  1015. Alloc(n); (* space for constants on the stack *)
  1016. FOR i := 1 TO n DO
  1017. stk[i] := Read;
  1018. token := Rdtok;
  1019. IF (Tag_of(token) <> inttag) OR (Info_of(token) <> 0) THEN
  1020. Writeln('*****BAD SYMBOL TABLE, ZERO EXPECTED AFTER CONSTANTS');
  1021. token := Rdtok; (* count of functions. *)
  1022. IF Tag_of(token) <> inttag THEN
  1023. Writeln('*****BAD SYMBOL TABLE, INTEGER EXPECTED BEFORE FUNCTIONS');
  1024. n := Info_of(token);
  1025. FOR i := 1 TO n DO
  1026. (* for each function *)
  1027. (* store associated code *)
  1028. idspace[Rdtok].funcell := Mkitem(codetag, i);
  1029. token := Rdtok;
  1030. IF (Tag_of(token) <> inttag) OR (Info_of(token) <> 0) THEN
  1031. Writeln('*****BAD SYMBOL TABLE, ZERO EXPECTED AFTER FUNCTIONS');
  1032. inchnl := 2; (* select standard input. *)
  1033. END (* init2 *);
  1034. BEGIN (* init *)
  1035. Init1;
  1036. Init2;
  1037. END (* init *);
  1038. (********************************************************)
  1039. (* *)
  1040. (* apply *)
  1041. (* *)
  1042. (********************************************************)
  1043. FUNCTION Apply(fn, arglist: any): any;
  1044. VAR arg1, arg2, arg3, arg4, arg5: any;
  1045. numargs: integer;
  1046. BEGIN (* apply *)
  1047. IF Tag_of(fn) <> codetag THEN
  1048. Writeln('*****APPLY: UNDEFINED FUNCTION.')
  1049. ELSE
  1050. BEGIN (* spread the arguments *)
  1051. numargs := 0;
  1052. WHILE Truep(Pairp(arglist)) DO
  1053. BEGIN
  1054. numargs := numargs + 1;
  1055. CASE numargs OF
  1056. 1: arg1 := Car(arglist);
  1057. 2: arg2 := Car(arglist);
  1058. 3: arg3 := Car(arglist);
  1059. 4: arg4 := Car(arglist);
  1060. 5: arg5 := Car(arglist);
  1061. 6: Writeln('APPLY: TOO MANY ARGS SUPPLIED.')
  1062. END (* case *);
  1063. arglist := Cdr(arglist)
  1064. END (* while *)
  1065. END (* if *);
  1066. CASE Info_of(fn) OF
  1067. 1: Apply := Atom(arg1);
  1068. END (* case *)
  1069. END (* apply *);
  1070. (*??* Missing closing point at end of program. *??*)
  1071. (*??* Missing closing point at end of program. *??*)