Boost.Spirit X3解析器‘no type named type’错误排查求助
Let's break down what's causing your compilation error and fix it step by step.
The Root Cause
Your error stems from how Spirit X3 handles attribute mapping for your custom ast::program struct. Here's the issue:
- Your
program_defrule uses a Kleene star (*) to parse zero or more statements (each being*char_ > ';'), which naturally produces astd::list<std::string>attribute. - But you've bound this rule to a
x3::ruletargetingast::program—a fusion-adapted struct containing astd::list<std::string>member, not a container itself. - X3 sees the outer
*and tries to treatast::programlike a directly fillable container (looking for avalue_typetrait), which it isn't—hence the error about missingvalue_typeinclient::ast::program.
The Fixes
We need to explicitly tell X3 how to map the parsed std::list<std::string> to your ast::program struct. Here are two clean ways to do this:
Option 1: Use x3::attr_cast to Bridge the Attribute Types
Modify your grammar definition to cast the parsed list into your AST struct:
namespace client { namespace grammar { x3::rule<class program, ast::program> const program("program"); // Explicitly cast the list<string> result to ast::program auto const program_def = x3::attr_cast<ast::program>(*((*char_) > ';')); BOOST_SPIRIT_DEFINE( program ); auto calculator = program; } using grammar::calculator; }
Option 2: Split Rules for Clarity
If you prefer more explicit separation, split the parsing into a rule for the statement list and another to wrap it into your AST:
namespace client { namespace grammar { // First, a rule that parses the list of statements (returns list<string>) x3::rule<class stmt_list, std::list<std::string>> const stmt_list("stmt_list"); auto const stmt_list_def = *((*char_) > ';'); BOOST_SPIRIT_DEFINE(stmt_list); // Then, a rule that wraps the list into your AST struct x3::rule<class program, ast::program> const program("program"); auto const program_def = x3::attr_cast<ast::program>(stmt_list); BOOST_SPIRIT_DEFINE(program); auto calculator = program; } using grammar::calculator; }
Bonus: Fix Statement Parsing to Preserve Spaces
Right now, your *char_ will skip spaces (because you're using phrase_parse with a space skipper), meaning input like hello world; test; will be parsed as helloworld and test instead of preserving the space. To fix this, wrap the character parser in x3::lexeme to disable the skipper for the statement content:
// Parse a single statement (preserves internal spaces) auto const stmt = x3::lexeme[*x3::char_]; // Update the statement list rule to use this auto const stmt_list_def = *(stmt > ';');
Why This Works
The x3::attr_cast tells X3 how to convert the attribute produced by the inner parser (std::list<std::string>) into your target ast::program type. Since you've already adapted the struct with BOOST_FUSION_ADAPT_STRUCT, X3 knows to assign the list to the stmts member automatically.
Modified Full Grammar Example
Putting it all together, your grammar would look like this:
namespace client { namespace grammar { x3::rule<class stmt_list, std::list<std::string>> const stmt_list("stmt_list"); auto const stmt = x3::lexeme[*x3::char_]; auto const stmt_list_def = *(stmt > ';'); BOOST_SPIRIT_DEFINE(stmt_list); x3::rule<class program, ast::program> const program("program"); auto const program_def = x3::attr_cast<ast::program>(stmt_list); BOOST_SPIRIT_DEFINE(program); auto calculator = program; } using grammar::calculator; }
内容的提问来源于stack exchange,提问作者rav

