如果输入无效,是否可以抛出异常? [英] Is it possible to throw an exception if the input isn't valid?

查看:37
本文介绍了如果输入无效,是否可以抛出异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的 ANLTR 语法和随附的访问者.一切正常,除非输入无效.如果输入无效,错误就会被吞噬,我的计算器会输出错误的输出.

I have a simple ANLTR grammar and accompanying Visitor. Everything works great, unless the input is invalid. If the input is invalid, the errors get swallowed and my calculator comes out with the wrong output.

我尝试过实现错误侦听器,克服了词法分析器的 Recover 方法,以及……嗯……今天还有六种其他的东西.有人可以告诉我如何简单地抛出错误而不是吞下坏的令牌"吗?(我使用引号是因为它们不是标记.字符在我的语法中是未定义的.)

I've tried implementing an error listener, over riding the Recover method of the lexer, and.. well... half a dozen other things today. Can someone show me how to simply throw an error instead of swallowing bad "tokens"? (I use quotes because they're not tokens at all. The characters are undefined in my grammar.)

有效输入:

1 + 2 * 3 - 4

1 + 2 * 3 - 4

无效输入:

1 + 2 + 3(4)

1 + 2 + 3(4)

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

I want to throw an ArgumentException if the parser/lexer comes across parenthesis (or any other undefined character). Currently, the invalid characters seem to just disappear into the ether and the parser just plods along like nothing is wrong.

如果我使用 grun 命令在控制台中运行它,我会得到以下输出,因此它在某种程度上识别了无效令牌.

If I run it in the console with the grun command, I get the following output, so it recognizes the invalid tokens on some level.

第 1:9 行标记识别错误:'('

line 1:9 token recognition error at: '('

第 1:11 行标记识别错误:')'

line 1:11 token recognition error at: ')'

以及生成的解析树.

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

推荐答案

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

@CoronA was right. The error happens in the lexer.. So, while I still think that creating an ErrorStrategy would be better, this is what actually worked for me and my goal of throwing an exception for undefined input.

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

First, I created a derived class that inherits from BaseErrorListener and implements IAntlrErrorListener<T>. The second part was my problem all along it seems. Because my visitor inherited from FooBarBaseVistor<int>, my error listener also needed to be of type to register it with my 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);
    }
}

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

And changed my Calculator class to attach my custom error listener to the lexer. Note that you don't have to remove the ConsoleListener like I did for the error to actually be thrown. Since I'm not really using it, I figured it best to go ahead and do so.

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

就是这样.抛出一个参数异常,这个测试现在通过了.

And that's it. An argument exception is thrown and this test now passes.

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

最后一点.如果你在这里抛出一个 RecognitionException,它会再次被吞噬.推荐使用 ParseCancelationException,因为它不是从 RecognitionException 派生的,但我选择了一个 ArgumentException,因为我觉得这对客户端 C# 最有意义代码.

One last note. If you throw a RecognitionException here, it will just get swallowed up again. ParseCancelationException is recommended, because it does not derive from RecognitionException, but I choose an ArgumentException because I felt that made the most sense to the client C# code.

这篇关于如果输入无效,是否可以抛出异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆