2015-09-07 13 views
5

Poniższy kod jest poprawnym programem w języku Java.Co może spowodować błąd kompilatora Java podczas analizowania komentarza?

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

Identyfikator main jest zapisywany przy użyciu sekwencji unikodowych Unicode. Kompiluje i działa dobrze.

$ javac Foo.java && java Foo 
hello, world 

Chociaż poniższe informacje mogą nie być konieczne do udzielenia tego pytania, udostępniam je na wypadek, gdyby ktoś był ciekawy. Używam kompilatora Java z OpenJDK na Debianie 8.0, ale to, o co pytam w tym pytaniu, powinno dotyczyć dowolnego kompilatora Java.

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

Poniższy program jest błąd, ponieważ sekwencja ucieczki używany do pisania m z main jest nieprawidłowy.

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

Kompilator narzeka na nielegalną sekwencję 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 

Co mnie zaskoczyło to, że następujący program jest również nieważny, mimo że nielegalny sekwencja escape Unicode wydaje się pojawiać się w komentarzu.

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

Tutaj jest błąd.

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

Kompilator uskarża się na nielegalną sekwencję unikodową Unicode, chociaż wydaje się, że jest w komentarzu.

Przyczyna tego zachowania staje się jasna, gdy widzimy, jak definiuje się komentarz końcowy w JLS §3.7.

EndOfLineComment: 
// {InputCharacter} 

JLS §3.4 określa InputCharacter następująco.

InputCharacter: 
    UnicodeInputCharacter but not CR or LF 

Wreszcie JLS §3.3 określa UnicodeInputCharacter następująco.

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 

Dlatego analizator leksykalny jest wymagane, aby najpierw rozpoznawać sekwencje Unicode w celu rozpoznania komentarze, a jeśli nielegalne sekwencja escape Unicode zostanie znaleziony, analiza leksykalna zawiedzie i błąd będzie występować. Dlatego kompilator nigdy nie przystąpiłby do rozpoznawania komentarza, który zawierał nielegalną sekwencję unikową Unicode.

Chociaż kiedyś myślałem, że od początku komentarza (powiedzmy //) do końca jest ignorowany, powyższy przykład pokazuje, że tak nie jest, ponieważ analizator leksykalny musi rozpoznawać sekwencje specjalne Unicode między początkiem komentarza i zakończenia komentarza, a nielegalna sekwencja eskejpowa Unicode może spowodować niepowodzenie analizy leksykalnej.

Co jeszcze może spowodować błąd kompilatora podczas analizowania komentarza?

+1

wygląd [tutaj] (http://stackoverflow.com/questions/9225124/error-due-to-content-in-a-legal- comment-in-java) – Dando18

+0

@ Dando18 Dzięki za udostępnienie linku. Jednak żadna z odpowiedzi nie odpowiada na to pytanie. Odpowiedź, która mówi o '@ przestarzałym 'nie jest odtwarzalna w OpenJDK. Odpowiedź, która wspomina o błędzie kompilatora '/ * z powodu tego znaku Unicode '* /' * /' jest niepoprawna, ponieważ końcowe "* /" wyraźnie nie znajduje się w komentarzu. Pozostałe dwie odpowiedzi nie odnoszą się do konkretnego pytania, które zadano. –

+1

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

Odpowiedz

2

Skrót:

nic (nic inny ).

Long:

Logicznie rzecz biorąc, sekwencje uciec \u są obsługiwane przed przetwarzanie leksykalny (skanowanie/tokenizing) zachodzi. Według https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.2: strumień znaków

Surowy Unicode jest przetłumaczony na sekwencję żetonów, stosując następujące trzy leksykalne kroki tłumaczeniowe, które są stosowane w następującej kolejności:

  1. Translacja Unicode ucieka (§3.3) w surowym strumieniu znaków Unicode do odpowiedniego znaku Unicode. Wyjście Unicode z postaci \ uxxxx, gdzie xxxx jest wartością szesnastkową, reprezentuje jednostkę kodową UTF-16, której kodowanie wynosi xxxx. Ten etap tłumaczenia umożliwia wyrażanie dowolnego programu za pomocą tylko znaków ASCII.

  2. Tłumaczenie strumienia Unicode z etapu 1 do strumienia znaków wejściowych i zakończeń linii (§3.4).

  3. Tłumaczenie strumienia znaków wejściowych i zakończeń linii wynikających z kroku 2 na sekwencję elementów wejściowych (§3.5), które po usunięciu odstępu (§3.6) i komentarza (§3.7) zawierają tokeny (§ 3.5), które są terminalnymi symbolami gramatyki składniowej (§2.3).

Więc technicznie, \u6d w przykładzie jest NIE częścią komentarza. To, czy należy do tego komentarza, jest określane jako po, a następnie jest tłumaczone z powrotem na kodowy kod Unicode. Ale niestety tam się nie udaje.

jako dowód, następujące klasy należy skompilować:

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

Myślę, że powinieneś podkreślać, dlaczego ta część JLS oznacza, że ​​* nic innego * nie spowoduje błędu w komentarzu, a mniej o przyczynę błędu, który wydaje się już zrozumieć. – RealSkeptic

Powiązane problemy