什么可能导致Java编译器在解析注释时失败?

Sus*_*Pal 5 java unicode grammar comments lexical-analysis

以下代码是有效的Java程序.

public class Foo
{
    public static void \u006d\u0061\u0069\u006e(String[] args)
    {
        System.out.println("hello, world");
    }
}
Run Code Online (Sandbox Code Playgroud)

main识别符是使用Unicode转义序列写入.它编译并运行良好.

$ javac Foo.java && java Foo
hello, world
Run Code Online (Sandbox Code Playgroud)

虽然这个问题可能不需要以下细节,但我会分享它,以防有人对此感到好奇.我在Debian 8.0上使用OpenJDK的Java编译器,但我在这个问题中要求的应该适用于任何Java编译器.

$ javac -version
javac 1.7.0_79
$ readlink -f $(which javac)
/usr/lib/jvm/java-7-openjdk-amd64/bin/javac
Run Code Online (Sandbox Code Playgroud)

下面的程序是一个错误,因为以前写的转义序列mmain是无效的.

public class Foo
{
    public static void \u6d\u0061\u0069\u006e(String[] args)
    {
        System.out.println("hello, world");
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器抱怨非法的unicode序列.

$ javac Foo.java && java Foo
Foo.java:3: error: illegal unicode escape
    public static void \u6d\u0061\u0069\u006e(String[] args)
                           ^
Foo.java:3: error: invalid method declaration; return type required
    public static void \u6d\u0061\u0069\u006e(String[] args)
                            ^
2 error
Run Code Online (Sandbox Code Playgroud)

让我感到惊讶的是,即使非法的unicode转义序列似乎出现在评论中,以下程序也无效.

public class Foo
{
    // This comment contains \u6d.
    public static void main(String[] args)
    {
        System.out.println("hello, world");
    }
}
Run Code Online (Sandbox Code Playgroud)

这是错误.

$ javac Foo.java && java Foo
Foo.java:3: error: illegal unicode escape
    // This comment contains \u6d.
                                 ^
1 error
Run Code Online (Sandbox Code Playgroud)

编译器抱怨非法的unicode转义序列,尽管它似乎在评论中.

当我们看到如何在JLS§3.7中定义行尾注释时,这种行为背后的原因就变得清晰了.

EndOfLineComment:
/ / {InputCharacter} 
Run Code Online (Sandbox Code Playgroud)

JLS§3.4定义InputCharacter如下.

InputCharacter:
  UnicodeInputCharacter but not CR or LF 
Run Code Online (Sandbox Code Playgroud)

最后,JLS§3.3定义UnicodeInputCharacter如下.

UnicodeInputCharacter:
  UnicodeEscape
  RawInputCharacter

UnicodeEscape:
  \ UnicodeMarker HexDigit HexDigit HexDigit HexDigit

UnicodeMarker:
  u {u}

HexDigit:
  (one of)
  0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F

RawInputCharacter:
  any Unicode character
Run Code Online (Sandbox Code Playgroud)

因此,词法分析器需要首先识别Unicode转义序列以识别注释,并且如果发现非法的Unicode转义序列,则词法分析将失败并且将发生错误.因此,编译器永远不会继续识别包含非法Unicode转义序列的注释.

虽然我曾经认为从注释(比如说//)开始到结束的所有内容都被忽略了,但上面的例子表明情况并非如此,因为词法分析器必须识别注释开头和注释之间的Unicode转义序列.注释结束,非法的Unicode转义序列可能导致词法分析失败.

还有什么可以导致编译器在解析注释时失败?

小智 2

短的:

\n

什么都没有(没有别的)。

\n

长的:

\n

从逻辑上讲,\\u转义序列是在词法处理(扫描/标记化)发生之前处理的。根据https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.2

\n
\n

使用以下三个词汇翻译步骤依次应用原始 Unicode 字符流被翻译为标记序列:

\n
    \n
  1. 将原始 Unicode 字符流中的 Unicode 转义 (\xc2\xa73.3) 转换为相应的 Unicode 字符。形式为 \\uxxxx 的 Unicode 转义符(其中 xxxx 是十六进制值)表示编码为 xxxx 的 UTF-16 代码单元。此转换步骤允许仅使用 ASCII 字符来表达任何程序。

    \n
  2. \n
  3. 将步骤 1 产生的 Unicode 流转换为输入字符和行终止符的流 (\xc2\xa73.4)。

    \n
  4. \n
  5. 将步骤 2 产生的输入字符和行终止符流转换为输入元素序列 (\xc2\xa73.5),其中在空格 (\xc2\xa73.6) 和注释 (\xc2\xa73.5) 之后。 7)被丢弃,包括作为句法语法(\xc2\xa72.3)的终端符号的标记(\xc2\xa73.5)。

    \n
  6. \n
\n
\n

因此从技术上讲,\\u6d在您的示例中不是评论的一部分。它是否属于该注释是在将其翻译回 unicode 代码点后确定的。但不幸的是它在那里失败了。

\n

作为证明,应编译以下类:

\n
public class Test {\n    // is comment, the rest, not\\u000a public static void main( String[] args) {\n        System.out.println("See!");\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n