【ネタ】コメントだけしか書いていないのに「Hello, world!」と表示されるJavaプログラム

これはJavaでポインタで使えるというネタから着想を得たプログラミングネタです。
厳密には **「コメントだけ書いてあるようにしか見えない」** です。

# コメントだけしか書いていないのに「Hello, world!」と表示されるJavaプログラム

```bash: 実行環境
 % java --version
openjdk 16.0.2 2021-07-20
OpenJDK Runtime Environment Microsoft-25298 (build 16.0.2+7)
OpenJDK 64-Bit Server VM Microsoft-25298 (build 16.0.2+7, mixed mode)
```

「百聞は一見にしかず」なので、まずは見てみましょう。

```Java:Main.java
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        //\u000a\u0053\u0079\u0073\u0074\u0065\u006d\u002e\u006f\u0075\u0074\u002e\u0070\u0072\u0069\u006e\u0074\u006c\u006e\u0028\u0022\u0048\u0065\u006c\u006c\u006f\u002c\u0020\u0077\u006f\u0072\u006c\u0064\u0021\u0022\u0029\u003b
    }
}
```

シンタックスハイライトだと、main関数の中にはコメントしかないですね。
しかし、実行すると「Hello, world!」と出力されます。

```bash:Main.javaの実行
% java Main.java
Hello, world!
```

## 種明かし
Javaはコンパイル前に、 **ソースコード中のUnicodeエスケープシーケンスをテキストへ変換する。**
**`\u000a` は改行なので、 `//\u000a` で実はコメントが終わっている。** 
そのため、それより後に書かれたテキストは、プログラムとしてコンパイルされる。
`\u0053\u0079...` のように、Unicodeエスケープシーケンスでプログラムを書いておけば、コメントの中にプログラムを仕込むことができる。

Unicodeエスケープシーケンスを展開すると、`System.out.println("Hello, world!");` となる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224134/141b406d-cb4b-8cde-7438-c563dc57806a.png)

コンパイラが認識している文字列は以下のようになっている。

```Java:Main.java
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        //
System.out.println("Hello, world!");
    }
}
```

シンタックスハイライトにハイライトに騙されるところでしたね。

# Javaでポインタが使える

着想の元になった記事の内容です。コードと種明かしだけ掲載しておきます。

http://blogs.wankuma.com/nagise/archive/2008/04/02/131242.aspx

*演算子を用いてJavaでポインタを扱う

```java:PointerTest.java
public class PointerTest {
    public static void main(String[] args) {
        int i = 5;
        // #start unsafe# http://java.sun.com\u000a\u002f\u002a
        int *ip = &i;
        // ポインタの内容に3を加算
        *ip += 3;
        // 演算結果をiに代入
        i = *ip;
        // #end unsafe# http://java.sun.com\u002a\u002fi+=\u0033\u003b
        System.out.println(i);
    }
}
```

## 種明かし

```java:PointerTest.java
public class PointerTest {
    public static void main(String[] args) {
        int i = 5;
        // #start unsafe# http://java.sun.com
/*
        int *ip = &i;
        // ポインタの内容に3を加算
        *ip += 3;
        // 演算結果をiに代入
        i = *ip;
        // #end unsafe# http://java.sun.com*/i+=3;
        System.out.println(i);
    }
}
```

# 本当にコメントだけしか書いていないのに「Hello, world!」と表示されるJavaプログラム
ソースコードに記述されてるすべてのUnicodeエスケープシーケンスが展開されるのなら、
プログラムすべてを、Unicodeエスケープシーケンスで記述しても動作するのではないか？

そこで作ってみた。
```java:Main2.java
//\u000a\u0069\u006d\u0070\u006f\u0072\u0074\u0020\u006a\u0061\u0076\u0061\u002e\u0075\u0074\u0069\u006c\u002e\u002a\u003b\u000a\u000a\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0063\u006c\u0061\u0073\u0073\u0020\u004d\u0061\u0069\u006e\u0032\u0020\u007b\u000a\u0020\u0020\u0020\u0020\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0073\u0074\u0061\u0074\u0069\u0063\u0020\u0076\u006f\u0069\u0064\u0020\u006d\u0061\u0069\u006e\u0028\u0053\u0074\u0072\u0069\u006e\u0067\u005b\u005d\u0020\u0061\u0072\u0067\u0073\u0029\u0020\u0074\u0068\u0072\u006f\u0077\u0073\u0020\u0045\u0078\u0063\u0065\u0070\u0074\u0069\u006f\u006e\u0020\u007b\u000a\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0053\u0079\u0073\u0074\u0065\u006d\u002e\u006f\u0075\u0074\u002e\u0070\u0072\u0069\u006e\u0074\u006c\u006e\u0028\u0022\u0048\u0065\u006c\u006c\u006f\u002c\u0020\u0077\u006f\u0072\u006c\u0064\u0021\u0022\u0029\u003b\u000a\u0020\u0020\u0020\u0020\u007d\u000a\u007d\u000a
```

```bash:Main2.javaの実行
% java Main2.java
Hello, world!
```

本当に **コメントだけしかないように見える** プログラムもしっかり動作した。

# その他
- Javaの言語仕様はここから読める。
https://docs.oracle.com/javase/specs/index.html

- Unicode関する記述はここ。
https://docs.oracle.com/javase/specs/jls/se16/html/jls-3.html

- コンパイラの実装はここから読めるのでコードリーディングして辿っていきたい。

https://github.com/openjdk/jdk/tree/jdk-16%2B7/src/jdk.compiler/share/classes/com/sun/tools/javac

https://github.com/openjdk/jdk/blob/jdk-16%2B7/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/UnicodeReader.java

# 最後に
ラインコメント(一行のコメント)に`\u000a`と記述したら大変なことになりそうです。