意味解析

最後に、意味解析を行うクラスを作ります。

class Calc
  def initialize
    @parser = Parser.new
  end
  def evalute src
    exp = @parser.parse(src)
    execute(exp)
  end
  
  def execute exp
    if exp.instance_of?(Array)
      case exp[0]
      when "+"
        execute(exp[1]) + execute(exp[2])
      when "-"
        execute(exp[1]) - execute(exp[2])
      when "*"
        execute(exp[1]) * execute(exp[2])
      when "/"
        execute(exp[1]) / execute(exp[2])
      end
    else
      exp
    end
  end
end

Calc クラスが意味解析を行うクラスです。メソッドは3つあります。
コンストラクタではパーサを作成しています。
evalute メソッドはプログラムソースを評価します。まずパーサで構文木を作成します。次に execute メソッドに構文木を渡して計算を行い結果を返します。
evalute メソッドと excete メソッドが別れている理由は計算するときに再帰呼び出しを行うからです。 execute メソッドを見てください。配列でない場合はそのまま値を返しますが、配列だった場合は配列の最初(記号が入っている)で分岐してその葉となる1つめと2つめの要素はさらに execute メソッドを呼び出しています。この計算過程は以下のように進みます。

execute([*,[+,1,2],3])
execute([+,1,2]) * execute(3)
(execute(1)+execute(2)) * execute(3)
(1+execute(2)) * execute(3)
(1+2) * execute(3)
3 * execute(3)
3 * 3
9

このようにして、意味解析を行うことができます。以上で今回のRubyによる計算機の作成はおしまいです。
次回はパーサをデータによって動的に変更できるようにしてみたいと思います。