4

Boost.Spirit (2.3) でカスタム Parser クラスを作成しようとしましたが、うまくいきませんでした。コードは次のとおりです。

template <class Iter>
class crule : public boost::spirit::qi::parser<crule<Iter> >
{
  rule<Iter> r_;
public:
  crule(const rule<Iter>& r) : r_(r) {}
  template <class T>
  crule(const T& t) : r_(t) {}
  template<class Ctx, class Skip>
  bool parse(Iter& f, const Iter& l, Ctx& context, Skip& skip, typename rule<Iter>::template attribute<Ctx, Iter>::type& attr) const {
    return r_.parse(f, l, context, skip, attr);
  }
  template <class Ctx>
  boost::spirit::info what(Ctx& context) const {
    return r_.what(context);
  }
  template <class Context, class It>
  struct attribute {
    typedef typename rule<Iter>::template attribute<Context, It>::type type;
  };
};

そして、私はすべての要件を満たしていますが (少なくとも私は満たしていると思います) 、解析式でこのクラスを使用しようとするとエラーが発生します。

shell_grammar.h:134: error: no match for 'operator!' in '!shell_grammar<Iter>::token(boost::spirit::qi::rule<Iter, boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type>) [with Iter = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >](boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type>(((const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type>&)((const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type>*)(&((shell_grammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >*)this)->shell_grammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::reserved_words)))))'

shell_grammar.h:134: note: candidates are: operator!(bool) <built-in>

他のパーセット (例: ) の実装を調べようとしましたnot_predicateが、それが機能する違いは何なのかわかりません。

モチベーション

私がそうする理由は、この質問に関連しています。独特の字句規則を持つ POSIX シェル言語を解析したい。特に、「スキッパーパーサー」は語彙素にも適用する必要がありますが、「句レベル」のスキッパーパーサーとは異なるものにする必要があります。これは、lexemeディレクティブが実行できないことであり、skipプリスキップ (AFAIK) も行いません。これは私が必要としているものでもあります。だから私は関数を作成したい

something token(std::string);

トークンに一致するルールを返します。1 つの方法は、端末として機能する独自のruleラッパーを作成することです (rule単独では参照セマンティクスに使用できないため)。別の方法は、新しいパーサーを作成し (これは の非端末になりますproto)、それにシェルのトークン解析を実装することです。

4

3 に答える 3

3

提供したコードは問題ないように見えます(少なくとも実際のパーサーのインターフェースに関する限り)。ただし、カスタムパーサーをSpiritと統合するには、さらに多くの作業を行う必要があります。SpiritのWebサイトには、ここで必要なすべての手順を説明するカスタムパーサーコンポーネントの例があります。

あなたが不必要に困難な方法で物事をやろうとしているように私には見えます。しかし、私はあなたが何を達成しようとしているのか完全には理解していないので、私は間違っているかもしれません。ユースケースを説明していただければ、もっと簡単な解決策を思いつくことができると思います。

于 2010-08-18T19:11:30.370 に答える
3

可能性は十分にありますが、独自のレクサーと再帰降下パーサーを手作業で作成するよりも多くの作業 (およびデバッグが困難) であることがわかりました。かなり小さな Spirit 文法でさえ、コンパイラーと格闘するのに何週間もかかることがあります。

このエラー メッセージは、発生した問題の種類を示しています。エラーが発生するときはいつでも、それは問題を混乱させるためにテンプレートのインスタンス化の多くのレイヤーが追加された、Spirit の腸の奥深くにあるテンプレートのインスタンス化によるエラーです。エラー メッセージを解読するには、機能全体のコードを理解する必要があります。

スピリットは価値ある取り組みなので、私は批判するのは嫌いです。オブジェクト指向のコンパイラージェネレーターの実装に関する修士論文を書いたので、この概念のファンです。私は本当にそれを気に入りたかったのですが、Spirit は真剣な C++ の専門家以外が使用するには難しすぎます。

何ができるかを比較するには、Ada OpenTokenプロジェクトを見てください。Spirit はおそらくより柔軟ですが、コンパイル エラーは OpenToken の方がはるかに賢明であり、そのページのバージョン履歴を一目見れば、ユーザーがエラーをデバッグするのを支援するために彼らの努力の非常に大きな割合が費やされていることがわかります。

于 2010-08-17T13:10:37.507 に答える
1

ところで、これは私が思いついたものです:

boost::proto次のように、クラスをリテラルとして登録する必要があります。

template <class T>
struct crulexx : public boost::proto::literal<rule<T> >
{
  template <class U>
  crulexx(const U& u) : boost::proto::literal<rule<T> >(rule<T>(u)) {}
};

このテストではうまくいきます。ただし、それを使用する他のコードでセグメンテーション違反が発生したため、デバッグする必要があります。

于 2010-08-20T12:32:18.553 に答える