Bison 如何根据生产情况更改令牌的类型';s型?

Bison 如何根据生产情况更改令牌的类型';s型?,bison,yacc,lex,Bison,Yacc,Lex,我正在用Lex和Yacc开发一个小项目,我必须处理数学表达式 在我的文件syntax.y中,我有以下两种类型的产生式规则: %union { char* lexeme; double value; } %token <lexeme> NUM %type <lexeme> expr %type <value> comp_expr expr : expr "+" expr { $$ = strcat($1,"+")

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

在我的文件syntax.y中,我有以下两种类型的产生式规则:

%union {
   char* lexeme;            
   double value;
   }

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

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

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

提前感谢您的关注。

我建议您在需要将
NUM
转换为double时,将其转换为double。单元制作非常适合此类转换,您正好有一个:

comp_expr: NUM { $$ = strtod($1, NULL); }
您可以通过调用
strtod
进行更仔细的错误检查,但可以合理地假设词法扫描程序已经验证了词法位


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

expr  : expr "+" expr { $$ = strcat($1,"+"); $$ = strcat($$,$3); }
$1
大概是在词法扫描程序中调用
strdup
的返回值。在这种情况下,它的长度正好足以容纳词素,而不再是。因此,在末尾连接更多内容是缓冲区溢出;您将覆盖不属于您的内存。那会很快给你带来麻烦

您需要为
expr
分配一个正确长度的新字符串
asprintf
在这方面非常方便,并且比一系列的
strcat
s更具可读性


您可能还应该考虑在连接
strdup
ed词素之后,由于未使用
free
而导致的内存泄漏。

谢谢,第一个解决方案很好,第二个技巧非常有用。
expr  : expr "+" expr { $$ = strcat($1,"+"); $$ = strcat($$,$3); }