【问题标题】:Where to free memory in Bison/Flex?Bison/Flex 在哪里释放内存?
【发布时间】:2014-04-27 10:01:12
【问题描述】:

我使用 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 将不知道该值(如果我理解正确,我试过它不起作用)。我真的不知道如何解决这个泄漏问题。

【问题讨论】:

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


    【解决方案1】:

    简单的答案:视情况而定。您应该在使用完毕后释放内存,无论何时。

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

    【讨论】:

    • 我只给出了我的代码示例,实际上我有 50 多个模式,所以我将所有内容都视为 char*。这里的问题是我必须复制 yytext 的值,这会创建分配,但我不知道释放这个“yylval.str”(char * str)的内容或位置。我的意思是,通常我知道如何处理记忆,但“bison-flex”对我来说还是有点模糊。
    • 当您不再需要它时释放它。在您给出的示例中,您只需 free($1);如果这就是您要使用该值的全部内容,请在打印之后。
    • TOKEN_BLABLA 需要被释放吗?
    【解决方案2】:

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

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

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

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

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

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

    【讨论】:

    • 当您说数据结构时,您是在谈论“%union”吗?另外我尝试这样做:`TOKEN_DATE TOKEN_X TOKEN_Y { cout
    • @blackmesa 不,我的意思是一些数据结构,例如独立于语义类型的 AST(可能是树或图)。 free($$) 肯定是错误的,因为 $$ 在那个时候没有值。它只有在您分配它时才具有一个值(或者如果没有操作,在这种情况下@blackmesa:flex 插入默认操作$$ = $1。在您修改的规则中,您有三个char*s;如果您想要要释放它们(您这样做,因为您没有将它们保存在任何地方),您需要释放所有它们:free($1); free($2); free($3);
    • @blackmesa:试图解释内部发生了什么。我很确定野牛手册中的所有内容。
    【解决方案3】:

    来自 flex 手册:

    21.3 关于 yytext 和内存的说明

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

    因此 make_pair 不应该是以下吗?

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-03
      • 1970-01-01
      • 2013-03-09
      • 2020-04-15
      相关资源
      最近更新 更多