[REBOL] Re: parsing expressions (Flash again)
From: brett:codeconscious at: 23-Nov-2001 13:30
> The "flash" question was, how to parse the expressions like:
> a: x + random 10
> in any dialect... unfortunately there was no reply...
Oh bother, I'd even thought up a response, but neglected to send it :(
The response is, Gabriele Santilli some time ago posted a script called
This fairly small script evaluates expressions and I feel it is similar to
what you want to achieve. Might be worth studying for ideas. I include it
below (I'm guessing it is ok with Gabriele - i hope anyway :) ).
Title: "Expression evaluator"
Author: "Gabriele Santilli <[giesse--writeme--com]>"
Evaluates expressions taking usual operator precedence
2. - [negation], ! [factorial]
3. ^ [power]
4. *, /
5. +, - [subtraction]
; A simple iterative implementation; returns 1 for negative
; numbers. FEEL FREE TO IMPROVE THIS!
factorial: func [n [integer!] /local res] [
if n < 2 [return 1]
; should avoid doing the loop for i = 1...
repeat i n [res: res * i]
expression-parser: make object! [
slash: to-lit-word first [/]
term (expr-val: term-val)
['+ (expr-op: 'add) | '- (expr-op: 'subtract)]
term (expr-val: compose [(expr-op) (expr-val) (term-val)])
pow (term-val: power-val)
['* (term-op: 'multiply) | slash (term-op: 'divide)]
pow (term-val: compose [(term-op) (term-val) (power-val)])
unary (power-val: unary-val)
opt ['^ unary (power-val: compose [power (power-val) (unary-val)])]
(post-uop: pre-uop: )
opt ['- (pre-uop: 'negate)]
opt ['! (post-uop: 'factorial)]
(unary-val: compose [(post-uop) (pre-uop) (prim-val)])
; WARNING: uses recursion for parens.
set prim-val [number! | word!]
| set prim-val paren! (prim-val: translate to-block :prim-val)
translate: func [expr [block!] /local res recursion] [
; to allow recursive calling, we need to preserve our state
recursion: reduce [
:expr-val :expr-op :term-val :term-op :power-val :unary-val
:pre-uop :post-uop :prim-val
res: if parse expr expression [expr-val]
expr-val expr-op term-val term-op power-val unary-val
pre-uop post-uop prim-val
set 'eval func [expr [block!] /translate] [
expr: self/translate expr
either translate [expr] [do expr]