2015-09-07 27 views
5

Der folgende Code ist ein gültiges Java-Programm.Was kann dazu führen, dass der Java-Compiler beim Analysieren eines Kommentars fehlschlägt?

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

main Die Kennung wird unter Verwendung geschrieben Unicode-Escape-Sequenzen. Es kompiliert und läuft gut.

Obwohl die folgenden Details für diese Frage möglicherweise nicht erforderlich sind, teile ich es für den Fall, dass jemand neugierig ist. Ich verwende den Java-Compiler von OpenJDK unter Debian 8.0, aber was ich in dieser Frage stelle, sollte für jeden Java-Compiler gelten.

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

Das folgende Programm ist ein Fehler, weil die verwendete Escape-Sequenz m von main ungültig zu schreiben ist.

Der Compiler beklagt sich über illegale Unicode-Sequenz.

$ 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 

Was mich überrascht, ist, dass das folgende Programm, obwohl die illegale Unicode-Escape-Sequenz auch ungültig ist zu erscheinen scheint in einem Kommentar zu sein.

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

Hier ist der Fehler.

$ javac Foo.java && java Foo 
Foo.java:3: error: illegal unicode escape 
    // This comment contains \u6d. 
           ^
1 error 

Der Compiler beschwert sich über die illegale Unicode-Escape-Sequenz, obwohl es scheint, in einem Kommentar zu sein.

Der Grund für dieses Verhalten wird deutlich, wenn wir sehen, wie ein End-of-Line-Kommentar in JLS §3.7 definiert ist.

EndOfLineComment: 
// {InputCharacter} 

JLS §3.4InputCharacter definiert wie folgt.

InputCharacter: 
    UnicodeInputCharacter but not CR or LF 

Schließlich JLS §3.3UnicodeInputCharacter definiert wie folgt.

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 

Daher wird die lexikalische Analyse erforderlich, zunächst die Escape-Sequenzen, um Unicode zu erkennen Kommentare zu erkennen, und wenn eine illegale Unicode-Escape-Sequenz gefunden wird, würde die lexikalische Analyse fehlschlagen und ein Fehler auftreten würde. Daher würde der Compiler niemals fortfahren, den Kommentar zu erkennen, der die ungültige Unicode-Escapesequenz enthielt.

Obwohl ich dachte, dass alles vom Anfang eines Kommentars (sagen //) bis zum Ende ignoriert wird, zeigt das obige Beispiel, dass dies nicht der Fall ist, weil der lexikalische Analysator Unicode-Escape-Sequenzen zwischen dem Start erkennen muss Ein Kommentar und das Ende eines Kommentars sowie eine ungültige Unicode-Escape-Sequenz können dazu führen, dass die lexikalische Analyse fehlschlägt.

Was kann sonst dazu führen, dass der Compiler beim Analysieren eines Kommentars fehlschlägt?

+1

Look [hier] (http://stackoverflow.com/questions/9225124/error-due-to-content-in-a-legal- Kommentar-in-Java) – Dando18

+0

@ Dando18 Danke für die Freigabe des Links. Keine der Antworten beantwortet diese Frage wirklich. Die Antwort, die von '@ deprecated' spricht, ist in OpenJDK nicht reproduzierbar. Die Antwort, die '/ * Compiler Error aufgrund dieses Unicode-Zeichens '* /' * /' erwähnt, ist falsch, weil das abschließende '* /' eindeutig nicht innerhalb des Kommentars ist. Die anderen beiden Antworten beziehen sich nicht auf die spezifische Frage, die gestellt wurde. –

+1

http://StackOverflow.com/q/30727515/2158288 – ZhongYu

Antwort

2

Kurz:

nichts (nichts sonst ).

Long:

Logisch, die \u Escape-Sequenzen behandelt werden, bevor lexikalische Verarbeitung (scanning/Tokenisierung) stattfindet. Nach https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.2:

Einem rohen Unicode Zeichenstrom in eine Folge von Tokens übersetzt wird, die folgenden drei lexikalischen Übersetzungs Schritte, die wiederum angewandt werden:

  1. A Übersetzung von Unicode entkommt (§3.3) im Rohdatenstrom von Unicode-Zeichen zum entsprechenden Unicode-Zeichen. Ein Unicode-Escape der Form \ uxxxx, wobei xxxx ein hexadezimaler Wert ist, stellt die UTF-16-Codeeinheit dar, deren Codierung xxxx ist. Dieser Übersetzungsschritt ermöglicht, dass jedes Programm nur mit ASCII-Zeichen ausgedrückt wird.

  2. Eine Übersetzung des aus Schritt 1 resultierenden Unicode-Streams in einen Strom von Eingabezeichen und Zeilenabschlusszeichen (§3.4).

  3. Eine Übersetzung des Stroms von Eingabezeichen und Zeilenabschlüssen, die aus Schritt 2 resultieren, in eine Folge von Eingabeelementen (§3.5), die nach Leerzeichen (§3.6) und Kommentare (§3.7) verworfen werden Token (§3.5), die die Endsymbole der syntaktischen Grammatik sind (§2.3).

Technisch gesehen, \u6d in Ihrem Beispiel ist NICHT ein Teil des Kommentars. Ob es zu diesem Kommentar gehört oder nicht, wird festgelegt nach wird es zurück in einen Unicode-Codepunkt übersetzt. Aber leider versagt es dort.

Als Beweis sollte folgende Klasse kompiliert:

public class Test { 
    // is comment, the rest, not\u000a public static void main(String[] args) { 
     System.out.println("See!"); 
    } 
} 
+1

Ich denke, Sie sollten betonen, warum dieser Teil der JLS bedeutet, dass * nichts anderes * einen Fehler in einem Kommentar verursacht und weniger über den Grund für den Fehler, den das OP bereits zu verstehen scheint. – RealSkeptic