home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d524 / kamin.lha / Kamin / P-Distr.lzh / lisp.p < prev    next >
Text File  |  1988-11-21  |  28KB  |  979 lines

  1. (*****************************************************************
  2.  *                     DECLARATIONS                              *
  3.  *****************************************************************)
  4. program lisp (input, output);
  5.  
  6. label 99;
  7.  
  8. const
  9.    NAMELENG = 20;      (* Maximum length of a name *)
  10.    MAXNAMES = 300;     (* Maximum number of different names *)
  11.    MAXINPUT = 4000;    (* Maximum length of an input *)
  12.    PROMPT = '-> ';
  13.    PROMPT2 = '> ';
  14.    COMMENTCHAR = ';';
  15.    TABCODE = 9;        (* in ASCII *)
  16.  
  17. type
  18.    NAMESIZE = 0..NAMELENG;
  19.    NAMESTRING = packed array [1..NAMELENG] of char;
  20.  
  21.    NAME = 1 .. MAXNAMES; (* a NAME is an index in printNames *)
  22.  
  23.    BUILTINOP = (IFOP,WHILEOP,SETOP,BEGINOP,PLUSOP,MINUSOP,
  24.                 TIMESOP,DIVOP,EQOP,LTOP,GTOP,CONSOP,
  25.                 CAROP,CDROP,NUMBERPOP,SYMBOLPOP,
  26.                 LISTPOP,NULLPOP,PRINTOP);
  27.    VALUEOP = PLUSOP .. PRINTOP;
  28.    CONTROLOP = IFOP .. BEGINOP;
  29.  
  30.    SEXP = ^SEXPREC;
  31.    EXP = ^EXPREC;
  32.    EXPLIST = ^EXPLISTREC;
  33.    ENV = ^ENVREC;
  34.    VALUELIST = ^VALUELISTREC;
  35.    NAMELIST = ^NAMELISTREC;
  36.    FUNDEF = ^FUNDEFREC;
  37.  
  38.    SEXPTYPE = (NILSXP,NUMSXP,SYMSXP,LISTSXP);
  39.    SEXPREC = record
  40.                case sxptype: SEXPTYPE of
  41.                   NILSXP: ();
  42.                   NUMSXP: (intval: integer);
  43.                   SYMSXP: (symval: NAME);
  44.                   LISTSXP: (carval, cdrval: SEXP)
  45.             end;
  46.  
  47.    EXPTYPE = (VALEXP,VAREXP,APEXP);
  48.    EXPREC = record
  49.                case etype: EXPTYPE of
  50.                   VALEXP: (sxp: SEXP);
  51.                   VAREXP: (varble: NAME);
  52.                   APEXP: (optr: NAME; args: EXPLIST)
  53.             end;
  54.  
  55.    EXPLISTREC = record
  56.                head: EXP;
  57.                tail: EXPLIST
  58.             end;
  59.  
  60.    VALUELISTREC = record
  61.                head: SEXP;
  62.                tail: VALUELIST
  63.             end;
  64.  
  65.    NAMELISTREC = record
  66.                head: NAME;
  67.                tail: NAMELIST
  68.             end;
  69.  
  70.    ENVREC = record
  71.                vars: NAMELIST;
  72.                values: VALUELIST
  73.             end;
  74.    FUNDEFREC = record
  75.                funname: NAME;
  76.                formals: NAMELIST;
  77.                body: EXP;
  78.                nextfundef: FUNDEF
  79.             end;
  80.  
  81. var
  82.    fundefs: FUNDEF;
  83.    
  84.    globalEnv: ENV;
  85.    
  86.    currentExp: EXP;
  87.    
  88.    userinput: array [1..MAXINPUT] of char;
  89.    inputleng, pos: 0..MAXINPUT;
  90.    
  91.    printNames: array [NAME] of NAMESTRING;
  92.    numNames, numBuiltins: NAME;
  93.  
  94.    nilValue, trueValue: SEXP;
  95.  
  96.    quittingtime: Boolean;
  97.  
  98. (*****************************************************************
  99.  *                     DATA STRUCTURE OP'S                       *
  100.  *****************************************************************)
  101.  
  102. (* mkVALEXP - return an EXP of type VALEXP with sxp s            *)
  103. function mkVALEXP (s: SEXP): EXP;
  104. var e: EXP;
  105. begin
  106.    new(e);
  107.    e^.etype := VALEXP;
  108.    e^.sxp := s;
  109.    mkVALEXP := e
  110. end; (* mkVALEXP *)
  111.  
  112. (* mkVAREXP - return an EXP of type VAREXP with varble nm        *)
  113. function mkVAREXP (nm: NAME): EXP;
  114. var e: EXP;
  115. begin
  116.    new(e);
  117.    e^.etype := VAREXP;
  118.    e^.varble := nm;
  119.    mkVAREXP := e
  120. end; (* mkVAREXP *)
  121.  
  122. (* mkAPEXP - return EXP of type APEXP w/ optr op and args el     *)
  123. function mkAPEXP (op: NAME; el: EXPLIST): EXP;
  124. var e: EXP;
  125. begin
  126.    new(e);
  127.    e^.etype := APEXP;
  128.    e^.optr := op;
  129.    e^.args := el;
  130.    mkAPEXP := e
  131. end; (* mkAPEXP *)
  132.  
  133. (* mkSExp - return SEXP of type t (but no value)                 *)
  134. function mkSExp (t: SEXPTYPE): SEXP;
  135. var s: SEXP;
  136. begin
  137.    new(s);
  138.    s^.sxptype := t;
  139.    mkSExp := s
  140. end; (* mkSExp *)
  141.  
  142. (* mkExplist - return an EXPLIST with head e and tail el         *)
  143. function mkExplist (e: EXP; el: EXPLIST): EXPLIST;
  144. var newel: EXPLIST;
  145. begin
  146.    new(newel);
  147.    newel^.head := e;
  148.    newel^.tail := el;
  149.    mkExplist := newel
  150. end; (* mkExplist *)
  151.  
  152. (* mkNamelist - return a NAMELIST with head n and tail nl        *)
  153. function mkNamelist (nm: NAME; nl: NAMELIST): NAMELIST;
  154. var newnl: NAMELIST;
  155. begin
  156.    new(newnl);
  157.    newnl^.head := nm;
  158.    newnl^.tail := nl;
  159.    mkNamelist := newnl
  160. end; (* mkNamelist *)
  161.  
  162. (* mkValuelist - return an VALUELIST with head s and tail vl     *)
  163. function mkValuelist (s: SEXP; vl: VALUELIST): VALUELIST;
  164. var newvl: VALUELIST;
  165. begin
  166.    new(newvl);
  167.    newvl^.head := s;
  168.    newvl^.tail := vl;
  169.    mkValuelist := newvl
  170. end; (* mkValuelist *)
  171.  
  172. (* mkEnv - return an ENV with vars nl and values vl              *)
  173. function mkEnv (nl: NAMELIST; vl: VALUELIST): ENV;
  174. var rho: ENV;
  175. begin
  176.    new(rho);
  177.    rho^.vars := nl;
  178.    rho^.values := vl;
  179.    mkEnv := rho
  180. end; (* mkEnv *)
  181.  
  182. (* lengthVL - return length of VALUELIST vl                      *)
  183. function lengthVL (vl: VALUELIST): integer;
  184. var i: integer;
  185. begin
  186.    i := 0;
  187.    while vl <> nil do begin
  188.       i := i+1;
  189.       vl := vl^.tail
  190.       end;
  191.    lengthVL := i
  192. end; (* lengthVL *)
  193.  
  194. (* lengthNL - return length of NAMELIST nl                       *)
  195. function lengthNL (nl: NAMELIST): integer;
  196. var i: integer;
  197. begin
  198.    i := 0;
  199.    while nl <> nil do begin
  200.       i := i+1;
  201.       nl := nl^.tail
  202.       end;
  203.    lengthNL := i
  204. end; (* lengthNL *)
  205.  
  206. (*****************************************************************
  207.  *                     NAME MANAGEMENT                           *
  208.  *****************************************************************)
  209.  
  210. (* fetchFun - get function definition of fname from fundefs      *)
  211. function fetchFun (fname: NAME): FUNDEF;
  212. var
  213.    f: FUNDEF;
  214.    found: Boolean;
  215. begin
  216.    found := false;
  217.    f := fundefs;
  218.    while (f <> nil) and not found do
  219.       if f^.funname = fname
  220.       then found := true
  221.       else f := f^.nextfundef;
  222.    fetchFun := f
  223. end; (* fetchFun *)
  224.  
  225. (* newFunDef - add new function fname w/ parameters nl, body e   *)
  226. procedure newFunDef (fname: NAME; nl: NAMELIST; e: EXP);
  227. var f: FUNDEF;
  228. begin
  229.    f := fetchFun(fname);
  230.    if f = nil (* fname not yet defined as a function *)
  231.    then begin
  232.            new(f);
  233.            f^.nextfundef := fundefs; (* place new FUNDEFREC *)
  234.            fundefs := f              (* on fundefs list *)
  235.         end;
  236.    f^.funname := fname;
  237.    f^.formals := nl;
  238.    f^.body := e
  239. end; (* newFunDef *)
  240.  
  241. (* initNames - place all pre-defined names into printNames       *)
  242. procedure initNames;
  243. var i: integer;
  244. begin
  245.    fundefs := nil;
  246.    i := 1;
  247.    printNames[i] := 'if                  '; i := i+1;
  248.    printNames[i] := 'while               '; i := i+1;
  249.    printNames[i] := 'set                 '; i := i+1;
  250.    printNames[i] := 'begin               '; i := i+1;
  251.    printNames[i] := '+                   '; i := i+1;
  252.    printNames[i] := '-                   '; i := i+1;
  253.    printNames[i] := '*                   '; i := i+1;
  254.    printNames[i] := '/                   '; i := i+1;
  255.    printNames[i] := '=                   '; i := i+1;
  256.    printNames[i] := '<                   '; i := i+1;
  257.    printNames[i] := '>                   '; i := i+1;
  258.    printNames[i] := 'cons                '; i := i+1;
  259.    printNames[i] := 'car                 '; i := i+1;
  260.    printNames[i] := 'cdr                 '; i := i+1;
  261.    printNames[i] := 'number?             '; i := i+1;
  262.    printNames[i] := 'symbol?             '; i := i+1;
  263.    printNames[i] := 'list?               '; i := i+1;
  264.    printNames[i] := 'null?               '; i := i+1;
  265.    printNames[i] := 'print               '; i := i+1;
  266.    printNames[i] := 'T                   ';
  267.    numNames := i;
  268.    numBuiltins := i
  269. end; (* initNames *)
  270.  
  271. (* install - insert new name into printNames                     *)
  272. function install (nm: NAMESTRING): NAME;
  273. var
  274.    i: integer;
  275.    found: Boolean;
  276. begin
  277.    i := 1; found := false;
  278.    while (i <= numNames) and not found
  279.    do if nm = printNames[i]
  280.       then found := true
  281.       else i := i+1;
  282.    if not found
  283.    then begin
  284.            if i > MAXNAMES
  285.            then begin
  286.                    writeln('No more room for names');
  287.                    goto 99
  288.                 end;
  289.            numNames := i;
  290.            printNames[i] := nm
  291.         end;
  292.    install := i
  293. end; (* install *)
  294.  
  295. (* prName - print name nm                                        *)
  296. procedure prName (nm: NAME);
  297. var i: integer;
  298. begin
  299.    i := 1;
  300.    while i <= NAMELENG
  301.    do if printNames[nm][i] <> ' '
  302.       then begin
  303.               write(printNames[nm][i]);
  304.               i := i+1
  305.            end
  306.       else i := NAMELENG+1
  307. end; (* prName *)
  308.  
  309. (* primOp - translate NAME optr to corresponding BUILTINOP       *)
  310. function primOp (optr: NAME): BUILTINOP;
  311. var
  312.    op: BUILTINOP;
  313.    i: integer;
  314. begin
  315.    op := IFOP; (* N.B. IFOP is first value in BUILTINOPS *)
  316.    for i := 1 to optr-1 do op := succ(op);
  317.    primOp := op
  318. end; (* primOp *)
  319.  
  320. (*****************************************************************
  321.  *                        INPUT                                  *
  322.  *****************************************************************)
  323.  
  324. (* isDelim - check if c is a delimiter                           *)
  325. function isDelim (c: char): Boolean;
  326. begin
  327.    isDelim := c in ['(', ')', ' ', COMMENTCHAR]
  328. end; (* isDelim *)
  329.  
  330. (* skipblanks - return next non-blank position in userinput      *)
  331. function skipblanks (p: integer): integer;
  332. begin
  333.    while userinput[p] = ' ' do p := p+1;
  334.    skipblanks := p
  335. end; (* skipblanks *)
  336.  
  337. (* matches - check if string nm matches userinput[s .. s+leng]   *)
  338. function matches (s: integer; leng: NAMESIZE;
  339.                    nm: NAMESTRING): Boolean;
  340. var
  341.    match: Boolean;
  342.    i: integer;
  343. begin
  344.    match := true; i := 1;
  345.    while match and (i <= leng) do begin
  346.       if userinput[s] <> nm[i] then match := false;
  347.       i := i+1;
  348.       s := s+1
  349.       end;
  350.    if not isDelim(userinput[s]) then match := false;
  351.    matches := match
  352. end; (* matches *)
  353.  
  354. (* reader - read char's into userinput; be sure input not blank  *)
  355. procedure reader;
  356.  
  357. (* readInput - read char's into userinput                        *)
  358.    procedure readInput;
  359.  
  360.    var c: char;
  361.  
  362. (* nextchar - read next char - filter tabs and comments          *)
  363.       procedure nextchar (var c: char);
  364.       begin
  365.          read(c);
  366.          if c = chr(TABCODE)
  367.          then c := ' '
  368.          else if c = COMMENTCHAR
  369.               then begin while not eoln do read(c); c := ' ' end
  370.       end; (* nextchar *)
  371.  
  372. (* readParens - read char's, ignoring newlines, to matching ')'  *)
  373.       procedure readParens;
  374.       var
  375.          parencnt: integer; (* current depth of parentheses *)
  376.          c: char;
  377.       begin
  378.          parencnt := 1; (* '(' just read *)
  379.          repeat
  380.             if eoln then write(PROMPT2);
  381.             nextchar(c);
  382.             pos := pos+1;
  383.             if pos = MAXINPUT
  384.             then begin
  385.                     writeln('User input too long');
  386.                     goto 99
  387.                  end;
  388.             userinput[pos] := c;
  389.             if c = '(' then parencnt := parencnt+1;
  390.             if c = ')' then parencnt := parencnt-1
  391.          until parencnt = 0
  392.       end; (* readParens *)
  393.  
  394.    begin (* readInput *)
  395.       write(PROMPT);
  396.       pos := 0;
  397.       repeat
  398.          pos := pos+1;
  399.          if pos = MAXINPUT
  400.          then begin
  401.                  writeln('User input too long');
  402.                  goto 99
  403.               end;
  404.          nextchar(c);
  405.          userinput[pos] := c;
  406.          if userinput[pos] = '(' then readParens
  407.       until eoln;
  408.       inputleng := pos;
  409.       userinput[pos+1] := COMMENTCHAR (* sentinel *)
  410.    end; (* readInput *)
  411.  
  412. begin (* reader *)
  413.     repeat
  414.        readInput;
  415.        pos := skipblanks(1);
  416.     until pos <= inputleng (* ignore blank lines *)
  417. end; (* reader *)
  418.  
  419. (* parseName - return (installed) NAME starting at userinput[pos]*)
  420. function parseName: NAME;
  421. var
  422.    nm: NAMESTRING; (* array to accumulate characters *)
  423.    leng: NAMESIZE; (* length of name *)
  424. begin
  425.    leng := 0;
  426.    while (pos <= inputleng) and not isDelim(userinput[pos])
  427.    do begin
  428.          if leng = NAMELENG
  429.          then begin
  430.                  writeln('Name too long, begins: ', nm);
  431.                  goto 99
  432.               end;
  433.          leng := leng+1;
  434.          nm[leng] := userinput[pos];
  435.          pos := pos+1
  436.       end;
  437.    if leng = 0
  438.    then begin
  439.            writeln('Error: expected name, instead read: ',
  440.                    userinput[pos]);
  441.            goto 99
  442.         end;
  443.    for leng := leng+1 to NAMELENG do nm[leng] := ' ';
  444.    pos := skipblanks(pos); (* skip blanks after name *)
  445.    parseName := install(nm)
  446. end; (* parseName *)
  447.  
  448. (* isNumber - check if a number begins at pos                    *)
  449. function isNumber (pos: integer): Boolean;
  450.  
  451. (* isDigits - check if sequence of digits begins at pos          *)
  452.    function isDigits (pos: integer): Boolean;
  453.    begin
  454.       if not (userinput[pos] in ['0'..'9'])
  455.       then isDigits := false
  456.       else begin
  457.               isDigits := true;
  458.               while userinput[pos] in ['0'..'9'] do pos := pos+1;
  459.               if not isDelim(userinput[pos])
  460.               then isDigits := false
  461.            end
  462.    end; (* isDigits *)
  463.  
  464. begin (* isNumber *)
  465.    isNumber := isDigits(pos) or
  466.               ((userinput[pos] = '-') and isDigits(pos+1))
  467. end; (* isNumber *)
  468.  
  469. (* isValue - check if a number or quoted const begins at pos     *)
  470. function isValue (pos: integer): Boolean;
  471. begin
  472.    isValue:= (userinput[pos] = '''') or isNumber(pos)
  473. end; (* isValue *)
  474.  
  475. (* parseVal - return S-expression starting at userinput[pos]     *)
  476. function parseVal: SEXP;
  477.  
  478. (* parseSExp - return quoted S-expr starting at userinput[pos]   *)
  479.    function parseSExp: SEXP;
  480.  
  481.    var s: SEXP;
  482.  
  483. (* parseInt - return number starting at userinput[pos]           *)
  484.       function parseInt: SEXP;
  485.       var sum, sign: integer;
  486.       begin
  487.          s := mkSExp(NUMSXP);
  488.          sum := 0; sign := 1;
  489.          if userinput[pos] = '-'
  490.          then begin
  491.                  sign := -1;
  492.                  pos := pos+1
  493.               end;
  494.          while userinput[pos] in ['0'..'9'] do begin
  495.             sum := 10*sum + (ord(userinput[pos]) - ord('0'));
  496.             pos := pos+1
  497.             end;
  498.          s^.intval := sum * sign;
  499.          pos := skipblanks(pos); (* skip blanks after number *)
  500.          parseInt := s
  501.       end; (* parseInt *)
  502.  
  503. (* parseSym - return symbol starting at userinput[pos]           *)
  504.       function parseSym: SEXP;
  505.       begin
  506.          s := mkSExp(SYMSXP);
  507.          s^.symval := parseName;
  508.          parseSym := s
  509.       end; (* parseSym *)
  510.  
  511. (* parseList - return list starting at userinput[pos]            *)
  512.       function parseList: SEXP;
  513.       var car, cdr: SEXP;
  514.       begin
  515.          if userinput[pos] = ')'
  516.          then begin
  517.                  parseList := mkSExp(NILSXP);
  518.                  pos := skipblanks(pos+1)
  519.               end
  520.          else begin
  521.                  car := parseSExp;
  522.                  cdr := parseList;
  523.                  s := mkSExp(LISTSXP);
  524.                  s^.carval := car;
  525.                  s^.cdrval := cdr;
  526.                  parseList := s
  527.               end
  528.       end; (* parseList *)
  529.  
  530.    begin (* parseSExp *)
  531.       if isNumber(pos)
  532.       then parseSExp := parseInt
  533.       else if userinput[pos] = '('
  534.            then begin
  535.                    pos := skipblanks(pos+1);
  536.                    parseSExp := parseList
  537.                 end
  538.            else parseSExp := parseSym
  539.    end; (* parseSExp *)
  540.  
  541. begin (* parseVal *)
  542.    if userinput[pos] = '''' then pos := pos+1;
  543.    parseVal := parseSExp
  544. end; (* parseVal *)
  545.  
  546. function parseEL: EXPLIST; forward;
  547.  
  548. (* parseExp - return EXP starting at userinput[pos]              *)
  549. function parseExp: EXP;
  550. var
  551.    nm: NAME;
  552.    el: EXPLIST;
  553. begin
  554.    if userinput[pos] = '('
  555.    then begin   (* APEXP *)
  556.            pos := skipblanks(pos+1); (* skip '( ..' *)
  557.            nm := parseName;
  558.            el := parseEL;
  559.            parseExp := mkAPEXP(nm, el)
  560.         end
  561.    else if isValue(pos)
  562.         then parseExp := mkVALEXP(parseVal)   (* VALEXP *)
  563.         else parseExp := mkVAREXP(parseName)  (* VAREXP *)
  564. end; (* parseExp *)
  565.  
  566. (* parseEL - return EXPLIST starting at userinput[pos]           *)
  567. function parseEL;
  568. var
  569.    e: EXP;
  570.    el: EXPLIST;
  571. begin
  572.    if userinput[pos] = ')'
  573.    then begin
  574.            pos := skipblanks(pos+1); (* skip ') ..' *)
  575.            parseEL := nil
  576.         end
  577.    else begin
  578.            e := parseExp;
  579.            el := parseEL;
  580.            parseEL := mkExplist(e, el)
  581.         end
  582. end; (* parseEL *)
  583.  
  584. (* parseNL - return NAMELIST starting at userinput[pos]          *)
  585. function parseNL: NAMELIST;
  586. var
  587.    nm: NAME;
  588.    nl: NAMELIST;
  589. begin
  590.    if userinput[pos] = ')'
  591.    then begin
  592.            pos := skipblanks(pos+1); (* skip ') ..' *)
  593.            parseNL := nil
  594.         end
  595.    else begin
  596.            nm := parseName;
  597.            nl := parseNL;
  598.            parseNL := mkNamelist(nm, nl)
  599.         end
  600. end; (* parseNL *)
  601.  
  602. (* parseDef - parse function definition at userinput[pos]        *)
  603. function parseDef: NAME;
  604. var
  605.    fname: NAME;        (* function name *)
  606.    nl: NAMELIST;       (* formal parameters *)
  607.    e: EXP;             (* body *)
  608. begin
  609.    pos := skipblanks(pos+1); (* skip '( ..' *)
  610.    pos := skipblanks(pos+6); (* skip 'define ..' *)
  611.    fname := parseName;
  612.    pos := skipblanks(pos+1); (* skip '( ..' *)
  613.    nl := parseNL;
  614.    e := parseExp;
  615.    pos := skipblanks(pos+1); (* skip ') ..' *)
  616.    newFunDef(fname, nl, e);
  617.    parseDef := fname
  618. end; (* parseDef *)
  619.  
  620. (*****************************************************************
  621.  *                     ENVIRONMENTS                              *
  622.  *****************************************************************)
  623.  
  624. (* emptyEnv - return an environment with no bindings             *)
  625. function emptyEnv: ENV;
  626. begin
  627.    emptyEnv := mkEnv(nil, nil)
  628. end; (* emptyEnv *)
  629.  
  630. (* bindVar - bind variable nm to value s in environment rho      *)
  631. procedure bindVar (nm: NAME; s: SEXP; rho: ENV);
  632. begin
  633.    rho^.vars := mkNamelist(nm, rho^.vars);
  634.    rho^.values := mkValuelist(s, rho^.values)
  635. end; (* bindVar *)
  636.  
  637. (* findVar - look up nm in rho                                   *)
  638. function findVar (nm: NAME; rho: ENV): VALUELIST;
  639. var
  640.    nl: NAMELIST;
  641.    vl: VALUELIST;
  642.    found: Boolean;
  643. begin
  644.    found := false;
  645.    nl := rho^.vars;
  646.    vl := rho^.values;
  647.    while (nl <> nil) and not found do
  648.       if nl^.head = nm
  649.       then found := true
  650.       else begin
  651.               nl := nl^.tail;
  652.               vl := vl^.tail
  653.            end;
  654.    findVar := vl
  655. end; (* findVar *)
  656.  
  657. (* assign - assign value s to variable nm in rho                 *)
  658. procedure assign (nm: NAME; s: SEXP; rho: ENV);
  659. var varloc: VALUELIST;
  660. begin
  661.    varloc := findVar(nm, rho);
  662.    varloc^.head := s
  663. end; (* assign *)
  664.  
  665. (* fetch - return SEXP bound to nm in rho                        *)
  666. function fetch (nm: NAME; rho: ENV): SEXP;
  667. var vl: VALUELIST;
  668. begin
  669.    vl := findVar(nm, rho);
  670.    fetch := vl^.head
  671. end; (* fetch *)
  672.  
  673. (* isBound - check if nm is bound in rho                         *)
  674. function isBound (nm: NAME; rho: ENV): Boolean;
  675. begin
  676.    isBound := findVar(nm, rho) <> nil
  677. end; (* isBound *)
  678. (*****************************************************************
  679.  *                     S-EXPRESSIONS                             *
  680.  *****************************************************************)
  681.  
  682. (* prValue - print S-expression s                                *)
  683. procedure prValue (s: SEXP);
  684. var s1: SEXP;
  685. begin
  686.    with s^ do
  687.       case sxptype of
  688.          NILSXP: write('()');
  689.          NUMSXP: write(intval:1);
  690.          SYMSXP: prName(symval);
  691.          LISTSXP:
  692.             begin
  693.                write('(');
  694.                prValue(carval);
  695.                s1 := cdrval;
  696.                while s1^.sxptype = LISTSXP do begin
  697.                   write(' ');
  698.                   prValue(s1^.carval);
  699.                   s1 := s1^.cdrval
  700.                   end;
  701.                write(')')
  702.             end
  703.       end (* case and with *)
  704. end; (* prValue *)
  705.  
  706. (* isTrueVal - return true if s is true (non-NIL) value          *)
  707. function isTrueVal (s: SEXP): Boolean;
  708. begin
  709.    isTrueVal := s^.sxptype <> NILSXP
  710. end; (* isTrueVal *)
  711.  
  712. (* applyValueOp - apply VALUEOP op to arguments in VALUELIST vl  *)
  713. function applyValueOp (op: VALUEOP; vl: VALUELIST): SEXP;
  714.  
  715. var
  716.    result: SEXP;
  717.    s1, s2: SEXP;
  718.  
  719. (* applyArithOp - apply binary, arithmetic VALUEOP to arguments  *)
  720.    procedure applyArithOp (n1, n2: integer);
  721.    begin
  722.       result := mkSExp(NUMSXP);
  723.       with result^ do
  724.          case op of
  725.             PLUSOP: intval := n1+n2;
  726.             MINUSOP: intval := n1-n2;
  727.             TIMESOP: intval := n1*n2;
  728.             DIVOP: intval := n1 div n2
  729.          end
  730.    end; (* applyArithOp *)
  731.  
  732. (* applyRelOp - apply binary, relational VALUEOP to arguments    *)
  733.    procedure applyRelOp (n1, n2: integer) ;
  734.    begin
  735.       case op of
  736.          LTOP: if n1 < n2 then result := trueValue;
  737.          GTOP: if n1 > n2 then result := trueValue
  738.       end
  739.    end; (* applyRelOp *)
  740.  
  741. (* arity - return number of arguments expected by op             *)
  742.    function arity (op: VALUEOP): integer;
  743.    begin
  744.       if op in [PLUSOP .. CONSOP] then arity := 2 else arity := 1
  745.    end; (* arity *)
  746.  
  747. begin (* applyValueOp *)
  748.    if arity(op) <> lengthVL(vl)
  749.    then begin
  750.            write('Wrong number of arguments to ');
  751.            prName(ord(op)+1);
  752.            writeln;
  753.            goto 99
  754.         end;
  755.    result := nilValue;
  756.    s1 := vl^.head; (* 1st actual *)
  757.    if arity(op) = 2 then s2 := vl^.tail^.head; (* 2nd actual *)
  758.    if op in [PLUSOP .. DIVOP, LTOP .. GTOP]
  759.    then if (s1^.sxptype = NUMSXP)
  760.            and (s2^.sxptype = NUMSXP)
  761.         then if op in [PLUSOP .. DIVOP]
  762.              then applyArithOp(s1^.intval, s2^.intval)
  763.              else applyRelOp(s1^.intval, s2^.intval)
  764.         else begin
  765.                 write('Non-arithmetic arguments to ');
  766.                 prName(ord(op)+1);
  767.                 writeln;
  768.                 goto 99
  769.              end
  770.    else with s1^ do
  771.            case op of
  772.               EQOP:
  773.                  if (sxptype = NILSXP)
  774.                     and (s2^.sxptype = NILSXP)
  775.                  then result := trueValue
  776.                  else if (sxptype = NUMSXP)
  777.                          and (s2^.sxptype = NUMSXP)
  778.                          and (intval = s2^.intval)
  779.                       then result := trueValue
  780.                       else if (sxptype = SYMSXP)
  781.                               and (s2^.sxptype = SYMSXP)
  782.                               and (symval = s2^.symval)
  783.                            then result := trueValue;
  784.               CONSOP:
  785.                  begin
  786.                     result := mkSExp(LISTSXP);
  787.                     with result^ do begin
  788.                        carval := s1;
  789.                        cdrval := s2
  790.                        end
  791.                  end;
  792.               CAROP:
  793.                  if sxptype <> LISTSXP
  794.                  then begin
  795.                          write('Error: car applied to non-list: ');
  796.                          prValue(s1);
  797.                          writeln
  798.                       end
  799.                  else result := carval;
  800.               CDROP:
  801.                  if sxptype <> LISTSXP
  802.                  then begin
  803.                          write('Error: cdr applied to non-list: ');
  804.                          prValue(s1);
  805.                          writeln
  806.                       end
  807.                  else result := cdrval;
  808.               NUMBERPOP:
  809.                  if sxptype = NUMSXP then result := trueValue;
  810.               SYMBOLPOP:
  811.                  if sxptype = SYMSXP then result := trueValue;
  812.               LISTPOP:
  813.                  if sxptype = LISTSXP then result := trueValue;
  814.               NULLPOP:
  815.                  if sxptype = NILSXP then result := trueValue;
  816.               PRINTOP:
  817.                  begin prValue(s1); writeln; result := s1 end
  818.            end; (* case and with *)
  819.    applyValueOp := result
  820. end; (* applyValueOp *)
  821.  
  822. (*****************************************************************
  823.  *                     EVALUATION                                *
  824.  *****************************************************************)
  825.  
  826. (* eval - return value of expression e in local environment rho  *)
  827. function eval (e: EXP; rho: ENV): SEXP;
  828.  
  829. var op: BUILTINOP;
  830.  
  831. (* evalList - evaluate each expression in el                     *)
  832.    function evalList (el: EXPLIST): VALUELIST;
  833.    var
  834.       h: SEXP;
  835.       t: VALUELIST;
  836.    begin
  837.       if el = nil then evalList := nil
  838.       else begin
  839.               h := eval(el^.head, rho);
  840.               t := evalList(el^.tail);
  841.               evalList := mkValuelist(h, t)
  842.            end
  843.    end; (* evalList *)
  844.  
  845. (* applyUserFun - look up definition of nm and apply to actuals  *)
  846.    function applyUserFun (nm: NAME; actuals: VALUELIST): SEXP;
  847.    var
  848.       f: FUNDEF;
  849.       rho: ENV;
  850.    begin
  851.       f := fetchFun(nm);
  852.       if f = nil
  853.       then begin
  854.               write('Undefined function: ');
  855.               prName(nm);
  856.               writeln;
  857.               goto 99
  858.            end;
  859.       with f^ do begin
  860.          if lengthNL(formals) <> lengthVL(actuals)
  861.          then begin
  862.                  write('Wrong number of arguments to: ');
  863.                  prName(nm);
  864.                  writeln;
  865.                  goto 99
  866.               end;
  867.          rho := mkEnv(formals, actuals);
  868.          applyUserFun := eval(body, rho)
  869.          end
  870.    end; (* applyUserFun *)
  871.  
  872. (* applyCtrlOp - apply CONTROLOP op to args in rho               *)
  873.    function applyCtrlOp (op: CONTROLOP;
  874.                        args: EXPLIST): SEXP;
  875.    var s: SEXP;
  876.    begin
  877.       with args^ do
  878.          case op of
  879.            IFOP:
  880.               if isTrueVal(eval(head, rho))
  881.               then applyCtrlOp := eval(tail^.head, rho)
  882.               else applyCtrlOp := eval(tail^.tail^.head, rho);
  883.            WHILEOP:
  884.               begin
  885.                  s := eval(head, rho);
  886.                  while isTrueVal(s)
  887.                  do begin
  888.                        s := eval(tail^.head, rho);
  889.                        s := eval(head, rho)
  890.                     end;
  891.                  applyCtrlOp := s
  892.               end;
  893.            SETOP:
  894.               begin
  895.                  s := eval(tail^.head, rho);
  896.                  if isBound(head^.varble, rho)
  897.                  then assign(head^.varble, s, rho)
  898.                  else if isBound(head^.varble, globalEnv)
  899.                       then assign(head^.varble, s, globalEnv)
  900.                       else bindVar(head^.varble, s, globalEnv);
  901.                  applyCtrlOp := s
  902.               end;
  903.            BEGINOP: 
  904.               begin
  905.                  while args^.tail <> nil do
  906.                     begin
  907.                        s := eval(args^.head, rho);
  908.                        args := args^.tail
  909.                     end;
  910.                  applyCtrlOp := eval(args^.head, rho)
  911.               end
  912.          end (* case and with *)
  913.    end; (* applyCtrlOp *)
  914.  
  915. begin (* eval *)
  916.    with e^ do
  917.       case etype of
  918.          VALEXP:
  919.             eval := sxp;
  920.          VAREXP:
  921.             if isBound(varble, rho)
  922.             then eval := fetch(varble, rho)
  923.             else if isBound(varble, globalEnv)
  924.                  then eval := fetch(varble, globalEnv)
  925.                  else begin
  926.                          write('Undefined variable: ');
  927.                          prName(varble);
  928.                          writeln;
  929.                          goto 99
  930.                       end;
  931.          APEXP: 
  932.             if optr > numBuiltins
  933.             then eval := applyUserFun(optr, evalList(args))
  934.             else begin
  935.                     op := primOp(optr);
  936.                     if op in [IFOP .. BEGINOP]
  937.                     then eval := applyCtrlOp(op, args)
  938.                     else eval := applyValueOp(op,
  939.                                      evalList(args))
  940.                  end
  941.       end (* case and with *)
  942. end; (* eval *)
  943.  
  944. (*****************************************************************
  945.  *                     READ-EVAL-PRINT LOOP                      *
  946.  *****************************************************************)
  947.  
  948. begin (* lisp main *)
  949.    initNames;
  950.  
  951.    nilValue := mkSExp(NILSXP);
  952.    trueValue := mkSExp(SYMSXP); trueValue^.symval := numNames;
  953.  
  954.    globalEnv := emptyEnv;
  955.  
  956.    quittingtime := false;
  957. 99:
  958.    while not quittingtime do begin
  959.       reader;
  960.       if matches(pos, 4, 'quit                ')
  961.       then quittingtime := true
  962.       else if (userinput[pos] = '(') and
  963.               matches(skipblanks(pos+1), 6, 'define              ')
  964.            then begin
  965.                    prName(parseDef);
  966.                    writeln
  967.                 end
  968.            else begin
  969.                    currentExp := parseExp;
  970.                    prValue(eval(currentExp, emptyEnv));
  971.                    writeln;
  972.                    writeln
  973.                 end
  974.       end (* while *)
  975. end. (* lisp *)
  976.    
  977.  
  978.  
  979.