在哪里可以释放Bison / Flex中的内存?

时间:2014-03-20 13:48:16

标签: c++ memory-management bison flex-lexer strdup

我正在使用Bison&弯曲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中。然后我创建一个具有该内容的新对(实际上是键/值),然后我返回bison的令牌日期。 我的解析器.y不超过yyparse;当抓到东西时,它就会打印出来。

我尝试在此运行valgrind,我有关于strdup的多个错误。我知道这个函数使用malloc,但我不知道WHERE和WHEN使用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文件中写自由(yylval.str),否则,野牛不会意识到这个值(如果我理解正确的话,我试过它并不起作用)。我真的不知道如何消除这个泄漏的问题。

3 个答案:

答案 0 :(得分:5)

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

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

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

非终端也具有语义值,因为每个动作都将值存储到伪变量bison中。 (如果操作不执行此操作,则$$的值无法预测,但仍然存在。)操作完成后,bison将删除$$$1 ...值从堆栈顶部开始,然后将伪变量$2复制到堆栈顶部。它对弹出的值没有任何作用,因此如果它们需要被释放或以其他方式被破坏,动作必须自己执行此操作。

由于语义值是天真地复制的,因此语义类型不应包含任何不易复制的C ++对象。

如果使用$$声明,则语义类型%unionYYSTYPE对象,您需要告诉union哪个联合标记适用于每个终端,非末端。在这种情况下,bison和所有$$都会自动附加正确的$n,这些操作会更加类型安全。

答案 1 :(得分:2)

来自flex手册:

  

21.3关于yytext和记忆的注释

     

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

因此,不应该将make_pair作为以下内容吗?

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

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

答案 2 :(得分:1)

答案很简单:这取决于。无论何时,只要可能,你就应该释放内存。

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