0

我希望 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);

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

%token_destructor TOK_LITERAL { free($$); }

但事实上,我不想在我的解析器和词法分析器中硬编码malloc,strdup和的用法。free我希望能够将分配器和释放器函数作为参数传递,但不仅在parserInitand中使用它们parserFree,而且还用于令牌分配和释放。

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

4

1 回答 1

1

to的malloc参数parserAlloc没有存储在任何地方,因为柠檬生成的解析器从不分配内存。[注 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不为 NULL)。详情请参阅man realloc。这不会打扰柠檬解析器,因为它从不使用 malloc 或 free。

笔记

  1. 这并不完全正确。据我所知,有一个未记录的功能:如果您设置%stack-size 0,则生成的解析器将在溢出之前重新分配解析器堆栈,而不是引发错误。在这种情况下,解析器使用标准库realloc分配或重新分配堆栈,而不是提供给的 malloc 函数parserAlloc,并parserFree使用标准库释放堆栈free,而不是作为参数传递的函数。
于 2016-04-02T05:52:01.587 回答