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

时间:2016-04-02 00:21:31

标签: c parsing 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);

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

%token_destructor TOK_LITERAL { free($$); }

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

如何声明parserAlloc的其他参数同时传递mallocfree? Lemon中有%extra_argument指令,但每当我提供令牌时它都会传递我的参数。

1 个答案:

答案 0 :(得分:1)

malloc的{​​{1}}参数不会存储在任何地方,因为柠檬生成的解析器永远不会分配内存。 [注1]当然,parserAlloc函数也没有存储在任何地方,因为在你调用free之前不会提供它。

通常,您在解析器操作中也不需要alloc函数,但如果使用parserFree / %destructor,则需要%token-destructor函数。唯一记录的机制就是额外参数功能,正如您所说,它需要在每次调用解析器时提供参数。这有点烦人,特别是因为解析器立即将它存储到解析器状态结构(即free的第一个参数),但这就是它的方式。它很容易改变,柠檬是不受阻碍的,所以你可以进行你想要的改变。但是按照规定,parse是唯一的方法。

如果你的动作需要alloc和free函数,无论出于何种原因,你可以使%extra-argument成为结构的指针(这实际上是%extra-argument的正常情况); struct将包含指向这两个函数的指针。或者,您可以使用标准%extra-argument界面的函数:realloc相当于realloc(NULL, sz)malloc(sz)相当于realloc(p, 0)(只要{{{ 1}}不是NULL)。有关详细信息,请参阅free(p)。这不会打扰柠檬解析器,因为它从不使用malloc或free。

注释

  1. 这不是真的。有一个至今我知道的未记录的功能:如果你设置p,那么生成的解析器将在溢出之前重新分配解析器堆栈而不是抛出错误。在这种情况下,解析器使用标准库man realloc来分配或重新分配堆栈,而不是提供给%stack-size 0的malloc函数,realloc使用标准库{{1}释放堆栈不是作为参数传递的函数。