也在 boost Spirit 邮件列表 http://boost.2283326.n4.nabble.com/Spirit-X3-Boost-1-59-Compilation-never-finishes-for-a-recursive-grammar-td4693813 上提出了问题。 html
我正在根据 RFC 创建一个 xpath2.0 解析器。它基本上是我正在从事的另一个项目的子项目。
在取得了一些初步的成功之后,我犯了一个错误,即编写了一堆语法规则和 AST,而不是在每个点都编译和测试它。在那之后,我基本上有一本小说要阅读的模板错误消息(实际上是我的错)。
下面我介绍了 xpath 的简化语法(不是特别按照 RFC),它没有完成编译,或者当我的 mac 在大约 7 分钟后开始变慢时我不得不停止这个过程。
#include <iostream>
#include <string>
#include <vector>
#include <boost/optional.hpp>
#include <boost/optional/optional_io.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
namespace x3 = boost::spirit::x3;
namespace ast {
struct or_expression;
struct function_call;
template <typename T>
struct operation_sequence_entry
{
std::string op;
T expr;
};
struct primary_expression: x3::variant<
std::string,
x3::forward_ast<or_expression>,
std::string,
int32_t,
uint32_t,
double,
x3::forward_ast<function_call>
>
{
using base_type::base_type;
using base_type::operator=;
};
struct filter_expression
{
primary_expression prim_expr;
std::vector<x3::forward_ast<or_expression>> predicates;
};
struct path_expression: x3::variant<
boost::optional<filter_expression>,
boost::optional<primary_expression>
>
{
using base_type::base_type;
using base_type::operator=;
};
using union_expression = std::vector<path_expression>;
struct unary_expression
{
union_expression expr;
};
struct eq_expression
{
using expr_seq_type = operation_sequence_entry<unary_expression>;
unary_expression lhs_expr;
std::vector<expr_seq_type> rhs_expr;
};
struct and_expression
{
using expr_seq_type = operation_sequence_entry<eq_expression>;
eq_expression lhs_expr;
std::vector<expr_seq_type> rhs_expr;
};
struct or_expression
{
using expr_seq_type = operation_sequence_entry<and_expression>;
and_expression lhs_expr;
std::vector<expr_seq_type> rhs_expr;
};
struct function_call
{
std::string func_name;
std::vector<or_expression> args;
};
}
BOOST_FUSION_ADAPT_TPL_STRUCT(
(T),
(ast::operation_sequence_entry)(T),
(std::string, op),
(T, expr)
);
BOOST_FUSION_ADAPT_STRUCT(
ast::unary_expression,
(ast::union_expression, expr)
);
BOOST_FUSION_ADAPT_STRUCT(
ast::eq_expression,
(ast::unary_expression, lhs_expr),
(std::vector<typename ast::eq_expression::expr_seq_type>, rhs_expr)
);
BOOST_FUSION_ADAPT_STRUCT(
ast::and_expression,
(ast::eq_expression, lhs_expr),
(std::vector<typename ast::and_expression::expr_seq_type>, rhs_expr)
);
BOOST_FUSION_ADAPT_STRUCT(
ast::or_expression,
(ast::and_expression, lhs_expr),
(std::vector<typename ast::or_expression::expr_seq_type>, rhs_expr)
);
BOOST_FUSION_ADAPT_STRUCT(
ast::function_call,
(std::string, func_name),
(std::vector<ast::or_expression>, args)
);
BOOST_FUSION_ADAPT_STRUCT(
ast::filter_expression,
(ast::primary_expression, prim_expr),
(std::vector<x3::forward_ast<ast::or_expression>>, predicates)
);
namespace grammar {
// Bring in the spirit parsers
using x3::lexeme;
using x3::alpha;
using x3::alnum;
using x3::ascii::char_;
using x3::ascii::string;
using x3::lit;
using x3::ascii::digit;
using x3::int_;
using x3::uint_;
using x3::double_;
template<typename T>
auto as = [](auto p) { return x3::rule<struct _, T>{} = as_parser(p); };
auto str_ = [](const char* lit) { return x3::string(lit); };
x3::rule<class path_expr, ast::path_expression> path_expr = "path-expr";
auto ncname = x3::rule<class ncname, std::string>{"ncname"}
= x3::lexeme[+(char_ - ':')]
;
auto qname = x3::rule<class qname, std::string>{"qname"}
= as<std::string>(ncname >> char_(':') >> ncname)
| as<std::string>(ncname)
;
auto union_expr = x3::rule<class union_expr, ast::union_expression>{"union-expr"}
= path_expr % '/'
;
auto unary_expr = x3::rule<class unary_expr, ast::unary_expression>{"unary-expr"}
= -x3::lit('-') >> union_expr
;
auto equality_expr = x3::rule<class eq_expr, ast::eq_expression>{"equality-expr"}
= unary_expr
>> *(as<ast::operation_sequence_entry<ast::unary_expression>>
( (str_("=") | str_("!=")) > unary_expr )
)
;
auto and_expr = x3::rule<class and_expr, ast::and_expression>{"and-expr"}
= equality_expr
>> *(as<ast::operation_sequence_entry<ast::eq_expression>>
( str_("and") > equality_expr )
)
;
auto or_expr = x3::rule<class or_expr, ast::or_expression>{"or-expr"}
= and_expr
>> *(as<ast::operation_sequence_entry<ast::and_expression>>
( str_("or") >> and_expr )
)
;
auto function_name = as<std::string>(qname);
auto function_arg = or_expr;
auto function_call = x3::rule<class func_call, ast::function_call>{"func-call"}
= function_name > '(' > (or_expr % ',') > ')'
;
auto prim_expr = x3::rule<class prim_expr, ast::primary_expression>{"prim-expr"}
= ('$' > qname)
| ('"' > *(char_ - '"') > '"')
| ('(' > or_expr > ')')
| (int_ | uint_ | double_)
| function_call
;
auto predicate = '[' > or_expr > ']';
auto filter_expr = x3::rule<class filter_expr, ast::filter_expression>{"filter-expr"}
= prim_expr >> *(predicate)
;
auto path_expr_def = -(filter_expr) >> -(lit("/") | lit("//")) >> -(prim_expr);
BOOST_SPIRIT_DEFINE (path_expr);
}
int main() {
using x3::space;
using grammar::or_expr;
ast::or_expression oexpr;
std::string input = "$ab/$cd or $ef";
bool res = phrase_parse(input.begin(),
input.end(),
or_expr,
space,
oexpr);
if (!res) {
std::cout << "Parsing failed miserably!\n";
return 1;
}
return 0;
}
编译为
g++ -std=c++14 -ftemplate-depth=1024 -o rec_ex rec_ex.cc
编译器:Clang 3.8
增强版:1.59
基于较低模板深度的模板错误实例化,我很确定某处深度递归正在进行。无论如何要优化上述语法以免引起这个问题?
谢谢。