如何根据产品类型更改令牌类型?

How can I change the type of a token basing on the production's type?

我正在使用 Lex 和 Yacc 开发一个小项目,我必须处理数学表达式。

在我的文件syntax.y中,我有这两种产生式规则:

%union {
   char* lexeme;            
   double value;
   }

%token <lexeme>  NUM
%type <lexeme> expr
%type <value> comp_expr

expr  : expr "+" expr { $$ = strcat(,"+"); $$ = strcat($$,); }
      | NUM 
      ;

comp_expr: comp_expr "+" comp_expr { $$ =  + ; }
         | NUM 
         ;

我使用 "expr" 以便 return 将表达式作为字符串,我使用 "comp_expr" 以便 return 将表达式作为计算表达式,在此算一笔账。

基于 syntax.y 中的其他部分(我没有包括在内,因为这里无关紧要)我有一个系统可以正确识别何时使用 "expr" 以及何时使用 "comp_expr".

但是当我使用 "comp_expr" 时出现错误,因为令牌 NUM 被声明为一个词位,因此是一个字符串,而产生式 "comp_expr" 有一个值,因此是一个双精度值,如类型。

如何将词位和值都分配给令牌 NUM?或者我如何根据我正在使用的生产更改 NUM 的值?

此外,我post还有我在文件中保存NUM的方式lexic.l:

{NUM}   { yylval.lexeme = strdup(yytext); return NUM; }

在此先感谢您的关注。

冒着陈述显而易见的风险,我建议您在需要时将 NUM 转换为双精度数。单元制作非常适合此类转换,而您恰好手头有一个:

comp_expr: NUM { $$ = strtod(, NULL); }

您可以通过调用 strtod 进行更仔细的错误检查,但假设词素已经被词法扫描器验证可能是合理的。


顺便说一句,有一个很大的问题:

expr  : expr "+" expr { $$ = strcat(,"+"); $$ = strcat($$,); }

</code> 大概是词法扫描器中调用 <code>strdup 的 return 值。在那种情况下,它正好足以容纳词位 而不再是 。所以在最后连接更多的东西是缓冲区溢出;您将覆盖不属于您的内存。那会让你很快陷入困境。

您需要为 expr 分配一个正确长度的新字符串; asprintf 对于这个目的来说非常方便,并且比一系列 strcat 更具可读性。

您可能还应该考虑在连接 strduped 词位后未 freeing 导致的内存泄漏。