JavaCC の LOOKAHEAD にまつわる不思議な挙動

JavaCC って LookAhead 内は LookAhead を無視するの? - SiroKuro Page に関して、実証コードができました。JavaCC4.0 で確認してます。

PARSER_BEGIN(Test)
import java.io.*;
public class Test {
    public static void main(String[] args) throws Exception {
        new Test(new StringReader("ac")).foo();
    }
}
PARSER_END(Test)

TOKEN : { "a" | "b" | "c" | "d" }

void foo():{
}{
    LOOKAHEAD(bar() <EOF>) bar() <EOF>    // ※
|   "d" <EOF>
}
void bar():{
}{
    LOOKAHEAD("a" "b") "a" ["b"]
|   "a" "c"
}

動作は以下の流れ。

  1. 入力は "ac" の二文字。トークンは "a" "c" の順。
  2. foo() が呼ばれる
  3. LOOKAHEAD(bar() ) を実行
  4. bar() を先読み開始
  5. "a" ["b"] を解釈し、トークン "a" を先読み消費
  6. bar() の先読み成功
  7. 残りは "c" だが、次に来るべきは なので先読み失敗
  8. LOOKAHEAD(bar() ) の先読みに失敗
  9. "d" をパースしようとして失敗
  10. 全体のパースが失敗する

ちなみに※印の行の LOOKAHEAD を削除すると、正常にパースできるようになる。ちょっと躓きやすい挙動だなぁ。JavaCC のマニュアル読めば書いてあるのかな。まあ、要は実態にそぐわない LOOKAHEAD("a" "b") なんて書くのが悪いんですけどね( ´ー`)y-~~