代数式を解析して評価する代わりに、パーサーが代数ステートメントが真であるかどうかを判断するように、電卓の例を拡張しようとしています。これは、1 + 5 * 5 - 10 = 19 - 3
(望ましいパーサー結果はtrue
)や3 - 1 = 9
(望ましいパーサー結果はfalse
)のようなステートメントを意味します。
私は初めてのことを認めなければなりません、boost::spirit
そしてそれは今のところすべての種類の圧倒的です。ただし、電卓の例は、少なくともある程度前進するのに十分理解していると思います。
提供された例を開始点として使用すると、文法は次のようになります。
calculator() : calculator::base_type(expression)
{
using qi::uint_;
using qi::_val;
using qi::_1;
expression =
term [_val = _1]
>> *( ('+' >> term [_val = _val + _1])
| ('-' >> term [_val = _val - _1])
);
term =
factor [_val = _1]
>> *( ('*' >> factor [_val = _val * _1])
| ('/' >> factor [_val = _val / _1])
);
factor =
uint_ [_val = _1]
| '(' >> expression [_val = _1] >> ')'
| ('-' >> factor [_val = -_1])
| ('+' >> factor [_val = _1]);
}
簡潔にするために、デバッグマクロを削除しました。
問題の範囲を制限するために、ステートメントごとに1つの等号のみを許可することにしました。閉じた括弧のペアの中に等号を表示することは(少なくとも通常の意味では)無意味なので、括弧も許可しないことにしました。これfactor
により、オプションのの削除が許可されるため、-parserが単純化されます'(' >> expression [_val = _1] >> ')'
。
この時点で私は少し立ち往生しています。まず、単一の等号を受け入れるパーサーが必要です。次に、最終的に比較を実行する前に、ステートメントの左側(LHS)と右側(RHS)を個別に評価するためのセマンティックアクションが必要です(つまり、これを実行する必要があると思います)。
最も簡単なアプローチは、等号に一致する3番目のパーサーで区切られた2つの別々のパーサー(1つはLHSと1つはRHS)を作成することであるかどうか疑問に思います。2つのパーサーLHSとRHSは、これらを最終的に比較するために入力を2つの異なるカテゴリーに明確に分離する必要があるセマンティックアクションを除いて、同一である必要があります。
2つの別々のパーサーLHSとRHSを作成する前に、評価された式がローカル変数に格納されるように元のパーサーを変更する方法を学びたいと思いました。(それがどこへの実行可能な道であるかさえわかりませんが、それは正しい方向への一歩のようです。)
これは私が試したものです:
int result;
expression =
term [result = _1]
>> *( ('+' >> term [result = result + _1])
| ('-' >> term [result = result - _1])
);
しかし、これは私のコンパイラ(Apple LLVMコンパイラ4.2、Xcode 4.6)を狂わせ、私にそれを怒鳴りつけます
互換性のない型'const_1_type'から'int'に割り当てます(別名'constactor<引数<0>>')
後から考えると、これはもちろん理にかなっています。なぜなら、そもそも_val
バインドさint
れていなかったからです(結局のところ、パーサーはAFAIUであり、一般的であると考えられています)。つまり、評価された解析式を一時的に格納するために使用する型を定義する方法を理解する必要があります。
問題は、誰かが私に正しい方向へのナッジを与えることができるかということです。LHSとRHSの分割は進むべき道のように見えますか?
どんな提案でも大歓迎です!