无法弄清楚为什么yacc / bison语法不起作用

时间:2016-05-17 22:10:07

标签: bison yacc

这不是作业,虽然它来自一本书。

我给出了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.

有人帮帮我吗?我究竟做错了什么?

1 个答案:

答案 0 :(得分:3)

number : '1' { $$ = $1; }

这表示解析器可以将终端'1'(单个字符标记)减少为number,并且当它这样做时,它应该复制语义值。

非常好。但是&#39; 1&#39;的语义价值是什么?与任何其他令牌一样,它是yylvalyylex返回令牌类型时存储的值。例如,在原始代码中,yylex使用scanf("%d", &yylval)来设置NUMBER令牌的语义值。但在新代码中,yylex并不符合合同。它永远不会将yylval设置为任何内容,因此它返回的任何标记的语义值都是未定义的。 (只要解析器从不使用令牌的语义值,那就完全没问题。'+'也没有给出语义值,但解析器并不期待它。)

对于令牌'1',解析器确实不需要扫描程序的帮助:它清楚语义值应该是什么:

number : '1' { $$ = 1; }

或者,扫描仪可以提供帮助:

if (isdigit(c)) yylval = c - '0';
return c;