class ShuntingYard::Interpreter
Attributes
functions[RW]
operators[RW]
Public Class Methods
new()
click to toggle source
# File lib/shunting_yard/interpreter.rb, line 6 def initialize @functions = [] @operators = [] end
Public Instance Methods
add_function(*args)
click to toggle source
# File lib/shunting_yard/interpreter.rb, line 11 def add_function(*args) functions << Function.new(*args) end
add_operator(*args)
click to toggle source
# File lib/shunting_yard/interpreter.rb, line 15 def add_operator(*args) operators << Operator.new(*args) end
evaluate(rpn_tokens)
click to toggle source
# File lib/shunting_yard/interpreter.rb, line 73 def evaluate(rpn_tokens) rpn = rpn_tokens.dup stack = [] while rpn.any? current = rpn.shift case current when Function, Operator arity = current.evaluator.arity raise InvalidArgumentsCountError if stack.size < arity operands = stack.pop(arity) stack << current.evaluator.(*operands) when Operand stack << current.value end end raise InvalidArgumentsCountError if stack.size > 1 stack[0] end
to_rpn(source_tokens)
click to toggle source
# File lib/shunting_yard/interpreter.rb, line 19 def to_rpn(source_tokens) tokens = source_tokens.dup output = ReversePolishNotation.new op_stack = [] while tokens.any? current = match_token(tokens.shift) case current when ArgumentSeparator while op_stack.any? && op_stack.last.class != Parenthesis output << op_stack.pop end when Function op_stack << current when Parenthesis case current.side when :left op_stack << current when :right while op_stack.last.class != Parenthesis raise MismatchedParenthesesError if op_stack.empty? output << op_stack.pop end op_stack.pop end when Operand output << current when Operator while op_stack.any? && op_stack.last.class != Parenthesis && (op_stack.last.class == Function || op_stack.last.precedence > current.precedence || op_stack.last.precedence == current.precedence && current.associativity == :left) output << op_stack.pop end op_stack << current end end while op_stack.any? current = op_stack.pop raise MismatchedParenthesesError if current.class == Parenthesis output << current end output end
Private Instance Methods
match_token(token)
click to toggle source
# File lib/shunting_yard/interpreter.rb, line 99 def match_token(token) matched = case token.name when :argument_separator ArgumentSeparator.new(token.value) when :function function = functions.find { |f| f.value == token.value } raise UnknownFunctionError, token.lexeme unless function function when :parenthesis case token.value when "(" Parenthesis.new(:left) when ")" Parenthesis.new(:right) else raise UnknownParenthesisError, token.lexeme end when :operand Operand.new(token.value) when :operator operator = operators.find { |op| binding.pry if op.kind_of?(Array); op.value == token.value } raise UnknownOperatorError, token unless operator operator else raise UnknownTokenTypeError, token.name end matched end