Parsing/Shunting-yard algorithm: Difference between revisions
Content added Content deleted
Line 39: | Line 39: | ||
* [[Parsing/RPN to infix conversion]]. |
* [[Parsing/RPN to infix conversion]]. |
||
<br><br> |
<br><br> |
||
=={{header|8th}}-- |
|||
<lang forth>\ Convert infix expression to postfix, using 'shunting-yard' algorithm |
|||
\ https://en.wikipedia.org/wiki/Shunting-yard_algorithm |
|||
\ precedence of infix tokens. negative means 'right-associative', otherwise left: |
|||
with: n |
|||
{ |
|||
"+" : 2, |
|||
"-" : 2, |
|||
"/" : 3, |
|||
"*" : 3, |
|||
"^" : -4, |
|||
"(" : 1, |
|||
")" : -1 |
|||
} var, tokens |
|||
: precedence \ s -- s n |
|||
tokens @ over m:@ nip |
|||
null? if drop 0 then ; |
|||
var ops |
|||
var out |
|||
: >out \ x -- |
|||
out @ swap |
|||
a:push drop ; |
|||
: >ops \ op prec -- |
|||
2 a:close |
|||
ops @ swap |
|||
a:push drop ; |
|||
: a:peek -1 a:@ ; |
|||
\ Check the array for items with greater or equal precedence, |
|||
\ and move them to the out queue: |
|||
: pop-ops \ op prec ops -- op prec ops |
|||
\ empty array, do nothing: |
|||
a:len not if ;; then |
|||
\ Look at top of ops stack: |
|||
a:peek a:open \ op p ops[] op2 p2 |
|||
\ if the 'p2' is not less p (meaning item on top of stack is greater or equal |
|||
\ in precedence), then pop the item from the ops stack and push onto the out: |
|||
3 pick \ p2 p |
|||
< not if |
|||
\ op p ops[] op2 |
|||
>out a:pop drop recurse ;; |
|||
then |
|||
drop ; |
|||
: right-paren |
|||
"RIGHTPAREN" . cr |
|||
2drop |
|||
\ move non-left-paren from ops and move to out: |
|||
ops @ |
|||
repeat |
|||
a:len not if |
|||
break |
|||
else |
|||
a:pop a:open |
|||
1 = if |
|||
2drop ;; |
|||
else |
|||
>out |
|||
then |
|||
then |
|||
again drop ; |
|||
: .state \ n -- |
|||
drop \ "Token: %s\n" s:strfmt . |
|||
"Out: " . |
|||
out @ ( . space drop ) a:each drop cr |
|||
"ops: " . ops @ ( 0 a:@ . space 2drop ) a:each drop cr cr ; |
|||
: handle-number \ s n -- |
|||
"NUMBER " . over . cr |
|||
drop >out ; |
|||
: left-paren \ s n -- |
|||
"LEFTPAREN" . cr |
|||
>ops ; |
|||
: handle-op \ s n -- |
|||
"OPERATOR " . over . cr |
|||
\ op precedence |
|||
\ Is the current op left-associative? |
|||
dup sgn 1 = if |
|||
\ it is, so check the ops array for items with greater or equal precedence, |
|||
\ and move them to the out queue: |
|||
ops @ pop-ops drop |
|||
then |
|||
\ push the operator |
|||
>ops ; |
|||
: handle-token \ s -- |
|||
precedence dup not if |
|||
\ it's a number: |
|||
handle-number |
|||
else |
|||
dup 1 = if left-paren |
|||
else dup -1 = if right-paren |
|||
else handle-op |
|||
then then |
|||
then ; |
|||
: infix>postfix \ s -- s |
|||
/\s+/ s:/ \ split to indiviual whitespace-delimited tokens |
|||
\ Initialize our data structures |
|||
a:new ops ! a:new out ! |
|||
( |
|||
nip dup >r |
|||
handle-token |
|||
r> .state |
|||
) a:each drop |
|||
\ remove all remaining ops and put on output: |
|||
out @ |
|||
ops @ a:rev |
|||
( nip a:open drop a:push ) a:each drop |
|||
\ final string: |
|||
" " a:join ; |
|||
"3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3" infix>postfix . cr |
|||
"Expected: \n" . "3 4 2 * 1 5 - 2 3 ^ ^ / +" . cr |
|||
bye |
|||
</lang> |
|||
{{out}} |
|||
<pre>NUMBER 3 |
|||
Out: 3 |
|||
ops: |
|||
OPERATOR + |
|||
Out: 3 |
|||
ops: + |
|||
NUMBER 4 |
|||
Out: 3 4 |
|||
ops: + |
|||
OPERATOR * |
|||
Out: 3 4 |
|||
ops: + * |
|||
NUMBER 2 |
|||
Out: 3 4 2 |
|||
ops: + * |
|||
OPERATOR / |
|||
Out: 3 4 2 * |
|||
ops: + / |
|||
LEFTPAREN |
|||
Out: 3 4 2 * |
|||
ops: + / ( |
|||
NUMBER 1 |
|||
Out: 3 4 2 * 1 |
|||
ops: + / ( |
|||
OPERATOR - |
|||
Out: 3 4 2 * 1 |
|||
ops: + / ( - |
|||
NUMBER 5 |
|||
Out: 3 4 2 * 1 5 |
|||
ops: + / ( - |
|||
RIGHTPAREN |
|||
Out: 3 4 2 * 1 5 - |
|||
ops: + / |
|||
OPERATOR ^ |
|||
Out: 3 4 2 * 1 5 - |
|||
ops: + / ^ |
|||
NUMBER 2 |
|||
Out: 3 4 2 * 1 5 - 2 |
|||
ops: + / ^ |
|||
OPERATOR ^ |
|||
Out: 3 4 2 * 1 5 - 2 |
|||
ops: + / ^ ^ |
|||
NUMBER 3 |
|||
Out: 3 4 2 * 1 5 - 2 3 |
|||
ops: + / ^ ^ |
|||
3 4 2 * 1 5 - 2 3 ^ ^ / + |
|||
Expected: |
|||
3 4 2 * 1 5 - 2 3 ^ ^ / + |
|||
</pre> |
|||
=={{header|ALGOL 68}}== |
=={{header|ALGOL 68}}== |