File information | |||
---|---|---|---|
Filename: | infixtopostfix.py | Uploaded: | Tue, 2nd Mar 2010 19:41:14 |
Size (bytes): | 6.97 KiB | md5 checksum: | bf74140203ea73df95ea3317f46372df |
Uploader | doug | Download: | infixtopostfix.py |
Description: |
Implementation of infix to postfix conversation. Based around the shunting yard algorithm see http://en.wikipedia.org/wiki/Shunting_yard_algorithm for more information. |
#!/usr/bin/python # author: doug@neverfear.org # date: 09/04/2007 # date: 02/03/2010: Cleaned code up a bit, added some syntactical checks. # # Implementation of infix to postfix conversation. # based around the shunting yard algorithm # see http://en.wikipedia.org/wiki/Shunting_yard_algorithm # for more information # # Long code because of all the verbose prints # # Example usage # $ ./infixtopostfix.py "(8 * 5) / 4" # # Ultra verbose usage with multiple expressions: # $ ./infixtopostfix.py -v -v -v "(8 * 5) / 4" "1+(42 +31)+1" "5+1" # import sys formattingops = ['(', ')'] associative = ["*", "+"] leftassociative = ["-", "/"] rightassociative = ["^"] operators = formattingops + associative + leftassociative + rightassociative arithmeticops = associative + leftassociative + rightassociative precedence = {} # high value == high precedence precedence["^"] = 3 precedence["+"] = 1 precedence["-"] = 1 precedence["*"] = 2 precedence["/"] = 2 precedence["%"] = 3 precedence["("] = 4 precedence[")"] = 4 simplestack = [] # ordered list input = [] # input list verbose = 0 # if 0 just output is printed # if 1 just the summary is printed. # if 2, token, output string, and stack are printed. # if 3, verbose information is printed def push(what): simplestack.append(what) def pop(): if len(simplestack): return simplestack.pop(-1) # remove the last return None def peek(): if len(simplestack): return simplestack[-1] return None def getprecedence(op): if op == None: return op return precedence[op] def stacktostring(stack): if not stack: return "Empty" out = "" for i in reversed(stack): out = out + str(i) + " " return out[:-1] def beVerbose(level, text): global verbose if verbose >= level: print text, def concatsymbol(current, token): return current + token def infixtopostfix(input): output = "" lastwasspace = False lasttoken = None for token in input: if not token.strip(): lastwasspace = True continue beVerbose(2, "Token='%c'" % (token)) if not token in operators: if lastwasspace and not lasttoken in operators: # Catch terms that were delimited by whitespace # but then the next token is a non-operator # Example string that would cause this "123 4+1" # since this doesn't make sense. print "ERROR: Unexpected token '%c'" % (token) sys.exit(1) output = output + token beVerbose(3, "added to output") lastwasspace = False else: # operators if lasttoken in arithmeticops and token in arithmeticops: # Catch duplication of operators. An example would # be "4 // 2" or "823 + - / 2" which makes no sense in infix. # The only operators allowed next to one another are # the formatting operators '(' and ')' used to group operations. print "ERROR: Unexpected token '%c'" % (token) sys.exit(1) if token == '(': push(token) beVerbose(3, "pushed onto stack") elif token == ')': tok = pop() beVerbose(3, "'%s' popped off stack" % (tok)) while tok != "(": if tok == None: #stack is empty print print "ERROR: Parenthesis mismatch" sys.exit(1) output = output + " " + tok beVerbose(3, "and added to output") tok = pop() beVerbose(3, "'%s' popped off stack" % (tok)) else: # mathematical operators tok = peek() while tok and tok != '(': beVerbose(3, "'%s' is on the top of the stack" % (tok)) if (( (token in associative or token in leftassociative) and (getprecedence(token) <= getprecedence(tok)) ) or ( token in rightassociative and getprecedence(token) < getprecedence(tok) )): tok = pop() output = output + " " + tok beVerbose(3, "'%s' popped off the stack and added to output" % (tok)) else: break tok = peek() push(token) beVerbose(3, "'%s' pushed onto stack" % (token)) output = output + " " lastwasspace = False lasttoken = token if verbose == 2: format = "Output=% -40s Stack: % -30s" elif verbose >= 3: format = "Output=%s Stack: %s" # no field justification if verbose >= 2: print format % (output, stacktostring(simplestack)) beVerbose(2, "Token=end") tok = peek() while tok: if tok == "(": print print "ERROR: Parenthesis mismatch" sys.exit(1) tok = pop() output = output + " " + tok beVerbose(3, "%s popped and added to output" % (tok)) tok = peek() if verbose >= 3: print if verbose >= 2: print if verbose >= 1: print "Infix input =", input print print "Postfix output =", output return output if (len(sys.argv) < 2): print "Please provide infix input string or use --help for help" sys.exit(1) # I should have really used getopts but I was young and naive when I wrote this! for v in sys.argv[1:]: if v == "-v" or v == "--verbose": verbose = verbose + 1 elif v == "-h" or v == "--help": print "usage: infixtopostfix [-v|-h] infix_input ..." print "-v, --verbose be verbose. use twice or thrice for more output" print "-h, --help show this help" sys.exit(0) else: input.append(v) if not len(input): print "Please provide infix input string" else: # Print all input strings for i in input: if verbose: print "Processing:", i print infixtopostfix(i.strip())