式の計算(カッコあり、演算子の結合優先順位なし)

何も見ずに書いたのですが、逆ポーランド記法に変換する処理に頭を使いました><
まだ演算子の結合優先順位が残ってる、ひー><

# 式を逆ポーランド記法に変換して計算
# カッコあり
# 演算子の結合優先順位なし


token_defs = [
	[:space, /\s+/],
	[:operator, /[+\-*\/]/],
	[:numeric, /-?[0-9]+(?:\.[0-9]+)?/],
	[:leftkakko, /\(/],
	[:rightkakko, /\)/],
]

input = gets.chomp
tokens = []
i = 0
while input[i]
	find = nil
	token_defs.each do |token_def|
		find = ( /\A#{token_def[1]}/ =~ input[i..-1] )
		if find
			tokens << [token_def[0], $&] unless token_def[0] == :space
			i += find + $&.size
			break
		end
	end
	raise unless find
end

# 逆ポーランド記法に変換する

# 右辺の括弧レベルを記録する
# (右辺の終了を調べるため)
rs_stack = []

kakko_level = 0

src_tokens = tokens
dest_tokens = [] # 逆ポーランド記法のトークン
dest_tokens_pointer = 0

before_src_token_type = :none
src_tokens.each do |src_token|
	case src_token[0]
	when :numeric
		raise unless [:none, :leftkakko, :operator].include?( before_src_token_type )
		dest_tokens.insert( dest_tokens_pointer, src_token )
		dest_tokens_pointer += 1
		if before_src_token_type == :operator # 右辺の場合
			if rs_stack.last == kakko_level
				rs_stack.pop
				dest_tokens_pointer += 1
			end
		end
	when :operator
		raise unless [:numeric, :rightkakko].include?( before_src_token_type )
		dest_tokens.insert( dest_tokens_pointer, src_token )
		rs_stack.push( kakko_level )
	when :leftkakko
		raise unless [:none, :operator, :leftkakko].include?( before_src_token_type )
		kakko_level += 1
	when :rightkakko
		raise unless kakko_level > 0
		raise unless [:numeric, :rightkakko].include?( before_src_token_type )
		kakko_level -= 1
		if rs_stack.last == kakko_level
			rs_stack.pop
			dest_tokens_pointer += 1
		end
	else
		raise
	end
	before_src_token_type = src_token[0]
end
raise unless dest_tokens.size == dest_tokens_pointer
raise unless kakko_level == 0

# 逆ポーランド記法の式を表示
puts dest_tokens.map{|v|v[1]}.join(' ')

# 逆ポーランド記法の式を計算する

tokens = dest_tokens

stack = []

tokens.each do |token|
	case token[0]
	when :numeric
		stack.push token[1].to_f
	when :operator
		raise unless stack.size >= 2
		b = stack.pop
		a = stack.pop
		case token[1]
		when '+'
			a += b
		when '-'
			a -= b
		when '*'
			a *= b
		when '/'
			a /= b
		else
			raise
		end
		stack.push a
	end
end

raise unless stack.size == 1
puts stack[0]