Postfix to expression-tree in scheme

by Tyler on July 2, 2007

So today someone on a mailing list asked for help with a postfix to expression-tree converter. While he hasn’t responded to me yet, I thought I’d share my solution on here. It was surprisingly easy to write in Scheme. Please feel free to comment if you have suggestions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
; define a tree structure to work with
(define (make-tree val left right)
  (list val left right))
(define (value tree)
  (car tree))
(define (left-branch tree)
  (cadr tree))
(define (right-branch tree)
  (caddr tree))
 
; converts postfix list to an expression-tree
(define (postfix-to-tree ops)
  (define (postfix-iter symbols values) ;progress through symbols keeping a list of values
    (if (null? symbols)
        (car values) ; returning end result
        (let ((x (car symbols)))
          (cond ((number? x) (postfix-iter (cdr symbols) (cons x values)))
                (else (postfix-iter
                       (cdr symbols)
                       (cons (make-tree x (cadr values) (car values))
                             (cddr values))))))))
  (postfix-iter ops '()))
;(postfix-to-tree '(2 1 + 3 4 * +)) == (+ (* 4 3) (+ 1 2))

Also, suppose rather than making an expression tree, we wanted to evaluate the postfix instead?
We could just eval the output of postfix-to-tree, i.e. (eval (postfix-to-tree ‘(2 1 + 3 4 * +))), but in general I think it’s preferred to avoid eval.
So alternatively, we’ll write a function to evaluate the symbols, and make a minor change to our main function and we’re there.

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
(define (eval-op op a b)
  (cond ((eq? '+ op) (+ a b))
        ((eq? '- op) (- a b))
        ((eq? '* op) (* a b))
        ((eq? '/ op) (/ a b))))
 
; evaluates postfix-expression
(define (eval-postfix ops)
  (define (postfix-iter symbols values) ;progress through symbols keeping a list of values
    (if (null? symbols)
        (car values) ; returning end result
        (let ((x (car symbols)))
          (cond ((number? x) (postfix-iter (cdr symbols) (cons x values)))
                (else (postfix-iter
                       (cdr symbols)
                       (cons (eval-op x (cadr values) (car values))
                             (cddr values))))))))
  (postfix-iter ops '()))
; (eval-postfix '(2 1 + 3 4 * +)) == 15

These solutions could probably use a little error-checking, but they both operate correctly on valid input and get the job done.

Share and Enjoy:
  • Print
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Blogplay
  • HackerNews
  • Reddit
  • StumbleUpon

Leave a Comment

Previous post: I’d like to welcome you with a little logic puzzle

Next post: XKCD #287 Comic Solution