私はANTLR 4の文法を持っており、そこからレクサーとパーサーを構築しました。今私はエラーに遭遇するまで解析するような方法でそのパーサーをインスタンス化しようとしています。エラーが発生した場合は、解析を継続すべきではありませんが、問題に関する有益な情報を提供する必要があります。理想的には機械可読の場所と人間が読めるメッセージです。ここで有用なメッセージで解析エラーを中止します
は私が現時点で持っているものです。
grammar Toy;
@parser::members {
public static void main(String[] args) {
for (String arg: args)
System.out.println(arg + " => " + parse(arg));
}
public static String parse(String code) {
ErrorListener errorListener = new ErrorListener();
CharStream cstream = new ANTLRInputStream(code);
ToyLexer lexer = new ToyLexer(cstream);
lexer.removeErrorListeners();
lexer.addErrorListener(errorListener);
TokenStream tstream = new CommonTokenStream(lexer);
ToyParser parser = new ToyParser(tstream);
parser.removeErrorListeners();
parser.addErrorListener(errorListener);
parser.setErrorHandler(new BailErrorStrategy());
try {
String res = parser.top().str;
if (errorListener.message != null)
return "Parsed, but " + errorListener.toString();
return res;
} catch (ParseCancellationException e) {
if (errorListener.message != null)
return "Failed, because " + errorListener.toString();
throw e;
}
}
static class ErrorListener extends BaseErrorListener {
String message = null;
int start = -2, stop = -2, line = -2;
@Override
public void syntaxError(Recognizer<?, ?> recognizer,
Object offendingSymbol,
int line,
int charPositionInLine,
String msg,
RecognitionException e) {
if (message != null) return;
if (offendingSymbol instanceof Token) {
Token t = (Token) offendingSymbol;
start = t.getStartIndex();
stop = t.getStopIndex();
} else if (recognizer instanceof ToyLexer) {
ToyLexer lexer = (ToyLexer)recognizer;
start = lexer._tokenStartCharIndex;
stop = lexer._input.index();
}
this.line = line;
message = msg;
}
@Override public String toString() {
return start + "-" + stop + " l." + line + ": " + message;
}
}
}
top returns [String str]: e* EOF {$str = "All went well.";};
e: 'a' 'b' | 'a' 'c' e;
保存これはToy.g
に、これらのコマンドを試してみてください。一方で
> java -jar antlr-4.5.2-complete.jar Toy.g
> javac -cp antlr-4.5.2-complete.jar Toy*.java
> java -cp .:tools/antlr-4.5.2-complete.jar ToyParser ab acab acc axb abc
ab => All went well.
acab => All went well.
acc => Failed, because 2-2 l.1: no viable alternative at input 'c'
axb => Parsed, but 1-1 l.1: token recognition error at: 'x'
Exception in thread "main" org.antlr.v4.runtime.misc.ParseCancellationException
at org.antlr.v4.runtime.BailErrorStrategy.recoverInline(BailErrorStrategy.java:90)
at org.antlr.v4.runtime.Parser.match(Parser.java:229)
at ToyParser.top(ToyParser.java:187)
at ToyParser.parse(ToyParser.java:95)
at ToyParser.main(ToyParser.java:80)
Caused by: org.antlr.v4.runtime.InputMismatchException
at org.antlr.v4.runtime.BailErrorStrategy.recoverInline(BailErrorStrategy.java:85)
... 4 more
、私は私はと感じてすでに過度にやっている。シンプルで一般的な作業でなければならないコードの量を見てもわかりませんが、シンプルな解決法がないのかどうか疑問に思います。一方で、それでも十分ではないように見える理由は2つあります。まず、レクサーエラーを報告することができましたが、残りのストリームでパーサーが続行されることはありません。これは入力axb
のParsed, but
文字列による証です。第二に、私はまだスタックトレースで示されているようにエラーリスナーに報告されないエラーが残っています。
私はBailErrorStrategy
をインストールしない場合、私はより多くの有用な出力を得る:
acc => Parsed, but 2-2 l.1: mismatched input 'c' expecting 'a'
axb => Parsed, but 1-1 l.1: token recognition error at: 'x'
abc => Parsed, but 2-2 l.1: extraneous input 'c' expecting {<EOF>, 'a'}
は、エラーメッセージのこの種を取得するが、それでもエラーに救済する方法はありますか?私はsee from the sourcesextraneous input
というメッセージが実際にDefaultErrorStrategy
によって生成されていることがわかります。明らかに、問題の修正方法が分かっています。私はそれをやらなければならないし、を、つまりBailErrorStrategy
という自分の変種を書いてからスローするのですか?
ありがとう!つまり、エラーメッセージのフォーマットはすべて自分で行う必要がありますか? [DefaultErrorStrategy'ソース](https://github.com/antlr/antlr4/blob/4.5/runtime/Java/src/org/antlr/v4/runtime/DefaultErrorStrategy)を見てください。java)は、エラー書式とエラー記者に通知するための呼び出しの間に得る方法がないように見えます。 – MvG
@MvG残念ながらはい。これは私が出会った唯一の信頼できる解決策です – vsminkov