94 lines
1.5 KiB
Ruby
94 lines
1.5 KiB
Ruby
# This pattern provides an interpreter to deal with an abstract language. Using
|
|
# classes we can understand the inputs for parse them
|
|
|
|
# Parsing entity
|
|
class Number
|
|
attr_reader :value
|
|
|
|
def initialize(value)
|
|
@value = value
|
|
end
|
|
|
|
def execute
|
|
value
|
|
end
|
|
end
|
|
|
|
# Operation interface
|
|
class Operation
|
|
attr_reader :left, :right
|
|
|
|
def initialize(left, right)
|
|
@left = left
|
|
@right = right
|
|
end
|
|
|
|
def execute
|
|
raise NotImplementedError
|
|
end
|
|
end
|
|
|
|
# Operations
|
|
class Plus < Operation
|
|
def execute
|
|
left.execute + right.execute
|
|
end
|
|
end
|
|
|
|
class Minus < Operation
|
|
def execute
|
|
left.execute - right.execute
|
|
end
|
|
end
|
|
|
|
class Multiply < Operation
|
|
def execute
|
|
left.execute * right.execute
|
|
end
|
|
end
|
|
|
|
class Devide < Operation
|
|
def execute
|
|
left.execute / right.execute
|
|
end
|
|
end
|
|
|
|
# Interpreter class
|
|
class Interpreter
|
|
def self.parse(input)
|
|
stack = []
|
|
|
|
input.lstrip!
|
|
while input.length > 0
|
|
case input
|
|
when /\A-?\d+(\.\d+)?/
|
|
stack << Number.new($&.to_i)
|
|
else
|
|
second, first = stack.pop(), stack.pop()
|
|
|
|
case input
|
|
when /\A\+/
|
|
stack << Plus.new(first, second)
|
|
when /\A\-/
|
|
stack << Minus.new(first, second)
|
|
when /\A\*/
|
|
stack << Multiply.new(first, second)
|
|
else
|
|
raise SyntaxError
|
|
end
|
|
end
|
|
|
|
input = $'
|
|
input.lstrip!
|
|
end
|
|
|
|
raise SyntaxError unless stack.size == 1
|
|
|
|
stack.first.execute
|
|
end
|
|
end
|
|
|
|
# Usage
|
|
puts Interpreter.parse('1 + 1 + 2 - 1') # => 3
|
|
|