Skip to content
Advertisement

How to extract line with syntax error when parsing PlSQL using Antlr4

I am using the grammar file for PlSql from this Github repository. I want to underline the line in plsql file that I parse if it has a syntax error. I have the following snippet to do so:

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

While this works fine in most cases, some scripting languages, like PlSql, need special handling for case-sensitivity. This means I had to use CaseChangingCharStream as follows:

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

Now when I try to get the input text inside my UnderlineListener using String input = tokens.getTokenSource().getInputStream().toString();, I do not get the actual text of my test.sql. This is because getInputStream() is returning CaseChangingCharStream object which does not give the desired actual text of my test.sql.

How do I get the actual file text in my case? One way could be to pass the file content to the the constructor of UnderlineListener, but I would prefer to stick to the above method of getting actual file text since it can be used for cases where CaseChangingCharStream is not used.

Advertisement

Answer

I have found a workaround. The current implementation of CaseChangingCharStream.java does not have a getter method, like getCharStream(), to access final CharStream stream; attribute. Simply adding a getter method for it allows us to access the underlying CharStream object as follows:

CaseChangingCharStream modifiedCharStream = (CaseChangingCharStream) tokens.getTokenSource().getInputStream();
String input = modifiedCharStream.getCharStream().toString();
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement