演算子

演算子はオブジェクトのコンポジションや埋め込みの意味で用いられる。 単純なパーサは演算子オーバーロードによって合成パーサを形成するために合成される。 この演算子オーバーロードは、拡張バッカス標準記法( EBNF )の一種のような構文を模して作られている。 次のような式:

    a | b

は、実際に、オペランド a と b のコンポジションである新しいパーサ型を作り出す。 この例をさらに進めよう。もし a と b が chlit<> 型であるなら、その結果は次の合成型になる:

    alternative<chlit<>, chlit<> >

全般に、あらゆる二項演算子は二つの引数 parser1 と parser2 を取り、次の形式の新しい合成パーサを作り出す:

    op<parser1, parser2>

ここで parser1 と parsre2 はそれ自身が任意の複雑なパーサであり得る。制限は、あなたのコンパイラが強制する事項のみである。

集合演算子
a | b 論理和 a または b に一致する。選択とも呼ばれる
a & b 論理積 a かつ b に一致する
a - b b 以外の a に一致する。 両方に一致する場合、 b に一致したテキストが a に一致したものより短ければ、一致判定に成功する
a ^ b 排他的論理和 a または b に一致するが、両方に一致することはない

短絡

選択のオペランドは与えられ順に最も左のオペランドから一つずつ試される。 一致判定に成功した選択肢が見つかると、構文解析器は探索を終えて、原則として他の潜在的に可能な候補の探索を避ける。 この短絡は暗黙裡に左端の選択に最も高い優先度を与えることになる。

短絡は C や C++ の論理式の作法と同様に処理される。 例えば、 if (x < 3 || y < 2) で、もし x が 3 より小さいと評価されれば、 y < 2 のテストはまったく実行されない。短絡はさらに、 Spirit パーサコンパイラに非決定性を与えるのに必要な 選択の暗黙の優先度というルールをもたらすことで、実行時間を改善している。 もし選択の順序に論理的な意味がないなら、最大の効率を得るためにもっとも良く用いられる(と期待される)選択肢を最初に置くようにしよう。

論理積

研究者の中には、論理積( a & b など)で文脈依存言語を定義できると主張する人もいる ("XBNF"[Leu-Weiner, 1973])。 " 有限個の文脈自由言語の論理積として言語を定義する方法論は、 Leu と Weiner によって 1973 年に開発された。 "

~ 演算子

当初、否定演算子 ~ は考慮の対象だった。 その価値と意味をより深く理解するほど、我々は確信を持てなくなった。 基本的な問題は、 ~aU - a を生じさせるという事実である。 ここで U はあらゆる文字のすべての組み合わせを表す。 とはいえ、それが意味をなす場合には、補完されうるパーサもある (例えば文字プリミティブパーサを参照)。

シーケンス制御演算子
a >> b シーケンス a と b がその順に一致する
a && b シーケンシャルな and シーケンシャルな and 。上と同じく、 a と b がその順に一致する
a || b シーケンシャルな or a または b がその順に一致する

シーケンス制御演算子 >> はシーケンシャルな and 演算子の代替物と考えられる。 式 a && b は、 a かつ b でその順に、と読む。 この論理を続けると、シーケンシャルな or が得られる。式 a || b は、 a または bをその順に、と読む。 すなわち、もし a と b の両方に一致するならその順でなければならない。 これは a | b | a >> b と等価である。


選択とループ
*a Kleene star 0 回またはそれ以上に一致する
+a 正符号 1 回またはそれ以上に一致する
!a 省略可能 0 または 1 回に一致する
a % b リスト b の出現で区切られた 1 回以上の a の繰り返しに一致する。 これは a >> *(b >> a) と同じものである。 ab にマッチしてはならない点に注意

より詳しく見るなら、 !a の形で表される省略可能式をループと同じカテゴリに一般化している点に注意して欲しい。 省略可能は、ある式が 0 回か 1 回続いた場合に一致することを考えれば、これは道理にかなっている。

プリミティブ型のオペランド

二項演算子では、オペランドの片方(両方は不可)が char wchar_tchar const* または wchar_t const* であってもよい。 以下は、 P がパーサオブジェクトであるとしたときの例である:

    P | 'x'
    P - L"Hello World"
    'x' >> P
    "bebop" >> P

C++ は、演算子をオーバーロードするには少なくても一つの引数がユーザ定義型であるよう命じている。このことをはっきりさせておくのは重要だ。 通常、複数の演算子を伴う式では、 パーサとして明示的に型付けされた最左端のオペランドがあれば十分である。 なぜなら、その右にある残りすべてのオペランドが受け付けられるように、その型が伝搬されるからだ。例えば:

    r = 'a' | 'b' | 'c' | 'd';          // ill formed
    r = ch_p('a')  | 'b' | 'c' | 'd';   // OK

二つ目のケースは、次のように構文解析される:

    r  (((chlit<char> | char) | char) | char)

    a  (chlit<char> | char)
    r  (((a) | char) | char)

    b  (a | char)
    r  (((b)) | char)

    c  (b | char)
    r  (((c)))

演算子の優先順位とグループ化

我々はこのメタ言語を C++ で定義しているので、 C / C++ の演算子の優先順位のルールに従っている。 式を括弧の内側にグループ化すれば、これをオーバーライドできる。 (例えば *(a | b) は、 a か b が 0 回以上現れればマッチする、と読む)。



このドキュメントの対象: Boost Version 1.30.0
最新版ドキュメント(英語)