2014-03-27 70 views
1

想象这个语法:的错误会发生什么 - 野牛

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_specifiers init_declarator_list - > init_declarator_list '' /*error*/

这里会发生什么?

野牛是否执行(4)代码?和(2)?如果野牛不执行(4),但它确实执行(2)什么是3美元的价值?我如何设置$变量的默认值?

我怎样才能删除错误产生我AST正常吗?

回答

1

这里有几个问题。

Bison通过处于分析状态来检测错误,其中当前先行令牌没有动作(移位或减少)。在你的例子中,在将','转换为init_declarator_list之后将处于该状态。在该状态下,只有FIRST(init_declarator)中的令牌才有效,因此任何其他令牌都会导致错误。

野牛代码中的动作会在相应的规则被减少时执行,所以动作(4)永远不会被调用 - 它永远不会足够减少该规则。当该规则减少时,动作(3)将运行,其发生在将,移至检测到错误的状态之前。

发生错误(并用错误消息调用yerror)后,解析器将尝试通过弹出堆栈状态进行恢复,以查找可以移动特殊error令牌的令牌。当它弹出并丢弃状态时,它会调用对应于这些状态的符号的%destructor操作,因此如果需要,可以使用它来清理事件(可用内存)。

就你而言,它看起来好像没有错误规则,所以没有可以移动错误标记的状态。所以它会弹出所有状态,然后从yyparse返回失败。如果它发现可以转移错误的状态,它将停止弹出并转移错误标记,并尝试在错误恢复模式下继续解析。在错误恢复模式下,它会统计自上次发生错误以来已移动了多少个令牌(除了错误令牌)。如果它在碰到另一个错误之前移动了少于3个标记,它将不会为新错误调用yyerror。另外,如果它已经移动了0个标记,它将通过读取并丢弃输入标记(而不是弹出状态)来尝试从错误中恢复,直到找到可以由当前状态处理的输入标记为止。当它丢弃令牌时,它会为这些令牌调用%destructor,因此您可以再次清理需要清理的任何内容。

所以要回答你最后一个问题,你可以使用%destructor声明来删除发生错误时的东西。 %destructor对于没有传递到野牛行动而被丢弃的每个物品,只会被调用一次。传递给动作的项目(如动作中的$1,$2 ......)将永远不会为其调用%destructor,因此如果在动作之后不需要它们,则应该在该处删除它们。

2

bison只在动作产量减少时执行一个动作,这意味着它必须与输入完全匹配,除非它是一个error生产,在这种情况下使用宽松的匹配表单。 (见下文)。因此可以放心的是,如果要执行的动作,然后与它的终端和非终端相关联的各种语义值是词法分析器或它们各自的动作的结果。

在错误恢复,然而,野牛将自动从堆栈丢弃语义值。使用合理的近期野牛版本,您可以指定在使用%destructor声明丢弃值时要执行的操作。 (见bison manual了解详情。)您可以按类型或符号指定析构函数(或两者兼而有之,但每个符号的析构函数优先。)

%destructor行动将运行时bison丢弃语义值。粗略地说,丢弃语义值意味着你的程序从来没有机会处理语义值。当生产下降,即使与减少关联没有明确的行动,而不适用于出栈值。 “放弃”的完整定义在前面引用的野牛手册章节的末尾。

没有错误产生,除了丢弃整个堆栈和任何先行符号(野牛会自动执行),然后终止解析,实际上没有太多可能的错误恢复方式。将错误生成添加到语法中,可以做得更好一些。错误生产包括特殊标记error;该标记在没有其他可能的匹配的情况下精确匹配空序列。与正常制作不同,错误制作不需要立即可见; bison将从栈丢弃状态(及对应的值),直到找到与error过渡的状态下,或它到达堆的端部。另外,在错误产生中,跟在error之后的终端不需要是预见标记; bison将放弃先行令牌(和相应的值),直到它能够继续产生错误(或到达输入的末尾)。请参阅handy manual以获取更详细的过程描述(或者如果附近有副本,请在龙书中阅读它)。