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