Hi! On Sat 20 Mar 2010 18:41, No Itisnt <theseaisinh...@gmail.com> writes:
> Here's a little expression evaluator for Guile 1.9 using the new > bytecode compiler. It does arithmetic, exponentiation, modulos, and > equality tests. See the tests at the bottom for example expressions. > This is probably the most dense Scheme program I've written and I > would really appreciate a critique of the code. Lovely, clear code. I have only a few comments. > (define (pp . ls) (for-each (lambda (y) (write y) (display #\space)) ls) > (newline)) There is (ice-9 pretty-print), if that's what you want. > ;;;;; PROPERTIES > ;; The following object properties may be set on tokens[...] Using object properties for the various operators is fine, but hash tables would probably be better, because they can be iterated over. Though, object properties do have a pleasant syntax. Using object properties for the "moving parts" of the compiler is a bit unfortunate, though; I feel like it decreases the referential transparency of the parser. If it were me, I would write read-calculator as one big function, containing e.g. read-expression and the rest as internal definitions, and the body of the function would just kick off the read. It would be easier for me to see how the parameters flow that way. But, your code is pleasantly succint. Another option would be to use lalr-scm (there is a copy in Guile that will get documented for the next release), or write a PEG parser generator (that would be fun!), or some sort of parser combinator lib. But what you have is fine. > ;; Input port > (define port (make-parameter #f)) Why bother? Just use (current-input-port), no? Lets you use peek-char instead of %peek-char too. > (define (initialize) > (letrec-syntax Nice syntax-rules use here :) > ;; eugh -- for define-infix-operator > (define (char->symbol c) > (string->symbol (list->string (list c)))) (string->symbol (string c)) > (define (syntax-error . args) (apply error (cons 'syntax args))) (apply error 'syntax args); but it's better to tighten up the meaning of these parameters, as in (define* (syntax-error message object #:optional context) ...) > ;; Number lexer > (define (char-number? c) (and (not (eof-object? c)) (char-numeric? c))) > (define (char->number c) (- (char->integer c) (char->integer #\0))) > (define (char-delimiter? c) (or (eof-object? c) (terminal c) > (char-whitespace? c))) > ;; Read a number > (define (read-number) > (let loop ((number (char->number (%read-char)))) > (if (char-number? (%peek-char)) > (loop (+ (* number 10) (char->number (%read-char)))) > number))) Guile could expose its number reader; perhaps that's a good idea. There have been a number of bugs over the years in the number reader. > ;; Compile any operation which takes two arguments > (define (compile-operation2 e operation first second) > `(apply ,(code-object operation) ,(compile e first) ,(compile e > second))) Nice use of tree-il literals. One thing your parser is missing though is source information; you can get that by attaching source info to the tree-il literals. Cool hack! Andy -- http://wingolog.org/