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

RE: [NOISE] Curly braces [was Re: Curl]



--- Tim Hickey <tim@cs.brandeis.edu> wrote:
> Would it be difficult to write a "matheval" macro in Scheme
> or Lisp that evaluates arithmetic expressions in infix notation

I'm sure it's been done before (although I couldn't find a nice macro
on Google), but FYI here's one I just whipped up for PLT Scheme since I
hate the (x . > . y) notation.

So, yes.

-m


(require-library "functio.ss")

;; infix->prefix: '(iexp) -> pexp
;;
;; Recursive descent infix parser for Scheme.  Used to implement
;; the infix macro.
;; 
;; iexp: iexp op iexp | unop iexp | symbol | number | (iexp)
;; pexp: number | symbol | (op pexp pexp) | (unop pexp) 
;; op:   + | * | - | / | ^ | > | < | = | <= | >= | and | or
;; unop: sqrt | cos | sin | tan | - | not | +
;;
;; Morgan McGuire
;; morgan@cs.brown.edu
(define (infix->prefix iexp)
  (if (not (list? iexp))
      
      (error 'infix->prefix "Argument must be a parse-tree")
      
      (letrec
        ;; The operator precedence rules.  Lowest precedence is first.
        ;; Operators of equal precedence are on the same line.  All
operators
        ;; must be binary; unary minus and not are handled specially
within
        ;; the parser.  Note that you may not call prefix functions
within
        ;; an infix form; the parser wouldn't know what to do. 
        ([precedence '((> < >= <= =)
                      (+ - or)
                      (* / and)
                      number-or-variable)]
         
         [unary-operator '(- + not sqrt cos sin tan)]
                                 
        ;; peek-token: void -> token
        [peek-token (lambda () (first tokens))]
        
        ;; pop-token: void->token
        ;; Removes a token.
        [pop-token (lambda ()
                     (let ([t (first tokens)])
                       (begin
                         (set! tokens (rest tokens))
                         t)))]
        
        
        ;; more-tokens?: void -> bool
        [more-tokens? (lambda () (not (empty? tokens)))]
        
        ;; while: (void->bool) x (void->void) -> void
        ;; Repeats body while test returns true.
        [while (lambda (test? body)
                 (if (test?) 
                     (begin
                       (body)
                       (while test? body))))]
               
        ;; parse-infix: (list operator) x (list (list operator)) ->
pexp
        ;; low is a set of equally low precedence operators, high-set
is a list of
        ;; lists of higher precedence operators.
        [parse-infix 
         (lambda (low high-set)
           (if (eq? low 'number-or-variable)
               
               (let ([left (pop-token)])
                 
                 ;; At the highest precedence, just return the next
token or expression
                 (cond 
                   ;; Parenthesized expression; recursively parse it
                   [(list? left)        (infix->prefix left)]
                     
                   ;; Unary operator
                   [(memq left unary-operator) `(,left ,(parse-infix
low high-set))]

                   ;; Number or symbol
                   [else left]))
                   
               ;; At this level of precedence, parse two higher level
expressions and
               ;; combine them.
               (let ([left (parse-infix (first high-set) (rest
high-set))])
                 (begin
                   (while (lambda () (and (more-tokens?) (memq
(peek-token) low)))
                          (lambda () 
                            (let* ([operator (pop-token)]
                                   [right    (parse-infix (first
high-set) (rest high-set))])
                              (set! left `(,operator ,left ,right)))))
                   left))))]
        
        [tokens iexp]) 
        
        (parse-infix (first precedence)
                     (rest precedence)))))


;; Infix math macro for PLT MzScheme and DrScheme/(full Scheme mode).
;; Only grouping parens and the following functions are supported in
infix form:
;;
;;  +  *  -  /  ^  >  <  =  <=  >= (and) (or) sqrt cos sin tan  not
;;
;; Morgan McGuire
;; morgan@cs.brown.edu
(define-macro infix (lambda (a . b) (infix->prefix (cons a b))))

=====
Morgan McGuire  
morgan3d@yahoo.com


__________________________________________________
Do You Yahoo!?
Buy the perfect holiday gifts at Yahoo! Shopping.
http://shopping.yahoo.com