C/Lex/Yacc - 如何使用 Yacc 编写最基本的解析器生成器

问题描述

我发现学习 Lex/Flex 很容易,但是由于缺乏简单的示例程序,学习 Yacc/Bison 似乎更加混乱。根据我的观察,介绍给学生的第一个示例解析器往往是一个计算器,对初学者不太友好。我很难通过查看复杂的源代码来理解 Yacc 的工作原理,因此我决定编写自己的非常简单的程序,其中包含 Lex 和 Yacc。

test.l:

%{
#include "y.tab.h"
%}

%%
"PRINT"     { printf("Returning PRINT\n"); return PRINT; }
"EXIT"      { printf("Returning EXIT\n");  return EXIT; }
.       ;
[ \t\n] ;
%%

int yywrap(void) { return 1; }

test.y:

%{
int yylex();
#include <stdio.h> 
#include <stdlib.h>
//#include "y.tab.h"
%}

%start line
%token PRINT
%token EXIT

%%
line: PRINT {printf("Caught PRINT\n");}
    | EXIT  {printf("Caught EXIT\n");}
    | ;

%%
int main() { yyparse(); }

编译:

yacc -d test.y
lex test.l
gcc lex.yy.c y.tab.h -ll

我知道这个程序非常简单,并且有大量 Yacc 的例子,我真诚地向你保证,我在寻求帮助之前尝试了几个小时。

虽然我认为我已经完成了基础知识,但我无法弄清楚为什么它不起作用,请告诉我如何解决它。我怀疑我可能编译不正确。如有必要,我还可以显示 y.tab.h。感谢您抽出宝贵时间。

编辑:目标只是让词法分析器将适当的返回值返回给 yacc 解析器,让 yacc 解析器“捕获”它并打印“Caught PRINT”或“Caught EXIT”。

编辑2:我的编译过程确实不正确。我要感谢帮助我了解如何解决问题的人。

解决方法

您不应该编译 *.h 文件。 使用 gcc y.tab.c lex.yy.cyyerror 中提供的 test.y 定义(野牛手册推荐 void yyerror (char const *s) { fprintf (stderr,"%s\n",s); }),它应该构建。