ANTLR(7) - Lexerのエラー処理
- @rulecatchでcatch節を書くと、全体に共通するエラー処理を書ける。
- @lexer::rulecatch はないみたい
- 確認したエラー
- LexerでTokenizeできない先頭文字を見つけると、NoViableAltException
- 2文字目以降がmatchできないと MismatchedTokenException
- 'a'..'z'などの範囲がmatchできないと MismatchedRangeException
- (...)+ が0回の繰り返しだと EarlyExitException
- ('hoge'|'foo') がヒットしないと MismatchedSetException
- ~(...) がヒットしないと MismatchedNotSetException
- 通常のエラー処理
- reportError(RecognitionException) を呼び出してコンソールに表示
- recover(RecognitionException) を呼び出して一文字スキップ
- 一部のエラーはrecoverが2回以上呼び出される。対策が必要になるかも。
Irenkaではコンソールにエラーを表示されても困るので、reportError(RecognitionException), recover(RecognitionException)を上書きしてエラー情報を収集する方向で。
ASTの生成
ANTLR(7) - Mini Irenka Query - しげるメモ を部分的に書き換え。
@lexer::header { package research; import java.util.ArrayList; import java.util.Collections; import java.util.List; } @lexer::members { private List<RecognitionException> exceptions; @Override public void reportError(RecognitionException e) { // skip } @Override public void recover(RecognitionException re) { if (exceptions == null) { exceptions = new ArrayList<RecognitionException>(); } // avoid re-recovering if (!exceptions.isEmpty() && exceptions.get(exceptions.size() - 1) == re) { return; } exceptions.add(re); input.consume(); // skip identifier if (Character.isJavaIdentifierPart(re.c)) { while (true) { int next = input.LA(1); if (!(next >= 0 && Character.isJavaIdentifierPart(next))) { break; } input.consume(); } } } }
エラーを表示するのではなく、リストにため込んでおくイメージで。そしてエラーリカバリは一文字または一識別子スキップ。ただ、エラーの限界個数を設定できるようにして、それ超えたらRuntimeExceptionの子で大域脱出した方がよさげ。