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