错误发生的情况- Bison
What happens on error - Bison
想象一下这个语法:
declaration
: declaration_specifiers ';' { /* allocate AST Node and return (1) */}
| declaration_specifiers init_declarator_list ';' { /* allocate AST Node and return (2)*/}
;
init_declarator_list
: init_declarator { /* alloc AST Node and return (3) */}
| init_declarator_list ',' init_declarator { /* allocate AST Node and return (4) */}
;
现在假设在','标记中有错误。目前我们有:
declaration -> declaration_specifiers init_declarator_list -> init_declarator_list ',' /*error*/
这里发生了什么?
bison执行(4)代码吗?(2) ?如果bison没有执行(4)但是执行了(2)$3的值是多少?如何设置$variables的默认值?
如何正确删除错误生成的AST ?
bison
仅在动作产生减少时执行动作,这意味着它必须完全匹配输入,除非它是error
产生,在这种情况下使用宽松的匹配形式。(见下文)。因此,您可以确信,如果执行了某个操作,那么与其终端和非终端相关联的各种语义值是词法分析器或它们各自操作的结果。
%destructor
声明指定在丢弃值时执行的操作。(详见野牛手册)可以按类型或按符号指定析构函数(或两者都指定,但按符号指定的析构函数优先)
当bison
丢弃语义值时,%destructor
动作将运行。粗略地说,丢弃一个语义值意味着您的程序永远没有机会处理这个语义值。它不适用于减少时从堆栈中弹出的值,即使没有与减少相关的显式操作。关于"丢弃"的完整定义在前面引用的bison手册部分的末尾。
如果不产生错误,除了丢弃整个堆栈和任何forward符号(bison将自动执行),然后终止解析之外,实际上没有太多可能的错误恢复方式。您可以通过在语法中添加错误结果来做得更好。错误产生包括特殊令牌error
;在没有其他可能的匹配的情况下,这个标记精确地匹配一个空序列。与正常的结果不同,错误结果不需要立即可见;bison
将从堆栈中丢弃状态(和相应的值),直到它找到具有error
转换的状态,或者它到达堆栈的末尾。此外,在错误产生中,error
后面的终端不需要是前瞻令牌;bison
将丢弃前瞻标记(和相应的值),直到它能够继续产生错误(或者到达输入的末尾)。关于这个过程的更详细的描述,请参阅方便的手册(或者在Dragon的书中阅读,如果你附近有一本的话)。
这里有几个问题
Bison通过处于解析状态来检测错误,在这种状态下,对当前的forward令牌没有操作(shift或reduce)。在您的示例中,将在init_declarator_list
中移动' ,
'后处于状态。在这种状态下,只有FIRST(init_declarator)中的令牌是有效的,因此任何其他令牌都将导致错误。
bison代码中的Actions将在相应的规则缩减时执行,因此action(4)将永远不会被调用——它永远不会执行到缩减该规则的程度。操作(3)将在该规则减少时运行,这发生在它将,
转移到检测到错误的状态之前。
出现错误(并调用yerror并给出错误消息)后,解析器将尝试通过弹出堆栈状态来恢复,寻找可以移动特殊error
令牌的状态。当它弹出和丢弃状态时,它将调用%destructor
动作来处理与这些状态相对应的符号,因此如果需要,您可以使用它来清理东西(释放内存)。
在您的示例中,似乎没有错误规则,因此没有可以转移错误令牌的状态。所以它将弹出所有状态,然后从yyparse返回失败。如果它确实找到了可以转移错误的状态,它将停止弹出并转移错误令牌,并尝试在错误恢复模式下继续解析。在错误恢复模式下,它会计算自上次发生错误以来移动了多少令牌(除了错误令牌)。如果它在遇到另一个错误之前移动了少于3个令牌,它将不会为新错误调用yyerror。此外,如果它移动了0个标记,它将尝试通过读取和丢弃输入标记(而不是弹出状态)来从错误中恢复,直到找到一个可以由当前状态处理的标记。当它丢弃令牌时,它会为这些令牌调用%destructor
,因此您可以再次清理任何需要清理的内容。
所以回答你的最后一个问题,你可以使用%destructor
声明来删除错误发生时的东西。对于每个被丢弃的项目,%destructor
只被调用一次,而不被传递给bison操作。传递给动作的项(如$1
, $2
,…)在动作中)将永远不会有%destructor
调用它们,所以如果你在动作后不需要它们,你应该删除它们。
- 在没有太多条件句的情况下,我如何避免被零除
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 函数中堆分配的效果与缺少堆分配的情况
- 在未初始化映射的情况下,将值插入到映射的映射中
- 是默认情况下分配给char数组常量的值
- 为什么我不能在不创建字符串变量的情况下使用函数的字符串输出
- 如何在不产生任何垃圾的情况下获得C中的像素
- 在已经使用Git的情况下减少编译时间
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- 如何在没有信号的情况下从C++执行QML插槽
- 如何在不知道向量大小的情况下输入向量内部的向量?
- 如何针对特定情况调试和修复此双自由内存损坏问题
- 为什么在某些情况下不写入此文件?
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 在没有Xcode的情况下在Mac捆绑包中嵌入框架
- 有没有一种方法可以测量c++程序的运行时内存使用情况
- UE4-如何在给定4个屏幕坐标的情况下缩放纹理或材质
- 为什么这个音频包络不能通过开关的情况?
- 在没有全局或静态变量的情况下配置Bison和Flex
- 错误发生的情况- Bison