ANTLR3的错误处理问题

ANTLR3的错误处理问题,antlr,grammar,antlr3,context-free-grammar,Antlr,Grammar,Antlr3,Context Free Grammar,我尝试了以下方式报告错误 @members{ public String getErrorMessage(RecognitionException e,String[] tokenNames) { List stack=getRuleInvocationStack(e,this.getClass().getName()); String msg=null; if(e instanceof NoViableAltException){

我尝试了以下方式报告错误

@members{
    public String getErrorMessage(RecognitionException e,String[] tokenNames)
    {
        List stack=getRuleInvocationStack(e,this.getClass().getName());
        String msg=null;
        if(e instanceof NoViableAltException){
            <some code>
        }
        else{
            msg=super.getErrorMessage(e,tokenNames);
        }
        String[] inputLines = e.input.toString().split("\r\n");
        String line = "";
        if(e.token.getCharPositionInLine()==0)
            line =  "at \"" + inputLines[e.token.getLine() - 2];
        else if(e.token.getCharPositionInLine()>0)
            line =  "at \"" + inputLines[e.token.getLine() - 1];
        return ": " + msg.split("at")[0] + line + "\" => [" + stack.get(stack.size() - 1) + "]";
    }

    public String getTokenErrorDisplay(Token t){
        return t.toString();
    }
}
我有两个问题

1) 有没有合适的方法来做我做过的同样的事情

2) 我想用它们真正的符号来代替CLOSSB、SEMICOL、CLOSB等。如何使用.g文件中的映射来实现这一点

谢谢。

1)有没有合适的方法来做我做过的同样的事情

我不知道是否有一个定义正确的方式来显示错误。我对显示错误的看法是一个litmis测试。如果用户能够根据您提供给他们的信息找出修复错误的方法,那就很好了。如果用户被错误消息弄糊涂了,那么该消息需要更多的工作。根据问题中给出的示例,符号仅为字符常量

我最喜欢看到错误的方式是用箭头指向该位置的线条

i、 e

第6行应为右括号

int a[6;
       ^
2) 我想用它们真正的符号来代替CLOSSB、SEMICOL、CLOSB等。如何使用.g文件中的映射来实现这一点

您必须读取单独生成的令牌文件,然后制作一个映射,即字典数据结构,以将令牌名称转换为令牌字符

编辑

首先,我们必须澄清符号的含义。如果您将符号的定义限制为仅在标记文件中使用字符或字符串定义的标记,则可以执行此操作,即“!”=13,或'public'=92,如果您选择使用符号的定义作为与令牌关联的任何文本,则这与我过去或计划要解决的问题不同

当ANTLR生成其令牌映射时,它使用三种不同的源:

  • lexer中的char或string常量

  • 解析器中的字符或字符串常量

  • 内部标记,如无效、向下、向上

  • 由于lexer中的令牌不是完整的集合,因此应该使用令牌文件作为起点。如果查看令牌文件,您会注意到最低值为4。如果查看TokenTypes文件(这是C#版本名),您将找到剩余的已定义标记。 如果您在tokens文件中找到像T_;这样的名称,那么这些名称就是ANTLR为解析器中的字符/字符串文本生成的名称

    如果您在解析器规则中使用字符串和/或字符文字,那么ANTLR必须创建一组新的lexer规则,其中包括解析器规则中的所有字符串和/或字符文字。请记住,解析器只能看到标记,而不能看到原始文本。因此,不能将字符串和/或字符文本传递给解析器

    要查看新的lexer规则集,请使用org.antlr.Tool–Xsavelexer,然后打开创建的语法文件。名称可能类似于.g。如果在解析器规则中有字符串和/或字符文字,您将看到名称以T开头的lexer规则

    现在您已经知道了所有标记及其值,您可以创建一个映射表,将错误中给出的信息映射到要输出的字符串,而不是符号

    代码在 这就是一个例子

    但是,标记的映射可能会因为某些事情而改变,比如在lexer中改变规则,或者在解析器中改变char/string文本。因此,如果消息突然为符号输出了错误的字符串,则必须手动更新映射表

    虽然这不是一个完美的解决方案,但它是一个可能的解决方案,具体取决于您如何定义符号

    注意:上一次我查看Antlr4.x时,它会自动创建表以便在解析器中进行访问,因为这对于许多使用Antlr3.x的人来说是一个问题

    Bhathiya写道:

    *1) 有没有合适的方法来做我做过的同样的事情

    没有单一的方法可以做到这一点。请注意,正确的错误处理和报告是很棘手的。特伦斯·帕尔在(第10章)中花了整整一章来讨论这个问题。我建议你拿一本读一读

    Bhathiya写道:

    2) 我想用它们真正的符号来代替CLOSSB、SEMICOL、CLOSB等。如何使用.g文件中的映射来实现这一点

    你不能。对于
    SEMICOL
    来说,这似乎很容易做到,但是对于
    FOO
    这样的令牌,您如何获取这些信息呢

    FOO : (X | Y)+;
    
    fragment X : '4'..'6';
    fragment Y : 'a' | 'bc' | . ;
    

    2) 是否有一种方法可以使用.g文件的lex标记进行映射,例如
    SEMICOL:';'等?@GuyCoder,
    .tokens
    文件不包含此信息:
    SEMICOL
    将映射到数值(int)值,而不是
    ;'。还是我误解了?@GuyCoder,
    bartkiers
    我想是对的。如果没有,那么使用
    .tokens
    文件的方法是什么?@GuyCoder,你在回复谁?您链接到的邮件列表讨论没有提到任何关于
    .tokens
    文件的内容,该文件包含您在上述答案中提到的信息。
    您不能。
    谢谢您的直接回答。我想你是对的。
    FOO : (X | Y)+;
    
    fragment X : '4'..'6';
    fragment Y : 'a' | 'bc' | . ;