C# 如果输入为';无效吗?

C# 如果输入为';无效吗?,c#,exception,antlr4,C#,Exception,Antlr4,我有一个简单的ANLTR语法和陪同访客。一切都很好,除非输入无效。如果输入无效,错误就会消失,我的计算器输出错误 我尝试过实现一个错误监听器,超越了lexer的Recover方法,并且。。好。。。今天还有六件事。有人能告诉我如何简单地抛出错误而不是吞下坏的“代币”吗?(我使用引号是因为它们根本不是标记。字符在我的语法中没有定义。) 有效输入: public static class Calculator { public static int Evaluate(string expres

我有一个简单的ANLTR语法和陪同访客。一切都很好,除非输入无效。如果输入无效,错误就会消失,我的计算器输出错误

我尝试过实现一个错误监听器,超越了lexer的
Recover
方法,并且。。好。。。今天还有六件事。有人能告诉我如何简单地抛出错误而不是吞下坏的“代币”吗?(我使用引号是因为它们根本不是标记。字符在我的语法中没有定义。)

有效输入:

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);
    }
}
1+2*3-4

无效输入:

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);
    }
}
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);
    }
}

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

由于错误发生在lexer中(lexer只是不知道字符
),因此必须将错误处理附加到lexer。在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);
        }
    });
lexer.addErrorListener(新的BaseErrorListener(){
@凌驾
public void syntaxError(识别器识别器、对象违规符号、int行、int charPositionInLine、字符串消息、识别异常e){
抛出新的运行时异常(e);
}
});
C#语法应该离这不远。但我建议不要抛出异常。最好将错误收集到一个列表中,并在lexer完成后报告它们,如果错误列表不是空的,不要开始解析。

。所以,虽然我仍然认为创建一个ErrorStrategy会更好,但这对我来说确实有效,我的目标是为未定义的输入抛出一个异常

首先,我创建了一个派生类,它继承自
BaseErrorListener
,并实现
iantlErrorListener
。第二部分似乎一直是我的问题。因为我的访问者继承自
FooBarBaseVistor
,所以我的错误侦听器也需要是向我的lexer注册它的类型

class ThrowExceptionErrorListener : BaseErrorListener, IAntlrErrorListener<int>
{
    //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<int> 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);
    }
}
就这样。引发参数异常,此测试现在通过

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

最后一个音符。如果您在此处抛出一个
RecognitionException
,它将再次被吞没<建议使用code>ParseCancelationException,因为它不是从
RecognitionException
派生的,但我选择了
ArgumentException
,因为我觉得这对客户端C代码最有意义

看看Antlr4cs的答案作者:是的。试过了@Alex。我继承了
BaseErrorListener
并将其附加到我的解析器中,但这些方法都没有被调用过。在我需要停止解析时,似乎已经尽了很大的努力来确保解析完成。
BailErrorStrategy
也无法引发任何异常。我用它得到的结果和我用
DefaultErrorStrategy
得到的结果一样,我错了。实际上,解析器和lexer在ANTLR中是严格分开的,所以我的第一个在解析器上使用ErrorStrategy的解决方案将不起作用。然而,将侦听器附加到lexer就可以做到这一点。我更正了我的答案,描述了解决方案,多亏你朝着正确的方向努力。非常感谢。这解决了我的问题,与OP中所述的问题相同。谢谢!