Le comportement par défaut lorsque l'analyseur ne sait pas quoi faire est d'imprimer des messages dans le terminal comme :
ligne 1:23 : DECIMAL manquant à '}'.
C'est un bon message, mais au mauvais endroit. Je préférerais le recevoir comme une exception.
J'ai essayé d'utiliser le BailErrorStrategy
mais cela déclenche un ParseCancellationException
sans message (causé par un InputMismatchException
(également sans message).
Existe-t-il un moyen de faire en sorte que les erreurs soient signalées par des exceptions tout en conservant les informations utiles dans le message ?
Voici ce que je cherche vraiment : j'utilise généralement des actions dans les règles pour construire un objet :
dataspec returns [DataExtractor extractor]
@init {
DataExtractorBuilder builder = new DataExtractorBuilder(layout);
}
@after {
$extractor = builder.create();
}
: first=expr { builder.addAll($first.values); } (COMMA next=expr { builder.addAll($next.values); })* EOF
;
expr returns [List<ValueExtractor> values]
: a=atom { $values = Arrays.asList($a.val); }
| fields=fieldrange { $values = values($fields.fields); }
| '%' { $values = null; }
| ASTERISK { $values = values(layout); }
;
Ensuite, lorsque j'invoque le parseur, je fais quelque chose comme ceci :
public static DataExtractor create(String dataspec) {
CharStream stream = new ANTLRInputStream(dataspec);
DataSpecificationLexer lexer = new DataSpecificationLexer(stream);
CommonTokenStream tokens = new CommonTokenStream(lexer);
DataSpecificationParser parser = new DataSpecificationParser(tokens);
return parser.dataspec().extractor;
}
Tout ce que je veux vraiment, c'est
- pour le
dataspec()
appel pour lancer une exception (idéalement une exception vérifiée) lorsque l'entrée ne peut pas être analysée. - pour que cette exception ait un message utile et donne accès au numéro de ligne et à la position où le problème a été trouvé
Ensuite, je laisserai cette exception remonter la pile d'appels jusqu'à l'endroit le plus approprié pour présenter un message utile à l'utilisateur - de la même manière que je traiterais une connexion réseau interrompue, la lecture d'un fichier corrompu, etc.
J'ai vu que les actions sont maintenant considérées comme "avancées" dans ANTLR4, alors peut-être que je m'y prends d'une manière étrange, mais je n'ai pas cherché à savoir quelle serait la manière "non avancée" de procéder puisque cette méthode a bien fonctionné pour nos besoins.