演算子順位解析

最終演習の課題として、第19章 電卓の作成 を変更して 「通常の式を計算する電卓にしたい」 という希望がありました。
通常の電卓は、演算子(演算ボタン)に優先順位はなく、 押された順に(1つ前に押された)演算を実行します。 演算結果は1つ保持しておけば十分です。
演算子の優先順位やカッコを考慮すると、そうはいきません。 右側に優先順位の高い演算子が現れた場合は、左側の演算せずに先にすすまなければなりません。
一般的には、構文解析という処理をして、式を木構造で表現したり、 前置記法後置記法に変換をします。
parse
簡単な構文解析として「演算子順位解析」や「再帰下降解析 recursive decent parse」があります。
ここでは、演算子順位解析を概説しますが、 入力された式を木表現に変換するのではなく、「計算できる部分から順に計算をすすめる」 という例を紹介します。

演算子順位表

演算子順位表は、となりあった(といっても通常は間に数値がある)演算子について どちらを先に計算するかを示した表です。下表において、 という意味になります。 + は + か − 、 * は × か ÷ のいずれかという意味です。 また、式の始点(左端)を ^ 、終点(右端)を $ で表現します。
2項演算子のみを扱うことにします。
下表の縦にならんだ演算子は解析中の左側の演算子、横にならべた演算子は右側に現れた演算子です。
演算順位表
+*()$
+> < > > >
*> > < > >
(< < < = x
)> > x > >
^< < < x =
上記の演算順位表をもとに、「入力を読み込みスタックに積む」(shift)、 「演算を行い、演算に使用した演算子、被演算子をスタックから取り除き、演算結果をスタックに積む」(reduce) という表に書き直したものが下表です。
数値が現れたら、shift すると決めておきます。
a and b+*()$
+reduce shift reduce reduce reduce
*reduce reduce shift reduce reduce
(shift shift shift pop x
)reduce reduce x reduce reduce
^shift shift shift x end

解析アルゴリズム

  1. スタックに ^ を積んでおく。また、最後の入力で $ を返すようにしておく。
  2. 入力する。数値であれば、スタックに積む。 2. から繰り返す
  3. 入力が演算子であれば、b とし、スタックの演算子(スタックの上から2番目にある)を a とする
  4. 構文表の a行目、b列を調べ、 reduce であればスタックの上3つ(数値、演算子、数値)の計算をし、 この3つを取り除き、結果をスタックに積む。 3. から繰り返す
  5. 構文表の a行目、b列目に shift が現れたら、b をスタックに積み 2. から繰り返す
  6. 構文表の a行目、b列目が pop のとき、 スタックの上の2つ(カッコ、数値)を取り除き、数値をスタックに積み 2. から繰り返す
  7. 構文表の a行目、b列目が end のとき、スタックの一番上が答

更新日:2011-12-26 UPTOP