This is my first program I can call 'something'. I would be glad to hear what you think of it, so I wouldn't pick up bad habits further on.
It catches errors, but requires numbers to be separated from operators. It ignores a lot of characters, therefore
(+ 2 2) is as valid as
(+ 2 blargh 2)
100 lines of code + comments that should make everything clear:
# This program evaluates an arithmetic problem written as an S-expression. # Thus 3 + (7 * 4 * 2) + 1 + (6 / 5) + 8 becomes (+ 3 (* 7 4 2) 1 (/ 6 5) 8). # IMPORTANT NOTE: every number must be separated from an arithmetic operator by # white space to avoid confusion between arithmetic operation and indicator of # positiveness or negativeness of the number.(+3 7) is INVALID and evaluates to # 7 because '(+3' bit is simplified to '+'. Instead use (+ 3 7) or (+ +3 +7)! # The program loop. def mainLoop(): while True: expression = getExpression() if (expression.upper() == "EXIT"): break expression = formatExpression(expression) result = evaluate(expression, 0) print (result) # Asks user to enter an expresion and returns the input. def getExpression(): print("Enter \"EXIT\" to exit. Numbers must be separated from operators.") expression = input("Enter expression: ") return expression # Formats an expression so it would be easy to be manipulated further on. def formatExpression(expression): exp =  expression = leaveCertainChars(expression, ")0123456789.+-*/ eE") expression = detachBrackets(expression) expression = expression.split() for item in expression: if isNumber(item): exp.append(item) else: for character in item: if isOperator(character) or character == ')': exp.append(character) return exp # Leaves only the characters that really matter. def leaveCertainChars(string, chars): new_string = "" for character in string: if character in chars: new_string += character return new_string # Converts each ')' to ' )' def detachBrackets(string): new_string = "" for character in string: if character == ')': new_string += " )" else: new_string += character return new_string # THE ALGORITHM: # There are 3 types of data: operators, operands and the END symbol ')'. Each # expression starts with an operator, has any number of operands and ends with # ')'. There are two possible errors to occur: division by zero and missing ')'. # Thus, for each operator, collect operands until ')' and calculate the result. # If an operator instead of an operand is encountered in the process of operand # collection simply put the result of evaluation of THAT expression in the place # of missing operand and continue forward from the end of THAT expression. # Evaluate an expression. Return result AND the index of ending bracket def evaluate(exp, i): operator = exp[i] (operands, indexOfBracket) = findOperands(exp, i+1) result = compute(operator, operands) return (result, indexOfBracket) # Search for operands until ')'. Skip ')'s of other expressions. Put the result # of nested expression as just another operand and continue forward from the end # of that nested expression. def findOperands(exp, i): operands =  index = i while exp[index] != ')': if isNumber(exp[index]): operands.append(exp[index]) else: (new_value, new_index) = evaluate(exp, index) operands.append(new_value) index = new_index # The key part. Incrementing index to avoid starting at ')' next time. index += 1 # Each expression must have ')' at the end. Otherwise it's an error! if index >= len(exp): operands.append('YOU MISSED A BRACKET SOMEWHERE!') break return (operands, index) # Returns True if string is an operator otherwise returns False. def isOperator(string): if string == '+' or string == '-' or string == '*' or string == '/': return True else: return False # Returns True if string can be converted into number otherwise returns False def isNumber(string): try: float(string) return True except ValueError: return False # Computes a value or reports an error def compute(operator, operands): # If any error was encountered before it will be passed forward immediately for operand in operands: if not isNumber(operand): return operand # The default value of zero operands is zero. if len(operands) == 0: return '0' # The default value of one operand is that operand elif len(operands) == 1: return operands # Amount of possible operators is infinite (though amount of ASCII symbols # is limited). Extensions could include root, power, etc... else: result = float(operands) if operator == '+': for operand in operands[1::]: result += float(operand) elif operator == '-': for operand in operands[1::]: result -= float(operand) elif operator == '*': for operand in operands[1::]: result *= float(operand) elif operator == '/': for operand in operands[1::]: # Division by zero error if float(operand) == 0: return "DIVISION BY ZERO" else: result /= float(operand) # What comes as a string, leaves as a string return str(result) # Don't forget to run the program! mainLoop()