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