【问题标题】:boost::spirit::x3 problem with any ast class representing a std::string表示 std::string 的任何 ast 类的 boost::spirit::x3 问题
【发布时间】:2021-05-20 22:04:15
【问题描述】:

我有两种我认为是合法的方法来在我的 ast 中定义一个代表字符串的类,如下所示:

  struct white : std::string {};

  struct white {std::string text;};

我在多个地方使用它来表示我想在我的 ast 中捕获的文字、标识符、cmets 甚至空白。

在某些地方我必须使用第一种形式,而在其他地方我必须使用第二种形式,否则我会收到带有可怕错误消息的编译错误:

  ...
  no matching function for call to ??minimal::ast::rules::rules(__gnu_cxx::__normal_iterator<minimal::ast::gap_item*,
    std::vector<minimal::ast::gap_item> >&,
    __gnu_cxx::__normal_iterator<minimal::ast::gap_item*, std::vector<minimal::ast::gap_item> >&)??
  ...

嵌入了几页错误输出,不知道可能有错误的源代码行。

我应该如何解释这种类型的错误信息? 为什么我必须在不同的地方使用不同的形式/风格的课程?

这个最小的例子说明了问题(当#defines被[un]注释时)

//{{{ Notes
/*
Purpose:    Demonstrate problem causing error messages like:
  no matching function for call to ??minimal::ast::rule::rule(std::_List_iterator<minimal::ast::gap_item>&,
    std::_List_iterator<minimal::ast::gap_item>&)??
  no matching function for call to ??minimal::ast::rules::rules(__gnu_cxx::__normal_iterator<minimal::ast::gap_item*,
    std::vector<minimal::ast::gap_item> >&,
    __gnu_cxx::__normal_iterator<minimal::ast::gap_item*, std::vector<minimal::ast::gap_item> >&)??

There are two aspects to this problem:
  1) The error message is enormous (sometimes larger than my terminal scroll buffer) and is undecipherable (to me).
  2) I do not understand what is really causing the problem, especially where, for similar requirements,
     one construct works in one place, but another construct is needed elsewhere.

The problem appears with a subtle change in coding style for the ast:
  #ifndef WITH_INSTANCED_STRING_WHITE
  struct white : string {};
  #else
  struct white {string text;};
  #endif
For this case, the problem occurs when WITH_INSTANCED_STRING_WHITE is undefined.
However, the opposite happens for WITH_INSTANCED_STRING_LITERAL or WITH_INSTANCED_STRING_C_IDENTIFIER.

Context:    Attempting to parse "yacc" as a precursor to morphing yacc to x3.
        There is important information in the c-style comments so gaps (comments or white) are not skipped.

Notation:   Nested pairs of "//{{{" and "//}}}" denote folds which some editors can hide or fold into one line

Compile:    g++ src/rgw29_minimal.cpp -o bin/rgw29_minimal
*/
//}}}
//{{{ rgw29_yacc.hpp
//{{{ Define
#define WITH_INSTANCED_STRING_WHITE
//#define WITH_INSTANCED_STRING_LITERAL
//#define WITH_INSTANCED_STRING_C_IDENTIFIER
//}}}
//{{{ include
#include <string>
#include <boost/cstdlib.hpp>                    // for boost::exit_success
#include <boost/filesystem.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>     // for x3::variant<...>
//}}}
//{{{ namespace and globals
namespace x3            = boost::spirit::x3;
using iterator_type     = std::string::const_iterator;
using context_type      = x3::phrase_parse_context<x3::ascii::space_type>::type;
//}}}
//}}}
//{{{ data/rgw29/yacc_grammar.yacc
//https://pubs.opengroup.org/onlinepubs/009696799/utilities/yacc.html
#include <string>
namespace minimal {
std::string bad_data = R"(
/* This is to demonstrate successful compilation, but a parse failure. */
spec  : defs MARK rules tail
      ;
)";
std::string yacc_data = R"(
%start    spec
%%
spec  : defs MARK rules tail
      ;
)";
}
//}}}
//{{{ rgw29_yacc_ast.hpp
//{{{ include
#include <iostream>
#include <boost/fusion/include/io.hpp>              // for boost::fusion::tuple_open/close/delimiter
#include <boost/fusion/include/std_pair.hpp>            // for usage inside BOOST_FUSION_ADAPT_STRUCT
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/optional/optional_io.hpp>           // for ostream<< boost::optional<>
//}}}
//{{{ ast yacc
namespace minimal { namespace ast
{  
  using namespace std;

  enum yacc_token
  { lcomment
  , rcomment
  , semi
  , colon
  , mark
  };
  inline ostream& operator<<(ostream& os, yacc_token const& a)
  {
    //os << "yacc_token: ";
    switch (a)
    {
      case lcomment     : os << "/*"; break;
      case rcomment     : os << "*/"; break;
      case semi         : os << ";"; break;
      case colon        : os << ":"; break;
      case mark         : os << "%%"; break;
      default           : BOOST_ASSERT(0);
    }
    return os;
  }

  #ifndef WITH_INSTANCED_STRING_WHITE
  struct white
  : string
  {
  };
  #else
  struct white
  {
    string          text;
  };
  #endif
 
  struct comment
  {
    yacc_token          open;
    string          text;
    yacc_token          close;
  };

  struct gap_item
  : x3::variant
  < comment
  , white
  >
  {
    using base_type::base_type;
    using base_type::operator=;
  };
  struct gap
  : vector<gap_item>
  {
  };
    
  #ifndef WITH_INSTANCED_STRING_LITERAL
  struct literal
  : string
  {
  };
  #else
  struct literal
  {
    string          text;
  };
  #endif

  #ifndef WITH_INSTANCED_STRING_C_IDENTIFIER
  struct c_identifier
  : string
  {
  };
  #else
  struct c_identifier
  {
    string          text;
  };
  #endif

  struct rule_item
  : x3::variant
  < yacc_token
  , c_identifier
  , gap
  , literal
  //, string
  >
  {
    using base_type::base_type;
    using base_type::operator=;
  };
  struct rule
  : vector<rule_item>
  {
  };  
  struct rules
  : vector<rule>
  {
  };

  struct def_item
  : x3::variant
  < gap
  , string
  >
  {
    using base_type::base_type;
    using base_type::operator=;
  };
  struct defs
  : vector<def_item>
  {
  };
  
  struct spec_item
  : x3::variant
  < defs
  , rules
  , yacc_token
  , gap
  >
  {
    using base_type::base_type;
    using base_type::operator=;
  };
  struct spec
  {
    defs            defs_;
    yacc_token          mark_;
    gap             gap1;
    rules           rules_;
  };

  using yacc_ast_type       = spec;
}}
//}}}
//{{{ fusion adapt
#ifdef WITH_INSTANCED_STRING_WHITE
BOOST_FUSION_ADAPT_STRUCT(minimal::ast::white,          text)
#endif
#ifdef WITH_INSTANCED_STRING_LITERAL
BOOST_FUSION_ADAPT_STRUCT(minimal::ast::literal,        text)
#endif
#ifdef WITH_INSTANCED_STRING_C_IDENTIFIER
BOOST_FUSION_ADAPT_STRUCT(minimal::ast::c_identifier,       text)
#endif
BOOST_FUSION_ADAPT_STRUCT(minimal::ast::comment,        open, text, close)
BOOST_FUSION_ADAPT_STRUCT(minimal::ast::spec,           defs_, mark_, gap1, rules_)
//}}}
//}}}
//{{{ rgw29_yacc_grammar.hpp
//{{{ alias
namespace minimal { namespace parser
{
  using x3::char_;
  using x3::lexeme;
  using x3::no_skip;
  using x3::alnum;
  using x3::alpha;
  using x3::print;
  using x3::ascii::string;
  using x3::ascii::space;
}}
//}}}
//{{{ parse rule type
namespace minimal { namespace parser
{
  struct comment_class;
  using comment_type            = x3::rule<comment_class,       ast::comment>;
  BOOST_SPIRIT_DECLARE(comment_type);
  struct white_class;
  using white_type          = x3::rule<white_class,         ast::white>;
  BOOST_SPIRIT_DECLARE(white_type);  
  struct gap_class;
  using gap_type            = x3::rule<gap_class,           ast::gap>;
  BOOST_SPIRIT_DECLARE(gap_type);
  
  struct defs_class;
  using defs_type           = x3::rule<defs_class,          ast::defs>;
  BOOST_SPIRIT_DECLARE(defs_type);

  struct c_identifier_class;
  using c_identifier_type       = x3::rule<c_identifier_class,      ast::c_identifier>;
  BOOST_SPIRIT_DECLARE(c_identifier_type);  
  struct literal_class;
  using literal_type            = x3::rule<literal_class,       ast::literal>;
  BOOST_SPIRIT_DECLARE(literal_type);
  
  struct rules_class;
  using rules_type          = x3::rule<rules_class,         ast::rules>;
  BOOST_SPIRIT_DECLARE(rules_type);
  struct rule_class;
  using rule_type           = x3::rule<rule_class,          ast::rule>;
  BOOST_SPIRIT_DECLARE(rule_type);
  
  struct spec_class;
  using spec_type           = x3::rule<spec_class,          ast::spec>;
  BOOST_SPIRIT_DECLARE(spec_type);
  struct inner_class;
  using inner_rule_type         = x3::rule<inner_class,         ast::yacc_ast_type>;
  BOOST_SPIRIT_DECLARE(inner_rule_type);
  struct start_class;
  using start_rule_type         = x3::rule<start_class,         ast::yacc_ast_type>;
  BOOST_SPIRIT_DECLARE(start_rule_type);
}}
//}}}
//}}}
//{{{ rgw29_yacc_grammar.cpp
//{{{ Token
namespace minimal { namespace parser
{
  x3::symbols<ast::yacc_token>      lcomment;
  x3::symbols<ast::yacc_token>      rcomment;
  x3::symbols<ast::yacc_token>      semi;
  x3::symbols<ast::yacc_token>      colon;
  x3::symbols<ast::yacc_token>      mark;
}}
//}}}
//{{{ add_keywords
namespace minimal { namespace parser
{
  void add_keywords()
  {
    static bool once = false;
    if (once)
      return;
    once = true;

    lcomment.add    ("/*",      ast::lcomment);
    rcomment.add    ("*/",      ast::rcomment);
    semi.add        (";",       ast::semi);
    colon.add       (":",       ast::colon);
    mark.add        ("%%",      ast::mark);
  }
}}
//}}}
//{{{ rule id
namespace minimal { namespace parser
{
  c_identifier_type const       c_identifier        = "c_identifier";
  literal_type const            literal         = "literal";
  comment_type const            comment         = "comment";
  white_type const          white           = "white";
  gap_type const            gap         = "gap";
  defs_type const           defs            = "defs";
  rules_type const          rules           = "rules";
  spec_type const           spec            = "spec";
  rule_type const           rule            = "rule";
  
  inner_rule_type const         inner_rule      = "inner_rule";  
  start_rule_type const         start_rule      = "start_rule";
}}
//}}}
//{{{ rule definition (cut down for this minimal example)
namespace minimal { namespace parser
{
  auto const comment_def        = lcomment >> *(char_ - rcomment) >> rcomment;  // /* ... */
  auto const white_def          = +space;                   // single space as string
  auto const gap_def            = +(white | comment);               // spaces/comments

  auto const c_identifier_def       = (alpha | char_("_.")) >> *(alnum | char_("_.")); // with non-initial number
  auto const literal_def        = char_("'") >> -char_("\\") >> (print - '\'') >> char_("'");   // 'c' or '\n'
  
  auto const spec_def           = defs >> mark >> gap >> rules;         // without tail
  auto const defs_def           = +(gap | +(char_ -lcomment -rcomment -mark));  // skip over all defs

  auto const rules_def          = +rule;
  auto const rule_def           = c_identifier > gap > colon > gap
    > *(gap | literal | +(char_ -lcomment -rcomment -semi -literal))            // catch_all to next semi
    > semi > gap;
  
  auto const inner_rule_def     = no_skip[spec];
  auto const start_rule_def     = inner_rule_def;
}}
//}}}
//{{{ tie rule to definition
namespace minimal { namespace parser
{
  BOOST_SPIRIT_DEFINE(comment, white, gap, c_identifier, literal)
  BOOST_SPIRIT_DEFINE(defs, rule, rules, spec);
  BOOST_SPIRIT_DEFINE(inner_rule, start_rule);
}}
//}}}
//{{{ start_rule()
namespace minimal
{
  parser::start_rule_type const& start_rule(){parser::add_keywords(); return parser::start_rule;}
}
//}}}
//{{{ parse_without_error_handler_and_positions(...)
namespace minimal { namespace parser
{
  bool
  parse_without_error_handler_and_positions
  ( iterator_type&          iter
  , iterator_type           end
  , ast::yacc_ast_type&         ast
  )
  {
    auto const parser_with_error_handler_and_positions = minimal::start_rule();  
    return phrase_parse(iter, end, parser_with_error_handler_and_positions, space, ast);
  }
}}
//}}}
//}}}
//{{{ rgw29_yacc_trial.cpp
//{{{ yacc implementation
namespace minimal
{
  //{{{ parse_yacc_string (not a lambda)
  bool
  parse_yacc_string(std::string const& source)
  {
    iterator_type                   iter        (source.begin());
    iterator_type const                 end     (source.end());
    minimal::ast::yacc_ast_type             ast;
    bool success = parser::parse_without_error_handler_and_positions(iter, end, ast);
    if (success && iter==end)
    {
      std::cout << "  parse succeeded" << std::endl;
    }
    else
    {
      std::cout << "  parse failed (as expected)" << std::endl;
    }
    return success;
  };
  //}}}
}
//}}}
//}}}
//{{{ rgw29_yacc.cpp
//{{{ main
int
main(int argc, char* argv[], char* envp[])
{
  using namespace std;
  using namespace minimal;
  
  parse_yacc_string(yacc_data);
  parse_yacc_string(bad_data);

  cout << "... successfully completed " << argv[0] << endl;
  return boost::exit_success;
}
//}}}
//}}}

****** 编辑 2021-05-30 ******

我认为 X3 中存在与多个嵌套容器和变体相关的错误。但这是开发人员需要解决的问题。

我有一个更简单的例子:

// Purpose: Demonstrate problem with lower level detail (gap_item) where wrapped rule (gap) should do.
#define BOOST_SPIRIT_X3_DEBUG       // Provide some meaningful reassuring output.
//#define WITHOUT_WHITE         // All ok until white added.
#define WITH_GAP_ITEM_IN_VARIANT    // Unnacceptable workaround

#include <string>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

namespace x3        = boost::spirit::x3;

namespace minimal { namespace ast
{
  struct white      : std::string           {using std::string::string;};
  struct braced                     {char open; std::string text; char close;};
  #ifdef WITHOUT_WHITE
  struct gap_item   : x3::variant<char,braced>  {using base_type::operator=;};
  #else // WITHOUT_WHITE
  struct gap_item   : x3::variant<white,braced> {using base_type::operator=;};
  #endif // WITHOUT_WHITE
  struct gap        : std::vector<gap_item>     {};

  #ifndef WITH_GAP_ITEM_IN_VARIANT
  struct start_item : x3::variant<gap,std::string>  {using base_type::operator=;};
  #else // WITH_GAP_ITEM_IN_VARIANT
  struct start_item : x3::variant<gap,std::string,gap_item,char>    {using base_type::base_type; using base_type::operator=;};
  #endif // WITH_GAP_ITEM_IN_VARIANT
  struct start  : std::vector<start_item>       {using std::vector<start_item>::vector;};
}}
BOOST_FUSION_ADAPT_STRUCT(minimal::ast::braced, open, text, close)

namespace minimal { namespace parser
{
  using x3::char_;
  using x3::space;
  using x3::raw;
  
  x3::rule<struct white,    ast::white> const   white       = "white";
  x3::rule<struct braced,   ast::braced>    const   braced      = "braced";
  x3::rule<struct gap,      ast::gap>   const   gap     = "gap";
  x3::rule<struct start,    ast::start> const   start       = "start";
  
  auto const white_def      = raw[+space];
  auto const braced_def     = char_('{') >> *(char_ -'}') >> char_('}');    // { ... }
  #ifdef WITHOUT_WHITE
  auto const gap_def        = +(space | braced);                // spaces etc
  #else // WITHOUT_WHITE
  auto const gap_def        = +(white | braced);                // spaces etc
  #endif // WITHOUT_WHITE
  auto const start_def      = +(gap | +(char_ -'{' -space));        // gap=container or string
  
  BOOST_SPIRIT_DEFINE(white, gap, braced, start);
}}

int
main()
{
  char const*           iter    = "? {;};", * const end = iter + std::strlen(iter);
  minimal::ast::start   ast;
  return !parse(iter, end, minimal::parser::start, ast) || iter!=end;
}
//}}}

我开始时没有 white 用于集体空白,而不是单个 char。 为了便于测试/演示,我包含了两个定义。

#define WITHOUT_WHITE           // All ok until white added.
//#define WITH_GAP_ITEM_IN_VARIANT  // Unnacceptable workaround

没有white,一切都很好。 当我添加white 通过评论//#define WITHOUT_WHITE 时,我收到错误消息,基本上是告诉我将chargap_item 添加到我的start_item 变体中。好的,现在代码编译并运行。但错误是 gap 被忽略/绕过,并且与 ast 中的间隙相关的操作(例如打印)没有执行。

谁能建议一种不同的方式来构建 AST 或语法,以使 X3 完成它应该做的事情?


****** 编辑 2021-05-31 ******

我找到了两种解决方法,它们一致可能可扩展到一个真实的 X3 完整应用程序(但我还没有将这些变通方法中的任何一个传播回 X3 应用程序——这将需要一些时间)。对于这个最小的示例,单独使用任何一种解决方法都可以,并且应用两者都可以。

  1. 用单个元素结构替换任何“无偿继承”的每个实例。这会导致生成单个元素元组,尽管这应该是受支持的,但可能存在潜伏错误的极端情况。
// Purpose: Working example using single element *** TUPLE *** consistently, instead of class inheritance

#define BOOST_SPIRIT_X3_DEBUG       // Provide some meaningful reassuring output.

#include <string>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

namespace x3        = boost::spirit::x3;

namespace ast {
  struct white                      {std::string            value;};    // *** TUPLE ***
  struct braced                     {char open; std::string text; char close;};
  struct gap_item   : x3::variant<white,braced> {using base_type::operator=;};
  struct gap                        {std::vector<gap_item>      value;};    // *** TUPLE ***
  struct start_item : x3::variant<gap,std::string>  {using base_type::operator=;};
  struct start                      {std::vector<start_item>    value;};    // *** TUPLE ***
}
BOOST_FUSION_ADAPT_STRUCT(ast::white,       value)                          // *** TUPLE ***
BOOST_FUSION_ADAPT_STRUCT(ast::gap,     value)                          // *** TUPLE ***
BOOST_FUSION_ADAPT_STRUCT(ast::start,       value)                          // *** TUPLE ***
BOOST_FUSION_ADAPT_STRUCT(ast::braced,      open, text, close)

namespace parser {
  using x3::char_; using x3::space; using x3::raw; using x3::graph;
  
  x3::rule<struct white,    ast::white> const   white       = "white";
  x3::rule<struct braced,   ast::braced>    const   braced      = "braced";
  x3::rule<struct gap,      ast::gap>   const   gap     = "gap";
  x3::rule<struct start,    ast::start> const   start       = "start";
  
  static auto const white_def       = raw[+space];
  static auto const braced_def      = char_('{') >> *~char_('}') >> char_('}'); // { ... }
  static auto const gap_def     = +(white | braced);                // spaces etc
  static auto const start_def       = +(gap | +(graph -'{'));           // gap or body
  
  BOOST_SPIRIT_DEFINE(white, braced, gap, start);
}

int main()
{
  char const*       iter    = "? {;};", * const end = iter + std::strlen(iter);
  ast::start        ast;
  return !parse(iter, end, parser::start, ast) || iter!=end;
}

  1. 对于存在变体容器的每种情况,在该变体的语法中添加一个额外的规则。
// Purpose: Working example when an *** EXTRA RULE *** (start_item) is used to break synthesized nested containers

#define BOOST_SPIRIT_X3_DEBUG       // Provide some meaningful reassuring output.

#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

namespace x3 = boost::spirit::x3;

namespace ast {
  struct white      : std::string           {using std::string::string;};
  struct braced                     {char open; std::string text; char close;};
  struct gap_item   : x3::variant<white,braced> {using base_type::operator=;};
  struct gap        : std::vector<gap_item>     {};
  struct start_item : x3::variant<gap,std::string>  {using base_type::operator=;};
  struct start      : std::vector<start_item>   {using std::vector<start_item>::vector;};
}
BOOST_FUSION_ADAPT_STRUCT(ast::braced, open, text, close)

namespace parser {
  using x3::char_; using x3::space; using x3::raw; using x3::graph;
  
  x3::rule<struct white,    ast::white>  const  white       = "white";
  x3::rule<struct braced,   ast::braced>     const  braced      = "braced";
  x3::rule<struct gap_item, ast::gap_item>   const  gap_item    = "gap_item";       // *** EXTRA RULE ***
  x3::rule<struct gap,      ast::gap>    const  gap     = "gap";
  x3::rule<struct start_item,   ast::start_item> const  start_item  = "start_item";     // *** EXTRA RULE ***
  x3::rule<struct start,    ast::start>  const  start       = "start";
  
  auto const white_def      = raw[+space];
  auto const braced_def     = char_('{') >> *~char_('}') >> char_('}'); // { ... }
  auto const gap_item_def   = white | braced;               // white etc    // *** EXTRA RULE ***
  auto const gap_def        = +gap_item;                    // spaces etc
  auto const start_item_def = gap | +(char_ - '{' - space);         // gap or body  // *** EXTRA RULE ***
  auto const start_def      = +start_item;                  // multiple gaps or bodies
  
  BOOST_SPIRIT_DEFINE(white, gap, braced, start_item, start);
}

int main() {
  char const*           iter    = "? {;};", * const end = iter + std::strlen(iter);
  ast::start            ast;
  return !parse(iter, end, parser::start, ast) || iter!=end;
}

更改分别用// *** TUPLE ***// *** EXTRA RULE *** 表示。

我个人更喜欢对 AST 的更改(它只是定义类的一种不同方式)而不是对解析器的更改(这会增加额外的混乱并破坏 X3 的精神 [双关语!])。

请各位专家帮助我和其他人确定哪个更好。

【问题讨论】:

  • 哇。我不会因为你没有在这个问题上付出足够的努力而责备你,但是......这不是最小的。它独立的,但它可能与最小化相反。

标签: c++ string boost-spirit


【解决方案1】:

我刚刚spent 100 minutes just making it compile in separate files as intended

让我来回答一些一般的抱怨:

我应该如何解释这种类型的错误信息?

借助您的工具(IDE 导航支持)通读它们。另见How do I grok boost spirit compiler errors

  1. 错误消息很大(有时比我的终端滚动缓冲区还大)并且无法辨认(对我而言)。

考虑使用camomilla 来帮助了解全局。

曾经有一个类似的东西(“STLFitler”之类的?)可能对 MSVC 仍然有用,尽管我不使用它。

对于这种情况,当 WITH_INSTANCED_STRING_WHITE 未定义时会出现问题。

好的,这立即告诉我您可能遇到了古老的“单元素融合序列”边缘情况,该情况从未完全解决:

探究原因

让我们取消定义WITH_INSTANCED_STRING_WHITE,然后

make |& camomilla -d0

这在我的系统上看起来像这样:

[ 33%] Building CXX object CMakeFiles/test.dir/rgw29_yacc_grammar.cpp.o
In file included from /home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/auxiliary/any_parser.hpp:17,
                 from /home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/auxiliary.hpp:11,
                 from /home/sehe/custom/boost_1_76_0/boost/spirit/home/x3.hpp:14,
                 from /home/sehe/Projects/stackoverflow/rgw29_yacc/rgw29_yacc.hpp:10,
                 from /home/sehe/Projects/stackoverflow/rgw29_yacc/rgw29_yacc_ast.hpp:2,
                 from /home/sehe/Projects/stackoverflow/rgw29_yacc/rgw29_yacc_grammar.hpp:2,
                 from /home/sehe/Projects/stackoverflow/rgw29_yacc/rgw29_yacc_grammar.cpp:1:
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/support/traits/move_to.hpp: In instantiation of ‘void boost::spirit::x3::traits::detail::move_to(Iterator, Iterator, Dest&, boost::spirit::x3::traits::container_attribute) [with Iterator = __gnu_cxx::__normal_iterator<?>; Dest = minimal::ast::defs]’:
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/support/traits/move_to.hpp:224:24:   required from ‘void boost::spirit::x3::traits::move_to(Iterator, Iterator, Dest&) [with Iterator = __gnu_cxx::__normal_iterator<?>; Dest = minimal::ast::defs]’
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/support/traits/move_to.hpp:88:28:   required from ‘typename boost::enable_if<?>::type boost::spirit::x3::traits::detail::move_to(Source&, Dest&, boost::spirit::x3::traits::container_attribute) [with Source = minimal::ast::gap; Dest = minimal::ast::defs; typename boost::enable_if<?>::type = void]’
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/support/traits/move_to.hpp:196:24:   required from ‘void boost::spirit::x3::traits::move_to(Source&&, Dest&) [with Source = minimal::ast::gap; Dest = minimal::ast::defs]’
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/nonterminal/detail/transform_attribute.hpp:30:28:   required from ‘static void boost::spirit::x3::default_transform_attribute<?>::post(Exposed&, Transformed&&) [with Exposed = minimal::ast::defs; Transformed = minimal::ast::gap]’
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/nonterminal/rule.hpp:156:32:   required from ‘bool boost::spirit::x3::rule<?>::parse(Iterator&, const Iterator&, const Context&, boost::spirit::x3::unused_type, Attribute_&) const [with Iterator = __gnu_cxx::__normal_iterator<?>; Context = boost::spirit::x3::context<?>; Attribute_ = minimal::ast::defs; ID = minimal::parser::gap_class; Attribute = minimal::ast::gap; bool force_attribute_ = false]’
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/operator/detail/alternative.hpp:189:20:   [ skipping 34 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/nonterminal/detail/rule.hpp:334:37:   required from ‘static bool boost::spirit::x3::detail::rule_parser<?>::call_rule_definition(const RHS&, const char*, Iterator&, const Iterator&, const Context&, ActualAttribute&, ExplicitAttrPropagation) [with RHS = boost::spirit::x3::no_skip_directive<?>; Iterator = __gnu_cxx::__normal_iterator<?>; Context = boost::spirit::x3::context<?>; ActualAttribute = minimal::ast::spec; ExplicitAttrPropagation = mpl_::bool_<?>; Attribute = minimal::ast::spec; ID = minimal::parser::start_class; bool skip_definition_injection = true]’
/home/sehe/Projects/stackoverflow/rgw29_yacc/rgw29_yacc_grammar.cpp:77:5:   required from ‘bool minimal::parser::parse_rule(boost::spirit::x3::detail::rule_id<?>, Iterator&, const Iterator&, const Context&, boost::spirit::x3::rule<?>::attribute_type&) [with Iterator = __gnu_cxx::__normal_iterator<?>; Context = boost::spirit::x3::context<?>; boost::spirit::x3::rule<?>::attribute_type = minimal::ast::spec]’
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/nonterminal/rule.hpp:155:27:   required from ‘bool boost::spirit::x3::rule<?>::parse(Iterator&, const Iterator&, const Context&, boost::spirit::x3::unused_type, Attribute_&) const [with Iterator = __gnu_cxx::__normal_iterator<?>; Context = boost::spirit::x3::context<?>; Attribute_ = minimal::ast::spec; ID = minimal::parser::start_class; Attribute = minimal::ast::spec; bool force_attribute_ = false]’
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/core/parse.hpp:119:36:   required from ‘bool boost::spirit::x3::phrase_parse_main(Iterator&, Iterator, const Parser&, const Skipper&, Attribute&, boost::spirit::x3::skip_flag) [with Iterator = __gnu_cxx::__normal_iterator<?>; Parser = boost::spirit::x3::rule<?>; Skipper = boost::spirit::x3::char_class<?>; Attribute = minimal::ast::spec]’
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/core/parse.hpp:136:33:   required from ‘bool boost::spirit::x3::phrase_parse(Iterator&, Iterator, const Parser&, const Skipper&, Attribute&, boost::spirit::x3::skip_flag) [with Iterator = __gnu_cxx::__normal_iterator<?>; Parser = boost::spirit::x3::rule<?>; Skipper = boost::spirit::x3::char_class<?>; Attribute = minimal::ast::spec]’
/home/sehe/Projects/stackoverflow/rgw29_yacc/rgw29_yacc_grammar.cpp:100:39:   required from here
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/support/traits/move_to.hpp:171:29: error: could not convert ‘first’ from ‘__gnu_cxx::__normal_iterator<?>’ to ‘vector<?>’
  171 |                 dest = Dest(first, last);
      |                             ^~~~~
      |                             |
      |                             __gnu_cxx::__normal_iterator<?>
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/support/traits/move_to.hpp: In instantiation of ‘void boost::spirit::x3::traits::detail::move_to(Iterator, Iterator, Dest&, boost::spirit::x3::traits::container_attribute) [with Iterator = __gnu_cxx::__normal_iterator<?>; Dest = minimal::ast::rule]’:
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/support/traits/move_to.hpp:224:24:   required from ‘void boost::spirit::x3::traits::move_to(Iterator, Iterator, Dest&) [with Iterator = __gnu_cxx::__normal_iterator<?>; Dest = minimal::ast::rule]’
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/support/traits/move_to.hpp:88:28:   required from ‘typename boost::enable_if<?>::type boost::spirit::x3::traits::detail::move_to(Source&, Dest&, boost::spirit::x3::traits::container_attribute) [with Source = minimal::ast::gap; Dest = minimal::ast::rule; typename boost::enable_if<?>::type = void]’
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/support/traits/move_to.hpp:196:24:   required from ‘void boost::spirit::x3::traits::move_to(Source&&, Dest&) [with Source = minimal::ast::gap; Dest = minimal::ast::rule]’
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/nonterminal/detail/transform_attribute.hpp:30:28:   required from ‘static void boost::spirit::x3::default_transform_attribute<?>::post(Exposed&, Transformed&&) [with Exposed = minimal::ast::rule; Transformed = minimal::ast::gap]’
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/nonterminal/rule.hpp:156:32:   required from ‘bool boost::spirit::x3::rule<?>::parse(Iterator&, const Iterator&, const Context&, boost::spirit::x3::unused_type, Attribute_&) const [with Iterator = __gnu_cxx::__normal_iterator<?>; Context = boost::spirit::x3::context<?>; Attribute_ = minimal::ast::rule; ID = minimal::parser::gap_class; Attribute = minimal::ast::gap; bool force_attribute_ = false]’
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/core/detail/parse_into_container.hpp:264:36:   [ skipping 41 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/nonterminal/detail/rule.hpp:334:37:   required from ‘static bool boost::spirit::x3::detail::rule_parser<?>::call_rule_definition(const RHS&, const char*, Iterator&, const Iterator&, const Context&, ActualAttribute&, ExplicitAttrPropagation) [with RHS = boost::spirit::x3::no_skip_directive<?>; Iterator = __gnu_cxx::__normal_iterator<?>; Context = boost::spirit::x3::context<?>; ActualAttribute = minimal::ast::spec; ExplicitAttrPropagation = mpl_::bool_<?>; Attribute = minimal::ast::spec; ID = minimal::parser::start_class; bool skip_definition_injection = true]’
/home/sehe/Projects/stackoverflow/rgw29_yacc/rgw29_yacc_grammar.cpp:77:5:   required from ‘bool minimal::parser::parse_rule(boost::spirit::x3::detail::rule_id<?>, Iterator&, const Iterator&, const Context&, boost::spirit::x3::rule<?>::attribute_type&) [with Iterator = __gnu_cxx::__normal_iterator<?>; Context = boost::spirit::x3::context<?>; boost::spirit::x3::rule<?>::attribute_type = minimal::ast::spec]’
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/nonterminal/rule.hpp:155:27:   required from ‘bool boost::spirit::x3::rule<?>::parse(Iterator&, const Iterator&, const Context&, boost::spirit::x3::unused_type, Attribute_&) const [with Iterator = __gnu_cxx::__normal_iterator<?>; Context = boost::spirit::x3::context<?>; Attribute_ = minimal::ast::spec; ID = minimal::parser::start_class; Attribute = minimal::ast::spec; bool force_attribute_ = false]’
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/core/parse.hpp:119:36:   required from ‘bool boost::spirit::x3::phrase_parse_main(Iterator&, Iterator, const Parser&, const Skipper&, Attribute&, boost::spirit::x3::skip_flag) [with Iterator = __gnu_cxx::__normal_iterator<?>; Parser = boost::spirit::x3::rule<?>; Skipper = boost::spirit::x3::char_class<?>; Attribute = minimal::ast::spec]’
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/core/parse.hpp:136:33:   required from ‘bool boost::spirit::x3::phrase_parse(Iterator&, Iterator, const Parser&, const Skipper&, Attribute&, boost::spirit::x3::skip_flag) [with Iterator = __gnu_cxx::__normal_iterator<?>; Parser = boost::spirit::x3::rule<?>; Skipper = boost::spirit::x3::char_class<?>; Attribute = minimal::ast::spec]’
/home/sehe/Projects/stackoverflow/rgw29_yacc/rgw29_yacc_grammar.cpp:100:39:   required from here
/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/support/traits/move_to.hpp:171:29: error: could not convert ‘first’ from ‘__gnu_cxx::__normal_iterator<?>’ to ‘vector<?>’
CMakeFiles/test.dir/build.make:95: recipe for target 'CMakeFiles/test.dir/rgw29_yacc_grammar.cpp.o' failed
make[2]: *** [CMakeFiles/test.dir/rgw29_yacc_grammar.cpp.o] Error 1
CMakeFiles/Makefile2:151: recipe for target 'CMakeFiles/test.dir/all' failed
make[1]: *** [CMakeFiles/test.dir/all] Error 2
Makefile:103: recipe for target 'all' failed
make: *** [all] Error 2

令人生畏,但远不及滚动缓冲区限制。让我们读一读。视觉上,第一个error:的那一行跳出来了:

/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/support/traits/move_to.hpp:171:29: error: could not convert ‘first’ from ‘__gnu_cxx::__normal_iterator&lt;?&gt;’ to ‘vector&lt;?&gt;’&lt;br/&gt;

  171 |               dest = Dest(first, last);
      |                             ^~~~~
      |                             |
      |                             __gnu_cxx::__normal_iterator<?>`

这很清楚。下一行告诉我们Dest = minimal::ast::rule。所以,这个构造函数是用迭代器调用的,而不是预期的东西。

凭直觉,我将using vector::vector; 添加到所有向量派生类型,并将using string::string; 添加到字符串派生类型:

  struct white : string {
      using string::string;
  };

现在我们得到

/home/sehe/custom/boost_1_76_0/boost/spirit/home/x3/support/ast/variant.hpp:151:39: error: no matching function for call to ‘boost::variant&lt;?&gt;::variant(minimal::ast::gap_item&amp;)’

此时我选择退出,因为我看到不少于 4 个不同的 x3::variant 派生 AST 节点,其中没有一个将 gap_item 作为元素类型。事实上,代码库中的任何内容都没有,除了

  struct gap : vector<gap_item> {
  };

这没有任何意义,除非gap 从未明确合成。但就是:

using gap_type = x3::rule<struct gap_class, ast::gap>;

我建议你从这里拿走。如果你减少到样本实际上最小,那么我可以再看一遍。

结束思考

在其他人开始之前:从std::vector/std::string 派生是一个有漏洞的抽象。类型不是为它设计的,隐式转换到基础混淆属性传播系统,正如您现在可能发现的那样。

【讨论】:

  • 您花了 100 分钟将我的示例重新构建为单独的文件,这让我感到震惊。对不起。 "//{{{ " cmets 旨在显示代码最初驻留在哪些文件中,而不是为了重构。我省略了很多结构,所以我可以看到这导致你做了大量工作来重新发明这些结构。我的示例旨在作为独立的单个可编译文件。我现在已经了解到,即使是这个例子也比它需要的要大得多。我未来的 MCVE 会小很多。
  • 1.我认识到不支持单元素元组。这很容易通过不使用来解决。 2.我认识到派生类/结构不继承可构造/可复制的方法,所以必须添加这些。 3. 理解来自大量模板库的错误消息是一个单独的问题,但感谢您的建议。
  • 100 分钟包括复习/阅读。出于这个原因,我把你的回购链接了。我有一些我没有推动的本地更改,因为它们没有带来改进。我很高兴您认识到样本比要求的要大得多。可能,它的大小也使您无法诊断根本原因,因为我可以告诉您,您在所需领域有足够的技能。
  • 1a。他们是,有时会有挥之不去的边缘情况。 1b。哎呀,游泳的方式不对。就像我说的那样,您很可能会导致系统因无根据的继承而出现故障。 3/ 干杯:)
  • 我不确定我是否已经实现了直到样本实际上最小化,但我已经把它变小了,并按照你的建议,谢谢,(虽然承认没有完全理解 leaky 抽象的含义)。通过上面的编辑添加。
猜你喜欢
  • 1970-01-01
  • 2021-06-06
  • 2023-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多