柠檬中令牌析构函数的自定义释放函数

Custom deallocation function for tokens destructor in Lemon

我希望 Lemon 解析一个简单的类 C 表达式,支持对一组具有已知名称的预定义变量进行整数和字符串比较。为简单起见,我们假设它仅支持 字符串比较。因此,以下字符串是我正在谈论的表达式种类的一个很好的例子:

a == "literal_1" || a == "literal_2"

因此,我的词法分析器必须按照以下顺序为解析器提供值:

void *p = parserAlloc(malloc);
parser(p, TOK_VARIABLE_A, NULL);
parser(p, TOK_OPERATOR_EQ, NULL);
parser(p, TOK_LITERAL, strdup("literal_1"));
parser(p, TOK_OPERATOR_OR, NULL);
parser(p, TOK_VARIABLE_A, NULL);
parser(p, TOK_OPERATOR_EQ, NULL);
parser(p, TOK_LITERAL, strdup("literal_2"));
parserFree(p, free);

我必须复制传递给解析器的文字字符串,因为它们可能包含我必须首先解码的转义序列。但是谁负责在解析完成后释放内存呢?幸运的是,柠檬用它的 %destructor 指令来拯救,所以我可以写:

%token_destructor TOK_LITERAL { free($$); }

但实际上,我不想在我的解析器和词法分析器中对 mallocstrdupfree 的用法进行硬编码。我希望能够将分配器和解除分配器函数作为参数传递,但不仅在 parserInitparserFree 中使用它们,而且还用于令牌分配和解除分配。

如何为 parserAlloc 声明附加参数以同时传递 mallocfree? Lemon 中有 %extra_argument 指令,但它让我在每次输入令牌时都传递我的参数。

parserAllocmalloc 参数没有存储在任何地方,因为 lemon 生成的解析器从不分配内存。 [注 1] 当然,free 函数也不会存储在任何地方,因为直到您调用 parserFree.

才会提供它

通常,您也不需要在解析器操作中使用 alloc 函数,但如果您使用 %destructor/%token-destructor,那么您将需要一个 free 函数。唯一记录在案的机制是额外参数功能,正如您所说,它需要在每次调用解析器时提供参数。这有点烦人,特别是因为解析器立即将它存储到解析器状态结构中(即 parse 的第一个参数),但事实就是这样。更改起来很容易,而且 Lemon 不受阻碍,因此您可以进行所需的更改。但是按照规定,%extra-argument是唯一的办法。

如果你在你的动作中同时需要 alloc 和 free 函数,不管出于什么原因,你可以让 %extra-argument 成为一个指向结构的指针(这实际上是 %extra-argument 的正常情况) ;该结构将包含指向这两个函数的指针。或者,您可以使用具有标准 realloc 接口的函数:realloc(NULL, sz) 等同于 malloc(sz)realloc(p, 0) 等同于 free(p)(只要 p 不为空)。有关详细信息,请参阅 man realloc。这不会打扰柠檬解析器,因为它从不使用 malloc 或 free。

备注

  1. 这不完全正确。据我所知,有一个未记录的功能:如果您设置 %stack-size 0,那么生成的解析器将在它溢出之前重新分配解析器堆栈,而不是抛出错误。在那种情况下,解析器使用标准库 realloc 来分配或重新分配堆栈,而不是提供给 parserAlloc 的 malloc 函数,并且 parserFree 使用标准库 [=12] 释放堆栈=], 而不是作为参数传递的函数。