yacc:区分整数和浮点数
我应该编写一个程序来执行 2 + 2 = 4 和 2.2 + 2 = 4.2。
我已经这样做了,以便它将所有内容视为浮点,但这是“错误的”。我必须区分它们。到目前为止,我遇到的问题是:
%{
#include <stdio.h>
#include <ctype.h>
%}
%token <dval> FLOAT
%token <ival> INTEGER
%union
{
float dval;
int ival;
}
%type <dval> command exp term factor
%%
command : exp {printf("%f\n",$1);}
;
exp : exp '+' term {$$ = $1 + $3;}
| exp '-' term {$$ = $1 - $3;}
| term {$$ = $1;}
;
term : term '*' factor {$$ = $1 * $3;}
| factor {$$ = $1;}
;
factor : '(' exp ')' {$$ = $2;}
| FLOAT {$$ = $1;}
| INTEGER {$$ = $1;}
;
%%
int main()
{
return yyparse();
}
int yylex()
{
int c;
while( (c=getchar()) == ' ');
if( isdigit(c) )
{
ungetc(c, stdin);
float f1;
scanf("%f", &f1);
int i1 = (int) f1;
if(f1 == 0)
{
yylval.ival = 0;
return INTEGER;
}
else if( (((float) i1) / f1 ) == 1)
{
yylval.ival = i1;
return INTEGER;
}
else
{
yylval.dval = f1;
return FLOAT;
}
//scanf("%f",&yylval.dval);
//return(NUMBER);
}
if(c == '\n') return 0;
return c;
}
int yyerror(char *s)
{
fprintf(stderr,"%s\n",s);
return 0;
}
我遇到的问题是每个表达式只能有 1 种类型。现在一切基本上都是浮动的,所以虽然操作是正确的,但这不是正确的解决方案。
我想过定义更多的表达式,基本上有factor_int和factor_float,然后替换其中的所有内容,但这似乎是错误的。我不知道如何完成这项工作,而且我看过的教程并没有真正帮助我。
I'm supposed to write a program that does 2 + 2 = 4 and 2.2 + 2 = 4.2.
I've already done it so that it treats everything as a floating point, but that's "wrong". I have to distinguish them. Here's what I have so far:
%{
#include <stdio.h>
#include <ctype.h>
%}
%token <dval> FLOAT
%token <ival> INTEGER
%union
{
float dval;
int ival;
}
%type <dval> command exp term factor
%%
command : exp {printf("%f\n",$1);}
;
exp : exp '+' term {$ = $1 + $3;}
| exp '-' term {$ = $1 - $3;}
| term {$ = $1;}
;
term : term '*' factor {$ = $1 * $3;}
| factor {$ = $1;}
;
factor : '(' exp ')' {$ = $2;}
| FLOAT {$ = $1;}
| INTEGER {$ = $1;}
;
%%
int main()
{
return yyparse();
}
int yylex()
{
int c;
while( (c=getchar()) == ' ');
if( isdigit(c) )
{
ungetc(c, stdin);
float f1;
scanf("%f", &f1);
int i1 = (int) f1;
if(f1 == 0)
{
yylval.ival = 0;
return INTEGER;
}
else if( (((float) i1) / f1 ) == 1)
{
yylval.ival = i1;
return INTEGER;
}
else
{
yylval.dval = f1;
return FLOAT;
}
//scanf("%f",&yylval.dval);
//return(NUMBER);
}
if(c == '\n') return 0;
return c;
}
int yyerror(char *s)
{
fprintf(stderr,"%s\n",s);
return 0;
}
The problem I have is that each expression can only have 1 type. Right now everything is basically float, so while the operations are right, this isn't the right solution.
I thought about defining more expressions, basically having factor_int and factor_float, and then replacing everything in it, but that seems really wrong. I have no idea how to get this done though, and the tutorials I've seen haven't really helped me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
基本上你可以做这样的事情:
等等..
通过这种方式,你可以在减少规则时检查操作数,确保生成新的正确类型..例如:
PS。我用 Flex+Bison 做了类似的事情,我不知道 Lex+Yacc 是否支持所有内容,但我认为是的。
Basically you can do something like this:
and so on..
in this way you can check operands when reducing rules being sure to generate new correct types.. for example:
PS. I did something similar with Flex+Bison, I don't know if everything is supported as well as in Lex+Yacc but I think so..
对 yylval 结构/联合中的数据类型进行编码。
不要编写每个可能的组合,例如 + 运算符,而是在 yacc 中为 + 运算符仅定义 1 个规则,并在运行时检查数据类型(存储在 yylval 中)的有效性。
使用容器或数组来存储所有有效组合,并使用该容器在运行时检查有效性。如果您找不到有效的组合,您至少可以给出一个像样的运行时错误,例如“对不起,酋长,您无法添加日期和浮点数。”而不是语法错误(如果您在 yacc 中定义单独的规则,则会出现该错误)。
作为最后的锦上添花,添加“自动转换”逻辑。如果找不到有效的组合,请尝试将其中一个操作数转换为另一种类型。一种典型的硬编码转换是“int 到 float”。例如,如果您的容器仅允许添加 2 个整数或 2 个浮点数,并且用户输入 1+3.14(即整数 + 浮点数),则您将在容器中找不到有效的组合。将 int 转换为 float 并在容器中再次查看。如果转换次数不是那么大,应该足够快。
Encode the data type within your yylval struct/union.
Instead of writing every possible combination of e.g. the + operator, define only 1 rule for the + operator in yacc, and check the validity of the data types (stored in yylval) at run time.
Use a container or array to store all valid combinations, and use this container to check the validity at run time. If you don't find a valid combination, you can give at least a decent run time error like "Sorry Chief, you cannot add a date and a float." instead of syntax error (which you would get if you would define separate rules in yacc).
As the final icing on the cake, add 'automatic-conversion' logic. If you don't find a valid combination, try to convert one of the operands to another type. One such a typical hard-coded conversion is "int to float". E.g. if your container only allows adding 2 integers or 2 floats and the user enters 1+3.14 (which is integer + float), you will not find a valid combination in the container. Convert the int to float and look again in the container. If the number of conversions is not that big, it should be fast enough.
我认为@Jack给出的答案会起作用,但是将所有规则都基于浮点数的计算可能会更简洁,然后在最上面的规则(最后一个要评估的)上检查结果是否是整数或浮点数并打印适当的结果。
您的主要方法将简化为:
并且您的最重要的规则应更改为:
使用这种方法,您只需要一个令牌(数字而不是 FLOAT 和 INTEGER),并且还需要您再添加一个
%type
声明到你的源代码中来占算符。您的%union
语句将包含double val;
和char op;
。I think the answer @Jack gave will work, but it might be more concise to base all of your rules on the calculation of floats, then on the top most rule (the last to be evaluated) check to see if the result is an integer or a float and print the appropriate result.
Your main method would be reduced to:
and your top most rule should be changed to:
Using this approach you would only need one token (NUMBER instead of FLOAT and INTEGER) and it would also require you to add one more
%type
statement to your source code to account for operators. Your%union
statement would then containdouble val;
andchar op;
.