Rubyで逆ポーランド記法

勉強のためにruby逆ポーランド記法で計算するクラスを作ってみた。

#!/usr/bin/ruby
# -*- coding: utf-8 -*-

class Calc
  attr_writer :siki

  def initialze
    @siki = ""
  end

  def rtnval val
    hs = Hash.new
    hs["("] = 5
    hs["*"] = 3
    hs["×"] = 3
    hs["/"] = 3
    hs["÷"] = 3
    hs["+"] = 2
    hs[""] = 2
    hs["-"] = 2
    hs[""] = 2
    hs[")"] = 1
    hs["BTM"] = 0

    rtn = hs[val]

    if rtn.nil?
      rtn = 4
    end
    return rtn
  end

  def do_calc
    a = @siki.scan(/\w+|[^\s\w]+/)
    stc1 = []
    stc2 = []

    stc1 << "BTM"

    a.each do |s|

      v1 = rtnval(s)
      v2 = rtnval(stc1[stc1.size-1])
      if(v2.to_i >= v1.to_i && stc1[stc1.size-1] != "(" )
        stc2 << stc1.pop
        if(s == ")")
          stc2 << stc1.pop
          stc1.pop
        else
          stc1 << s
        end
      elsif(v1.to_i > v2.to_i && s != "(" )
        stc1 << s
      else
        stc1 << s
      end
    end

    stc1.size.times do |r|
      stc2 <<  stc1.pop
    end

    stc2.size.times do |str|
      i = stc2.shift
      case(i)
      when("+" || "")
        stc1 << stc1.pop.to_i + stc1.pop.to_i
      when("-" || "")
        stc1 << stc1.pop.to_i - stc1.pop.to_i
      when("*" || "×")
        stc1 << stc1.pop.to_i * stc1.pop.to_i
      when("/" || "÷")
        stc1 << stc1.pop.to_i / stc1.pop.to_i
      when("BTM")
        break
      else
        stc1 << i
      end
    end

    stc1[0]
 
 end
end

一応ちゃんと動くかチェック

c = Calc.new
c.siki = "2 + 5 / 5"
c.do_calc # => 3
c.siki ="(1+1) * 3 * (1+4)"
c.do_calc # => 30

ちゃんと()つきでも動いた

※もっとうまい書き方があればコメントしていただけるとありがたいです

追記

ちゃんとテストしたらだめだめだったので直しました。
以下修正版

#!/usr/bin/ruby
# -*- coding: utf-8 -*-

class Calc

  #値の取り出し順序を判断するメソッド
  def rtnval val
    hs = {  "(" => 5, "*" => 3, "×" => 3, "/" => 3, "÷" => 3, "+" => 2,
      "" => 2, "-" => 2, "" => 2, ")" => 1, "BTM" => 0  }

    rtn = hs[val]

    rtn = 4 unless rtn

    return rtn
  end

  #通常の式を逆ポーランド記法に変換して計算するメソッド
  def do_it siki
    arr = siki.scan(/\d+|[^\s\w]/)
    stc = []                         #逆ポーランド記法変換時に使用する一時スタック
    rev_prd = []                     #逆ポーランド記法の式を格納するスタック

    stc << "BTM"                     #stackの底を判断するために識別用変数を入れておく

    #引数で渡された式を逆ポーランド記法に変換
    #1.式から取り出した項目の取り出し順がスタックの一番上の取り出し順と同じか小さい かつ
    #  式から取り出した項目が(でない限りはスタックの一番上の項目を逆ポーランド記法のスタックに格納
    #2.式から取り出した項目の取り出し順がスタックの一番上の取り出し順より大きい場合はスタックに取り出した項目を格納
    #3.式から取り出した項目が)かつスタックの一番上の項目が(の場合はスタックから(を取り除く
    arr.each do |crt|

      crt_val = rtnval(crt)

      stc.size.times do |val|
        stc_val = rtnval(stc[stc.size-1])

        if(stc_val.to_i >= crt_val.to_i && stc[stc.size-1] != "(" )
          rev_prd << stc.pop
        elsif(crt_val.to_i > stc_val.to_i )
          stc << crt
          break
        elsif(stc_val.to_i == 5 && crt_val.to_i == 1)
          stc.pop
          break
        else
          stc << crt
          break
        end

      end
    end

    #スタックに残った値を逆ポーランド記法のスタックにPUSH
    stc.size.times do |param|
      rev_prd <<  stc.pop
    end

    # 逆ポーランド記法の式を計算する
    rev_prd.size.times do |str|
      i = rev_prd.shift
      case(i)
      when("+" || "")
        stc << stc.pop.to_i + stc.pop.to_i
      when("-" || "")
        stc << stc.pop.to_i - stc.pop.to_i
      when("*" || "×")
        stc << stc.pop.to_i * stc.pop.to_i
      when("/" || "÷")
        stc << stc.pop.to_i / stc.pop.to_i
      when("BTM")
        break
      else
        stc << i
      end
    end

    stc[0] # 計算結果

 end
end