Skip to content

Instantly share code, notes, and snippets.

@mono0x mono0x/calc.rb
Created Jun 9, 2012

Embed
What would you like to do?
Calc
# -*- coding: utf-8 -*-
class Expression
attr_reader :value
def initialize(tokens)
left = Term.new(tokens)
@value = left.value
until tokens.empty?
op = tokens.first
break unless op == '+' || op == '-'
tokens.shift
right = Term.new(tokens)
case op
when '+'
@value += right.value
when '-'
@value -= right.value
end
end
end
end
class Term
attr_reader :value
def initialize(tokens)
left = Factor.new(tokens)
@value = left.value
until tokens.empty?
op = tokens.first
break unless op == '*' || op == '/'
tokens.shift
right = Factor.new(tokens)
case op
when '*'
@value *= right.value
when '/'
@value /= right.value
end
end
end
end
class Factor
attr_reader :value
def initialize(tokens)
case token = tokens.shift
when '('
expr = Expression.new(tokens)
raise 'invalid symbol' unless tokens.shift == ')'
@value = expr.value
when '+'
@value = Expression.new(tokens).value
when '-'
@value = -Expression.new(tokens).value
when Numeric
@value = token
else
raise 'invalid token'
end
end
end
def tokenize(input)
result = []
chars = input.each_char.to_a
until chars.empty?
case char = chars.shift
when '+', '-', '*', '/', '(', ')'
result << char
when /[1-9]/
n = [ char ]
while chars.first =~ /[0-9]/
n << chars.shift
end
result << Integer(n.join)
else
raise 'invalid token'
end
end
result
end
def calc(input)
Expression.new(tokenize(input)).value
end
p calc('19+23')
p calc('19+23-4')
p calc('1+2*4')
p calc('(1+2)*4')
p calc('(4/2+2*3)*4')
p calc('(4/2+2*3)*4+') rescue p 'exception'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.