使用 Flex 和 Yacc 时未声明 yylineno

问题描述

我试图为编译器课程构建一个迷你编译器,我正在 GitHub 上的 https://github.com/rabishah/Mini-C-Compiler-using-Flex-And-Yacchttps://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 跟踪行号(强烈推荐但不是由您使用的源代码完成)。

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

  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. 通过在调用 -l 时添加 lex 命令行选项来在 lex 兼容模式下运行 flex(这实际上是 flex):

     lex -l c.l
    

意见如下。 您已被警告。

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