使用 Flex 和 Yacc 时未声明 yylineno

yylineno undeclared when using Flex and Yacc

我正在尝试为编译器课程构建一个迷你编译器,我正在 https://github.com/rabishah/Mini-C-Compiler-using-Flex-And-Yacc and https://github.com/vikash002/C---mini-Compiler 浏览 GitHub 和许多其他此类迷你编译器的代码。

当我克隆它们并使用代码运行它们时

$ 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版本有关运行ning。

与 lex 和非常旧版本的 flex 不同,您可能遇到的任何 flex 都不会定义(或初始化)yylineno,除非您 运行 它处于 lex 兼容模式(不真正推荐)或请求 flex 跟踪行号(强烈推荐但不是由您使用的源代码完成)。

所以你有以下选项,大致按照我的偏见排序:只做其中一个!它们彼此不兼容。

  1. %option yylineno 添加到 c.l 文件的开头。然后将第5行改为:

     [ \t\n]   ;
    

    并删除第 6 行(具有模式 [ \n] 的规则)。这删除了递增 yylineno 的操作,这是必需的,因为 %option yylineno 要求 Flex 构建一个自行跟踪行号的扫描器。

  2. 在文件开头的#include语句之后(即第4行左右)在c.y中添加如下行:

     extern int yylineno = 1;
    

    这将声明全局 yylineno 变量并对其进行初始化。在此选项中,您不要求 Flex 生成跟踪行号的扫描仪。所以你将不得不自己做。

    一个稍微好一点的选择(但需要更多的工作)是将整个代码中 yylineno 的名称更改为其他名称。这样您就不必担心意外启用行号跟踪。 (但就个人而言,我会从一开始就启用行号跟踪,如选项 1 中所示。)

  3. 运行 通过在调用 lex 时添加 -l 命令行选项来在 lex 兼容模式下进行 flex(这实际上是 flex):

     lex -l c.l
    

意见如下。 您已被警告。

说了这么多,我真的建议如果你想复制代码,找一些真正知道如何编写解析器的人编写的代码,而不是从随机复制糟糕的、未完成的和可能有错误的代码 GitHub 存储库。一般来说,复制别人的错误是一种糟糕的学习编程的方法。自己编写代码显然在短期内更耗时,但更有教育意义,你最终只需要处理自己的错误。