guile-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Arithmetic evaluator for Guile


From: Andy Wingo
Subject: Re: Arithmetic evaluator for Guile
Date: Mon, 22 Mar 2010 00:08:00 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.0.92 (gnu/linux)

Hi!

On Sat 20 Mar 2010 18:41, No Itisnt <address@hidden> 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/




reply via email to

[Prev in Thread] Current Thread [Next in Thread]