问题描述
我试图为编译器课程构建一个迷你编译器,我正在 GitHub 上的 https://github.com/rabishah/Mini-C-Compiler-using-Flex-And-Yacc 和 https://github.com/vikash002/C---mini-Compiler 以及许多其他此类迷你编译器中浏览代码。
当我克隆它们并使用代码运行它们时
$ lex c.l
$ yacc c.y
$ gcc y.tab.c -ll -ly
In file included from c.y:140:
c.l: In function ‘yylex’:
c.l:6:3: error: ‘yylineno’ undeclared (first use in this function); did you mean ‘yyleng’?
6 | [ \n] { yylineno = yylineno + 1;}
| ^~~~~~~~
| yyleng
c.l:6:3: note: each undeclared identifier is reported only once for each function it appears in
c.y: At top level:
c.y:157:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
157 | yyerror(char *s) {
| ^~~~~~~
c.y:157:1: warning: conflicting types for ‘yyerror’
c.y:8:6: note: prevIoUs declaration of ‘yyerror’ was here
8 | void yyerror(const char *s);
| ^~~~~~~
c.y: In function ‘yyerror’:
c.y:158:25: error: ‘yylineno’ undeclared (first use in this function); did you mean ‘yyleng’?
158 | printf("%d : %s %s\n",yylineno,s,yytext );
| ^~~~~~~~
| yyleng
我仍在学习 Fex 和 Yacc,当我在网上查看时,我发现 yylineno 是其中的默认变量。我什至尝试将其初始化为 1,但我遇到了同样的错误。
知道我哪里出错了吗?或者这是与新版本的 Flex 和 Yacc 相关的错误?
任何帮助将不胜感激。
解决方法
是的,这与您运行的 flex 版本有关。
与 lex 和非常旧版本的 flex 不同,您可能遇到的任何 flex 都不会定义(或初始化)yylineno
,除非您在 lex 兼容模式(不真正推荐)或请求下运行它flex 跟踪行号(强烈推荐但不是由您使用的源代码完成)。
所以你有以下选择,大致按照我的偏见排序:只做其中一个!它们彼此不兼容。
-
将
%option yylineno
添加到c.l
文件的开头。然后将第 5 行更改为:[ \t\n] ;
并删除第 6 行(模式为
[ \n]
的规则)。这删除了增加yylineno
的操作,这是必要的,因为%option yylineno
要求 Flex 构建一个自行跟踪行号的扫描器。 -
在文件开头的
#include
语句之后(即大约第 4 行)在 c.y 中添加以下行:extern int yylineno = 1;
这将声明全局
yylineno
变量并初始化它。在此选项中,您不会要求 Flex 生成跟踪行号的扫描仪。所以你将不得不自己做。一个更好的选择(但需要做更多的工作)是将整个代码中
yylineno
的名称更改为其他名称。这样您就不必担心意外启用行号跟踪。 (但就我个人而言,我会从一开始就启用行号跟踪,如选项 1 中所示。) -
通过在调用
-l
时添加lex
命令行选项来在 lex 兼容模式下运行 flex(这实际上是 flex):lex -l c.l
意见如下。 您已被警告。
说了这么多,我真的建议如果你想复制代码,找一些真正知道如何编写解析器的人写的代码,而不是从随机的 GitHub 存储库中复制糟糕的、未完成的和可能有缺陷的代码。一般来说,复制别人的错误是学习编程的一种糟糕方式。短期来看,自己编写代码显然更耗时,但它更具教育意义,您最终只需要处理自己的错误。