我正在使用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; }
提前感谢您的关注。
答案 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
编辑词汇导致的内存泄漏。