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