2 ;; @description Infix expression parser
3 ;; @version 2.1 - comments redone for automatic documentation
4 ;; @author Lutz Mueller
6 ;; <h2>Infix expression parser</h2>
7 ;; Parses infix, prefix or postfix expressions given in strings and returns a
8 ;; newLISP expressions, which can be evaluated; captures syntax errors.
10 ;; At the beginning od the program using this module include the following
13 ;; (load "/usr/share/newlisp/modules/infix.lsp")
16 ;; @syntax (INFIX:xlate <str-expression> [<context-target>])
17 ;; @param <str-expression> The infix expression in a string
18 ;; @param <context-target> An optional context as compile taret.
19 ;; @return A newLISP expression or 'nil' on failure.
20 ;; When 'nil' is returned then the error message is in 'result'.
21 ;; As an optional second parameter a target context can be passed,
22 ;; if not used, MAIN is assumed.
24 ;; Note that the parser requires operators, variables and constants surrounded
25 ;; by spaces except where parenthesis are used.
28 ;; (INFIX:xlate "3 + 4") => (add 3 4) ;; parses infix
29 ;; (INFIX:xlate "+ 3 4") => (add 3 4) ;; parses prefix s-expressions
30 ;; (INFIX:xlate "3 4 +") => (add 2 4) ;; parses postfix
32 ;; (INFIX:xlate "3 + * 4") => "ERR: missing argument for +"
34 ;; (eval (INFIX:xlate "3 + 4")) => 7
36 ;; (INFIX:xlate "(3 + 4) * (5 - 2)") => (mul (add 3 4) (sub 5 2))
38 ;; (INFIX:xlate "(a + b) ^ 2 + (a - b) ^ 2") => (add (pow (add a b) 2) (pow (sub a b) 2))
40 ;; (INFIX:xlate "x = (3 + sin(20)) * (5 - 2)") => (setq x (mul (add 3 (sin 20)) (sub 5 2)))
42 ;; (INFIX:xlate "x = (3 + sin(10 - 2)) * (5 - 2)")
43 ;; => (setq x (mul (add 3 (sin (sub 10 2))) (sub 5 2)))
45 ; operator priority table
46 ; (token operator arg-count priority)
61 (set 'targetContext MAIN
)
63 (define (xlate str ctx
)
64 (if ctx
(set 'targetContext ctx
))
65 (if (catch (infix-xlate str
) 'result
)
66 result
;; if starts with ERR: is error else result
67 (append "ERR: " result
))) ;; newLISP error has ocurred
70 (define (infix-xlate str
)
71 (set 'tokens
(parse str
))
76 ("(" (push tkn opstack
))
77 (")" (close-parenthesis))
78 (true (if (assoc tkn operators
)
80 (push tkn varstack
)))))
81 (while (not (empty? opstack
))
84 (set 'result
(first varstack
))
85 (if (or (> (length varstack
) 1) (not (list? result
)))
86 (throw "ERR: wrong syntax")
90 ; pop all operators and make expressions
91 ; until an open parenthesis is found
93 (define (close-parenthesis)
94 (while (not (= (first opstack
) "("))
99 ; pop all operator, which have higher/equal priority
100 ; and make expressions
102 (define (process-op tkn
)
103 (if (not (empty? opstack
))
104 (while (<= (lookup tkn operators
3) (lookup (first opstack
) operators
3))
108 ; pops an operator from the opstack and makes/returns an
111 (define (make-expression)
112 (set 'expression
'())
114 (throw "ERR: missing parenthesis"))
115 (set 'ops
(pop opstack
))
116 (set 'op
(lookup ops operators
1))
117 (set 'nops
(lookup ops operators
2))
119 (if (empty? varstack
) (throw (append "ERR: missing argument for " ops
)))
120 (set 'vars
(pop varstack
))
122 (if (not (or (set 'var
(float vars
))
123 (and (legal? vars
) (set 'var
(sym vars targetContext
))) ))
124 (throw (append vars
"ERR: is not a variable"))
125 (push var expression
))
126 (push vars expression
)))
128 (push expression varstack
))