Skip to main content

掛け算を追加しよう

構文解析

次は、掛け算を追加します。足し算と掛け算の違いは何でしょうか?

そう、優先順位です。掛け算は足し算よりも優先順位が高いですね。それでは、どのようにすれば優先順位を文法で表現出来るでしょうか?

具体例で考えてみましょう。1+2+3は、((1+2)+3)のようにマッチされるのでした。それでは、3*3+4*4はどのように構文解析されて欲しいでしょうか?((3*3)+(4*4))のように構文解析されるのが望ましいですね。つまり、+の左側、右側に来る式が、掛け算の式を含むようにすれば良いことが分かります。

それでは、これをPEG.jsのコードに落とし込んでいきましょう。

例えば次のようになります。+の左右にあるTermは、掛け算の式を含んでいますね。

example
Expression = Term ("+" Term)*
Term = Factor ("*" Factor)*
次に、Termの戻り値を定義していきます。ASTのtag名は"Mul"などが良いでしょう。足し算の時のコードを参考にして書いてみましょう。

それでは、入力に足し算と掛け算を使った式を入れて、期待した結果が返ってくるか確かめてみましょう。優先順位の高い式の部分木が、木の深い場所にあれば正しく動いています。次はevalを書き換えます。

評価

次はeval関数に、ast.tagが"Mul"のときの分岐を追加しますが、評価規則は足し算の時とほぼ変わりません。足し算を参考にして実装してみましょう。

発展

引き算と割り算を追加して、四則演算が出来るようにしてみましょう。

そのためには、PEGの重要な文法定義方法である選択を知る必要があります。選択とは、e1, e2を文法として、e1 / e2のように文法同士が/で区切られた文法のことを言います。この文法は、e1をまず最初に適用して、e1が適合しなかったら、e1が適用される前の状態に戻して、e2を適用するという意味です。(e.g. "+" / "-"は+か-に適合する文法、戻り値は先に適合した文法の戻り値)

また、"a" / "b" "c"はどのような文字列にマッチすると思いますか?これは、"a"または"bc"にマッチします。これを、"ac"または"bc"にマッチさせたければ、("a" / "b") "c"のようにする必要があります。(括弧で囲むことで、"a" / "b"をグループ化することが出来ます。)

引き算のASTのtagは"Sub"、割り算は"Div"などにするのが良いでしょう。