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