How to resolve the algorithm Parsing/Shunting-yard algorithm step by step in the Python programming language
How to resolve the algorithm Parsing/Shunting-yard algorithm step by step in the Python programming language
Table of Contents
Problem Statement
Given the operator characteristics and input from the Shunting-yard algorithm page and tables, use the algorithm to show the changes in the operator stack and RPN output as each individual token is processed.
Add extra text explaining the actions and an optional comment for the action on receipt of each token.
The handling of functions and arguments is not required.
Let's start with the solution:
Step by Step solution about How to resolve the algorithm Parsing/Shunting-yard algorithm step by step in the Python programming language
The provided Python code takes an infix mathematical expression as input and converts it into an equivalent Reverse Polish Notation (RPN) expression. The key idea behind this conversion is to rearrange the operators and operands in the expression such that the operators appear in the order of their precedence, and operands appear in the same order as in the infix expression. This conversion is useful for evaluating mathematical expressions efficiently using a stack-based approach.
Here's a step-by-step explanation of how this code works:
-
NamedTuple and Constants:
- The code defines a named tuple
OpInfo
to represent the precedence and associativity of operators. - It also defines constants
L
andR
to represent left and right associativity, respectively.
- The code defines a named tuple
-
Operator Information:
- The
ops
dictionary contains information about the precedence and associativity of various operators.
- The
-
Tokenization:
- The
get_input
function takes an infix expression as input and tokenizes it, returning a list of tuples containing the token type (e.g.,NUM
) and the token value (e.g., the number "3").
- The
-
Shunting-Yard Algorithm:
- The
shunting
function implements the Shunting-yard algorithm to convert the tokenized infix expression into RPN. This algorithm maintains two data structures: an output queue and an operator stack. - It iterates through the tokenized expression and processes each token as follows:
- If the token is a number, it is directly added to the output queue.
- If the token is an operator, it is compared with operators on the operator stack based on their precedence and associativity. Operators with higher precedence are pushed onto the stack, while operators with lower precedence or equal precedence and left associativity are popped from the stack and added to the output queue.
- If the token is a left parenthesis, it is pushed onto the operator stack.
- If the token is a right parenthesis, operators are popped from the stack and added to the output queue until a left parenthesis is encountered. The left parenthesis is then discarded.
- Once all tokens have been processed, any remaining operators on the stack are popped and added to the output queue.
- The
-
Formatting and Output:
- The main part of the code defines an infix expression as a string
infix
and invokes theget_input
function to tokenize this expression. - It then calls the
shunting
function to convert the tokenized expression to RPN. - The resulting RPN expression is printed, along with a formatted table that shows the steps involved in the conversion, including the token, action taken, RPN output so far, operator stack contents, and notes explaining the actions.
- The main part of the code defines an infix expression as a string
In summary, this code provides a detailed implementation of the Shunting-yard algorithm to convert infix expressions into RPN, with step-by-step explanations in a formatted table. This conversion is useful for efficiently evaluating mathematical expressions using a stack-based approach.
Source code in the python programming language
from collections import namedtuple
from pprint import pprint as pp
OpInfo = namedtuple('OpInfo', 'prec assoc')
L, R = 'Left Right'.split()
ops = {
'^': OpInfo(prec=4, assoc=R),
'*': OpInfo(prec=3, assoc=L),
'/': OpInfo(prec=3, assoc=L),
'+': OpInfo(prec=2, assoc=L),
'-': OpInfo(prec=2, assoc=L),
'(': OpInfo(prec=9, assoc=L),
')': OpInfo(prec=0, assoc=L),
}
NUM, LPAREN, RPAREN = 'NUMBER ( )'.split()
def get_input(inp = None):
'Inputs an expression and returns list of (TOKENTYPE, tokenvalue)'
if inp is None:
inp = input('expression: ')
tokens = inp.strip().split()
tokenvals = []
for token in tokens:
if token in ops:
tokenvals.append((token, ops[token]))
#elif token in (LPAREN, RPAREN):
# tokenvals.append((token, token))
else:
tokenvals.append((NUM, token))
return tokenvals
def shunting(tokenvals):
outq, stack = [], []
table = ['TOKEN,ACTION,RPN OUTPUT,OP STACK,NOTES'.split(',')]
for token, val in tokenvals:
note = action = ''
if token is NUM:
action = 'Add number to output'
outq.append(val)
table.append( (val, action, ' '.join(outq), ' '.join(s[0] for s in stack), note) )
elif token in ops:
t1, (p1, a1) = token, val
v = t1
note = 'Pop ops from stack to output'
while stack:
t2, (p2, a2) = stack[-1]
if (a1 == L and p1 <= p2) or (a1 == R and p1 < p2):
if t1 != RPAREN:
if t2 != LPAREN:
stack.pop()
action = '(Pop op)'
outq.append(t2)
else:
break
else:
if t2 != LPAREN:
stack.pop()
action = '(Pop op)'
outq.append(t2)
else:
stack.pop()
action = '(Pop & discard "(")'
table.append( (v, action, ' '.join(outq), ' '.join(s[0] for s in stack), note) )
break
table.append( (v, action, ' '.join(outq), ' '.join(s[0] for s in stack), note) )
v = note = ''
else:
note = ''
break
note = ''
note = ''
if t1 != RPAREN:
stack.append((token, val))
action = 'Push op token to stack'
else:
action = 'Discard ")"'
table.append( (v, action, ' '.join(outq), ' '.join(s[0] for s in stack), note) )
note = 'Drain stack to output'
while stack:
v = ''
t2, (p2, a2) = stack[-1]
action = '(Pop op)'
stack.pop()
outq.append(t2)
table.append( (v, action, ' '.join(outq), ' '.join(s[0] for s in stack), note) )
v = note = ''
return table
if __name__ == '__main__':
infix = '3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3'
print( 'For infix expression: %r\n' % infix )
rp = shunting(get_input(infix))
maxcolwidths = [len(max(x, key=len)) for x in zip(*rp)]
row = rp[0]
print( ' '.join('{cell:^{width}}'.format(width=width, cell=cell) for (width, cell) in zip(maxcolwidths, row)))
for row in rp[1:]:
print( ' '.join('{cell:<{width}}'.format(width=width, cell=cell) for (width, cell) in zip(maxcolwidths, row)))
print('\n The final output RPN is: %r' % rp[-1][2])
You may also check:How to resolve the algorithm Regular expressions step by step in the MAXScript programming language
You may also check:How to resolve the algorithm Modular inverse step by step in the Maple programming language
You may also check:How to resolve the algorithm Queue/Definition step by step in the FreeBASIC programming language
You may also check:How to resolve the algorithm The Twelve Days of Christmas step by step in the C++ programming language
You may also check:How to resolve the algorithm Bitmap/Histogram step by step in the PHP programming language