如何根据作品的类型更改标记的类型?

时间:2017-12-19 21:48:36

标签: 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,"+"); $$ = strcat($$,$3); }
      | NUM 
      ;

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

我使用“expr”将表达式作为字符串返回,并使用“comp_expr”将表达式作为计算表达式返回,在本例中为和。

基于syntax.y中的其他部分(我没有包含,因为这里不相关)我有一个系统可以正确识别何时使用“expr”以及何时使用“comp_expr”。

但是当我使用“comp_expr”时出现错误,因为Token NUM被声明为lexeme,因此是一个字符串,而制作“comp_expr”有一个值,因此是一个double类型。

如何为令牌NUM分配词汇和值?或者我如何根据我正在使用的生产来更改NUM的值?

此外,我还发布了我在文件lexic.l中保存NUM的方式:

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

提前感谢您的关注。

1 个答案:

答案 0 :(得分:1)

冒着说明问题的风险,我建议你将NUM转换为双倍时需要它。单元制作非常适合这种转换,而且您碰巧有一个方便的选择:

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

您可以通过调用strtod进行更仔细的错误检查,但可以合理地假设词法扫描程序已经验证了词法。

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

expr  : expr "+" expr { $$ = strcat($1,"+"); $$ = strcat($$,$3); }
据推测,

$1是词法扫描程序中strdup调用的返回值。在这种情况下,保持lexeme 并且不再的时间足够长。因此,最后连接更多的东西是缓冲区溢出;你将覆盖不属于你的记忆。这会让你很快陷入困境。

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

你可能还应该考虑在连接它们之后free strdup编辑词汇导致的内存泄漏。