逆ポーランド記法に潜む罠 -単項演算子に気をつけろ!-

 スクリプトの計算がいつまでも

自前で用意した中間記法*1を根性で処理する

代物なのも、危険極まりない気がしてきたので、

内部的に逆ポーランド記法(以下「RevP」)に書き換えるようにしようかなと思い立ったわけですが。



(結論は一番下です)

 …はてさて、何故かはわからないんですが、

単項演算子を用いたRevPな式ってほとんど見ないんですよね。

僕が初めに参考にしていた所だと


なお、今回はカッコ以外は全て2項演算子でしたが
単項演算子(符合反転の - とか)の場合でも処理は変わりません。

  「もんしょの巣穴」さんの
コンパイラを作ろう -中置記法から逆ポーランド記法へ-」より抜粋

と書いてあるわけですが、実際の所どうなのか試してみる。



 一応、こんな感じで変換中も書いてみます。


[出力分]{演算子のスタック} 「元の式の残り」
・「-3+4」

 …


[]{-} 「3+4」
[3]{-} 「+4」
[3-]{+} 「4」
[3-4]{+} 「」
[3-4+]{} 「」
「3-4+」かな?

…確かに「-」を「数値x1に対して適応できる演算子(=単項演算子ですが(笑))として扱えればいけそう。

結果は「1」。



・「-3+4*5」

 … 積算と組み合わせてみる


[]{-} 「3+4*5」
[3]{-} 「+4*5」
[3-]{+} 「4*5」
[3-]{+} 「4*5」
[3-4]{+} 「*5」
[3-4]{+} 「*5」
[3-4]{+*} 「5」
[3-45]{+*} 「」
[3-45*+]{} 「」
「3-45*+」?

…これも問題なし。

結果は「17」。





・「(-3+4)*(3+5)」

 … 括弧と組み合わせてみる


[]{(} 「-3+4)*(3+5)」
[]{(-} 「3+4)*(3+5)」
[3]{(-} 「+4)*(3+5)」
[3-]{(+} 「4)*(3+5)」
[3-4]{(+} 「)*(3+5)」
[3-4+]{} 「*(3+5)」
[3-4+]{*} 「(3+5)」
[3-4+]{*(} 「3+5)」
[3-4+3]{*(} 「+5)」
[3-4+3]{*(+} 「5)」
[3-4+35]{*(+} 「)」
[3-4+35+]{*} 「」
[3-4+35+*]{} 「」
…えー、「3-4+35+*」?

これも問題なく、8が出る。





・「(-3+4)*(-3+5)」

 … 後ろの括弧の方に入れてみる


[]{(} 「-3+4)*(-3+5)」
[]{(-} 「3+4)*(-3+5)」
[3]{(-} 「+4)*(-3+5)」
[3-]{(+} 「4)*(-3+5)」
[3-4]{(+} 「)*(-3+5)」
[3-4+]{} 「*(-3+5)」
[3-4+]{*} 「(-3+5)」
[3-4+]{*(} 「-3+5)」
[3-4+]{*(-} 「3+5)」
[3-4+3]{*(-} 「+5)」
[3-4+3-]{*(+} 「5)」
[3-4+3-5]{*(+} 「)」
[3-4+3-5+]{*} 「」
[3-4+3-5+*]{} 「」
…えーっと、「3-4+3-5+*」かな?

……アレ?二回目の「-」が単項演算子二項演算子かこれでは判別できないんですが…(汗)

ちなみに、素直にやると結果は「3」。(…というか、最後の積算をするのに項が足りない…。)





 …さて、それではどうしましょうか…(何)

…要するに、「単項演算子二項演算子かの判別」が出来ればいいので、

符号関連の「+」「-」を別の記号(…というか演算子)で表すことが出来れば大丈夫そうです。

(ちなみに、C言語の「+」「-」も符号関連と演算関連は別物扱いみたいですね。

(優先度が全く異なる)

…どうやって判別してるんでしょうか(汗))



 というわけで、

先程の式の「-」を「_」に置き換えて再計算してみます。



・「(_3+4)*(_3+5)」

 … 後ろの括弧の方に入れてみる(改定版)


[]{(} 「_3+4)*(_3+5)」
[]{(_} 「3+4)*(_3+5)」
[3]{(_} 「+4)*(_3+5)」
[3_]{(+} 「4)*(_3+5)」
[3_4]{(+} 「)*(_3+5)」
[3_4+]{} 「*(_3+5)」
[3_4+]{*} 「(_3+5)」
[3_4+]{*(} 「_3+5)」
[3_4+]{*(_} 「3+5)」
[3_4+3]{*(_} 「+5)」
[3_4+3_]{*(+} 「5)」
[3_4+3_5]{*(+} 「)」
[3_4+3_5+]{*} 「」
[3_4+3_5+*]{} 「」
…えー、変換式は本当に置き換えただけなんですが(汗)

「3_4+3_5+*」かな?

…お、コレだと結果はきちんと「2」になりますね。







 …というわけで、長ったらしくなりましたが、

逆ポーランド記法だと、符号関連の「+」「-」は別の記号で表現する必要がある。

みたいです。




*1:一般的な数式の記法(「3+4」とか)。演算子が中間にくるため、こう呼ばれるそうです。