Class: Dhaka::Evaluator

Inherits:
Object
  • Object
show all
Defined in:
lib/evaluator/evaluator.rb

Overview

This is the abstract base evaluator class. It is not directly instantiated. When defining an evaluator for a specific grammar, we subclass it. e.g. for FooGrammar we create a FooEvaluator that subclasses Evaluator. Note that FooEvaluator may not be further subclassed.

An evaluation rule for a given production named bar is defined by calling for_bar with a block that performs the evaluation. For detailed examples, see the evaluators in the test suite.

The following is an evaluator for arithmetic expressions. When a syntax tree node is encountered that corresponds to the production named addition, the block passed to for_addition is invoked. The evaluate method is then recursively called on the child nodes, in this case the operands to the addition operation. The result is obtained by adding the evaluation results of the child nodes.

class ArithmeticPrecedenceEvaluator < Dhaka::Evaluator

  self.grammar = ArithmeticPrecedenceGrammar

  define_evaluation_rules do

    for_subtraction do 
      evaluate(child_nodes[0]) - evaluate(child_nodes[2])
    end

    for_addition do
      evaluate(child_nodes[0]) + evaluate(child_nodes[2])
    end

    for_division do
      evaluate(child_nodes[0]).to_f/evaluate(child_nodes[2]) 
    end

    for_multiplication do
      evaluate(child_nodes[0]) * evaluate(child_nodes[2])
    end

    for_literal do
      child_nodes[0].token.value.to_i
    end

    for_parenthetized_expression do
      evaluate(child_nodes[1])
    end

    for_negated_expression do
      -evaluate(child_nodes[1])
    end

    for_power do
      evaluate(child_nodes[0])**evaluate(child_nodes[2])
    end

  end

end

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.define_evaluation_rulesObject

Evaluation rules are defined within a block passed to this method.



77
78
79
80
81
# File 'lib/evaluator/evaluator.rb', line 77

def define_evaluation_rules
  self.actions = []
  yield
  check_definitions
end

.inherited(evaluator) ⇒ Object



59
60
61
62
63
# File 'lib/evaluator/evaluator.rb', line 59

def inherited(evaluator)
  class << evaluator
    attr_accessor :grammar, :actions
  end
end

.method_missing(method_name, *args, &blk) ⇒ Object



65
66
67
68
69
70
71
72
73
74
# File 'lib/evaluator/evaluator.rb', line 65

def method_missing(method_name, *args, &blk)
  name = method_name.to_s
  if name =~ /^for_(.+)$/
    rule_name = $1
    actions   << rule_name
    send(:define_method, rule_name, &blk)
  else
    super
  end
end

Instance Method Details

#child_nodesObject

Returns the array of child nodes of the node being currently evaluated.



108
109
110
# File 'lib/evaluator/evaluator.rb', line 108

def child_nodes
  @node_stack.last
end

#evaluate(node) ⇒ Object

Evaluate a syntax tree node.



99
100
101
102
103
104
105
# File 'lib/evaluator/evaluator.rb', line 99

def evaluate node
  @node_stack ||= []
  @node_stack << node.child_nodes
  result      = send(node.production.name)
  @node_stack.pop
  result
end