什么会导致Java编译器在解析注释时失败?
以下代码是一个有效的Java程序。
public class Foo
{
public static void u006du0061u0069u006e(String[] args)
{
System.out.println("hello, world");
}
}
main
标识符是使用Unicode转义序列编写的。 它编译和运行良好。
$ javac Foo.java && java Foo
hello, world
虽然下面的细节可能不需要这个问题,我分享它,以防有人对此感到好奇。 我在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
以下程序是错误的,因为用于写入m
的main
的转义序列无效。
public class Foo
{
public static void u6du0061u0069u006e(String[] args)
{
System.out.println("hello, world");
}
}
编译器抱怨非法unicode序列。
$ javac Foo.java && java Foo
Foo.java:3: error: illegal unicode escape
public static void u6du0061u0069u006e(String[] args)
^
Foo.java:3: error: invalid method declaration; return type required
public static void u6du0061u0069u006e(String[] args)
^
2 error
令我感到惊讶的是,即使非法的Unicode转义序列似乎在注释中,以下程序也是无效的。
public class Foo
{
// This comment contains u6d.
public static void main(String[] args)
{
System.out.println("hello, world");
}
}
这是错误。
$ javac Foo.java && java Foo
Foo.java:3: error: illegal unicode escape
// This comment contains u6d.
^
1 error
编译器会抱怨非法的Unicode转义序列,尽管它看起来在注释中。
当我们看到如何在JLS§3.7中定义行尾注释时,这种行为背后的原因就变得清晰了。
EndOfLineComment:
/ / {InputCharacter}
JLS§3.4定义了InputCharacter
,如下所示。
InputCharacter:
UnicodeInputCharacter but not CR or LF
最后, UnicodeInputCharacter
定义了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
因此,词法分析器需要首先识别Unicode转义序列以识别注释,并且如果找到非法的Unicode转义序列,则词法分析将失败并发生错误。 因此,编译器永远不会继续识别包含非法Unicode转义序列的注释。
尽管我曾经认为从注释开始(比如//
)到结束的所有内容都被忽略,但上面的例子表明,情况并非如此,因为词法分析器必须识别注释开始之前的Unicode转义序列和注释的结尾以及非法的Unicode转义序列可能会导致词法分析失败。
还有什么会导致编译器在解析注释时失败?
短:
没有(没有别的 )。
长:
逻辑上, u
转义序列在词法处理(扫描/标记)发生之前处理。 根据https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.2:
一个原始的Unicode字符流被翻译成一个令牌序列,使用以下三个词法转换步骤,依次应用:
Unicode转换(§3.3)在Unicode字符的原始流中转换为相应的Unicode字符。 形式为 uxxxx的Unicode转义符(其中xxxx是十六进制值)表示编码为xxxx的UTF-16编码单元。 该翻译步骤允许任何程序仅使用ASCII字符表示。
将步骤1产生的Unicode流转换为输入字符和行结束符(§3.4)。
将由步骤2产生的输入字符和行终止符的流转换为输入元素序列(第3.5节),在空白区(§3.6)和注释(§3.7)被丢弃之后,该输入元素序列包含标记(§3.5)这是句法语法的终端符号(§2.3)。
因此从技术上讲, u6d
在你的例子是不评论的一部分。 它是否属于该评论是在它被翻译回unicode代码点之后确定的。 但不幸的是,它失败了。
作为一个证明,下面的类应该编译:
public class Test {
// is comment, the rest, notu000a public static void main( String[] args) {
System.out.println("See!");
}
}
链接地址: http://www.djcxy.com/p/20579.html
上一篇: What can cause Java compiler to fail while parsing a comment?