为什么使用 yyclearin 不会在 bison 中触发 %destructor

Why does the use of yyclearin not trigger %destructor in bison

尽管有 %destructor 处理程序,但我在 bison 语法的错误恢复中遇到了内存泄漏。看来要看yyclearin的使用了。

这是语法的摘录:

%union {
    int val;
    const char* str; /* allocated in the lexer with strdup() */
}
%token <int> KEYWORD
%token <str> STR
%destructor { free($$); } <str>
...
%%
...
problem
    : KEYWORD KEYWORD STR {doSomething(); free(); }
    | KEYWORD ERROR       { yyclearin; yyerrok; someResync(); }
    ;

对于以下输入:

KEYWORD KEYWORD "string1"
KEYWORD "string2"

第一个输入行与第一个规则匹配,字符串被所属操作释放 'manually'。 第二个输入行被错误规则选中。作为前瞻读取的字符串 令牌触发错误并被 yyclearin 遗忘。但是 分配的内存仍然泄漏。需要做什么才能调用 %destructor?

这是一个很好的问题。

我本以为丢弃lookahead token会落入"when user actions cannot manage memory"的范畴。但是 yyclearin 所做的只是重置 yych,强制在下次需要前瞻时读取新令牌。

实际上,这意味着您的使用操作(调用 yyclearin)需要管理内存。通过稍微深入 bison 的内部结构,我们可以相当简单地做到这一点:

#define my_yyclearin \
      yydestruct ("Clearin: discarding", yytoken, &yylval); \
      yychar = YYEMPTY;

(如果您使用位置,则必须将 yylloc 添加到 yydestruct 调用中。)

yydestruct 是一个未记录的 bison 内部,如果启用了跟踪,它会调用正确的析构函数并打印出 teace 消息。 yytoken 是保存在 yychar 中的令牌值的内部版本(使用索引值的压缩范围来减少 table 大小)。 yycharyylval 变量已记录在案,因此使用它们应该是安全的。

这充其量只是一种粗略的解决方法。我已将此问题作为错误报告给野牛维护人员。