如果输入无效,是否可以抛出exception?

我有一个简单的ANLTR语法和随附的访问者。 除非输入无效,否则一切都很好。 如果输入无效,则吞下错误并且我的计算器输出错误。

我已经尝试实现一个错误监听器,而不是使用词法分析器的Recover方法,以及……好吧……今天还有其他几十件事。 有人可以告诉我如何简单地抛出错误而不是吞下糟糕的“代币”吗? (我使用引号,因为它们根本不是标记。我的语法中的字符未定义。)

有效输入:

1 + 2 * 3 – 4

输入无效:

1 + 2 + 3(4)

如果解析器/词法分析器遇到括号(或任何其他未定义的字符),我想抛出ArgumentException 。 目前,无效字符似乎只是消失在以太中,解析器就像没有错一样。

如果我使用grun命令在控制台中运行它,我会得到以下输出,因此它会在某个级别识别无效的标记。

第1:9行令牌识别错误:’(’

第1:11行令牌识别错误:’)’

这导致解析树。

在此处输入图像描述

BasicMath.g4

 grammar BasicMath; /* * Parser Rules */ compileUnit : expression+ EOF; expression : expression MULTIPLY expression #Multiplication | expression DIVIDE expression #Division | expression ADD expression #Addition | expression SUBTRACT expression #Subtraction | NUMBER #Number ; /* * Lexer Rules */ NUMBER : INT; //Leave room to extend what kind of math we can do. INT : ('0'..'9')+; MULTIPLY : '*'; DIVIDE : '/'; SUBTRACT : '-'; ADD : '+'; WS : [ \t\r\n] -> channel(HIDDEN); 

计算器:

 public static class Calculator { public static int Evaluate(string expression) { var lexer = new BasicMathLexer(new AntlrInputStream(expression)); var tokens = new CommonTokenStream(lexer); var parser = new BasicMathParser(tokens); var tree = parser.compileUnit(); var visitor = new IntegerMathVisitor(); return visitor.Visit(tree); } } 

实际上每个错误消息都是由exception引起的。 捕获此exception并且解析器尝试恢复。 解析树是恢复的结果。

由于词法分析器中发生错误(词法分析器只是不知道字符() ),因此必须将error handling附加到词法分析器。 在Java中,这看起来像:

  lexer.addErrorListener(new BaseErrorListener() { @Override public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { throw new RuntimeException(e); } }); 

C#语法应该不远了。 但我建议不要抛出exception。 更好地将错误收集到列表中并在词法分析器完成后报告它们,如果错误列表不为空,则不要开始解析。

@CoronA是对的。 错误发生在词法分析器中。 。 所以,虽然我仍然认为创建ErrorStrategy会更好 ,但这实际上对我有用,我的目标是为未定义的输入抛出exception。

首先,我创建了一个inheritance自BaseErrorListener的派生类, 实现了IAntlrErrorListener 。 第二部分似乎是我的问题。 因为我的访问者inheritance自FooBarBaseVistor ,我的错误监听器也需要是类型来向我的词法分析器注册它。

 class ThrowExceptionErrorListener : BaseErrorListener, IAntlrErrorListener { //BaseErrorListener implementation; not called in my test, but left it just in case public override void SyntaxError(IRecognizer recognizer, IToken offendingSymbol, int line, int charPositionInLine, string msg, RecognitionException e) { throw new ArgumentException("Invalid Expression: {0}", msg, e); } //IAntlrErrorListener implementation; this one actually gets called. public void SyntaxError(IRecognizer recognizer, int offendingSymbol, int line, int charPositionInLine, string msg, RecognitionException e) { throw new ArgumentException("Invalid Expression: {0}", msg, e); } } 

并更改了我的Calculator类,将我的自定义错误监听器附加到词法分析器 。 请注意,您不必像我为实际抛出的错误那样删除ConsoleListener 。 由于我并没有真正使用它,我认为最好继续这样做。

 public static class Calculator { public static int Evaluate(string expression) { var lexer = new BasicMathLexer(new AntlrInputStream(expression)); lexer.RemoveErrorListeners(); //removes the default console listener lexer.AddErrorListener(new ThrowExceptionErrorListener()); var tokens = new CommonTokenStream(lexer); var parser = new BasicMathParser(tokens); var tree = parser.compileUnit(); var visitor = new IntegerMathVisitor(); return visitor.Visit(tree); } } 

就是这样。 抛出一个参数exception,此测试现在通过。

  [TestMethod] [ExpectedException(typeof(ArgumentException))] public void BadInput() { var expr = "1 + 5 + 2(3)"; int value = Calculator.Evaluate(expr); } 

最后一点。 如果你在这里抛出一个RecognitionException ,它将再次被吞没。 建议使用ParseCancelationException ,因为它不是从RecognitionException派生的,但我选择了ArgumentException因为我认为对客户端C#代码最有意义。