C++ Boost spirit需要永远解析表达式

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 |常数双 |常数×整数 |名字 |弦;

我是新来这里工作的,精神振奋

在阅读了大量关于boost Spirit的优秀文章后,我决定制作一个自己的解析器,并遇到了解析这样一个表达式的问题

1+(2+(3+(4+(5+(6+)(7+(8‘‘‘‘‘‘)’)

在运行时花费永远的时间。。让它更简单1+(2+(3))很好。看起来解析器的回溯是活动的。请给我一个提示,如何修改语法或行为,使之及时运行

这是语法中的位代码。我使用“iter_pos”跟踪位置

问候 马库斯

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表达式节点

  • 类似的处理,更直观的解释

也许很有趣:


此输入的thx。我尝试了您的示例,它的工作方式与预期的一样(而且很快)…无论如何,我无法将“Boost::Spirit:优化表达式解析器”中的解决方案用于我的语义操作。只是不知道如何将我的操作放入此示例中。。 所有其他链接都是一个很好的来源,我也理解幕后的想法,但似乎这仍然是一个解决更普遍的PEG语法和回溯问题的方法。那么有没有更普遍的方法来解决这个问题?例如,使用“>”操作符而不是“>>“以避免在某个时候出现回溯。到目前为止,我未能在示例中使用“>”运算符

在玩过链接上的其他信息后,我将规则改写为这一条,现在它工作得又好又快

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];