1

我将 Boost.Spirit.Lex 和 .Qi 用于一个简单的计算器项目,并且(像往常一样)它给我调试和使用带来了一些痛苦。调试打印:

<expression>
  <try>boost::spirit::multi_pass::illegal_backtracking

抛出此异常,我不明白为什么。我在我的代码中使用宏,给出一个最小的例子会很痛苦,所以我给出了整个项目。只需在根目录执行“make”,然后启动./sash,会出现提示,如果要测试只需执行“-echo $5-8”即可。

谷歌似乎没有发现任何关于这个异常的类似问题......

解析器在算术/中,解析器的调用在算术/求值器.cpp的末尾

任何帮助都非常感谢。

4

1 回答 1

3

您的代码正在破坏,因为 BOOST_SPIRIT_QI_DEBUG 以及on_error<>处理程序似乎在迭代器可能已失效后使用了迭代器。

老实说,我不完全确定这是怎么发生的。

背景

AFAICT lexertlspirit::multipass<>split_functor输入策略和split_std_deque存储策略[1]一起使用。

现在,(幸运的是?)检查策略buf_id_check意味着迭代器将在取消引用时检查无效。

如果出现以下情况,则迭代器预计会失效

  1. 迭代器被取消引用,将缓冲区增加到> 16个令牌,并且迭代器是唯一引用共享状态的迭代器。
  2. 或沿线的某个地方clear_queue被明确地调用(例如,来自flush_multi_path精神库中的原语)

老实说,我没有看到满足这两个条件中的任何一个。一个又快又脏

token_iterator_type clone = iter; // just to make it non-unique...

inevaluator.cpp没有区别(排除原因#1)

在制作的 valgrind 中临时禁用docheck实现buf_id_check_policy指出on_error<>和 BOOST_SPIRIT_DEBUG* 导致无效的内存引用。评论两者确实使所有问题都消失了(eval_expression现在有效)。

但是,这可能不是您的首选解决方案。

建议的解决方案

自从

  • 您正在处理一个固定的内存容器,表示您并不真正需要multi_pass行为仿真的输入
  • 您使用的是微不足道的语法,但您并没有真正从lexertl中受益——而您却获得了很多额外的复杂性(如您所见)

我很快重构了一些代码:https ://github.com/sehe/sash-refactor/commits/master

  • 提交 dec31496 4 个文件已更改,59 次插入(+),146 次删除(-)sanity - lets do without macros

  • 提交 6056574c 5 个文件更改,38 次插入(+),62 次删除(-)dead code, excess scope, excess instantiation

  • 提交 99d441db 9 个文件更改,25 次插入(+),177 次删除(-)remove lexer

现在,您会发现您的代码通常更简单,也更短,没有遇到 multi_pass 限制,您仍然可以拥有 SPIRIT_DEBUG 以及on_error处理 :) 最后

  • -g3 中的二进制大小从 16Mb 减少到 6.5Mb
  • 删除263行代码
  • 更重要的是,它有效

这是一些示例(没有调试输出):

$ ./sash <<< '-echo $8-9'
    -1
    Warning: Empty environment variable "8-9".
$ ./sash <<< '-echo $8\*9'
    72
    Warning: Empty environment variable "8*9".
$ ./sash <<< '-echo $8\*(9-1)'
    64
    Warning: Empty environment variable "8*(9-1)".
$ ./sash <<< '-echo $--+-+8\*(9-1)'
    -64
    Warning: Empty environment variable "--+-+8*(9-1)".

[1]尽管它的名字,它缓冲了以前看到的标记std::vector<>

于 2013-11-20T13:48:04.213 回答