I\'ve developed an equation parser using a simple stack algorithm that will handle binary (+, -, |, &, *, /, etc) operators, unary (!) operators, and parenthesis.
<
I found this on the PIClist about the Shunting Yard algorithm:
Harold writes:
I remember reading, a long time ago, of an algorithm that converted algebraic expressions to RPN for easy evaluation. Each infix value or operator or parenthesis was represented by a railroad car on a track. One type of car split off to another track and the other continued straight ahead. I don't recall the details (obviously!), but always thought it would be interesting to code. This is back when I was writing 6800 (not 68000) assembly code.
This is the "shunting yard algorythm" and it is what most machine parsers use. See the article on parsing in Wikipedia. An easy way to code the shunting yard algorythm is to use two stacks. One is the "push" stack and the other the "reduce" or "result" stack. Example:
pstack = () // empty rstack = () input: 1+2*3 precedence = 10 // lowest reduce = 0 // don't reduce
start: token '1': isnumber, put in pstack (push) token '+': isoperator set precedence=2 if precedence < previous_operator_precedence then reduce() // see below put '+' in pstack (push) token '2': isnumber, put in pstack (push) token '*': isoperator, set precedence=1, put in pstack (push) // check precedence as // above token '3': isnumber, put in pstack (push) end of input, need to reduce (goal is empty pstack) reduce() //done
to reduce, pop elements from the push stack and put them into the result stack, always swap the top 2 items on pstack if they are of the form 'operator' 'number':
pstack: '1' '+' '2' '' '3' rstack: () ... pstack: () rstack: '3' '2' '' '1' '+'
if the expression would have been:
1*2+3
then the reduce trigger would have been the reading of the token '+' which has lower precendece than the '*' already pushed, so it would have done:
pstack: '1' '' '2' rstack: () ... pstack: () rstack: '1' '2' ''
and then pushed '+' and then '3' and then finally reduced:
pstack: '+' '3' rstack: '1' '2' '' ... pstack: () rstack: '1' '2' '' '3' '+'
So the short version is: push numbers, when pushing operators check the precedence of the previous operator. If it was higher than the operator's that is to be pushed now, first reduce, then push the current operator. To handle parens simply save the precedence of the 'previous' operator, and put a mark on the pstack that tells the reduce algorythm to stop reducing when solving the inside of a paren pair. The closing paren triggers a reduction as does the end of input, and also removes the open paren mark from the pstack, and restores the 'previous operation' precedence so parsing can continue after the close paren where it left off. This can be done with recursion or without (hint: use a stack to store the previous precedence when encountering a '(' ...). The generalized version of this is to use a parser generator implemented shunting yard algorythm, f.ex. using yacc or bison or taccle (tcl analog of yacc).
Peter
-Adam