Guile-arith is a module to demonstrate one way of building yacc/lex parsers into guile C modules.
You can get the source to guile-arith via http from http://www.cl.cam.ac.uk/users/ig206/guile-arith/guile-arith-0.02.tar.gz
Please note that this is not meant to be used. It will not necessarily be supported in future and it may not even work properly now. (Who wants to use infix notation for arithmetic anyway?) The intention is just to demonstrate some techniques.
To build the module do the usual
./configure
make
make install
To use it, run guile and load the module with something like
(use-modules (syntax arith))
After this you can use the procedures INFIX-STRING->PREFIX-LIST, EVAL-INFIX-STRING and ARITH-PARSE. INFIX-STRING->PREFIX-LIST takes a single argument which is an expression in infix notation and returns a list which is the same expression in scheme and can be evaluated. EVAL-INFIX-STRING evaluates the expression given. ARITH-PARSE is the low-level function. It takes two arguments: a port for input of the expression, an action procedure, and a third optional argument which is an error handling procedure. In the event of an error the error-handling procedure is called with two arguments: a string describing the errror and the port which the parser is using for input. The action procedure is executed by the parser as the action of each production in the grammar (see guile-arith-parse.y for a definition of the grammar). The first argument to the action procedure is always a symbol identifying the production. This can be one of the following:
+ - * / modulo quotient expt parenthesis number symbol
or it could be *any* other symbol interpreted as the name of a function taking a single numeric argument. The remaining arguments are the semantic values from other productions. The return value of the procedure is the semantic value of the production. For example, here is the action procedure of INFIX-STRING->PREFIX-LIST
(lambda (x . rest)
(if (or (eq? x 'parenthesis)
(eq? x 'symbol)
(eq? x 'number))
(car rest)
(cons x rest)))
Here we pass up parenthesised expressions, symbols and numbers unaltered. Anything else we assume is a procedure name and we return a list of the form (procedure-name arg1 arg2 ... ) In addition you can invoke the parser using the read-hash extension #[ infix-expression-here ]. For example:
(define (square x) #[ x ^ 2 ])
(square 2) ==> 4
(define (cube x) #[ square(x) * x ])
(cube 2) ==> 8
Please feel free to send me any improvements. Here are a few ideas:
I hope you have some fun with it -- I did.
Ian Grant