5

我正在使用 Bison & Flex 或多或少 1 个月,所以如果我没有看到明显的东西,我很抱歉(但我认为不是)。

我有一个关于使用 Flex Bison 释放内存的问题。这是我的代码的样子:

 parser.l

 {DATE}      { yylval.str= strdup(yytext);
             pair<string,string> newpair = make_pair("DATE",yytext);
             myvector.push_back(newpair);
              return TOKEN_DATE ;}

这是我的 .l 文件的示例之一。我将 yytext 的值复制到 yylval.str 中。然后我使用该内容(实际上是键/值)创建一个新对,然后返回野牛的令牌日期。我的解析器 .y 不超过 yyparse;当有东西被捕捉到时,它就会打印出来。

我试图对此运行 valgrind,但我有多个关于 strdup 的错误。我知道这个函数使用 malloc,但我不知道何时何地使用 FREE。

我可能猜它在 .y 文件中,但在哪里?

 test:
      TOKEN_DATE                 { cout << $1 << endl; // here ? and what to free ?}

我真的不明白这一切,我真的很感激一个简单而清晰的解释。

提前致谢,


编辑:

我尝试了几件事,例如:

 test:
      TOKEN_DATE TOKEN_TOTO TOKEN_BLABLA { cout << $1 << endl; free($1); free($2);}
    | TOKEN_DATE test { cout << $1 << endl, free($1); }

好像编译执行不错,但是valgrind还是跟我说strdup函数中包含的malloc有问题。但是我不能在 flex 文件中写 free(yylval.str) ,否则,bison 将不知道该值(如果我理解正确,我试过它不起作用)。我真的不知道如何解决这个泄漏问题。

4

3 回答 3

6

一旦不再需要复制的字符串,就需要释放它。在您相当简单的情况下,您可以在打印出来后释放($1),但通常情况下,解析器将复制的字符串插入到某个数据结构中,在这种情况下,该数据结构成为 malloc 存储的所有者,并且对 free 的调用将在析构函数中执行。

它与任何其他资源管理问题并没有真正的不同。您需要始终清楚谁是已分配资源的所有者,因为所有者有责任在不再需要资源时释放该资源。

内部发生的事情是bison维护一堆语义值,每个语义值都有类型YYSTYPE(即“语义类型”),这也是yylval. 当令牌移入堆栈时,bison复制yylval到堆栈顶部。在执行与产生式对应的动作之前,将产生bison式中每个终结符和非终结符的语义值安排为$1,$2等。(这不是副本;各种$x符号被替换为对位置的引用在bison堆栈上。)

非终结符也有语义值,因为每个动作都将一个值存储到伪变量$$中。(如果动作不这样做, 的值$$是不可预测的,但它仍然存在。)动作完成后,bison 从堆栈顶部删除$1, $2... 值,然后将伪变量$$复制到栈顶。它不会对弹出的值做任何事情,所以如果它们需要被释放或以其他方式破坏,动作必须自己做。

因为语义值是天真地复制的,所以语义类型不应该包含任何不可复制的 C++ 对象。

如果你使用%union声明,那么语义类型YYSTYPE是一个union对象,你需要告诉bison哪个联合标签适用于每个终端和非终端。在这种情况下,$$所有这些都会自动附加$n正确.tag的内容,并且这些操作变得更加类型安全。

于 2014-03-20T14:23:43.597 回答
2

从弹性手册:

21.3 关于yytext和内存的注意事项

当 flex 找到匹配项时,yytext 指向输入缓冲区中匹配项的第一个字符。字符串本身是输入缓冲区的一部分,不会单独分配。yytext 的值将在下次调用 yylex() 时被覆盖。简而言之,yytext 的值仅在匹配规则的操作中有效。

因此 make_pair 不应该是以下吗?

pair<string,string> newpair = make_pair("DATE",yylval.str);

如果是这样,那么在清理内存对时应该释放字符串。

于 2015-03-18T10:48:05.603 回答
1

简单的答案:这取决于。您应该在使用完毕后释放内存,无论何时。

更有帮助的答案:尝试使用尽可能少的内存分配。如果你从来没有malloc任何记忆,你就永远不需要free任何记忆。在您给出的示例中,您在日期上进行模式匹配。通常,日期具有一定的格式并具有一定的长度上限;例如,格式 'yyyy/mm/dd' 有 10 个字符。如果您可以预料到这一点,您可以简单地将静态大小的字符数组放入 中,而不是创建一个新字符串来保存日期yylval,例如char date[10];.

于 2014-03-20T14:19:01.073 回答