home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / sa104os2.zip / SATHR104.ZIP / SATHER / CONTRIB / LISP / LISP.SA < prev    next >
Text File  |  1994-10-25  |  26KB  |  920 lines

  1. -- Copyright (C) International Computer Science Institute, 1994.  COPYRIGHT  --
  2. -- NOTICE: This code is provided "AS IS" WITHOUT ANY WARRANTY and is subject --
  3. -- to the terms of the SATHER LIBRARY GENERAL PUBLIC LICENSE contained in    --
  4. -- the file "Doc/License" of the Sather distribution.  The license is also   --
  5. -- available from ICSI, 1947 Center St., Suite 600, Berkeley CA 94704, USA.  --
  6. --------> Please email comments to "sather-bugs@icsi.berkeley.edu". <----------
  7.  
  8. ----------------------------------------------------------------------
  9. -- Lisp.sa: Implementation of a primitive Lisp interpreter. The only
  10. -- purpose of this program is to serve as a non-trivial but still com-
  11. -- prehensible Sather 1.0 program. Although the interpreter allows
  12. -- to execute pretty sophisticated programs, it is fairly restricted
  13. -- and especially doesn't allow to define higher order functions
  14. -- (due to the very simple implementation of lambda). The basic
  15. -- Lisp data structures are mapped to corresponding Sather types
  16. -- and classes. To understand the implementation, basic knowledge
  17. -- of Lisp is required. A very brief documentation can be found in
  18. -- Lisp.Docu.ps.
  19. --
  20. -- Author: Robert Griesemer (gri@icsi.berkeley.edu)
  21. -- Created: 17 Aug 1994
  22. ----------------------------------------------------------------------
  23.  
  24. type $LIST is
  25. -- Base type for all Lisp objects. Everything is a $LIST.
  26. --
  27.    eval: $LIST; -- every object can evaluate itself
  28.    str: STR; -- every object can print itself
  29.  
  30. -- The following methods raise a STR exception if the
  31. -- object is not of the expected type. Otherwise the
  32. -- object (self) is returned. These routines greatly
  33. -- simplify the implementation of predefined functions
  34. -- and unify error handling.
  35. --
  36.    pair: PAIR;
  37.    lpair: PAIR;
  38.    number: NUMBER;
  39.    string: STRING;
  40.    symbol: SYMBOL;
  41.    function: $FUNCTION;
  42.    is_nil: BOOL -- nil predicate
  43. end;
  44.  
  45.  
  46. class LIST < $LIST is
  47. -- Basic implementation for Lisp objects.
  48. --
  49.    eval: $LIST is raise 0 end; -- must be overriden in derived classes
  50.    str: STR is raise 1 end; -- must be overriden in derived classes
  51.  
  52.    pair: PAIR is raise str + " is not a pair" end;
  53.    lpair: PAIR is raise str + " is not a pair" end;
  54.    number: NUMBER is raise str + " is not a number" end;
  55.    string: STRING is raise str + " is not a string" end;
  56.    symbol: SYMBOL is raise str + " is not a symbol" end;
  57.    function: $FUNCTION is raise str + " is not a function" end;
  58.    is_nil: BOOL is return false end
  59. end;
  60.  
  61.  
  62. class NIL < $LIST is
  63. -- A unique Lisp object is used to represent the empty list.
  64. -- The advantage of not using void instead is that
  65. -- method access is always possible (e.g. all the methods
  66. -- defined for $LISTs can be called without explicit
  67. -- void tests).
  68. --
  69.    include LIST;
  70.    private shared nil: NIL; -- only instance
  71.    
  72.    create: NIL is
  73.       if void(nil) then nil := new end;
  74.       return nil
  75.    end;
  76.    
  77.    eval: $LIST is return nil end;
  78.    str: STR is return "()" end;
  79.    is_nil: BOOL is return true end
  80. end;
  81.  
  82.  
  83. type $FUNCTION < $LIST is
  84. -- Base type for all predefined function objects.
  85. -- The argument x of apply is the tail of the function
  86. -- list expression, e.g., if f is a symbol refering to a
  87. -- predefined function [f], and (f a b c) is evaluated,
  88. -- [f].apply is called with argument (a b c).
  89. --
  90.    apply (x: $LIST): $LIST
  91. end;
  92.  
  93.  
  94. class FUNCTION < $FUNCTION is
  95. -- Basic implementation for predefined function objects.
  96. --
  97.    include LIST;
  98.    private attr sym: SYMBOL; -- associated symbol
  99.  
  100.    apply (x: $LIST): $LIST is raise 2 end; -- must be overriden in derived classes
  101.    create (name: STR) is p ::= new; p.sym := #SYMBOL(name); p.sym.bound := p end;
  102.    eval: $LIST is return self end; -- functions evaluate to themselves
  103.  
  104.    str: STR is
  105.       if void(sym) or ~SYS::ob_eq(sym.bound, self) then sym := SYMBOL::find(self) end;
  106.       if void(sym) then return "[" + SYS::id(self) + ']'
  107.       else return "[" + sym.str + ']'
  108.       end
  109.    end;
  110.  
  111.    function: $FUNCTION is return self end
  112. end;
  113.  
  114.  
  115. class TRACER < $FUNCTION is
  116.    include FUNCTION;
  117.    readonly shared on: BOOL;
  118.    private shared level: INT;
  119.  
  120.    reset is level := 0 end;
  121.  
  122.    apply (x: $LIST): $LIST is
  123.       if ~x.is_nil then on := SYS::ob_eq(x.lpair.car.symbol, #SYMBOL("on")) end;
  124.       if on then return #SYMBOL("on")
  125.       else return #SYMBOL("off")
  126.       end
  127.    end;
  128.  
  129.    private indent is
  130.       i: INT := level;
  131.       loop while!(i > 0); i := i-1; #OUT + "   " end
  132.    end;
  133.  
  134.    trace (f: $FUNCTION, x: $LIST): $LIST is
  135.       indent; #OUT + f.str + " called with " + x.str + '\n';
  136.       level := level+1; x := f.apply(x); level := level-1;
  137.       indent; #OUT + f.str + " returns " + x.str + '\n';
  138.       return x
  139.    end
  140. end;
  141.  
  142.  
  143. class FRAME is
  144. -- Stack frame for evaluation of user-defined functions.
  145. -- Every frame contains an array with arguments.
  146. --
  147.    include ARRAY {$LIST}; -- arguments
  148.    readonly shared top: FRAME; -- top of stack
  149.    private attr prev: FRAME; -- previous stack frame
  150.    readonly attr this: USERDEF; -- corresponding function
  151.  
  152.    create (nofArgs: INT, this: USERDEF): FRAME is
  153.       f ::= new(nofArgs); f.prev := void; f.this := this; return f
  154.    end;
  155.  
  156.    reset is top := void end;
  157.    enter is prev := top; top := self end;
  158.    exit is top := prev end
  159. end;
  160.  
  161.  
  162. class LOCAL < $LIST is
  163. -- Objects referring to local variable (no) on topmost stack frame.
  164. --
  165.    include LIST;
  166.    readonly attr no: INT;
  167.  
  168.    create (n: INT): LOCAL is r ::= new; r.no := n; return r end;
  169.    eval: $LIST is return FRAME::top[no] end;
  170.    str: STR is return "#" + no end
  171. end;
  172.  
  173.  
  174. class USERDEF < $FUNCTION is
  175. -- User defined functions contain a list of expressions (fun), to be
  176. -- evaluated when the function is called. Within these expressions,
  177. -- local variables are accessed via LOCAL objects.
  178. --
  179.    include FUNCTION;
  180.    private attr nofArgs: INT; -- no. of arguments
  181.    private attr argExt: INT; -- either 0 or 1
  182.    private attr fun: $LIST; -- list of expressions
  183.  
  184.    create (nofArgs, argExt: INT, fun: $LIST): USERDEF is
  185.       r ::= new; r.sym := void; r.nofArgs := nofArgs; r.argExt := argExt; r.fun := fun;
  186.       return r
  187.    end;
  188.  
  189.    apply (x: $LIST): $LIST is
  190.    -- create new stack frame
  191.       f ::= #FRAME(nofArgs + argExt, self); i ::= 0;
  192.    -- evaluate and pass arguments
  193.       loop while!(i < nofArgs); p ::= x.pair; f[i] := p.car.eval; x := p.cdr; i := i+1 end;
  194.    -- pass extension, if any (no evaluation)
  195.       if argExt > 0 then f[i] := x; x := LISP::nil end;
  196.    -- call function and evaluate function expressions
  197.       h: $LIST := LISP::nil;
  198.       if x.is_nil then
  199.          f.enter; x := fun;
  200.          loop until!(x.is_nil); p ::= x.pair; x := p.cdr; h := p.car.eval end;
  201.          f.exit
  202.       else raise "number of args and params does not match"
  203.       end;
  204.       return h
  205.    end;
  206.  
  207.    str: STR is
  208.       if void(sym) or ~SYS::ob_eq(sym.bound, self) then sym := SYMBOL::find(self) end;
  209.       if void(sym) then return "[" + fun.str + ']'
  210.       else return "[" + sym.str + ']'
  211.       end
  212.    end
  213. end;
  214.  
  215.  
  216. class LAMBDA < $FUNCTION is
  217. -- "Compiler" for user defined functions: Lambda expressions
  218. -- are translated into USERDEF objects. Symbols representing
  219. -- local variables are substituted by LOCAL objects (subst).
  220. --
  221.    include FUNCTION;
  222.  
  223.    subst (x: $LIST, pars: FLIST {SYMBOL}): $LIST is
  224.       r ::= x;
  225.       typecase x
  226.       when PAIR then
  227.          r := #PAIR(subst(x.car, pars), subst(x.cdr, pars))
  228.       when SYMBOL then i ::= 0;
  229.          loop while!((i < pars.size) and ~SYS::ob_eq(x, pars[i])); i := i+1 end;
  230.          if i < pars.size then r := #LOCAL(i) end
  231.       else end;
  232.       return r
  233.    end;
  234.  
  235.    apply (x: $LIST): $LIST is
  236.       pars: FLIST {SYMBOL} := void; argExt ::= 0;
  237.       p ::= x.pair; q ::= p.car; x := p.cdr;
  238.       loop
  239.          typecase q
  240.          when PAIR then pars := pars.push(q.car.symbol); p := q
  241.          when NIL then break!
  242.          else pars := pars.push(q.symbol); argExt := 1; break!
  243.          end;
  244.          q := p.cdr
  245.       end;
  246.       return #USERDEF(pars.size - argExt, argExt, subst(x, pars))
  247.    end
  248. end;
  249.  
  250.  
  251. class CAR < $FUNCTION is
  252.    include FUNCTION;
  253.    apply (x: $LIST): $LIST is return x.lpair.car.eval.pair.car end
  254. end;
  255.  
  256.  
  257. class CDR < $FUNCTION is
  258.    include FUNCTION;
  259.    apply (x: $LIST): $LIST is return x.lpair.car.eval.pair.cdr end
  260. end;
  261.  
  262.  
  263. class CONS < $FUNCTION is
  264.    include FUNCTION;
  265.    apply (x: $LIST): $LIST is p ::= x.pair; return #PAIR(p.car.eval, p.cdr.lpair.car.eval) end
  266. end;
  267.  
  268.  
  269. class QUOTE < $FUNCTION is
  270.    include FUNCTION;
  271.    apply (x: $LIST): $LIST is return x.lpair.car end
  272. end;
  273.  
  274.  
  275. class ADD < $FUNCTION is
  276.    include FUNCTION;
  277.    apply (x: $LIST): $LIST is
  278.       p ::= x.pair; x := p.cdr; t ::= p.car.eval.number.val;
  279.       loop p := x.pair; x := p.cdr; t := t + p.car.eval.number.val; until!(x.is_nil) end;
  280.       return #NUMBER(t)
  281.    end
  282. end;
  283.  
  284.  
  285. class SUB < $FUNCTION is
  286.    include FUNCTION;
  287.    apply (x: $LIST): $LIST is
  288.       p ::= x.pair; x := p.cdr; t ::= p.car.eval.number.val;
  289.       loop p := x.pair; x := p.cdr; t := t - p.car.eval.number.val; until!(x.is_nil) end;
  290.       return #NUMBER(t)
  291.    end
  292. end;
  293.  
  294.  
  295. class MUL < $FUNCTION is
  296.    include FUNCTION;
  297.    apply (x: $LIST): $LIST is
  298.       p ::= x.pair; x := p.cdr; t ::= p.car.eval.number.val;
  299.       loop p := x.pair; x := p.cdr; t := t * p.car.eval.number.val; until!(x.is_nil) end;
  300.       return #NUMBER(t)
  301.    end
  302. end;
  303.  
  304.  
  305. class DIV < $FUNCTION is
  306.    include FUNCTION;
  307.    apply (x: $LIST): $LIST is
  308.       p ::= x.pair; x := p.cdr; t ::= p.car.eval.number.val;
  309.       loop p := x.pair; x := p.cdr; t := t / p.car.eval.number.val; until!(x.is_nil) end;
  310.       return #NUMBER(t)
  311.    end
  312. end;
  313.  
  314.  
  315. class MOD < $FUNCTION is
  316.    include FUNCTION;
  317.    apply (x: $LIST): $LIST is
  318.       p ::= x.pair; x := p.cdr; t ::= p.car.eval.number.val;
  319.       loop p := x.pair; x := p.cdr; t := t % p.car.eval.number.val; until!(x.is_nil) end;
  320.       return #NUMBER(t)
  321.    end
  322. end;
  323.  
  324.  
  325. class POW < $FUNCTION is
  326.    include FUNCTION;
  327.    apply (x: $LIST): $LIST is
  328.       p ::= x.pair; x := p.cdr; t ::= p.car.eval.number.val;
  329.       loop p := x.pair; x := p.cdr; t := t ^ p.car.eval.number.val.floor.int; until!(x.is_nil) end;
  330.       return #NUMBER(t)
  331.    end
  332. end;
  333.  
  334.  
  335. class EQL < $FUNCTION is
  336.    include FUNCTION;
  337.    apply (x: $LIST): $LIST is
  338.       p ::= x.pair; x := p.cdr; h ::= p.car.eval;
  339.       typecase h
  340.       when NUMBER then n ::= h.val;
  341.          loop p := x.pair; x := p.cdr; m ::= p.car.eval.number.val;
  342.             if n /= m then return LISP::nil end;
  343.             n := m; until!(x.is_nil)
  344.          end
  345.       when STRING then s ::= h.s;
  346.          loop p := x.pair; x := p.cdr; t ::= p.car.eval.string.s;
  347.             if s /= t then return LISP::nil end;
  348.             s := t; until!(x.is_nil)
  349.          end
  350.       else raise h.str + " is not a number or string"
  351.       end;
  352.       return LISP::t
  353.    end
  354. end;
  355.  
  356.  
  357. class NEQ < $FUNCTION is
  358.    include FUNCTION;
  359.    apply (x: $LIST): $LIST is
  360.       p ::= x.pair; x := p.cdr; h ::= p.car.eval;
  361.       typecase h
  362.       when NUMBER then n ::= h.val;
  363.          loop p := x.pair; x := p.cdr; m ::= p.car.eval.number.val;
  364.             if n = m then return LISP::nil end;
  365.             n := m; until!(x.is_nil)
  366.          end
  367.       when STRING then s ::= h.s;
  368.          loop p := x.pair; x := p.cdr; t ::= p.car.eval.string.s;
  369.             if s = t then return LISP::nil end;
  370.             s := t; until!(x.is_nil)
  371.          end
  372.       else raise h.str + " is not a number or string"
  373.       end;
  374.       return LISP::t
  375.    end
  376. end;
  377.  
  378.  
  379. class LSS < $FUNCTION is
  380.    include FUNCTION;
  381.    apply (x: $LIST): $LIST is
  382.       p ::= x.pair; x := p.cdr; h ::= p.car.eval;
  383.       typecase h
  384.       when NUMBER then n ::= h.val;
  385.          loop p := x.pair; x := p.cdr; m ::= p.car.eval.number.val;
  386.             if n >= m then return LISP::nil end;
  387.             n := m; until!(x.is_nil)
  388.          end
  389.       when STRING then s ::= h.s;
  390.          loop p := x.pair; x := p.cdr; t ::= p.car.eval.string.s;
  391.             if s >= t then return LISP::nil end;
  392.             s := t; until!(x.is_nil)
  393.          end
  394.       else raise h.str + " is not a number or string"
  395.       end;
  396.       return LISP::t
  397.    end
  398. end;
  399.  
  400.  
  401. class LEQ < $FUNCTION is
  402.    include FUNCTION;
  403.    apply (x: $LIST): $LIST is
  404.       p ::= x.pair; x := p.cdr; h ::= p.car.eval;
  405.       typecase h
  406.       when NUMBER then n ::= h.val;
  407.          loop p := x.pair; x := p.cdr; m ::= p.car.eval.number.val;
  408.             if n > m then return LISP::nil end;
  409.             n := m; until!(x.is_nil)
  410.          end
  411.       when STRING then s ::= h.s;
  412.          loop p := x.pair; x := p.cdr; t ::= p.car.eval.string.s;
  413.             if s > t then return LISP::nil end;
  414.             s := t; until!(x.is_nil)
  415.          end
  416.       else raise h.str + " is not a number or string"
  417.       end;
  418.       return LISP::t
  419.    end
  420. end;
  421.  
  422.  
  423. class GTR < $FUNCTION is
  424.    include FUNCTION;
  425.    apply (x: $LIST): $LIST is
  426.       p ::= x.pair; x := p.cdr; h ::= p.car.eval;
  427.       typecase h
  428.       when NUMBER then n ::= h.val;
  429.          loop p := x.pair; x := p.cdr; m ::= p.car.eval.number.val;
  430.             if n <= m then return LISP::nil end;
  431.             n := m; until!(x.is_nil)
  432.          end
  433.       when STRING then s ::= h.s;
  434.          loop p := x.pair; x := p.cdr; t ::= p.car.eval.string.s;
  435.             if s <= t then return LISP::nil end;
  436.             s := t; until!(x.is_nil)
  437.          end
  438.       else raise h.str + " is not a number or string"
  439.       end;
  440.       return LISP::t
  441.    end
  442. end;
  443.  
  444.  
  445. class GEQ < $FUNCTION is
  446.    include FUNCTION;
  447.    apply (x: $LIST): $LIST is
  448.       p ::= x.pair; x := p.cdr; h ::= p.car.eval;
  449.       typecase h
  450.       when NUMBER then n ::= h.val;
  451.          loop p := x.pair; x := p.cdr; m ::= p.car.eval.number.val;
  452.             if n < m then return LISP::nil end;
  453.             n := m; until!(x.is_nil)
  454.          end
  455.       when STRING then s ::= h.s;
  456.          loop p := x.pair; x := p.cdr; t ::= p.car.eval.string.s;
  457.             if s < t then return LISP::nil end;
  458.             s := t; until!(x.is_nil)
  459.          end
  460.       else raise h.str + " is not a number or string"
  461.       end;
  462.       return LISP::t
  463.    end
  464. end;
  465.  
  466.  
  467. class FLOOR < $FUNCTION is
  468.    include FUNCTION;
  469.    apply (x: $LIST): $LIST is return #NUMBER(x.lpair.car.eval.number.val.floor) end
  470. end;
  471.  
  472.  
  473. class CEILING < $FUNCTION is
  474.    include FUNCTION;
  475.    apply (x: $LIST): $LIST is return #NUMBER(x.lpair.car.eval.number.val.ceiling) end
  476. end;
  477.  
  478.  
  479. class FACT < $FUNCTION is
  480.    include FUNCTION;
  481.    apply (x: $LIST): $LIST is return #NUMBER(x.lpair.car.eval.number.val.floor.factorial) end
  482. end;
  483.  
  484.  
  485. class EQ < $FUNCTION is
  486.    include FUNCTION;
  487.    apply (x: $LIST): $LIST is
  488.       p ::= x.pair;
  489.       a ::= p.car.eval; b ::= p.cdr.lpair.car.eval;
  490.       if SYS::ob_eq(a, b) then return LISP::t
  491.       else return LISP::nil
  492.       end
  493.    end
  494. end;
  495.  
  496.  
  497. class COND < $FUNCTION is
  498.    include FUNCTION;
  499.    apply (x: $LIST): $LIST is
  500.       t: $LIST := LISP::nil;
  501.       loop p ::= x.pair; x := p.cdr; y ::= p.car;
  502.          if ~y.is_nil then p := y.pair; y := p.cdr; t := p.car.eval;
  503.             if ~t.is_nil then x := LISP::nil;
  504.                loop while!(~y.is_nil); p := y.pair; y := p.cdr; t := p.car.eval end
  505.             end
  506.          end;
  507.          until!(x.is_nil)
  508.       end;
  509.       return t
  510.    end
  511. end;
  512.  
  513.  
  514. class EVAL < $FUNCTION is
  515.    include FUNCTION;
  516.    apply (x: $LIST): $LIST is return x.lpair.car.eval.eval end
  517. end;
  518.  
  519.  
  520. class ATOM < $FUNCTION is
  521.    include FUNCTION;
  522.    apply (x: $LIST): $LIST is x := x.lpair.car.eval;
  523.       typecase x when PAIR then return LISP::nil
  524.       else return LISP::t
  525.       end
  526.    end
  527. end;
  528.  
  529.  
  530. class SET < $FUNCTION is
  531.    include FUNCTION;
  532.    apply (x: $LIST): $LIST is
  533.       p ::= x.pair; d ::= p.car.eval; s ::= p.cdr.lpair.car.eval;
  534.       typecase d
  535.       when LOCAL then FRAME::top[d.no] := s
  536.       when SYMBOL then d.bound := s
  537.       else raise d.str + " is not a variable"
  538.       end;
  539.       return s
  540.    end
  541. end;
  542.  
  543.  
  544. class SETQ < $FUNCTION is
  545.    include FUNCTION;
  546.    apply (x: $LIST): $LIST is
  547.       p ::= x.pair; d ::= p.car; s ::= p.cdr.lpair.car.eval;
  548.       typecase d
  549.       when LOCAL then FRAME::top[d.no] := s
  550.       when SYMBOL then d.bound := s
  551.       else raise d.str + " is not a variable"
  552.       end;
  553.       return s
  554.    end
  555. end;
  556.  
  557.  
  558. class SYMBOLS < $FUNCTION is
  559.    include FUNCTION;
  560.    apply (x: $LIST): $LIST is assert x.is_nil; return SYMBOL::list end
  561. end;
  562.  
  563.  
  564. class EXIT < $FUNCTION is
  565.    include FUNCTION;
  566.    apply (x: $LIST): $LIST is assert x.is_nil; LISP::exit := true; return x end
  567. end;
  568.  
  569.  
  570. class WRITE < $FUNCTION is
  571.    include FUNCTION;
  572.    apply (x: $LIST): $LIST is x := x.lpair.car.eval; #OUT + x.str; return x end
  573. end;
  574.  
  575.  
  576. class WRITELN < $FUNCTION is
  577.    include FUNCTION;
  578.    apply (x: $LIST): $LIST is assert x.is_nil; #OUT + '\n'; return x end
  579. end;
  580.  
  581.  
  582. class READFILE < $FUNCTION is
  583.    include FUNCTION;
  584.    apply (x: $LIST): $LIST is
  585.       name ::= x.lpair.car.eval.string.s;
  586.       file ::= FILE::open_for_read(name);
  587.       if ~void(file) and ~file.error then
  588.          reader ::= #READER(file);
  589.          protect
  590.             loop
  591.                h ::= reader.line; until!(void(h));
  592.                x := h.eval
  593.             end
  594.          else file.close;
  595.             #OUT + "in file: " + name + '\n';
  596.             raise exception
  597.          end
  598.       end;
  599.       return x
  600.    end
  601. end;
  602.  
  603.  
  604. class PAIR < $LIST is
  605. -- Base class used to form lists. Head and tail are called 'car' and
  606. -- 'cdr' respectively for historical reasons (the first Lisp implementation
  607. -- on a IBM 704 used two special registers called CAR = Contents of Address
  608. -- Register and CDR = Contents of Displacement Register for this purpose).
  609. -- Evaluating a pair means evaluating its head and applying the resulting
  610. -- function to its tail.
  611. --
  612.    include LIST;
  613.    attr car, cdr: $LIST;
  614.  
  615.    create (car, cdr: $LIST): PAIR is p ::= new; p.car := car; p.cdr := cdr; return p end;
  616.  
  617.    eval: $LIST is
  618.       if TRACER::on then return TRACER::trace(car.eval.function, cdr)
  619.       else return car.eval.function.apply(cdr)
  620.       end
  621.    end;
  622.    
  623.    str: STR is
  624.       s ::= "(" + car.str; x ::= cdr;
  625.       loop p: PAIR;
  626.          typecase x when PAIR then p := x else break! end;
  627.          s := s + ' ' + p.car.str; x := p.cdr
  628.       end;
  629.       if ~x.is_nil then s := s + " . " + x.str end;
  630.       return s + ')'
  631.    end;
  632.  
  633.    pair: PAIR is return self end;
  634.  
  635.    lpair: PAIR is
  636.       if self.cdr.is_nil then return self
  637.       else raise str + " contains more than one element"
  638.       end
  639.    end
  640. end;
  641.  
  642.  
  643. class NUMBER < $LIST is
  644. -- Implementation of numbers.
  645. --
  646.    include LIST;
  647.    readonly attr val: RAT;
  648.  
  649.    create (val: INTI): NUMBER is r ::= new; r.val := #RAT(val); return r end;
  650.    create (val: RAT): NUMBER is r ::= new; r.val := val; return r end;
  651.    eval: $LIST is return self end;
  652.    str: STR is return val.str end;
  653.    number: NUMBER is return self end
  654. end;
  655.  
  656.  
  657. class STRING < $LIST is
  658. -- Implementation of strings.
  659. --
  660.    include LIST;
  661.    readonly attr s: STR;
  662.  
  663.    create (s: STR): STRING is r ::= new; r.s := s; return r end;
  664.    eval: $LIST is return self end;
  665.    str: STR is return "\"" + s + '"' end;
  666.    string: STRING is return self end
  667. end;
  668.  
  669.  
  670. class SYMBOL < $LIST is
  671. -- Implementation of symbols. All known symbols are inserted
  672. -- into a binary tree (root).
  673. --
  674.    include LIST;
  675.    attr bound: $LIST; -- assigned value
  676.    private attr name: STR; -- symbol name
  677.    private shared root: SYMBOL;
  678.    private attr left, right: SYMBOL;
  679.  
  680.    private traverse (x: $LIST, s: SYMBOL): $LIST is
  681.       if ~void(s) then x := traverse(#PAIR(s, traverse(x, s.right)), s.left) end;
  682.       return x
  683.    end;
  684.  
  685.    list: $LIST is return traverse(LISP::nil, root) end;
  686.  
  687.    private search (q: SYMBOL, x: $LIST): SYMBOL is
  688.       r ::= q;
  689.       if ~void(q) then
  690.          if ~SYS::ob_eq(q.bound, x) then
  691.             r := search(q.left, x);
  692.             if void(r) then r := search(q.right, x) end
  693.          end
  694.       end;
  695.       return r
  696.    end;
  697.  
  698.    find (x: $LIST): SYMBOL is return search(root, x) end;
  699.  
  700.    create (name: STR): SYMBOL is
  701.       p: SYMBOL := void; q ::= root;
  702.       loop while!(~void(q)); p := q;
  703.          if name < q.name then q := q.left
  704.          elsif q.name < name then q := q.right
  705.          else return q
  706.          end
  707.       end;
  708.       q := new; q.name := name; q.bound := LISP::nil;
  709.       if void(p) then root := q
  710.       elsif name < p.name then p.left := q
  711.       else p.right := q
  712.       end;
  713.       return q
  714.    end;
  715.  
  716.    eval: $LIST is return bound end;
  717.    str: STR is return name end;
  718.    symbol: SYMBOL is return self end
  719. end;
  720.  
  721.  
  722. class READER is
  723. -- Scanner and parser for Lisp expressions. Strategy:
  724. -- Conventional recursive descent parser (expr), one
  725. -- character lookahead (ch).
  726. --
  727.    private attr file: FILE; -- read file
  728.    private attr buf: FSTR; -- reader workspace
  729.    private attr ch: CHAR; -- one character look ahead
  730.    private attr lev: INT; -- list nesting level
  731.    private const eof: CHAR := '\0';
  732.    private const eol: CHAR := '\12';
  733.  
  734.    create (file: FILE): READER is
  735.    -- file must be ready to read from
  736.       r ::= new; r.file := file; r.buf := #FSTR(32); r.ch := ' '; r.lev := 0;
  737.       return r
  738.    end;
  739.  
  740.    private next is
  741.       ch := file.get_char;
  742.       if file.eof then ch := eof
  743.       elsif ch = eof then ch := ' '
  744.       end
  745.    end;
  746.  
  747.    private comment is
  748.       assert ch = '{'; next; n ::= 1;
  749.       loop
  750.          while!((ch /= eof) and (n > 0));
  751.          if ch = '{' then n := n+1
  752.          elsif ch = '}' then n := n-1
  753.          end;
  754.          next
  755.       end
  756.    end;
  757.  
  758.    private skip is
  759.       loop
  760.          if ch = '{' then comment
  761.          elsif (ch > ' ') or (ch = eof) or ((ch = eol) and (lev = 0)) then break!
  762.          else next
  763.          end
  764.       end
  765.    end;
  766.  
  767.    private is_special (ch: CHAR): BOOL is
  768.       case ch when '!', '#', '$', '%', '&', '*', '+', '-', '/', ':', '<', '=', '>', '?', '@', '\\', '^', '|', '~' then return true
  769.       else return false
  770.       end
  771.    end;
  772.  
  773.    private enter is lev := lev+1 end;
  774.    private exit is lev := lev-1 end;
  775.  
  776.    private error (loc: STR) is
  777.       ch0 ::= ch;
  778.       loop while!((ch /= eol) and (ch /= eof)); next end;
  779.       raise "illegal character '" + ch0 + "' found in " + loc
  780.    end;
  781.  
  782.    private int: INTI is
  783.       assert ch.is_digit; buf.clear;
  784.       loop buf := buf + ch; next; while!(ch.is_digit) end;
  785.       return #INTI(buf)
  786.    end;
  787.  
  788.    private number (neg: BOOL): $LIST is
  789.       assert ch.is_digit;
  790.       u ::= int; v ::= #INTI(1);
  791.       if ch = '/' then next;
  792.          if ch.is_digit then v := int
  793.          else error("rational number")
  794.          end
  795.       end;
  796.       skip;
  797.       if neg then u := -u end;
  798.       return #NUMBER(#RAT(u, v))      
  799.    end;
  800.  
  801.    private operator (sign: BOOL): $LIST is
  802.       buf.clear;
  803.       if sign then buf := buf + '-' end;
  804.       loop while!(is_special(ch)); buf := buf + ch; next end;
  805.       skip; return #SYMBOL(buf.str)
  806.    end;
  807.  
  808.    private expr: $LIST is
  809.       x: $LIST; p, q: PAIR;
  810.       if ch = '\'' then next; skip; x := #PAIR(#SYMBOL("quote"), #PAIR(expr, LISP::nil))
  811.       elsif ch = '(' then enter; next; skip;
  812.          if ch = ')' then exit; next; skip; x := LISP::nil
  813.          else p := #PAIR(expr, LISP::nil); x := p;
  814.             loop while!((ch /= '.') and (ch /= ')'));
  815.                q := #PAIR(expr, LISP::nil); p.cdr := q; p := q
  816.             end;
  817.             if ch = '.' then next; skip; p.cdr := expr end;
  818.             if ch = ')' then exit; next; skip
  819.             else error("list")
  820.             end
  821.          end
  822.       elsif ch.is_alpha then -- symbol
  823.          buf.clear;
  824.          loop buf := buf + ch; next; while!(ch.is_alpha or ch.is_digit) end;
  825.          skip; x := #SYMBOL(buf.str)
  826.       elsif ch = '-' then -- operator or number
  827.          next;
  828.          if ch.is_digit then x := number(true)
  829.          else x := operator(true)
  830.          end
  831.       elsif is_special(ch) then x := operator(false)
  832.       elsif ch.is_digit then x := number(false)
  833.       elsif ch = '"' then -- string
  834.          next; buf.clear;
  835.          loop while!((ch >= ' ') and (ch /= '"')); buf := buf + ch; next end;
  836.          if ch = '"' then next; skip; x := #STRING(buf.str)
  837.          else error("string")
  838.          end
  839.       else error("expression")
  840.       end;
  841.       return x
  842.    end;
  843.  
  844.    line: $LIST is
  845.       lev := 1; skip; -- ignore eol's
  846.       if ch = eof then return void
  847.       else lev := 0; return expr
  848.       end
  849.    end
  850. end;
  851.  
  852.  
  853. class LISP is
  854. -- Main class. Contains initialization of symbol table (init),
  855. -- the read-eval-write loop, and exception handling.
  856. --
  857.    readonly shared nil: $LIST; -- unique value for nil
  858.    readonly shared t: SYMBOL; -- unique truth value
  859.    shared exit: BOOL;
  860.  
  861.    init is
  862.       nil := #NIL;
  863.       t := #SYMBOL("t"); t.bound := t;
  864.    -- predefined functions
  865.       TRACER::create("tracer");
  866.       CAR::create("car");
  867.       CDR::create("cdr");
  868.       CONS::create("cons");
  869.       QUOTE::create("quote");
  870.       ADD::create("+");
  871.       SUB::create("-");
  872.       MUL::create("*");
  873.       DIV::create("/");
  874.       MOD::create("%");
  875.       POW::create("^");
  876.       EQL::create("=");
  877.       NEQ::create("#");
  878.       LSS::create("<");
  879.       LEQ::create("<=");
  880.       GTR::create(">");
  881.       GEQ::create(">=");
  882.       FLOOR::create("floor");
  883.       CEILING::create("ceiling");
  884.       FACT::create("!");
  885.       EQ::create("eq");
  886.       COND::create("cond");
  887.       EVAL::create("eval");
  888.       ATOM::create("atom");
  889.       SET::create("set");
  890.       SETQ::create("setq");
  891.       SYMBOLS::create("symbols");
  892.       EXIT::create("exit");
  893.       LAMBDA::create("lambda");
  894.       WRITE::create("write");
  895.       WRITELN::create("writeLn");
  896.       READFILE::create("readFile")
  897.    end;
  898.  
  899.    main is
  900.       #OUT + "Sather Lisp - gri 17 Aug 94\n";
  901.       #OUT + "(symbols) returns a list of all defined symbols\n";
  902.       LISP::init;
  903.       reader ::= #READER(FILE::stdin); exit := false;
  904.       loop
  905.          protect
  906.             TRACER::reset; FRAME::reset;
  907.             #OUT + "> "; OUT::flush; x ::= reader.line;
  908.             if ~void(x) then #OUT + x.eval.str + '\n'
  909.             else exit := true
  910.             end
  911.          when STR then #OUT + "error";
  912.             if ~void(FRAME::top) then #OUT + " in " + FRAME::top.this.str end;
  913.             #OUT + ": " + exception + '\n'
  914.          end;
  915.          until!(exit)
  916.       end
  917.    end
  918.  
  919. end
  920.