I wrote this originally some time ago. Mostly for my own amusement. It converts from infix to postfix notation.

I expect most of our readers know what these are but for the benefits of completeness infix is a functional notation we humans use for instance in mathematics where the operator sits in between the operands. Example:

(8 * 5) / 4

Postfix is a functional notation that machines like to use because it lacks the ambiguity of infix. Example:

8 5 * 4 /

As a machine reads this it sees term 8 and stores it. It sees term 5 and stores it. It sees operator * which it knows is a binary operator and uses the two stored terms and stores the value internally. It then sees 4 and stores that. It then sees / which is a binary operator and uses the stored value from the first operation with the last term 4 and applies the operation to get a result.

As a result of this approach postfix has no need of parenthesis to clarify the order of operations in an expression.

More information on postfix and infix can be found at Postfix notation and Infix notation. See also Prefix notation.

The following code makes use of the Shunting yard algorithm invented to convert infix to postfix by our good friend in computer science, Edsger Dijkstra.

The code is a little verbose so people can see what is going on. You can download this code at http://neverfear.org/files/view/65

#!/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())