Skip to content

Instantly share code, notes, and snippets.

@rpdillon
Created June 18, 2012 15:28
Show Gist options
  • Save rpdillon/2948914 to your computer and use it in GitHub Desktop.
Save rpdillon/2948914 to your computer and use it in GitHub Desktop.
Evaluate simple infix arthimetic (four operators + parens)
# Requires space-delimited input if negative numbers are used
def tokenize(s)
s.split(/(-?[0-9]+|[*-\/+()])/).map { |t| t.strip }.select { |token| token != "" }
end
# Evaluates token collections that have only the + and - operators
def evaluate(tokens)
current = 0
value = Integer(tokens.shift)
op = tokens.shift
while op
num = tokens.shift
value = value.send(op, Integer(num))
op = tokens.shift
end
value
end
# Evaluates any expressions that have * or / in them
def remove_multiply_divide(tokens)
while i = tokens.index("*") or i = tokens.index("/")
i -= 1 # Move back one token to get the beginning of the expression
value = Integer(tokens[i]).send(tokens[i+1], Integer(tokens[i+2]))
tokens.slice!(i..i+2)
tokens.insert(i, value)
end
tokens
end
# Handles parenthetical expressions recursively
def eval(tokens)
def find_closing_paren(i,tokens)
depth = 1
while token = tokens[i] and depth > 0
if token == "("
depth += 1
elsif token == ")"
depth -= 1
end
i += 1
end
i
end
while i = tokens.index("(")
slice = tokens.slice!(i...find_closing_paren(i+1,tokens))
value = eval(slice[1..-2])
tokens.insert(i, value)
end
evaluate(remove_multiply_divide(tokens))
end
# Sort of an ad hoc test framework.
tests = [["2" , 2],
["-2" , -2],
["2 + 4" , 6],
["-2 + -6" , -8],
["2+3" , 5],
["2 - 3 + 4" , 3],
["2 + 3 * 4" , 14],
["2 * 3 + 4 * 3 / 2" , 12],
["(2 + 4) * 3" , 18],
["((2) + 4) * 3" , 18],
["((2 - 1) + (3 + 1)) * 3" , 15]]
passed = 0
tests.each do |test, expected|
if eval(tokenize(test)) != expected
puts "Failed on input: #{test}"
else
passed += 1
end
end
puts "Passed #{passed} tests."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment