问题
PREFACE: I am asking this question because for some reason I can not get my code to compile. I just want to know whether an incorrect understanding of spirit::x3 is the cause or not
Hello, I'd just like to verify something; is the following the correct way (at least technically) of defining rules for a large set of heavily recursive parsers? So for each parser, I do the following operations:
// This is for reference only, it greatly simplifies the process of defining attributes.
template <class Tag, class... Bases> // the tag is for uniqueness
struct Access_base_s : Bases... {
using base = Access_base_s;
using Bases::Bases..., Bases::operator=...;
};
here's what I actually do for each parser:
struct attribute : Access_base_s<class attribute_tag, underlying_type /*eg. std::string*/> {
using base::base, base::operator=; // Access_base_s helps here
};
x3::rule<class rule_tag, attribute, true> rule_name = "rule_name";
auto rule_name_def = some_definition;
BOOST_SPIRIT_DEFINE(rule_name);
I have this all automated with macros so it actually looks more like this:
DECLARE_RULE(rulename1, "rulename1", rule1_attribute_type);
DECLARE_RULE(rulename2, "rulename2", rule2_attribute_type);
DECLARE_RULE(rulename3, "rulename3", rule3_attribute_type);
DEFINE_RULE(rulename1, rule1_definition);
DEFINE_RULE(rulename2, rule2_definition);
DEFINE_RULE(rulename3, rule3_definition);
I have organized the declarations and definitions of the different parser so that they're in two sections; they are all declared first and defined later when all of them are already declared. By declared I mean that their attribute struct is defined and that the rule is declared, and by defined I mean that the rule_name_def is implemented and BOOST_SPIRIT_DEFINE is called on the rule.
I have tried the latest versions of MSVC, G++, and clang++, and all of them:
- take at least 3 minutes
- encounter some internal compiler error with no proper error message
- abort and leave me with no executable
when I try to compile my code. I've been having this same issue for 2 days now, which is also why, sehe, if you're reading this, which you probably are, I haven't marked your answer to my last spirit question as the answer; I haven't had the opportunity to test it out while I've been too busy wrestling with the compiler.
EDIT: Here's the simplified code with the parsers that still causes the same error:
DECLARE_RULE(string_literal, "", std::string);
DECLARE_RULE(identifier , "", std::string);
struct list;
struct dictionary;
struct expression;
DECLARE_RULE(literal , "", x3::variant<double, int, string_literal, x3::forward_ast<list>, x3::forward_ast<dictionary>>);
DECLARE_RULE(parameter_pack, "", std::vector<expression>);
DECLARE_RULE(invocation , "", parameter_pack);
DECLARE_RULE(expression , "", x3::variant<literal, identifier, invocation>);
DECLARE_RULE(list , "", std::vector<expression>);
DECLARE_RULE(dictionary , "", std::vector<fusion::vector<expression, expression>>);
struct statement;
struct declaration;
DECLARE_RULE(compound_statement , "", std::vector<statement>);
DECLARE_RULE(control_block_body , "", x3::variant<x3::forward_ast<statement>, compound_statement>);
DECLARE_RULE(identifier_sequence , "", std::vector<identifier>);
DECLARE_RULE(function_definition , "", fusion::vector<identifier, std::vector<identifier>, control_block_body>);
DECLARE_RULE(structure_definition , "", fusion::vector<identifier, std::vector<declaration>>);
DECLARE_RULE(enumeration_definition, "", fusion::vector<identifier, std::vector<fusion::vector<identifier, int>>>);
DECLARE_RULE(namespace_scope , "", std::vector<declaration>);
DECLARE_RULE(namespace_extension , "", fusion::vector<identifier, namespace_scope>);
DECLARE_RULE(declaration , "", x3::variant<function_definition, structure_definition, enumeration_definition, namespace_extension>);
DECLARE_RULE(for_loop , "", fusion::vector<identifier, expression, control_block_body>);
DECLARE_RULE(while_loop , "", fusion::vector<expression, control_block_body>);
DECLARE_RULE(if_else_statement , "", fusion::vector<expression, control_block_body, control_block_body>);
DECLARE_RULE(switch_statement , "", fusion::vector<expression, std::vector<fusion::vector<expression, control_block_body>>>);
DECLARE_RULE(control_statement , "", x3::variant<for_loop, while_loop, if_else_statement, switch_statement>);
DECLARE_RULE(statement_terminator , "", std::string);
DECLARE_RULE(statement , "", fusion::vector<x3::variant<expression, declaration, control_statement>, statement_terminator>);
DEFINE_RULE(string_literal, x3::lexeme['"' > *x3::char_ > '"']); // just a placeholder
DEFINE_RULE(identifier , x3::lexeme[(x3::alpha | x3::char_('_')) >> *(x3::alnum | x3::char_('_'))]);
DEFINE_RULE(literal , x3::double_ | x3::int_ | string_literal_ | list_ | dictionary_)
DEFINE_RULE(parameter_pack, +expression_);
DEFINE_RULE(invocation , '(' > parameter_pack_ > ')');
DEFINE_RULE(expression , literal_ | identifier_ | invocation_);
DEFINE_RULE(list , '[' > *expression_ > ']');
DEFINE_RULE(dictionary , '{' > *(expression_ > ':' > expression_) > '}');
DEFINE_RULE(compound_statement, '{' > *statement_ > '}');
DEFINE_RULE(control_block_body, (':' > statement_) | compound_statement_);
DEFINE_RULE(identifier_sequence, +identifier_);
DEFINE_RULE(function_definition, x3::lit("") > '(' > identifier_ > *identifier_ > ')' > control_block_body_);
DEFINE_RULE(structure_definition, "" > identifier_ > namespace_scope_);
DEFINE_RULE(enumeration_definition, "" > identifier_ > '{' > *(identifier_ > '=' > x3::int_) > '}');
DEFINE_RULE(namespace_scope, '{' > *declaration_ > '}');
DEFINE_RULE(namespace_extension, "" > identifier_ > namespace_scope_);
DEFINE_RULE(declaration, function_definition_ | structure_definition_ | enumeration_definition_ | namespace_extension_);
DEFINE_RULE(for_loop, "" > identifier_ > "" > expression_ > control_block_body_);
DEFINE_RULE(while_loop, "" > expression_ > control_block_body_);
DEFINE_RULE(if_else_statement, "" > expression_ > control_block_body_ > "" > control_block_body_);
DEFINE_RULE(switch_statement, "" > expression_ > '{' > *("" > expression_ > control_block_body_) > '}');
DEFINE_RULE(control_statement, for_loop_ | while_loop_ | if_else_statement_ | switch_statement_);
DEFINE_RULE(statement_terminator, x3::string("") | x3::string("") | x3::string(""));
DEFINE_RULE(statement, (expression_ | declaration_ | control_statement_) > statement_terminator_);
where DECLARE_RULE
and DEFINE_RULE
are defined as follows:
class empty_t {};
#define DEFINE_ATTRIBUTE(name, ...) \
struct name : Access_base_s<class name ## _base_access_tag, std::conditional_t<!std::is_base_of_v<x3::position_tagged, __VA_ARGS__>, x3::position_tagged, empty_t>, __VA_ARGS__> { \
using base::base, base::operator=; \
} // the conditional is there to make sure each attribute inherits from position_tagged no more than once.
#define DECLARE_RULE(name, text, ...) \
DEFINE_ATTRIBUTE(name, __VA_ARGS__); \
x3::rule<class name ## _tag, name, true> name ## _ = text
#define DEFINE_RULE(name, definition) \
auto name ## __def = definition; \
BOOST_SPIRIT_DEFINE(name ## _)
I made the macros variadic to cheat a little bit; it allows me to pass in the templated types without having to worry about the preprocessor's idiocy. For example, x3::variant<std::string, int>
would count as 2 separate macro arguments, and __VA_ARGS__
fixes that. Wherever you see it it's always just the underlying type of the attribute. The macros result in the attribute type being the name itself, and the parser being that but with an underscore appended to it's end to conform with x3
stuff like x3::int_
.
Here's the driver code:
int main() {
std::string str = read_file("filename");
auto begin = std::begin(str), end = std::end(str);
std::cout << std::boolalpha << x3::phrase_parse(begin, end, statement_, x3::ascii::space);
}
Also, if you couldn't tell by the names, I'm trying to write a parser for a simple DSL. I could use something like YACC but I think it's fairly useful to be familiar with a general purpose parsing library such as spirit::x3 so I'm trying to get familiar with it by doing this.
来源:https://stackoverflow.com/questions/61800010/is-this-the-correct-way-of-defining-a-set-of-recursive-rules