Boost Qi解析器为何在文本结束前停止解析?
问题分析与解决方案
核心问题:term规则的文法定义错误
你当前的term规则采用备选分支(|)定义:
term = factor[_val = _1] | (factor[_val = _1] >> "&&" >> factor)[_val = _val && _1];
Boost Spirit的备选分支是按顺序尝试匹配的,第一个分支factor[_val = _1]会优先匹配成功(比如解析完$32后就满足条件),导致整个term规则直接结束,完全不会尝试后续的&& $33部分,这就是解析在&& $33处停止的原因。
修正方案
逻辑与(&&)是左结合的运算符,正确的文法应该用**重复匹配(Kleene星号)**来实现连续的&&表达式,修改term规则如下:
term = factor[_val = _1] >> *("&&" >> factor)[_val = _val && _1];
这个写法的逻辑是:
- 先匹配第一个
factor,将结果赋值给_val - 重复匹配
"&&" >> factor,每次匹配成功后,将当前_val与新的factor结果做逻辑与运算,更新_val - 重复0次时,就等价于单个
factor,自然覆盖了原规则的第一个分支
修正后的完整文法代码
template<typename iterator> struct composite : qi::grammar<iterator, bool()> { composite() : composite::base_type(start) { using qi::lit; using qi::_val; using qi::_1; using qi::long_; using ascii::char_; using phx::ref; using phx::val; stepid = long_[ref(longv) = _1, _val = _1]; // 优化stepref:直接传递stepid的结果给evaluate_step,避免依赖成员变量的时序问题 stepref = (lit("$") >> stepid)[phx::bind(&evaluate_step, _1, ref(boolv)), _val = ref(boolv)]; // 修正后的term规则 term = factor[_val = _1] >> *("&&" >> factor)[_val = _val && _1]; factor = stepref[_val = _1] | ("!" >> stepref)[_val = !_1]; start = term[_val = _1]; } qi::rule<iterator, long()> stepid; qi::rule<iterator, bool()> stepref; qi::rule<iterator, bool()> term; qi::rule<iterator, bool()> factor; qi::rule<iterator, bool()> start; long longv; bool boolv; };
额外建议
- 后续扩展支持
||和括号时,要遵循运算符优先级:括号 >!>&&>||,需要新增expr规则处理||,保持term处理&&,factor处理括号和!,比如:expr = term[_val = _1] >> *("||" >> term)[_val = _val || _1]; factor = stepref[_val = _1] | ("!" >> factor)[_val = !_1] | ("(" >> expr >> ")")[_val = _1]; start = expr[_val = _1]; - 成员变量
longv和boolv会在多次解析时被覆盖,建议将evaluate_step的结果直接绑定到_val,避免依赖全局/成员状态,比如:
这样可以去掉stepref = lit("$") >> long_[_val = phx::bind(&evaluate_step, _1)];longv和boolv两个成员变量,让文法更健壮。
内容的提问来源于stack exchange,提问作者luca paganotti
相关产品推荐
相关产品推荐

