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

can't figure out why yacc/bison grammar doesn't work

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

我得到了一个 yacc/bison 规范文件。任务是添加一个新的production

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", ); }
        ; /* allows printing of the result */

exp : exp '+' term { $$ =  + ; }
    | exp '-' term { $$ =  - ; }
    | term { $$ = ; }
    ;

term : term '*' factor { $$ =  * ; }
     | factor { $$ = ; }
     ;

factor : NUMBER { $$ = ; }
       | '(' exp ')' { $$ = ; }
       ;

%%

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' {$$ = ;}

factor 生产更改为

factor : number {$$ = ;}

并被淘汰

if (isdigit(c)) {
  ungetc(c, stdin);
  scanf("%d", &yylval);
  return (NUMBER);
}

来自 yylex() 函数。换句话说,规范文件如下所示:

%{
#include <stdio.h>
#include <ctype.h>

int yylex();
int yyerror();
%}


%%

command : exp { printf("%d\n", ); }
        ; /* allows printing of the result */

exp : exp '+' term { $$ =  + ; }
    | exp '-' term { $$ =  - ; }
    | term { $$ = ; }
    ;

term : term '*' factor { $$ =  * ; }
     | factor { $$ = ; }
     ;

factor : number { $$ = ; }
       | '(' exp ')' { $$ = ; }
       ;

number : '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 的答案。

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

number : '1' { $$ = ; }

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

很好。但是'1'的语义值是什么?与任何其他令牌一样,当它 returns 令牌类型时,它是 yylex 存储到 yylval 中的值。例如,在原始代码中,yylex 使用 scanf("%d", &yylval) 来设置 NUMBER 标记的语义值。但是在新代码中,yylex 没有履行其合同。它从不将 yylval 设置为任何东西,因此它 returns 的任何标记的语义值都是未定义的。 (只要解析器从不使用令牌的语义值就完全可以。'+' 也没有给出语义值,但解析器不期望一个。)

在令牌 '1' 的情况下,解析器确实不需要扫描器的帮助:很清楚语义值应该是什么:

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

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

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