(module infix mzscheme
(provide (all-defined))
(require (lib "list.ss")
(lib "plt-match.ss")
(lib "stx.ss" "syntax")
(lib "lex.ss" "parser-tools")
(lib "yacc.ss" "parser-tools"))
(define-tokens tokens (lparen atom rparen comma eof
plus minus times divide
cmp))
(define (syntax->token-list stx)
(define (operator? stx)
(and (operator-token/#f stx)
#t))
(define identifier=? module-transformer-identifier=?)
(define (operator-token/#f stx)
(cond
[(not (identifier? stx)) #f]
[(identifier=? stx (syntax +))
(token-plus stx)]
[(identifier=? stx (syntax -))
(token-minus stx)]
[(identifier=? stx (syntax *))
(token-times stx)]
[(identifier=? stx (syntax /))
(token-divide stx)]
[(ormap (lambda (op-stx) (identifier=? stx op-stx))
(list (syntax <) (syntax <=) (syntax =) (syntax >) (syntax >=)))
(token-cmp stx)]
[else #f]))
(syntax-case* stx (unquote) identifier=?
[(unquote e)
(cons (token-comma stx)
(syntax->token-list (syntax e)))]
[(e ...)
`( ,(token-lparen stx)
,@(apply append (map syntax->token-list (syntax-e (syntax (e ...)))))
,(token-rparen stx))]
[e (operator? stx)
(list (operator-token/#f stx))]
[else
(list (token-atom stx))]))
(define (token-list->producer a-token-list)
(lambda ()
(cond [(empty? a-token-list)
(token-eof (void))]
[else
(let ([next-token (first a-token-list)])
(set! a-token-list (rest a-token-list))
next-token)])))
(define-struct app-node (op rands) #f)
(define-struct cmp-node (op lhs rhs) #f)
(define-struct atom-node (atom) #f)
(define parse-expression
(parser
(tokens tokens)
(start top-expr)
(end eof)
(grammar [top-expr ((expr) $1)]
[expr ((comparison) $1)
((arithmetic) $1)
((function-application) $1)
((parenthesized) $1)
((atom) (make-atom-node $1))]
[comparison ([expr cmp expr] (make-cmp-node (make-atom-node $2) $1 $3))]
[parenthesized ((lparen expr rparen) $2)]
[arithmetic ((expr plus expr) (make-app-node (make-atom-node $2) (list $1 $3)))
((expr minus expr) (make-app-node (make-atom-node $2) (list $1 $3)))
((expr times expr) (make-app-node (make-atom-node $2) (list $1 $3)))
((expr divide expr) (make-app-node (make-atom-node $2) (list $1 $3)))]
[function-application ((expr lparen comma-separated-exprs rparen)
(make-app-node $1 $3))]
[comma-separated-exprs ((expr comma comma-separated-exprs) (cons $1 $3))
((expr) (list $1))
(() (list))])
(precs (left cmp)
(left plus minus)
(left times divide)
(nonassoc lparen))
(error (lambda (token-ok token-name token-value)
(raise-syntax-error 'parse-expression "while parsing" token-value)))))
(define (expression->code node context-stx)
(match node
[(struct app-node (op rands))
(app-node->code op rands context-stx)]
[(struct cmp-node (op l r))
(cmp-node->code node context-stx)]
[(struct atom-node (atom))
(atom-node->code atom)]))
(define (app-node->code op-node rand-nodes context-stx)
(let ([op (expression->code op-node context-stx)]
[rands (map (lambda (node) (expression->code node context-stx)) rand-nodes)])
(datum->syntax-object context-stx `(,op ,@rands))))
(define (cmp-node->code node context-stx)
(define (cmp-node->code/tmp node tmp k-stx)
(match node
[(struct cmp-node (op (and left
(struct cmp-node (op-child l-child r-child)))
right))
(let* ([fresh-tmp (syntax fresh-tmp)]
[new-k-stx
(datum->syntax-object context-stx
` (let ([,tmp ,(expression->code right context-stx)])
(if (,(expression->code op context-stx)
,fresh-tmp ,tmp)
,k-stx
#f)))])
(cmp-node->code/tmp left fresh-tmp new-k-stx))]
[(struct cmp-node (op l r))
(datum->syntax-object context-stx
` (let ([,tmp ,(expression->code r context-stx)])
(if (,(expression->code op context-stx)
,(expression->code l context-stx) ,tmp)
,k-stx
#f)))]))
(cmp-node->code/tmp node
(syntax tmp-1)
(datum->syntax-object context-stx #t)))
(define (atom-node->code atom-stx)
atom-stx))