home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d524 / kamin.lha / Kamin / P-Distr.lzh / scheme.p < prev    next >
Text File  |  1989-03-22  |  29KB  |  988 lines

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