Androidで電卓を作ってみる その1

 SableCC 3.2を使ってAndroidで電卓を作ってみようかと思います。これだとgrammerファイルを書き終わった後のコーディングは殆ど無いってレベルです。

簡単な仕様

  • 計算式を入力してボタンを押すと答えが表示される
  • 計算式は半角数字と半角演算記号だけ
  • 改行コードとタブ、半角スペースは無視する。
  • 数値は整数系32bit
  • 使える演算子は以下
    • () 優先順位の変更
    • +-*/ の二項演算子

SableCCのgrammarファイル

ソースファイル

解説

Package

 Parserのクラスを出力するJavaのパッケージを指定。

Helpers

 ここでは改行コードとか半角とか数字を定義しています。これは後でTokens節で使います。

States

 今回は特に語句の解析を状況によって切り替えたりしないので、normalだけ定義して終わり。

Tokens

 ここで定義した単語が一つずつ認識されてプログラムから利用する事が可能になります。

 連なった数字を見つけたらnumberという語句として認識。digitはHelpersで定義した正規表現を利用しています。解析結果のTreeではTNumberというクラスのオブジェクトとして現れます。

 l_parenとr_paren。括弧です。

この場合クラス名はアンダースコアの直後の文字も大文字になりますのでTLParenとTRParenというクラスになります。

 add,sub,mul,div。加減乗除の演算子です。

それぞれTAdd,TSub,TMul,TDiv。

 blank,eol。それぞれスペース、タブと改行です。

 という事でこの文法ファイルでは上記が入力対象として認識できる語句という事になります。ここで定義されていないような文字が出てきたらエラーになります。

Ignored Tokens

 blankとeolは特に文法上は必要ない語句です。ここで指定された語句は入力の中で見つけても何もせず捨てられるようになります。

Productions

 ここから文法を定義します。

  • 入力されるのは一番最初に書いてある「式(Expression)」です。
  • 式 PExprは、「ただ一つの項である」ATermExpr、「式と項の足し算」AAddExpr、「式と項の引き算」ASubExprです。
  • 項 PTermは、「ただ一つの要素」AFactorTerm、「項と要素の掛け算」AMulTerm、「項と要素の割り算」ADivTermです。
  • 要素 PFactorは、「ただの数字」ANumberFactor、「括弧で括られた式」AParensFactorのどちらかです。

Parserの生成

 これで入力文章からCSTを作成するParserを生成することができます。sableccのコマンドを使ってソースを生成します。

Parserの利用

 生成されたParserを使う場合は以下のようにします。

 PushbackReaderからLexer、Parserとインスタンスを作り、その後parseを実行してTreeの開始点となるStartを得ます。

木をたどるVisitorをStartのインスタンスにapplyする事で構文木を処理できます。

Visitorの実装

 Visitorはanalysis.DepthFirstAdapter継承して作ります。

 Visitorは勝手に木をたどっていきますので、Visitorのクラスで実装すべき事は与えられたノードの出入りで必要な処理を記述するだけです。

具体的にはinAProduction(AProduction node);とoutAProduction(AProduction node);という感じの関数がすでに定義されているので、それらをOverrideしていきます。

 この簡易電卓を実現するのに必要な実装は以下だけです。

  • 最終結果を格納して取り出すためのインターフェースを準備する
  • 計算結果を途中結果格納するためのStackを準備する
  • 数字ANumberFactorを見つけたら(inでもoutでも良い)値をStackにPush
  • 演算子のノードから出るタイミング(たとえば掛け算ならoutAMulTerm)で、Stackから2つ取り出して計算して結果をスタックに積む。

ソース

 Parser部分の実装はほぼこれで終了です。ちょっと長くなったので、今回はここまでにして次回は これをGUIと紐づけてやって電卓を完成させます。