【问题标题】:Why does the Java compiler only report one kind of error at a time?为什么Java编译器一次只报告一种错误?
【发布时间】:2011-09-26 23:47:03
【问题描述】:

我有一个sn-p

class T{
    int y;
    public static void main(String... s){
        int x;
        System.out.println(x);
        System.out.println(y);
    }
}

这里有两个错误,但是编译时为什么只显示一个错误?

显示的错误是:

non-static variable y cannot be referenced from a static context
    System.out.println(y);
                       ^

但是错误呢

variable x might not have been initialized
    System.out.println(x);
                       ^

【问题讨论】:

  • 你还在手工编译Java代码吗?您可能想尝试在 Eclipse 之类的 IDE 中进行开发。 :)
  • @Eric,在很长一段时间内都需要从编译器中解析错误消息——无论人们如何执行编译器。 (见鬼,这个例子并没有说明它没有在 IDE 中被发现。)
  • @sarnold:我参加了他引用 javac 逐字命令行输出的部分,作为他手动运行 javac 的证据。不过,也许我草草下了结论。

标签: java compiler-construction compiler-errors


【解决方案1】:

Java 编译器在几个 中编译您的代码。在每次通过时,都会检测到某些类型的错误。在您的示例中,javac 不会查看是否可以初始化 x,直到其余代码实际通过了之前的编译器通道。

【讨论】:

  • 但是如果我们正在处理一个大型程序并且有多个错误怎么办。然后它显示了几乎所有的错误?
  • @Mohammed Faisal - 这与错误的数量无关。这完全是关于它们的错误类型,以及编译器何时能够检测到它们。如果您觉得这很难理解,请不要担心。这是你在“编译器写作”课程中学到的东西。
【解决方案2】:

@Greg Hewgill 成功了。

特别是,对正在初始化的变量、声明的异常、无法访问的代码和其他一些事情的检查会在稍后的过程中发生。如果之前的传递中有错误,则此传递不会运行。

这是有充分理由的。前面的传递构造了一个修饰的解析树,它代表编译器理解的程序。如果早先出现错误,则该树将无法准确表示开发人员所理解的程序。 (不可能!)。如果编译器然后继续运行后面的传递以产生更多错误消息,那么很多这些错误消息很可能是错误解析树的误导性工件。这只会让开发者感到困惑。

无论如何,这就是大多数编程语言的大多数编译器的工作方式。修复一些编译错误可能会导致其他(以前未报告的)错误浮出水面。

【讨论】:

    【解决方案3】:

    The Dragon Book(“编译器:原理、技术和工具”,Aho、Sethi 和 Ullman 着语言规范。

    他们给出的一些技巧:

    • 紧急模式恢复:跳过输入流中的所有输入标记,直到找到“同步标记”——想想;}end 语句和块终止符或分隔符,或 dowhileforfunction 等关键字,可以显示新代码块的预期开头等。希望从那时起的输入将足够有意义,可以解析并返回有用的错误消息.

    • 短语级恢复:猜猜一个短语可能是什么意思:插入分号、将逗号改为分号、插入=赋值运算符等,希望结果足够解析并返回有用的错误消息。

    • 错误产生式:除了识别允许的语法运算符的“合法”产生式之外,还包括识别语言中可能违反语法的错误的“错误产生式”,但编译器作者认为很可能是错误。这些错误消息可能非常好,但会大大增加解析器的大小以优化输入错误(这应该是例外,而不是常见情况)。

    • 全局更正:尝试对输入字符串进行最少的修改,以尝试将其带回可以解析的程序。由于可以通过多种不同方式进行更正(插入、更改和删除任意数量的字符),因此请尝试全部生成它们并发现使程序解析得足够好以继续解析的“最低成本”更改。

    这些选项在解析语法一章(我的版本中的第 161 页)中进行了介绍——显然,一些错误仅在输入文件被解析后才发现,但开始被转换为优化和代码的基本块一代。在早期语法级别中出现的任何错误都会阻止典型编译器启动代码优化和生成阶段,并且在这些阶段可能检测到的任何错误都必须等待固定输入才能运行。

    我强烈建议您找一本《龙之书》,它会给您一些同情,并希望对我们友好的编译器作者产生新的尊重。

    【讨论】:

      【解决方案4】:

      错误的全部意义在于编译器不知道如何正确解释您的代码。这就是为什么你应该总是在第一个错误之后忽略错误,因为编译器的混淆可能会导致额外/缺失的错误。

      【讨论】:

      • 什么?您显然没有阅读问题,这两个错误都是完全有效的,只是第二个错误在第一个错误解决之前不会出现
      • 这就是我想说的:在这种情况下,存在丢失的错误,而不是额外的错误,因为一旦编译器遇到一个错误,其以后的行为可能无法预测。
      • @Jesus - 什么?您显然没有阅读答案,答案很清楚地表明某些错误可能会使编译器有些混乱,以至于不会报告所有错误。
      • @nnnnnn 这显然不是这里的情况。
      • 如果您对 Java 编译器的实现方式非常了解......或者可以从其行为中推断出来,那么“显然”情况并非如此。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-24
      • 1970-01-01
      • 2019-02-12
      • 1970-01-01
      • 1970-01-01
      • 2018-10-11
      • 1970-01-01
      相关资源
      最近更新 更多