{+ PASCAL/Z COMPILER OPTIONS +} {++++++++++++++++++++++++++++++++++++++++++++++++++++++++} {$C- <<< CONTROL-C KEYPRESS CHECKING OFF >>> } {$F- <<< FLOATING POINT ERROR CHECKING OFF >>> } {$M- <<< INTEGER MULT & DIVD ERROR CHECKING OFF >>> } {++++++++++++++++++++++++++++++++++++++++++++++++++++++++} PROGRAM LISP {VERSION 1.7}; { + PROGRAM TITLE: THE ESSENCE OF A LISP INTERPRETER. + WRITTEN BY: W. TAYLOR AND L. COX + + WRITTEN FOR: US DEPT OF ENERGY + CONTRACT # W-7405-ENG-48 + + FIRST DATA STARTED : 10/29/76 + LAST DATE MODIFIED : 12/10/76 + + ENTERED BY RAY PENLEY 8 DEC 80. + -SOME IDENTIFIERS HAVE BEEN SLIGHTLY MODIFIED BECAUSE OF THE + LIMITATION ON IDENTIFIER LENGTH OF 8 CHARACTERS. + + MODIFIED BY LANFRANCO EMILIANI IN THE PERIOD MARS-MAY 1983 : + - TO REMOVE THE TWO JUMPS OUT OF PROCEDURES PRESENT IN THE + ZUG VOL # 14 VERSION; + - TO REMOVE TWO BUGS PRESENT IN THAT VERSION; + - TO PROVIDE ADDITIONAL FEATURES. + + REFER TO LISP.DOC FOR A DESCRIPTION OF THE MAIN FEATURES OF THE + INTERPRETER AND HOW TO OPERATE IT. + + REFER TO THE COMMENTS IN THE ZUG VOL # 14 VERSION FOR SPECIFIC + EXPLANATORY NOTES CONCERNING THE MOST SIGNIFICANT PROCEDURES OR + FUNCTIONS. + } LABEL 1, { USED TO RECOVER AFTER AN ERROR BY THE USER } 2; { IN CASE THE END OF FILE IS REACHED BEFORE A FIN CARD } CONST MAXNODE = 1000; {}INPUT = 0; { Pascal/Z = console as input } {}IDLENGTH = 10; TYPE {}ALFA = ARRAY [1..IDLENGTH] OF CHAR; INPUTSYMBOL = (ATOM, PERIOD, LPAREN, RPAREN); RESERVEWORDS = ( ANDSYM, APPENDSYM, ATOMSYM, HEADSYM, TAILSYM, CONDSYM, CONSSYM, COPYSYM, DEFEXPSYM, DEFFEXPSYM, DEFMACSYM, EQSYM, EQUALSYM, EVALSYM, FLAMBDASYM, FUNARGSYM, FUNCTSYM, GOSYM, LABELSYM, LAMBDASYM, LASTSYM, LENGTHSYM, LISTSYM, NOTSYM, NULLSYM, ORSYM, PROGSYM, PROG2SYM, PROGNSYM, QUOTESYM, RELACEHSYM, RELACETSYM, REMOBSYM, RETURNSYM, REVERSESYM, SETSYM, SETQSYM, TRACESYM, UNTRACESYM ); STATUSTYPE = (UNMARKED, LEFT, RIGHT, MARKED); SYMBEXPPTR = ^SYMBOLICEXPRESSION; SYMBOLICEXPRESSION = RECORD STATUS : STATUSTYPE; NEXT : SYMBEXPPTR; CASE ANATOM: BOOLEAN OF TRUE: (NAME: ALFA; CASE ISARESERVEDWORD: BOOLEAN OF TRUE: (RESSYM: RESERVEWORDS)); FALSE: (HEAD, TAIL: SYMBEXPPTR) END; VAR END_FREELIST : BOOLEAN; ERR_COND : BOOLEAN; TRACE_ON : BOOLEAN; NESTCOUNT : INTEGER; { VARIABLES WHICH PASS INFORMATION FROM THE SCANNER TO THE READ ROUTINE } LOOKAHEADSYM, { USED TO SAVE A SYMBOL WHEN WE BACK UP } SYM : INPUTSYMBOL; { THE SYMBOL THAT WAS LAST SCANNED } ID : ALFA; { NAME OF THE ATOM THAT WAS LAST READ } ALREADYPEEKED : BOOLEAN; { TELLS 'NEXTSYM' WHETHER WE HAVE PEEKED } CH : CHAR; { THE LAST CHAR READ FROM INPUT } PTR : SYMBEXPPTR; { POINTER TO THE EXPRESSION BEING EVALUATED } TEMP : SYMBEXPPTR; { THE GLOBAL LISTS OF LISP NODES } FREELIST, { POINTER TO THE LINEAR LIST OF FREE NODES } NODELIST, { POINTER USED TO MAKE A LINEAR SCAN OF ALL} { THE NODES DURING GARBAGE COLLECTION. } ALIST : SYMBEXPPTR;{ POINTER TO THE ASSOCIATION LIST } { TWO NODES WHICH HAVE CONSTANT VALUES } NILNODE, TNODE : SYMBOLICEXPRESSION; { VARIABLES USED TO IDENTIFY ATOMS WITH PRE-DEFINED MEANINGS } RESWORD : RESERVEWORDS; RESERVED : BOOLEAN; RESWORDS : ARRAY [RESERVEWORDS] OF ALFA; FREENODES : INTEGER; { NUMBER OF CURRENTLY FREE NODES KNOWN } NUMBEROFGCS : INTEGER; { # OF GARBAGE COLLECTIONS MADE } INFILE : TEXT; PROCEDURE GARBAGEMAN; PROCEDURE MARK(LIST: SYMBEXPPTR); VAR FATHER, SON, CURRENT: SYMBEXPPTR; BEGIN FATHER := NIL; CURRENT := LIST; SON := CURRENT; WHILE ( CURRENT<>NIL ) DO WITH CURRENT^ DO CASE STATUS OF UNMARKED: IF ( ANATOM ) THEN STATUS := MARKED ELSE IF (HEAD^.STATUS <> UNMARKED) OR (HEAD = CURRENT) THEN IF (TAIL^.STATUS <> UNMARKED) OR (TAIL = CURRENT) THEN STATUS := MARKED ELSE BEGIN STATUS := RIGHT; SON := TAIL; TAIL := FATHER; FATHER := CURRENT; CURRENT := SON END ELSE BEGIN STATUS := LEFT; SON := HEAD; HEAD := FATHER; FATHER := CURRENT; CURRENT := SON END; LEFT: IF ( TAIL^.STATUS <> UNMARKED ) THEN BEGIN STATUS := MARKED; FATHER := HEAD; HEAD := SON; SON := CURRENT END ELSE BEGIN STATUS := RIGHT; CURRENT := TAIL; TAIL := HEAD; HEAD := SON; SON := CURRENT END; RIGHT: BEGIN STATUS := MARKED; FATHER := TAIL; TAIL := SON; SON := CURRENT END; MARKED: CURRENT := FATHER END { OF CASE } END { OF MARK }; PROCEDURE COLLECTFREENODES; VAR TEMP: SYMBEXPPTR; BEGIN { WRITELN(' NUMBER OF FREE NODES BEFORE COLLECTION = ', FREENODES:1, '.'); } FREELIST := NIL; FREENODES := 0; TEMP := NODELIST; WHILE ( TEMP <> NIL ) DO BEGIN IF ( TEMP^.STATUS <> UNMARKED ) THEN TEMP^.STATUS := UNMARKED ELSE BEGIN FREENODES := FREENODES + 1; TEMP^.HEAD := FREELIST; FREELIST := TEMP END; TEMP := TEMP^.NEXT; END {WHILE}; { WRITELN(' NUMBER OF FREE NODES AFTER COLLECTION = ', FREENODES:1,'.'); } END { OF COLLECTFREENODES }; BEGIN{ GARBAGEMAN } NUMBEROFGCS := NUMBEROFGCS + 1; { WRITELN; WRITELN(' GARBAGE COLLECTION. '); WRITELN; } MARK(ALIST); IF ( PTR <> NIL ) THEN MARK(PTR); COLLECTFREENODES END{ OF GARBAGEMAN }; PROCEDURE POP(VAR SPTR: SYMBEXPPTR); LABEL 1; BEGIN IF ( FREELIST = NIL ) THEN BEGIN WRITELN(' NOT ENOUGH SPACE TO EVALUATE THE EXPRESSION.'); END_FREELIST := TRUE; GOTO 1; END; FREENODES := FREENODES - 1; SPTR := FREELIST; FREELIST := FREELIST^.HEAD; 1: END{ OF POP }; PROCEDURE ERROR(NUMBER: INTEGER); BEGIN WRITELN; WRITE(' ERROR ', NUMBER:1, ', '); CASE NUMBER OF 1: WRITELN('ATOM OR LPAREN EXPECTED IN THE S-EXPR.'); 2: WRITELN('ATOM, LPAREN, OR RPAREN EXPECTED IN THE S-EXPR.'); 3: WRITELN('LABEL, LAMBDA, FLAMBDA, ETC. ARE NOT FUNCTIONS NAMES.'); 4: WRITELN('RPAREN EXPECTED IN THE S-EXPR.'); 5: WRITELN('1ST ARGUMENT OF REPLACEH IS AN ATOM.'); 6: WRITELN('1ST ARGUMENT OF REPLACET IS AN ATOM.'); 7: WRITELN('ARGUMENT HEAD IS AN ATOM.'); 8: WRITELN('ARGUMENT TAIL IS AN ATOM.'); 9: WRITELN('1ST ARGUMENT OF APPEND IS NOT A LIST.'); 10: WRITELN('LABEL OR LAMBDA OR FLAMBDA ETC. EXPECTED.'); 11: WRITELN('NAME OF VARIABLE IS NOT AN ATOM.'); 12: WRITELN('ARGUMENT OF LENGTH IS NOT A LIST.'); 13: WRITELN('ARGUMENT OF PROG IS NOT A LIST.'); 14: WRITELN('LOOP IDENTIFIER NOT FOUND.'); END{CASE}; ERR_COND := TRUE END { OF ERROR }; PROCEDURE BACKUPINPUT; BEGIN ALREADYPEEKED := TRUE; LOOKAHEADSYM := SYM; SYM := LPAREN END{ OF BACKUPINPUT }; PROCEDURE NEXTSYM1; VAR I: INTEGER; BEGIN IF ( ALREADYPEEKED ) THEN BEGIN SYM := LOOKAHEADSYM; ALREADYPEEKED := FALSE END ELSE BEGIN WHILE ( CH=' ' ) DO BEGIN IF ( EOLN(INFILE) ) THEN READLN(INFILE); READ(INFILE, CH); END{WHILE}; IF ( CH IN ['(','.',')'] ) THEN BEGIN CASE CH OF '(': SYM := LPAREN; '.': SYM := PERIOD; ')': SYM := RPAREN END{CASE}; IF ( EOLN(INFILE) ) THEN READLN(INFILE); READ(INFILE, CH); END ELSE BEGIN SYM := ATOM; ID := ' '; I := 0; REPEAT I := I + 1; IF ( I < (IDLENGTH+1) ) THEN ID[I] := CH; IF ( EOLN(INFILE) ) THEN READLN(INFILE); READ(INFILE, CH); UNTIL ( CH IN [' ','(','.',')'] ); RESWORD := ANDSYM; WHILE (ID <> RESWORDS[RESWORD]) AND (RESWORD <> UNTRACESYM) DO RESWORD := SUCC(RESWORD); RESERVED := ( ID=RESWORDS[RESWORD] ) END END END{ OF NEXTSYM1 }; PROCEDURE READEXP1(VAR SPTR: SYMBEXPPTR); LABEL 1; VAR NXT: SYMBEXPPTR; BEGIN IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN POP(SPTR); IF END_FREELIST THEN GOTO 1; NXT := SPTR^.NEXT; CASE SYM OF RPAREN, PERIOD: BEGIN ERROR(1); GOTO 1 END; ATOM: WITH SPTR^ DO BEGIN { } ANATOM := TRUE; NAME := ID; ISARESERVEDWORD := RESERVED; IF ( RESERVED ) THEN RESSYM := RESWORD END; LPAREN: WITH SPTR^ DO BEGIN NEXTSYM1; IF ( SYM=PERIOD ) THEN BEGIN ERROR(2); GOTO 1 END ELSE IF ( SYM=RPAREN ) THEN SPTR^ := NILNODE { () = NIL } ELSE BEGIN ANATOM := FALSE; READEXP1(HEAD); NEXTSYM1; IF ( SYM=PERIOD ) THEN BEGIN { ( . ) } NEXTSYM1; READEXP1(TAIL); NEXTSYM1; IF (SYM<>RPAREN) THEN BEGIN ERROR(4); GOTO 1 END END ELSE BEGIN { ( ... ) } BACKUPINPUT; READEXP1(TAIL) END END END{WITH} END{CASE}; SPTR^.NEXT := NXT; END; 1: END{ OF READEXP1 }; PROCEDURE NEXTSYM; VAR I: INTEGER; BEGIN IF ( ALREADYPEEKED ) THEN BEGIN SYM := LOOKAHEADSYM; ALREADYPEEKED := FALSE END ELSE BEGIN WHILE ( CH=' ' ) DO BEGIN IF ( EOLN(INPUT) ) THEN READLN; READ(CH); END{WHILE}; IF ( CH IN ['(','.',')'] ) THEN BEGIN CASE CH OF '(': SYM := LPAREN; '.': SYM := PERIOD; ')': SYM := RPAREN END{CASE}; IF ( EOLN(INPUT) ) THEN READLN; READ(CH); END ELSE BEGIN SYM := ATOM; ID := ' '; I := 0; REPEAT I := I + 1; IF ( I < (IDLENGTH+1) ) THEN ID[I] := CH; IF (EOLN (INPUT) ) THEN READLN; READ(CH); UNTIL ( CH IN [' ','(','.',')'] ); RESWORD := ANDSYM; WHILE (ID <> RESWORDS[RESWORD]) AND (RESWORD <> UNTRACESYM) DO RESWORD := SUCC(RESWORD); RESERVED := ( ID=RESWORDS[RESWORD] ) END END END{ OF NEXTSYM }; PROCEDURE READEXPR(VAR SPTR: SYMBEXPPTR); LABEL 1; VAR NXT: SYMBEXPPTR; BEGIN IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN POP(SPTR); IF END_FREELIST THEN GOTO 1; NXT := SPTR^.NEXT; CASE SYM OF RPAREN, PERIOD: BEGIN ERROR(1); GOTO 1 END; ATOM: WITH SPTR^ DO BEGIN { } ANATOM := TRUE; NAME := ID; ISARESERVEDWORD := RESERVED; IF ( RESERVED ) THEN RESSYM := RESWORD END; LPAREN: WITH SPTR^ DO BEGIN NEXTSYM; IF ( SYM=PERIOD ) THEN BEGIN ERROR(2); GOTO 1 END ELSE IF ( SYM=RPAREN ) THEN SPTR^ := NILNODE { () = NIL } ELSE BEGIN ANATOM := FALSE; READEXPR(HEAD); NEXTSYM; IF ( SYM=PERIOD ) THEN BEGIN { ( . ) } NEXTSYM; READEXPR(TAIL); NEXTSYM; IF (SYM<>RPAREN) THEN BEGIN ERROR(4); GOTO 1 END END ELSE BEGIN { ( ... ) } BACKUPINPUT; READEXPR(TAIL) END END END{WITH} END{CASE}; SPTR^.NEXT := NXT; END; 1: END{ OF READEXPR }; PROCEDURE PRINTNAME(NAME: ALFA); VAR I: INTEGER; BEGIN I := 0; REPEAT I := I + 1; WRITE(NAME[I]) UNTIL (NAME[I]=' ') OR ( I=IDLENGTH ); IF ( I=IDLENGTH ) THEN WRITE(' ') END{ OF PRINTNAME }; PROCEDURE PRINTEXPR(SPTR : SYMBEXPPTR); LABEL 1, 2; BEGIN IF (ERR_COND) OR (END_FREELIST) THEN GOTO 2 ELSE BEGIN IF ( SPTR^.ANATOM ) THEN PRINTNAME(SPTR^.NAME) ELSE BEGIN WRITE('('); 1: PRINTEXPR(SPTR^.HEAD); IF ( SPTR^.TAIL^.ANATOM ) AND ( SPTR^.TAIL^.NAME='NIL ') THEN WRITE(')') ELSE IF ( SPTR^.TAIL^.ANATOM ) THEN BEGIN WRITE('.'); PRINTEXPR(SPTR^.TAIL); WRITE(')') END ELSE BEGIN SPTR := SPTR^.TAIL; GOTO 1 END END END; 2: END{ OF PRINTEXPR }; PROCEDURE TRACENTER(ID : ALFA); VAR J : INTEGER; BEGIN NESTCOUNT := NESTCOUNT + 1; FOR J := 0 TO NESTCOUNT DO WRITE(' '); WRITE('ENTERING : '); FOR J := 1 TO IDLENGTH DO WRITE(ID[J]); WRITELN END{ OF TRACENTER }; PROCEDURE TRACEXIT(ID : ALFA); VAR J : INTEGER; BEGIN FOR J := 0 TO NESTCOUNT DO WRITE(' '); WRITE('EXITING : '); FOR J := 1 TO IDLENGTH DO WRITE(ID[J]); WRITELN; NESTCOUNT := NESTCOUNT - 1 END{ OF TRACEXIT }; FUNCTION EVAL( E : SYMBEXPPTR; VAR ALIST : SYMBEXPPTR ): SYMBEXPPTR; LABEL 1; VAR TEMP, CAROFE, CAAROFE: SYMBEXPPTR; FUNCTION MKATOM(ID : ALFA): SYMBEXPPTR; LABEL 1; VAR TEMP: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('MKATOM '); POP(TEMP); IF END_FREELIST THEN GOTO 1; RESWORD := APPENDSYM; WHILE (ID <> RESWORDS[RESWORD]) AND (RESWORD <> SETQSYM) DO RESWORD := SUCC(RESWORD); RESERVED := ( ID = RESWORDS[RESWORD] ); WITH TEMP^ DO BEGIN ANATOM := TRUE; NAME := ID; ISARESERVEDWORD := RESERVED; IF (RESERVED) THEN RESSYM := RESWORD END; MKATOM := TEMP; 1: IF TRACE_ON THEN TRACEXIT('MKATOM ') END{ OF MKATOM }; FUNCTION REPLACEH(SPTR1, SPTR2: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; BEGIN IF TRACE_ON THEN TRACENTER('REPLACEH '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN IF ( SPTR1^.ANATOM ) THEN BEGIN ERROR(5); GOTO 1 END ELSE SPTR1^.HEAD := SPTR2; REPLACEH := SPTR1; END; 1: IF TRACE_ON THEN TRACEXIT('REPLACEH ') END{ OF REPLACEH }; FUNCTION REPLACET(SPTR1, SPTR2: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; BEGIN IF TRACE_ON THEN TRACENTER('REPLACET '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN IF ( SPTR1^.ANATOM ) THEN BEGIN ERROR(6); GOTO 1 END ELSE SPTR1^.TAIL := SPTR2; REPLACET := SPTR1; END; 1: IF TRACE_ON THEN TRACEXIT('REPLACET ') END{ OF REPLACET }; FUNCTION HEAD(SPTR: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; BEGIN IF TRACE_ON THEN TRACENTER('CAR '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN IF ( SPTR^.ANATOM ) THEN BEGIN ERROR(7); GOTO 1 END ELSE HEAD := SPTR^.HEAD; END; 1: IF TRACE_ON THEN TRACEXIT('CAR ') END{ OF HEAD }; FUNCTION TAIL(SPTR: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; BEGIN IF TRACE_ON THEN TRACENTER('CDR '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN IF ( SPTR^.ANATOM ) THEN BEGIN ERROR(8); GOTO 1 END ELSE TAIL := SPTR^.TAIL; END; 1: IF TRACE_ON THEN TRACEXIT('CDR ') END{ OF TAIL }; FUNCTION CONS(SPTR1, SPTR2: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('CONS '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN POP(TEMP); IF END_FREELIST THEN GOTO 1; TEMP^.ANATOM := FALSE; TEMP^.HEAD := SPTR1; TEMP^.TAIL := SPTR2; CONS := TEMP; END; 1: IF TRACE_ON THEN TRACEXIT('CONS ') END{ OF CONS }; FUNCTION COPY(SPTR: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP, NXT: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('COPY '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN IF ( SPTR^.ANATOM ) THEN BEGIN POP(TEMP); IF END_FREELIST THEN GOTO 1; NXT := TEMP^.NEXT; TEMP^ := SPTR^; TEMP^.NEXT := NXT; COPY := TEMP END ELSE COPY := CONS(COPY(SPTR^.HEAD), COPY(SPTR^.TAIL)); END; 1: IF TRACE_ON THEN TRACEXIT('COPY ') END{ OF COPY }; FUNCTION APPEND(SPTR1, SPTR2: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; BEGIN IF TRACE_ON THEN TRACENTER('APPEND '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN IF ( SPTR1^.ANATOM ) THEN IF ( SPTR1^.NAME<>'NIL ' ) THEN BEGIN ERROR(9); GOTO 1 END ELSE APPEND := SPTR2 ELSE APPEND := CONS(COPY(SPTR1^.HEAD), APPEND(SPTR1^.TAIL,SPTR2)); END; 1: IF TRACE_ON THEN TRACEXIT('APPEND ') END{ OF APPEND }; FUNCTION LIST(SPTR1: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR NILPTR: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('LIST '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN IF NOT SPTR1^.ANATOM THEN LIST := CONS(EVAL(SPTR1^.HEAD, ALIST), LIST(SPTR1^.TAIL)) ELSE BEGIN IF SPTR1^.NAME <> 'NIL ' THEN BEGIN NEW(NILPTR); WITH NILPTR^ DO BEGIN ANATOM := TRUE; NAME := 'NIL ' END {WITH}; LIST := CONS(EVAL(SPTR1, ALIST), NILPTR) END ELSE LIST := SPTR1 END END; 1: IF TRACE_ON THEN TRACEXIT('LIST ') END{ OF LIST }; FUNCTION EQQ(SPTR1, SPTR2: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP, NXT: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('EQ '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN POP(TEMP); IF END_FREELIST THEN GOTO 1; NXT := TEMP^.NEXT; IF ((SPTR1^.ANATOM) AND (SPTR2^.ANATOM) AND (SPTR1^.NAME=SPTR2^.NAME)) OR (SPTR1 = SPTR2) THEN TEMP^ := TNODE ELSE TEMP^ := NILNODE; TEMP^.NEXT := NXT; EQQ := TEMP; END; 1: IF TRACE_ON THEN TRACEXIT('EQ ') END{ OF EQQ }; FUNCTION EQUAL(SPTR1, SPTR2 : SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP, NXT : SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('EQUAL '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN POP(TEMP); IF END_FREELIST THEN GOTO 1; NXT := TEMP^.NEXT; IF (SPTR1^.ANATOM) THEN BEGIN IF (SPTR2^.ANATOM) THEN TEMP := EQQ(SPTR1, SPTR2) ELSE TEMP^ := NILNODE END ELSE BEGIN IF SPTR2^.ANATOM THEN TEMP^ := NILNODE ELSE BEGIN TEMP := EQUAL(HEAD(SPTR1), HEAD(SPTR2)); IF ( TEMP^.NAME = 'T ' ) THEN TEMP := EQUAL(TAIL(SPTR1), TAIL(SPTR2)) ELSE BEGIN TEMP^ := NILNODE END END END; TEMP^.NEXT := NXT; EQUAL := TEMP END; 1: IF TRACE_ON THEN TRACEXIT('EQUAL ') END{ OF EQUAL }; FUNCTION NULL(SPTR : SYMBEXPPTR) : SYMBEXPPTR; LABEL 1; VAR TEMP, NXT : SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('NULL '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN POP(TEMP); IF END_FREELIST THEN GOTO 1; NXT := TEMP^.NEXT; TEMP^ := NILNODE; TEMP^.NEXT := NXT; NULL := EQQ(SPTR, TEMP) END; 1: IF TRACE_ON THEN TRACEXIT('NULL ') END{ OF NULL }; FUNCTION ET(SPTR: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('AND '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN IF (SPTR^.ANATOM) AND (SPTR^.NAME = 'NIL ') THEN ET := MKATOM('T ') ELSE BEGIN TEMP := EVAL(HEAD(SPTR), ALIST); IF (TEMP^.ANATOM) AND (TEMP^.NAME = 'NIL ') THEN ET := TEMP ELSE ET := ET(TAIL(SPTR)) END END; 1: IF TRACE_ON THEN TRACEXIT('AND ') END{ OF ET }; FUNCTION OU(SPTR: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('OR '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN IF (SPTR^.ANATOM) AND (SPTR^.NAME = 'NIL ') THEN OU := SPTR ELSE BEGIN TEMP := EVAL(HEAD(SPTR), ALIST); IF (TEMP^.ANATOM) AND (TEMP^.NAME <> 'NIL ') THEN OU := MKATOM('T ') ELSE OU := OU(TAIL(SPTR)) END END; 1: IF TRACE_ON THEN TRACEXIT('OR ') END{ OF OU }; FUNCTION ATOM(SPTR : SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP, NXT: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('ATOM '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN POP(TEMP); IF END_FREELIST THEN GOTO 1; NXT := TEMP^.NEXT; IF ( SPTR^.ANATOM ) THEN TEMP^ := TNODE ELSE TEMP^ := NILNODE; TEMP^.NEXT := NXT; ATOM := TEMP; END; 1: IF TRACE_ON THEN TRACEXIT('ATOM ') END{ OF ATOM }; FUNCTION LAST(SPTR: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('LAST '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN IF (SPTR^.ANATOM) THEN LAST := SPTR ELSE BEGIN TEMP := TAIL(SPTR); IF (TEMP^.ANATOM) AND (TEMP^.NAME = 'NIL ') THEN LAST := HEAD(SPTR) ELSE LAST := LAST(TEMP) END END; 1: IF TRACE_ON THEN TRACEXIT('LAST ') END{ OF LAST }; FUNCTION REVERSE(SPTR: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('REVERSE '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN TEMP := NULL(SPTR); IF (TEMP^.NAME = 'T ') THEN REVERSE := SPTR ELSE REVERSE := APPEND(REVERSE(TAIL(SPTR)), CONS(HEAD(SPTR), MKATOM('NIL '))) END; 1: IF TRACE_ON THEN TRACEXIT('REVERSE ') END{ OF REVERSE }; FUNCTION LENGTH(SPTR: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP: SYMBEXPPTR; IDENTIFIER: ALFA; J: INTEGER; BEGIN IF TRACE_ON THEN TRACENTER('LENGTH '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN J := 0; TEMP := SPTR; IF (TEMP^.ANATOM) THEN BEGIN IF (TEMP^.NAME = 'NIL ') THEN J := 0 ELSE BEGIN ERROR(12); GOTO 1 END END ELSE REPEAT J := J + 1; TEMP := TAIL(TEMP) UNTIL (TEMP^.ANATOM) AND (TEMP^.NAME = 'NIL '); IDENTIFIER := ' '; IDENTIFIER[1] := CHR( (J DIV 100) + 48); {LIMIT FOR J IS 999} IDENTIFIER[2] := CHR((J - ((J DIV 100)*100)) DIV 10 + 48); IDENTIFIER[3] := CHR( J - ((J DIV 100)*100) - ((J DIV 10)*10) + 48); LENGTH := MKATOM(IDENTIFIER) END; 1: IF TRACE_ON THEN TRACEXIT('LENGTH ') END{ OF LENGTH }; FUNCTION LOOKUP(KEY, ALIST: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('LOOKUP '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN TEMP := EQQ( HEAD( HEAD(ALIST)), KEY); IF ( TEMP^.NAME='T ' ) THEN LOOKUP := TAIL(HEAD(ALIST)) ELSE LOOKUP := LOOKUP(KEY, TAIL(ALIST)) END; 1: IF TRACE_ON THEN TRACEXIT('LOOKUP ') END{ OF LOOKUP }; FUNCTION BINDARGS(NAMES, VALUES, ENV: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP, TEMP2: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('BINDARGS '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN IF ( NAMES^.ANATOM ) AND (NAMES^.NAME='NIL ') THEN BINDARGS := ENV ELSE BEGIN TEMP := CONS( HEAD(NAMES), EVAL(HEAD(VALUES), ENV) ); TEMP2 := BINDARGS(TAIL(NAMES), TAIL(VALUES), ENV); BINDARGS := CONS(TEMP, TEMP2) END END; 1: IF TRACE_ON THEN TRACEXIT('BINDARGS ') END{ OF BINDARGS }; FUNCTION BINDARG1(NAMES, VALUES, ENV: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP, TEMP2: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('BINDARG1 '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN IF ( NAMES^.ANATOM ) AND ( NAMES^.NAME='NIL ') THEN BINDARG1 := ENV ELSE BEGIN TEMP := CONS( HEAD(NAMES), HEAD(VALUES) ); TEMP2 := BINDARG1( TAIL(NAMES), TAIL(VALUES), ENV); BINDARG1 := CONS(TEMP, TEMP2) END END; 1: IF TRACE_ON THEN TRACEXIT('BINDARG1 ') END{ OF BINDARG1 }; FUNCTION EVCON(CONDPAIRS: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('EVCON '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN TEMP := EVAL( HEAD(HEAD(CONDPAIRS)),ALIST ); IF ( TEMP^.ANATOM ) AND (TEMP^.NAME='NIL ') THEN EVCON := EVCON( TAIL(CONDPAIRS) ) ELSE EVCON := EVAL( HEAD(TAIL(HEAD(CONDPAIRS))),ALIST ) END; 1: IF TRACE_ON THEN TRACEXIT('EVCON ') END{ OF EVCON }; FUNCTION MKFUNARG(SPTR : SYMBEXPPTR) : SYMBEXPPTR; VAR TEMP : SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('MKFUNARG '); IF (SPTR^.ANATOM) AND (NOT SPTR^.ISARESERVEDWORD) THEN TEMP := CONS(MKATOM('FUNARG '), CONS(EVAL(SPTR, ALIST), ALIST)) ELSE TEMP := CONS(MKATOM('FUNARG '), CONS(SPTR, ALIST)); MKFUNARG := TEMP; IF TRACE_ON THEN TRACEXIT('MKFUNARG ') END{ OF MKFUNARG }; FUNCTION ASSOC(KEY, S_TABLE : SYMBEXPPTR) : SYMBEXPPTR; LABEL 1; VAR TEMP1, TEMP2 : SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('ASSOC '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN TEMP1 := EQQ(HEAD(HEAD(S_TABLE)), KEY); IF (TEMP1^.NAME = 'T ') THEN ASSOC := HEAD(S_TABLE) ELSE BEGIN TEMP2 := HEAD(HEAD(TAIL(S_TABLE))); IF NOT (TEMP2^.ANATOM) OR (TEMP2^.NAME <> 'NIL ') THEN ASSOC := ASSOC(KEY, TAIL(S_TABLE)) ELSE ASSOC := HEAD(TAIL(S_TABLE)) END END; 1: IF TRACE_ON THEN TRACEXIT('ASSOC ') END{OF ASSOC}; PROCEDURE SETT(SPTR1, SPTR2 : SYMBEXPPTR; VAR ALIST : SYMBEXPPTR); LABEL 1; VAR TEMP1, TEMP2, TEMP3, NXT : SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('SETT '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN IF NOT SPTR1^.ANATOM THEN BEGIN ERROR(11); GOTO 1 END; TEMP1 := ASSOC(SPTR1, ALIST); TEMP2 := HEAD(TEMP1); IF (TEMP2^.ANATOM) AND (TEMP2^.NAME = 'NIL ') THEN {VARIABLE NOT LOCATED IN THE ALIST} BEGIN POP(TEMP3); IF END_FREELIST THEN GOTO 1; TEMP3^.ANATOM := FALSE; TEMP3^.STATUS := UNMARKED; TEMP3^.TAIL := ALIST; ALIST := TEMP3; POP(ALIST^.HEAD); IF END_FREELIST THEN GOTO 1; WITH ALIST^.HEAD^ DO BEGIN ANATOM := FALSE; STATUS := UNMARKED; HEAD := COPY(SPTR1); TAIL := COPY(SPTR2) END END ELSE {VARIABLE LOCATED IN THE ALIST} TEMP1^.TAIL := COPY(SPTR2) END; 1: IF TRACE_ON THEN TRACEXIT('SETT ') END{OF SETT}; PROCEDURE REMOB(KEY: SYMBEXPPTR; VAR S_TABLE: SYMBEXPPTR); LABEL 1; VAR TEMP1, TEMP2, TEMP3: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('REMOB '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN TEMP1 := EQQ(HEAD(HEAD(S_TABLE)), KEY); IF (TEMP1^.NAME = 'T ') THEN S_TABLE := TAIL(S_TABLE) ELSE BEGIN TEMP2 := HEAD(TAIL(S_TABLE)); IF NOT (TEMP2^.ANATOM) OR (TEMP2^.NAME <> 'NIL ') THEN BEGIN TEMP3 := TAIL(S_TABLE); REMOB(KEY, TEMP3) END; S_TABLE := CONS(HEAD(S_TABLE), TEMP3) END END; 1: IF TRACE_ON THEN TRACEXIT('REMOB ') END{ OF REMOB }; FUNCTION PROG(SPTR: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP1, TEMP2, TEMP3, AUX: SYMBEXPPTR; BEGIN IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN IF TRACE_ON THEN TRACENTER('PROG '); IF SPTR^.ANATOM THEN BEGIN ERROR(13); GOTO 1 END ELSE BEGIN {ZEROING THE LIST OF VARIABLES} AUX:= HEAD(SPTR); WHILE NOT (AUX^.ANATOM) OR (AUX^.NAME <> 'NIL ') DO BEGIN SETT(HEAD(AUX), MKATOM('NIL '), ALIST); AUX := TAIL(AUX) END {WHILE}; {CARRYING OUT THE PROGRAM} TEMP3 := TAIL(SPTR); REPEAT TEMP1 := HEAD(TEMP3); {SKIP ATOMS} IF TEMP1^.ANATOM THEN TEMP1 := HEAD(TAIL(TEMP3)); TEMP2 := EVAL(TEMP1, ALIST); IF NOT TEMP2^.ANATOM THEN BEGIN TEMP := HEAD(TEMP2); IF TEMP^.ANATOM THEN BEGIN IF TEMP^.NAME = 'RETURN ' THEN BEGIN PROG := MKATOM('NIL '); GOTO 1 END ELSE BEGIN IF TEMP^.NAME = 'GO ' THEN BEGIN {GO TO THE TOP OF THE LIST} AUX := TAIL(SPTR); {LOOK FOR THE TAG} TEMP1 := HEAD(AUX); TEMP := HEAD(TAIL(TEMP2)); WHILE NOT (TEMP1^.ANATOM) OR (TEMP1^.NAME <> TEMP^.NAME) DO BEGIN AUX := TAIL(AUX); IF (AUX^.ANATOM) AND (AUX^.NAME = 'NIL ') THEN BEGIN ERROR(14); GOTO 1 END; TEMP1 := HEAD(AUX) END {WHILE}; TEMP3 := AUX END END END END; TEMP3 := TAIL(TEMP3) UNTIL (TEMP3^.ANATOM) AND (TEMP3^.NAME = 'NIL '); PROG := TEMP2 END END; 1: IF TRACE_ON THEN TRACEXIT('PROG ') END{ OF PROG }; FUNCTION PROG2(SPTR1, SPTR2: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('PROG2 '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN TEMP := EVAL(SPTR1, ALIST); TEMP := EVAL(SPTR2, ALIST); PROG2 := TEMP END; 1: IF TRACE_ON THEN TRACEXIT('PROG2 ') END{ OF PROG2 }; FUNCTION PROGN(SPTR: SYMBEXPPTR): SYMBEXPPTR; LABEL 1; VAR TEMP1, TEMP2, TEMP3: SYMBEXPPTR; BEGIN IF TRACE_ON THEN TRACENTER('PROGN '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN IF (SPTR^.ANATOM) THEN PROGN := EVAL(SPTR, ALIST) ELSE BEGIN TEMP3 := SPTR; REPEAT TEMP1 := HEAD(TEMP3); TEMP2 := EVAL(TEMP1, ALIST); TEMP3 := TAIL(TEMP3) UNTIL (TEMP3^.ANATOM) AND (TEMP3^.NAME = 'NIL '); PROGN := TEMP2 END END; 1: IF TRACE_ON THEN TRACEXIT('PROGN ') END{ OF PROGN }; BEGIN { * E V A L * } IF TRACE_ON THEN TRACENTER('EVAL '); IF (ERR_COND) OR (END_FREELIST) THEN GOTO 1 ELSE BEGIN IF ( E^.ANATOM ) THEN EVAL := LOOKUP(E, ALIST) ELSE BEGIN CAROFE := HEAD(E); IF ( CAROFE^.ANATOM ) THEN IF NOT ( CAROFE^.ISARESERVEDWORD ) THEN EVAL := EVAL( CONS(LOOKUP(CAROFE,ALIST),TAIL(E)), ALIST ) ELSE CASE CAROFE^.RESSYM OF LABELSYM, LAMBDASYM, FUNARGSYM, FLAMBDASYM: BEGIN ERROR(3); GOTO 1 END; TRACESYM : BEGIN TRACE_ON := TRUE; EVAL := MKATOM('NIL ') END; UNTRACESYM : BEGIN TRACE_ON := FALSE; EVAL := MKATOM('NIL ') END; QUOTESYM : EVAL := HEAD(TAIL(E)); ATOMSYM : EVAL := ATOM(EVAL(HEAD(TAIL(E)),ALIST)); EQSYM : EVAL := EQQ(EVAL(HEAD(TAIL(E)),ALIST), EVAL(HEAD(TAIL(TAIL(E))), ALIST)); EQUALSYM : EVAL := EQUAL(EVAL(HEAD(TAIL(E)), ALIST), EVAL(HEAD(TAIL(TAIL(E))), ALIST)); HEADSYM : EVAL := HEAD(EVAL(HEAD(TAIL(E)),ALIST)); TAILSYM : EVAL := TAIL(EVAL(HEAD(TAIL(E)),ALIST)); CONSSYM : EVAL := CONS(EVAL(HEAD(TAIL(E)),ALIST), EVAL(HEAD(TAIL(TAIL(E))), ALIST)); CONDSYM : EVAL := EVCON(TAIL(E)); LISTSYM : EVAL := LIST(TAIL(E)); ANDSYM : EVAL := ET(TAIL(E)); ORSYM : EVAL := OU(TAIL(E)); NULLSYM, NOTSYM : EVAL := NULL(EVAL(HEAD(TAIL(E)), ALIST)); EVALSYM : EVAL := EVAL(EVAL(HEAD(TAIL(E)), ALIST), ALIST); APPENDSYM : EVAL := APPEND(EVAL(HEAD(TAIL(E)),ALIST), EVAL(HEAD(TAIL(TAIL(E))), ALIST)); RELACEHSYM : EVAL := REPLACEH(EVAL(HEAD(TAIL(E)),ALIST), EVAL(HEAD(TAIL(TAIL(E))), ALIST)); RELACETSYM : EVAL := REPLACET(EVAL(HEAD(TAIL(E)),ALIST), EVAL(HEAD(TAIL(TAIL(E))), ALIST)); LASTSYM : EVAL := LAST(EVAL(HEAD(TAIL(E)), ALIST)); LENGTHSYM : EVAL := LENGTH(EVAL(HEAD(TAIL(E)), ALIST)); REVERSESYM : EVAL := REVERSE(EVAL(HEAD(TAIL(E)), ALIST)); FUNCTSYM : EVAL := MKFUNARG(HEAD(TAIL(E))); SETSYM : BEGIN TEMP := EVAL(HEAD(TAIL(TAIL(E))), ALIST); SETT(EVAL(HEAD(TAIL(E)), ALIST), TEMP, ALIST); EVAL := TEMP END; SETQSYM : BEGIN TEMP := EVAL(HEAD(TAIL(TAIL(E))), ALIST); SETT(HEAD(TAIL(E)), TEMP, ALIST); EVAL := TEMP END; DEFEXPSYM : BEGIN TEMP := HEAD(TAIL(E)); SETT(TEMP, CONS(MKATOM('LAMBDA '), TAIL(TAIL(E))), ALIST); EVAL := TEMP END; DEFFEXPSYM : BEGIN TEMP := HEAD(TAIL(E)); SETT(TEMP, CONS(MKATOM('FLAMBDA '), TAIL(TAIL(E))), ALIST); EVAL := TEMP END; REMOBSYM : BEGIN REMOB(HEAD(TAIL(E)), ALIST); EVAL := MKATOM('NIL ') END; GOSYM : EVAL := CONS(MKATOM('GO '), TAIL(E)); RETURNSYM: EVAL := CONS(MKATOM('RETURN '), MKATOM('NIL ')); PROGSYM : EVAL := PROG(TAIL(E)); PROG2SYM : EVAL := PROG2(HEAD(TAIL(E)), HEAD(TAIL(TAIL(E)))); PROGNSYM : EVAL := PROGN(TAIL(E)); END{CASE} ELSE BEGIN CAAROFE := HEAD(CAROFE); IF ( CAAROFE^.ANATOM ) AND ( CAAROFE^.ISARESERVEDWORD ) THEN IF NOT (CAAROFE^.RESSYM IN [LABELSYM, LAMBDASYM, FUNARGSYM, FLAMBDASYM]) THEN BEGIN ERROR(10); GOTO 1 END ELSE CASE CAAROFE^.RESSYM OF LABELSYM: BEGIN TEMP := CONS( CONS(HEAD(TAIL(CAROFE)), HEAD(TAIL(TAIL(CAROFE)))), ALIST); EVAL := EVAL(CONS(HEAD(TAIL(TAIL(CAROFE))), TAIL(E)),TEMP) END; LAMBDASYM: BEGIN TEMP := BINDARGS(HEAD(TAIL(CAROFE)), TAIL(E), ALIST); EVAL := EVAL( HEAD( TAIL( TAIL(CAROFE))), TEMP) END; FUNARGSYM: BEGIN TEMP := TAIL(TAIL(CAROFE)); EVAL := EVAL(CONS(HEAD(TAIL(CAROFE)), TAIL(E)), TEMP) END; FLAMBDASYM: BEGIN TEMP := BINDARG1(HEAD(TAIL(CAROFE)), TAIL(E), ALIST); EVAL := EVAL( HEAD( TAIL( TAIL(CAROFE))), TEMP) END; END{ CASE } ELSE EVAL := EVAL(CONS(EVAL(CAROFE, ALIST), TAIL(E)), ALIST) END END END; 1: IF TRACE_ON THEN TRACEXIT('EVAL ') END{ OF EVAL }; PROCEDURE INITIALIZE; VAR I: INTEGER; TEMP, NXT: SYMBEXPPTR; BEGIN END_FREELIST := FALSE; ERR_COND := FALSE; TRACE_ON := FALSE; NESTCOUNT := 0; ALREADYPEEKED := FALSE; NUMBEROFGCS := 0; FREENODES := MAXNODE; WITH NILNODE DO BEGIN ANATOM := TRUE; NEXT := NIL; NAME := 'NIL '; STATUS := UNMARKED; ISARESERVEDWORD := FALSE END; WITH TNODE DO BEGIN ANATOM := TRUE; NEXT := NIL; NAME := 'T '; STATUS := UNMARKED; ISARESERVEDWORD := FALSE END; { ALLOCATE STORAGE AND MARK IT FREE } FREELIST := NIL; FOR I:=1 TO MAXNODE DO BEGIN NEW(NODELIST); NODELIST^.NEXT := FREELIST; NODELIST^.HEAD := FREELIST; NODELIST^.STATUS := UNMARKED; FREELIST := NODELIST END; { INITIALIZE RESERVED WORD TABLE } RESWORDS[ ANDSYM ] := 'AND '; RESWORDS[ APPENDSYM ] := 'APPEND '; RESWORDS[ ATOMSYM ] := 'ATOM '; RESWORDS[ HEADSYM ] := 'CAR '; RESWORDS[ TAILSYM ] := 'CDR '; RESWORDS[ CONDSYM ] := 'COND '; RESWORDS[ CONSSYM ] := 'CONS '; RESWORDS[ COPYSYM ] := 'COPY '; RESWORDS[ DEFEXPSYM ] := 'DEFEXP '; RESWORDS[ DEFFEXPSYM ] := 'DEFFEXP '; RESWORDS[ DEFMACSYM ] := 'DEFMACRO '; RESWORDS[ EQSYM ] := 'EQ '; RESWORDS[ EQUALSYM ] := 'EQUAL '; RESWORDS[ EVALSYM ] := 'EVAL '; RESWORDS[ FLAMBDASYM ] := 'FLAMBDA '; RESWORDS[ FUNARGSYM ] := 'FUNARG '; RESWORDS[ FUNCTSYM ] := 'FUNCTION '; RESWORDS[ GOSYM ] := 'GO '; RESWORDS[ LABELSYM ] := 'LABEL '; RESWORDS[ LAMBDASYM ] := 'LAMBDA '; RESWORDS[ LASTSYM ] := 'LAST '; RESWORDS[ LENGTHSYM ] := 'LENGTH '; RESWORDS[ LISTSYM ] := 'LIST '; RESWORDS[ NOTSYM ] := 'NOT '; RESWORDS[ NULLSYM ] := 'NULL '; RESWORDS[ ORSYM ] := 'OR '; RESWORDS[ PROGSYM ] := 'PROG '; RESWORDS[ PROG2SYM ] := 'PROG2 '; RESWORDS[ PROGNSYM ] := 'PROGN '; RESWORDS[ QUOTESYM ] := 'QUOTE '; RESWORDS[ RELACEHSYM ] := 'REPLACEH '; RESWORDS[ RELACETSYM ] := 'REPLACET '; RESWORDS[ REMOBSYM ] := 'REMOB '; RESWORDS[ RETURNSYM ] := 'RETURN '; RESWORDS[ REVERSESYM ] := 'REVERSE '; RESWORDS[ SETSYM ] := 'SET '; RESWORDS[ SETQSYM ] := 'SETQ '; RESWORDS[ TRACESYM ] := 'TRACE '; RESWORDS[ UNTRACESYM ] := 'UNTRACE '; { INITIALIZE THE A-LIST WITH T AND NIL } POP(ALIST); ALIST^.ANATOM := FALSE; ALIST^.STATUS := UNMARKED; POP(ALIST^.TAIL); NXT := ALIST^.TAIL^.NEXT; ALIST^.TAIL^ := NILNODE; ALIST^.TAIL^.NEXT := NXT; POP(ALIST^.HEAD); { BIND NIL TO THE ATOM NIL } WITH ALIST^.HEAD^ DO BEGIN ANATOM := FALSE; STATUS := UNMARKED; POP(HEAD); NXT := HEAD^.NEXT; HEAD^ := NILNODE; HEAD^.NEXT := NXT; POP(TAIL); NXT := TAIL^.NEXT; TAIL^ := NILNODE; TAIL^.NEXT := NXT END; POP(TEMP); TEMP^.ANATOM := FALSE; TEMP^.STATUS := UNMARKED; TEMP^.TAIL := ALIST; ALIST := TEMP; POP(ALIST^.HEAD); { BIND T TO THE ATOM T } WITH ALIST^.HEAD^ DO BEGIN ANATOM := FALSE; STATUS := UNMARKED; POP(HEAD); NXT := HEAD^.NEXT; HEAD^ := TNODE; HEAD^.NEXT := NXT; POP(TAIL); NXT := TAIL^.NEXT; TAIL^ := TNODE; TAIL^.NEXT := NXT END; RESET('INITLISP', INFILE); READ(INFILE, CH); NEXTSYM1; READEXP1(PTR); WHILE NOT ( PTR^.ANATOM ) OR ( PTR^.NAME<>'FIN ' ) DO BEGIN TEMP := EVAL(PTR, ALIST); NEXTSYM1; READEXP1(PTR); {CALL THE} GARBAGEMAN END; WRITELN; WRITELN(' R E A D Y'); WRITELN; READ(CH); END{ OF INITIALIZE }; BEGIN{+ LISP MAIN PROGRAM +} INITIALIZE; NEXTSYM; READEXPR(PTR); WHILE NOT ( PTR^.ANATOM ) OR ( PTR^.NAME<>'FIN ' ) DO BEGIN IF NOT TRACE_ON THEN WRITE(' '); PRINTEXPR( EVAL(PTR, ALIST) ); { NESTCOUNT := 0; } IF END_FREELIST THEN GOTO 2; 1: ERR_COND := FALSE; IF ( EOF(INPUT) ) THEN BEGIN WRITELN('END OF FILE ENCOUNTERED BEFORE A "FIN" CARD.'); GOTO 2 END; PTR := NIL; WRITELN; WRITELN; { CALL THE } GARBAGEMAN; NEXTSYM; READEXPR(PTR); IF ERR_COND THEN GOTO 1; IF END_FREELIST THEN GOTO 2; END; 2:WRITELN; WRITELN; WRITELN(' TOTAL NUMBER OF GARBAGE COLLECTIONS = ', NUMBEROFGCS:1,'.'); WRITELN; WRITELN(' FREE NODES LEFT UPON EXIT = ', FREENODES:1, '.'); WRITELN END { OF LISP }.