wirito:
That was an amusing diversion. I played around with it and added a couple of features for fun:
- Parenthesis now work for grouping
- Now we have variables
- It emits the RPN version of the expression
I tried monkeying with regexes to add parenthesis, and then remembered Text::Balanced, so I used that to extract the subexpressions. The parsed subexpressions are then stored in the %temps hash. The expression is then rewritten, replacing the subexpression with the temp name. Finally, when we wind up with a single token (variable, value or temp name), we check the temps hash, and if we get a match, we return the parse tree we stowed away there.
In order to prevent collisions between temp names and variable names, I map the expression to lower case before parsing. So I split the parse function into two bits.
I built a to_RPN() function by whacking on your original evaluate() routine. Then I made an evaluator for the RPN string. I didn't update your evaluate() function, so I removed it for now. It's a simple modification to bring it up-to-date with the variable assignments, but I gotta get back to work.
Finally, I handle variables by simply looking at any scalar I pop from the stack to see if it has any alpha characters and if it's in the %vars hash. If so, I look up the appropriate value.
There's still plenty of room for cleanup, simplification and such, but I thought I'd stop for now. I hope someone finds it amusing...
A sample run gives:
$ ./expression_evaluator.pl
a:=1*(2+(3/5+2))
RPN: a 1 2 3 5 / 2 + + * := (a set to <4.6>) ====> 4.6
Variables: a:4.6
b:=a+15
RPN: b a 15 + := (b set to <19.6>) ====> 19.6
Variables: a:4.6, b:19.6
c:=(b-a)*(5+3+(9-6)*3)
RPN: c b a - 5 3 + 9 6 - 3 * + * := (c set to <255>) ====> 255
Variables: a:4.6, b:19.6, c:255
...roboticus
When your only tool is a hammer, all problems look like your thumb. |