使用 Antlr4 解析 PlSQL 时如何提取带有语法错误的行

Posted

技术标签:

【中文标题】使用 Antlr4 解析 PlSQL 时如何提取带有语法错误的行【英文标题】:How to extract line with syntax error when parsing PlSQL using Antlr4 【发布时间】:2020-08-27 07:05:37 【问题描述】:

我正在使用来自 Github repository 的 PlSql 语法文件。如果它有语法错误,我想在我解析的 plsql 文件中加下划线。我有以下 sn-p 这样做:

public static class UnderlineListener extends BaseErrorListener 

    public void syntaxError(Recognizer<?, ?> recognizer,
                            Object offendingSymbol,
                            int line, int charPositionInLine,
                            String msg,
                            RecognitionException e)
    
        System.err.println("line "+line+":"+charPositionInLine+" "+msg);
        underlineError(recognizer,(Token)offendingSymbol,
                       line, charPositionInLine);
    

    protected void underlineError(Recognizer recognizer,
                                  Token offendingToken, int line,
                                  int charPositionInLine) 
        CommonTokenStream tokens =
            (CommonTokenStream)recognizer.getInputStream();
        String input = tokens.getTokenSource().getInputStream().toString();
        String[] lines = input.split("\n");
        String errorLine = lines[line - 1];
        System.err.println(errorLine);
        for (int i=0; i<charPositionInLine; i++) System.err.print(" ");
        int start = offendingToken.getStartIndex();
        int stop = offendingToken.getStopIndex();
        if ( start>=0 && stop>=0 ) 
        for (int i=start; i<=stop; i++) System.err.print("^");
        
    System.err.println();
    

虽然这在大多数情况下都可以正常工作,但某些脚本语言,如 PlSql,需要special handling for case-sensitivity。这意味着我必须使用CaseChangingCharStream,如下所示:

CharStream s = CharStreams.fromPath(Paths.get('test.sql'));
CaseChangingCharStream upper = new CaseChangingCharStream(s, true);
Lexer lexer = new SomeSQLLexer(upper);

现在,当我尝试使用String input = tokens.getTokenSource().getInputStream().toString(); 获取UnderlineListener 中的输入文本时,我没有得到test.sql 的实际文本。这是因为 getInputStream() 正在返回 CaseChangingCharStream 对象,它没有给出我的 test.sql 所需的实际文本。

在我的案例中,如何获取实际的文件文本?一种方法是将文件内容传递给UnderlineListener的构造函数,但我更愿意坚持上述获取实际文件文本的方法,因为它可以用于不使用CaseChangingCharStream的情况。

【问题讨论】:

【参考方案1】:

我找到了解决方法。 CaseChangingCharStream.java 的当前实现没有像 getCharStream() 这样的 getter 方法来访问 final CharStream stream; 属性。只需为其添加一个 getter 方法,我们就可以访问底层的 CharStream 对象,如下所示:

CaseChangingCharStream modifiedCharStream = (CaseChangingCharStream) tokens.getTokenSource().getInputStream();
String input = modifiedCharStream.getCharStream().toString();

【讨论】:

以上是关于使用 Antlr4 解析 PlSQL 时如何提取带有语法错误的行的主要内容,如果未能解决你的问题,请参考以下文章

使用Antlr4和neo4j解析sql生成数据地图

如何将生成的解析树保存为 IntelliJ 上 ANTLR4 插件的 .svg 文件?

ANTLR4 如何编写语法文件之语法解析器规则

ANTLR4 如何编写语法文件之语法解析器规则

ANTLR4入门:使用mave ANTLR4插件(antlr4-maven-plugin)执行语法解析生成器

ANTLR4入门:使用mave ANTLR4插件(antlr4-maven-plugin)执行语法解析生成器