BISON 和 YACC - 如何输入完整的语句

BISON and YACC - How to input a complete statement

这是我第一次尝试 BISON,我一直在努力弄清楚如何获取完整的语句,例如 astros = 2。每当我尝试这样做时,我都没有得到任何输出。但是如果我分别尝试每个部分,那么我会得到每个部分的输出。我的代码如下,当然只是其中的一部分:

.y 文件

%token ASSIGNMENT
%token <intToken> INTNUMBER
%token <intToken> INTTOKEN
%type <statement> STATEMENT

STATEMENT:    '\n'
              | INTTOKEN STATEMENT {printf("Token");}
              | INTNUMBER STATEMENT {printf("Number");}
              | STATEMENT ASSIGNMENT STATEMENT{printf("Assinging");}
              |  INTTOKEN '\t' ASSIGNMENT '\t' INTNUMBER STATEMENT {printf("FULL STATEMENT COMPLETE");}

               |error {yyerror("ERROR");}

我的 .l 文件:

"="                                 return ASSIGNMENT;
[0-9]+                      { ECHO; yylval.integer = atoi(yytext); return INTNUMBER; }
[a-fA-F]+[a-zA-Z]+      { ECHO; yylval.variableInteger = yytext; return INTTOKEN; }

此外,如果有人可以向我解释代币规则的工作原理,那就太好了。也许那样我可以自己想出来。

规则很简单,Lex 依次搜索正则表达式、匹配标记并将它们交给Yacc。为此,Yacc 使用 yylex() 函数。

你的问题不完整。 Yacc 文件中还有其他内容吗?

yacc文件由三部分组成:

  • C 代码稍后位于 y.tab.c 文件(由 Yacc 生成)开始附近的某个位置,在文件的这一部分您需要声明 extern int yylex(void) 函数。 Yacc 实际上需要两件事才能工作,第一个是 yylex(),第二个是 yyerror()
  • 第二部分是语法规则和动作

  • 第三部分是调用 yyparse() 的主要函数。

至于标记和类型的声明,可以在文件的 %{ %} 部分之前或之后完成。一些基本的 Yacc 代码如下所示:

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

 /* Extern keyword is just good practice, it doesn't have to be written */
 extern int yylex(void);

 void yyerror(char *string){

   fprintf(stderr,"Syntax error: %s", string);
   exit(EXIT_FAILURE);
 }

%}

%%
  /* Grammar with actions */
%%

int main(){

  yyparse();
  return 0;
}

那么这是如何工作的呢? Yacc 使用 yylex() 函数来获取标记,然后使用他的语法来确定其他所有内容。为了使其工作,您必须将使用 flex 生成的 lex.yy.c 和使用 yacc 生成的 y.tab.c 编译为目标文件,然后将这两个目标文件编译为一个可执行文件。

例如:

yacc program.y
flex program.lex
gcc -c y.tab.c -o y.tab.o
gcc -c lex.yy.c -o lex.yy.o
gcc y.tab.o lex.yy.o -o program

注意: 如果你在 Yacc 文件中声明标记,你需要在 运行 Yacc 命令时生成 y.tab.h 文件yacc -d program.y 然后将此文件包含在您的 Lex 中。选项 -d 就是为了这个。