Monday, January 31, 2005

lab 27 - sh sexpr


lab 27 - sh sexpr


The implementation of the lisp dialect in lab 26 had some problems. For each car or cdr operator I recursively descended the syntax tree rather than holding the lists in memory in a more convenient fomat and simply taking the head or tail of the list.

I did not want to build further on this implementation. Instead I wanted to rewrite eval to use the sexprs(2) module and convert the sh's syntax tree to an s-expression.

Converting from the syntax tree to an s-expression is pretty easy to do, though it took me a while to remember the method. The first file lisp1.b is a brute force implementation, which of course once I got working I remembered the method I should of used.

          % load ./lisp1
          % eval {a {b} c}
          (a (b) c)
          % unload ./lisp1

The second file lisp2.b maintains a global stack of lists of sexprs. As it recursively descends the syntax tree it pushes expressions onto the list at the top of the stack. If it descends into a new block, it pushes a new list.

Next lisp3.b handles all the syntax tree's node types. The result is an sexpr which preserves all information from the shell's abstract syntax tree.

          % load ./lisp3
          % eval {echo `{a b c} &}
          ((Nowait echo (Quote (a b c))))
          % eval { echo "{ (a (nested (list)))}}
          (echo (SquashQuote ((List a (List nested (List list))))))
          % eval {a 
          (Seq (a) (Seq (sequence) (Seq (of) (cmds))))
          % unload ./lisp3

The sequences should really be flattened to (Seq (a) (sequence) (of) (cmds)) But since I wanted to treat newlines not as sequences of commands but as lists I didn't bother.

The point here is that we represent the sh's abstract syntax tree as a symbolic expression ready for manipulation and evaluation. A new symbolic expression could be composed and converted back to the sh's AST for evaluation by the shell. The above builtin should not really be called eval since I am not evaluating the expression. I am just converting from input form into s-expression form.

In lisp4.b I implemented the special forms, cons, car,cdr, and atom, which are all trivial to implement given the sexpr data structure. I also added a builtin FullForm to print an shell expression converted to an s-expression, and eval now evaluates the expression using lisp semantics.

          % load ./lisp4.dis
          % FullForm { a b c {d} e {{f}}}
          (a b c (d) e ((f)))
          % FullForm {echo (a b c) `{cat t1}}
          (echo (List a b c) (quote (cat t1)))
          % eval {cdr `{a b c}}
          (b c)

In lisp5.b I added the define and lambda expressions bringing me back to the point I was at in lab 26. I have followed the evolution of eval described in the Sussman and Steele paper, The Art of the Interpreter. The environment for the eval builtin is stored as an sexpr and no longer uses the shell's Context.

The scope in lisp5.b is dynamic. The next step was to add lexical scope as is done in lisp6.b

          % eval {define {subst x y z} 
           {cond {{atom z} 
               {cond {{eq z y} x} 
                 {`t z}}}
            {`t {cons {subst x y {car z}}
                   {subst x y {cdr z}}}}}}
          % eval {subst `m `b `{a b { a b c} d} }
          (a m (a m c) d)


There are several steps to take including adding side effects, macros, and a method for calling builtins. Only side effects are still needed to implement the accumulator generator and some handling for math expressions.

This is still just for experimentation. It may be valuable in the long run to implement a real scheme compiler for dis.

Part of the experimentation is to try multiple evaluators, one of them is a lisp dialect, another is sh. I should try transforming the s-expression back to the sh syntax tree for evaluation or display to the user.

The principle being that I can take a parse tree, transform to FullForm (s-expressions), evaluate using a chosen evaluator, then transfrom to another parse tree for display. (I am not going to start using XML/XSL in these labs.)

I can experiment with a variety of input forms: man(6) macros, popi input form, Mathematica syntax. I can treat the s-expression as the standard form for all expressions within inferno and establish a standard semantics for this form.

The are other possible eval semantics I should look at: Transform by applying rules until the expression reaches a fixed point (as in Mathematica); All unbound variable names and functions to remain as symbols (as in other Computer Algebra Systems like Maxima).Seeessaysby Fateman on different symbolic evaluators.

Long term, I want a powerful, expressive, succinct language that can be embedded within a narrative and edited, and evaluated within the document by the editor (acme). If I can plug new languages into the inferno shell it may make a good vehicle for a range of expressive languages that could be included within an active essay.

No comments: