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