这不是作业,虽然它来自一本书。
我给出了yacc / bison规范文件。任务是添加新的生产
number -> number digit
digit -> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
计算数字的值并取消NUMBER
令牌。语法如下。
%{
#include <stdio.h>
#include <ctype.h>
int yylex();
int yyerror();
%}
%token NUMBER
%%
command : exp { printf("%d\n", $1); }
; /* allows printing of the result */
exp : exp '+' term { $$ = $1 + $3; }
| exp '-' term { $$ = $1 - $3; }
| term { $$ = $1; }
;
term : term '*' factor { $$ = $1 * $3; }
| factor { $$ = $1; }
;
factor : NUMBER { $$ = $1; }
| '(' exp ')' { $$ = $2; }
;
%%
int main() {
return yyparse();
}
int yylex() {
int c;
while((c = getchar()) == ' ');
/* eliminate blanks*/
if (isdigit(c)) {
ungetc(c, stdin);
scanf("%d", &yylval);
return (NUMBER);
}
if (c == '\n') return 0;
/* makes the parse stop */
return (c);
}
int yyerror(char * s) {
fprintf(stderr, "%s\n", s);
return 0;
} /* allows for printing of an error message */
作为确保我正确完成所有操作的实验,我删除了数字标记,添加了以下产品:
number : '1' {$$ = $1;}
将factor
制作更改为
factor : number {$$ = $1;}
并取消
if (isdigit(c)) {
ungetc(c, stdin);
scanf("%d", &yylval);
return (NUMBER);
}
来自yylex()
函数的。换句话说,spec文件如下所示:
%{
#include <stdio.h>
#include <ctype.h>
int yylex();
int yyerror();
%}
%%
command : exp { printf("%d\n", $1); }
; /* allows printing of the result */
exp : exp '+' term { $$ = $1 + $3; }
| exp '-' term { $$ = $1 - $3; }
| term { $$ = $1; }
;
term : term '*' factor { $$ = $1 * $3; }
| factor { $$ = $1; }
;
factor : number { $$ = $1; }
| '(' exp ')' { $$ = $2; }
;
number : '1' { $$ = $1; }
;
%%
int main() {
return yyparse();
}
int yylex() {
int c;
while((c = getchar()) == ' ');
/* eliminate blanks*/
if (c == '\n') return 0;
/* makes the parse stop */
return (c);
}
int yyerror(char * s) {
fprintf(stderr, "%s\n", s);
return 0;
} /* allows for printing of an error message */
然而,在我运行以下表达式的代码后:1 + 1,我得到的答案为0.
有人帮帮我吗?我究竟做错了什么?答案 0 :(得分:3)
number : '1' { $$ = $1; }
这表示解析器可以将终端'1'
(单个字符标记)减少为number
,并且当它这样做时,它应该复制语义值。
非常好。但是&#39; 1
&#39;的语义价值是什么?与任何其他令牌一样,它是yylval
在yylex
返回令牌类型时存储的值。例如,在原始代码中,yylex
使用scanf("%d", &yylval)
来设置NUMBER
令牌的语义值。但在新代码中,yylex
并不符合合同。它永远不会将yylval
设置为任何内容,因此它返回的任何标记的语义值都是未定义的。 (只要解析器从不使用令牌的语义值,那就完全没问题。'+'
也没有给出语义值,但解析器并不期待它。)
对于令牌'1'
,解析器确实不需要扫描程序的帮助:它清楚语义值应该是什么:
number : '1' { $$ = 1; }
或者,扫描仪可以提供帮助:
if (isdigit(c)) yylval = c - '0';
return c;