1

次のような文法規則があります。

rule<Iterator, utree()> expr, factor;

expr =
    (
       +(
           (
              toks.symbol // toks.symbol attribute type is an std::string
              [
                 // I'm trying to force the attribute type to be utree
                 _val = construct<utree::list_type>()
                 // some code here
              ]
           |  (
                 factor >>
                +(
                    // the 3 tokens here have unsigned long attribute
                    toks.arrow >> factor
                 |  toks.squiggleArrow >> factor
                 |  toks.dot >> factor
                 )
              )
              [

                 // I'm trying to force the attribute type to be utree
                 _val = construct<utree::list_type>()
                 // some code here
              ]
           ) >> toks.assign // toks.assign is token_def<omit>
        ) >> factor
     ) [ _val = ternary(_1, _2) ]
   ;

私がここから理解する限り:

http://boost-spirit.com/home/articles/attribute_handling/attribute-propagation-and-attribute-compatibility/

この場合、セマンティックアクションがあるため、属性の互換性を無効にする必要があります。それにもかかわらず、ternary()内にコンパイルエラーが表示されます。これは、_1の型が期待どおりのベクトルではなく、次のことを示唆しています。

vector<
    variant<std::string,
            fusion::vector2<utree,
                            fusion::vector2<long unsigned int, utree>
                           >
           >
       >

つまり、何らかの理由で、セマンティックアクションが開始されませんでした。

これが起こっている理由のヒントはありますか?

注:ここに問題を示す最小化された例を貼り付けました:

http://pastebin.com/rgiy2QBW

ありがとう!

4

1 に答える 1

3

コンパイラが文句を言う割り当ては本体の内部にありternaryImpl::operator()ます。これは、明らかに、セマンティックアクションが開始されたことを意味します。

これで、SAが自動属性伝播を防止することは正しいですが(演算子%=がルールの割り当てに使用されている場合を除く)、これは、プリミティブパーサーによって公開される型が魔法のように変化することを意味するものではありません。

質問にリストするタイプは、パーサー式/演算子が返すものを正確に反映しています。

  • または(|)はバリアントに解析します
  • シーケンス( )は、 etc>>に解析されます。fusion::vector2<...>

さて、これがこのコンパイルを行う私の単純で最小限の変更です。秘訣は、正確には、明示的な属性タイプでサブルールを分割することにより、属性の割り当てを機能せることです。これにより、Spiritが属性変換を行うことができます。

struct Parser: public qi::grammar<Iterator, utree()>
{
    template <typename Tokens>
        Parser(const Tokens &toks):
            Parser::base_type(expression)
    {
        chain = +(
            (
               toks.symbol
               [
                  _val = construct<utree::list_type>()
                  // some code here
               ]
            |  (
                  factor >>
                 +(
                     toks.arrow >> factor
                  |  toks.dot >> factor
                  )
               )
               [
                  _val = construct<utree::list_type>()
                  // some code here
               ]
            ) >> toks.assign
         );
        expression = factor
            | (chain >> factor) [ _val = ternary(_1, _2) ]
            ;
    }

   rule<Iterator, utree::list_type()> chain;
   rule<Iterator, utree()> expression, factor, test;
};

必要に応じて、追加のルール定義なしで同じことを実行できるようにする必要があります(たとえばqi::attr_cast<>、を使用qi::as<>)が、読み取り可能/保守可能になるとは思えません。

PS。SAを使用するバージョンcalc_utree_naive.cppよりも、必然的に、より明示的なルール属性タイプを綴る、同様のポイントを取り除くことができます。calc_utree_ast.cpp

これが完全なコンパイルバージョンで、コメントにいくつかのインラインノートがあります。

// #define BOOST_SPIRIT_USE_PHOENIX_V3
// #define BOOST_RESULT_OF_USE_DECLTYPE
#include <algorithm>
#include <string>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_utree.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>

namespace lex    = boost::spirit::lex;
namespace qi     = boost::spirit::qi;
namespace spirit = boost::spirit;
namespace phx    = boost::phoenix;

using lex::token_def;
using qi::rule;
using qi::_1;
using qi::_2;
using qi::_val;
using spirit::utree;
using phx::construct;

// base iterator type
typedef std::string::iterator BaseIteratorT;

// token type
typedef lex::lexertl::token<BaseIteratorT, boost::mpl::vector</*double, int, */std::string> > TokenT;

// lexer type
typedef lex::lexertl::actor_lexer<TokenT> LexerT;

template <typename LexerT>
struct Tokens: public lex::lexer<LexerT>
{
   Tokens()
   {
      using lex::_pass;
      using lex::pass_flags;

      // literals
      symbol = "[a-zA-Z_?](\\w|\\?)*|@(\\w|\\?)+";
      arrow  = "->";
      dot    = '.';
      assign = "=";

      // literal rules
      this->self += symbol;
      this->self += arrow;
      this->self += dot;
      this->self += assign;
   }

   ~Tokens() {}

   // literal tokens
   token_def<std::string> symbol;
   token_def<> arrow, dot; // HINT: lex::omit here? 
   /*
    * ^ Otherwise, expect these to be all exposed as Qi attributes as well, so
    * _1, _2, _3, _4 a bit more than you'd expect
    */
   token_def<lex::omit> assign;
};

struct ternaryImpl
{
   template <typename Expr1Type, typename Expr2Type>
   struct result { typedef utree type; };

   template <typename Expr1Type, typename Expr2Type>
   utree operator()(Expr1Type &vec, Expr2Type &operand) const {
      utree ret;

      for (typename Expr1Type::iterator it = vec.begin(); it != vec.end(); ++it) {
         // some code
         ret = *it;
         // more code
      }

      // some code here

      return ret;
   }
};

phx::function<ternaryImpl> ternary = ternaryImpl();

template <typename Iterator>
struct Parser: public qi::grammar<Iterator, utree()>
{
    template <typename Tokens>
        Parser(const Tokens &toks):
            Parser::base_type(expression)
    {
        chain = +(
            (
               toks.symbol
               [
                  _val = construct<utree::list_type>()
                  // some code here
               ]
            |  (
                  factor >>
                 +(
                     toks.arrow >> factor
                  |  toks.dot >> factor
                  )
               )
               [
                  _val = construct<utree::list_type>()
                  // some code here
               ]
            ) >> toks.assign
         );
        expression = factor
            | (chain >> factor) [ _val = ternary(_1, _2) ]
            ;
    }

   rule<Iterator, utree::list_type()> chain;
   rule<Iterator, utree()> expression, factor, test;
};

int main()
{
   typedef Tokens<LexerT>::iterator_type IteratorT;

   Tokens<LexerT> l;
   Parser<IteratorT> p(l);
}
于 2012-07-16T23:54:50.363 に答える