C++ Boost spirit需要永远解析表达式
我是新来这里工作的,精神振奋 在阅读了大量关于boost Spirit的优秀文章后,我决定制作一个自己的解析器,并遇到了解析这样一个表达式的问题 1+(2+(3+(4+(5+(6+)(7+(8‘‘‘‘‘‘)’) 在运行时花费永远的时间。。让它更简单1+(2+(3))很好。看起来解析器的回溯是活动的。请给我一个提示,如何修改语法或行为,使之及时运行 这是语法中的位代码。我使用“iter_pos”跟踪位置 问候 马库斯C++ Boost spirit需要永远解析表达式,c++,boost,runtime,expression,boost-spirit,C++,Boost,Runtime,Expression,Boost Spirit,我是新来这里工作的,精神振奋 在阅读了大量关于boost Spirit的优秀文章后,我决定制作一个自己的解析器,并遇到了解析这样一个表达式的问题 1+(2+(3+(4+(5+(6+)(7+(8‘‘‘‘‘‘)’) 在运行时花费永远的时间。。让它更简单1+(2+(3))很好。看起来解析器的回溯是活动的。请给我一个提示,如何修改语法或行为,使之及时运行 这是语法中的位代码。我使用“iter_pos”跟踪位置 问候 马库斯 primary=functioncall |常数双 |常数×整数 |名字 |弦;
primary=functioncall
|常数双
|常数×整数
|名字
|弦;
常量double=real_解析器()[_val=construct(type_const_double,key_value,_1)];
name=name\u pure\u location[\u val=construct(type\u name,phoenix::bind(&getLocation,_1),key\u value,phoenix::bind(&getString,_1));
字符串=(lexeme[L''>>+(boost::spirit::standard_-wide::char''>>L'])[\u val=construct(type_const_string,key_value,phoenix::bind(&makeString,_1));
常量(整型=int)[u val=construct(类型(const)int,键值,construct(_1))];
附加的=
lit(“(”)>>表达式>>lit(“)”)
|初级的;
一元=
(国际热核实验堆位置>>一元空间>>一元空间>>国际热核实验堆位置)[u val=construct](
键入\命令\成员\调用,
位置(_1,_4),
键调用名,构造(_2),
此键,构造(_3)
)]
|插入的
;
乘法=
(国际热核实验堆>>一元>>(乘法运算、除法运算、模运算)>>乘法运算>>国际热核实验堆][u val=construct(
键入\命令\成员\调用,
位置(_1,_5),
键调用名,构造(_3),
键_this,construct(_2),
键参数,构造(_4)
)]
|一元[_val=_1];
添加剂=
(iter\u pos>>乘法>>(加法减去法)>>加法>>iter\u pos)[\u val=construct(
键入\命令\成员\调用,
位置(_1,_5),
键调用名,构造(_3),
键_this,construct(_2),
键参数,构造(_4)
)]
|乘法的
;
比较=
(国际热核实验堆位置>>添加剂>>(比较操作)>>比较>>国际热核实验堆位置[\u val=construct(
键入\命令\成员\调用,
位置(_1,_5),
键调用名,构造(_3),
键_this,construct(_2),
键参数,构造(_4)
)]
|加法[_val=_1]
;
表达式=比较[_val=_1];
您正确地确定了问题的根源:规则是“惰性地”指定的(因为它们——正如它们应该的那样——描述性地给出了规则的结果)
正如您所看到的,在PEG语法中,如果存在大量回溯,这将很快导致糟糕的性能
我已经展示了非常相似的表达式的优化。总结如下:与其“期望”一个二进制表达式,如果结果不满足则进行回溯,不如“贪婪地”解析第一个操作数,并根据下面的内容组成不同的AST表达式节点
- 类似的处理,更直观的解释
primary = functioncall | constant_double | constant_integer | name | string;
constant_double = real_parser<double, strict_ureal_policies<double>>()
[_val = construct<common_node>(type_const_double, key_value, _1)];
name = name_pure_location[_val = construct<common_node>(
type_name, phoenix::bind(&getLocation, _1),
key_value, phoenix::bind(&getString, _1))];
string = (lexeme[L'"' >> +(boost::spirit::standard_wide::char_ - L'"') >> L'"'])
[_val = construct<common_node>(type_const_string, key_value,
phoenix::bind(&makeString, _1))];
constant_integer = int_[_val = construct<common_node>(type_const_int, key_value,
construct<int>(_1))];
parenthetical = lit('(') >> expression >> lit(')') | primary;
// this define is used to make to code more readable ..
#define EXPR_ACTION(NAME) \
[_val = construct<common_node>(type_cmd_member_call, LOCATION(_1, _3), \
key_callname, construct<std::wstring>(NAME), \
key_this, construct<common_node>(_val), \
key_parameter, construct<common_node>(_2))]
unary = (iter_pos >> unary_op >> unary >>
iter_pos)[_val = construct<common_node>(
type_cmd_member_call, LOCATION(_1, _4), key_callname,
construct<std::wstring>(_2), key_this,
construct<common_node>(_3))]
| parenthetical[_val = _1];
multiplicative = unary[_val = _1] >>
*(iter_pos >> lit('*') >> unary >> iter_pos) EXPR_ACTION(L"_mul") >>
*(iter_pos >> lit('/') >> unary >> iter_pos) EXPR_ACTION(L"_div");
additive = multiplicative[_val = _1] >>
*(iter_pos >> lit('-') >> multiplicative >> iter_pos) EXPR_ACTION(L"_sub") >>
*(iter_pos >> lit('+') >> multiplicative >> iter_pos) EXPR_ACTION(L"_add");
compares =
additive[_val = _1] >>
*(iter_pos >> lit('<') >> additive >> iter_pos) EXPR_ACTION(L"_cmp_low") >>
*(iter_pos >> lit('>') >> additive >> iter_pos) EXPR_ACTION(L"_cmp_gre") >>
*(iter_pos >> lit('=') >> additive >> iter_pos) EXPR_ACTION(L"_cmp_equ");
logical = compares[_val = _1] >>
*(iter_pos >> nocaselit(L"and") >> compares >> iter_pos) EXPR_ACTION(L"_and") >>
*(iter_pos >> nocaselit(L"or") >> compares >> iter_pos) EXPR_ACTION(L"_or");
expression = logical[_val = _1];
primary=functio
primary = functioncall | constant_double | constant_integer | name | string;
constant_double = real_parser<double, strict_ureal_policies<double>>()
[_val = construct<common_node>(type_const_double, key_value, _1)];
name = name_pure_location[_val = construct<common_node>(
type_name, phoenix::bind(&getLocation, _1),
key_value, phoenix::bind(&getString, _1))];
string = (lexeme[L'"' >> +(boost::spirit::standard_wide::char_ - L'"') >> L'"'])
[_val = construct<common_node>(type_const_string, key_value,
phoenix::bind(&makeString, _1))];
constant_integer = int_[_val = construct<common_node>(type_const_int, key_value,
construct<int>(_1))];
parenthetical = lit('(') >> expression >> lit(')') | primary;
// this define is used to make to code more readable ..
#define EXPR_ACTION(NAME) \
[_val = construct<common_node>(type_cmd_member_call, LOCATION(_1, _3), \
key_callname, construct<std::wstring>(NAME), \
key_this, construct<common_node>(_val), \
key_parameter, construct<common_node>(_2))]
unary = (iter_pos >> unary_op >> unary >>
iter_pos)[_val = construct<common_node>(
type_cmd_member_call, LOCATION(_1, _4), key_callname,
construct<std::wstring>(_2), key_this,
construct<common_node>(_3))]
| parenthetical[_val = _1];
multiplicative = unary[_val = _1] >>
*(iter_pos >> lit('*') >> unary >> iter_pos) EXPR_ACTION(L"_mul") >>
*(iter_pos >> lit('/') >> unary >> iter_pos) EXPR_ACTION(L"_div");
additive = multiplicative[_val = _1] >>
*(iter_pos >> lit('-') >> multiplicative >> iter_pos) EXPR_ACTION(L"_sub") >>
*(iter_pos >> lit('+') >> multiplicative >> iter_pos) EXPR_ACTION(L"_add");
compares =
additive[_val = _1] >>
*(iter_pos >> lit('<') >> additive >> iter_pos) EXPR_ACTION(L"_cmp_low") >>
*(iter_pos >> lit('>') >> additive >> iter_pos) EXPR_ACTION(L"_cmp_gre") >>
*(iter_pos >> lit('=') >> additive >> iter_pos) EXPR_ACTION(L"_cmp_equ");
logical = compares[_val = _1] >>
*(iter_pos >> nocaselit(L"and") >> compares >> iter_pos) EXPR_ACTION(L"_and") >>
*(iter_pos >> nocaselit(L"or") >> compares >> iter_pos) EXPR_ACTION(L"_or");
expression = logical[_val = _1];