How can I get rid of the default ANTLR recognition error?
I want to write another message using my own error class instead of ANTLR's error.
I mean is there any possibility that some ANTLR error classes can be extended in order to display my own message?
More clearly, I do not want to see the following error message in my console :
token recognition error at:
If you simply want to suppress the messages, you can call lexer.removeErrorListeners(). However, a better approach is writing your lexer rules such that all possible input is tokenized, with the following rule at the end of the lexer. This will cause all error reporting to go through the parser instead of both the parser and lexer.
// handle characters which failed to match any other token
ErrorCharacter : . ;
In order to create a custom error handler you can extend the BaseErrorListener class and override the syntaxError method, e.g.:
public class MyErrorListener extends BaseErrorListener {
#Override
public void syntaxError( Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine,
String msg, RecognitionException e ) {
// method arguments should be used for more detailed report
throw new RuntimeException("syntax error occurred");
}
}
Now when you create a lexer and a parser you should remove the default error listeners and attach your custom one:
MyErrorListener errorListener = new MyErrorListener();
Lexer lexer = new MyLexer( ... );
lexer.removeErrorListeners();
lexer.addErrorListener( errorListener );
CommonTokenStream tokens = new CommonTokenStream( lexer );
Parser parser = new MyParser( tokens );
parser.removeErrorListeners();
parser.addErrorListener( errorListener );
The default message "line x:x token recognition error at: 'xxx'" comes from the default ConsoleErrorListener class. If you don't remove it using lexer/parser.removeErrorListeners() and only add your custom one it will still be triggered.
The error handling strategies are thoroughly described in a dedicated chapter of The Definitive ANTLR4 Reference book (mentioned on the ANTLR4 Documentation page). I currently have no access to the book itself, so would be grateful if someone edits this answer with a concrete page number of the book. Also, I couldn't find a related guide on the ANTLR4 doc page, so if it exists - a link would be helpful, too.
Related
If I have a string like "2020-12-15T12:10:00.202" how can I parse this into NodaTime.LocalDateTime directly, rather than doing something like:
LocalDateTime.FromDateTime(DateTime.Parse("2020-12-15T12:10:00.202"))
And similarly for the other NodaTime types like LocalDate, Instant etc.
You use a LocalDateTimePattern. For example:
// Note: patterns are thread-safe and immutable. Various patterns are provided as
// static properties on the relevant pattern class. If you can't use one of those
// patterns, it's often useful to store the pattern in a static readonly field.
var pattern = LocalDateTimePattern.CreateWithInvariantCulture("yyyy-MM-dd'T'HH:mm:ss.fff");
// There's no Parse/TryParse separation - there's just Parse, which returns a
// ParseResult<T> that indicates success/failure.
ParseResult<LocalDateTime> parsed = pattern.Parse("2020-12-15T12:10:00.202");
// Note: if you're okay with invalid input causing an exception, just use
// parsed.Value directly - it will throw a descriptive exception if parsing failed.
if (parsed.Success)
{
LocalDateTime result = parsed.Value;
// Use the result here
}
else
{
// Handle the failure
}
For more details about text handling, see the section in the user guide.
Note that there's no direct equivalent of DateTime.Parse itself, that tries multiple different date/time formats automatically - but you can use a CompositePatternBuilder<T> to try multiple patterns when parsing if you want.
I have a rule that looks like this:
INTEGER : [0-9]+;
myFields : uno=INTEGER COMMA dos=INTEGER
Right now to access uno I need to code:
Integer i = Integer.parseInt(myFields.uno.getText())
It would be much cleaner if I could tell antler to do that conversion for me; then I would just need to code:
Integer i = myFields.uno
What are my options?
You could write the code as action, but it would still be explicit conversion (eventually). The parser (like every parser) parses the text and then it's up to "parsing events" (achieved by listener or visitor or actions in ANTLR4) to create meaningful structures/objects.
Of course you could extend some of the generated or built-in classes and then get the type directly, but as mentioned before, at some point you'll always need to convert text to some type needed.
A standard way of handling custom operations on tokens is to embed them in a custom token class:
public class MyToken extends CommonToken {
....
public Integer getInt() {
return Integer.parseInt(getText()); // TODO: error handling
}
}
Also create
public class MyTokenFactory extends TokenFactory { .... }
to source the custom tokens. Add the factory to the lexer using Lexer#setTokenFactory().
Within the custom TokenFactory, override the method
Symbol create(int type, String text); // (typically override both factory methods)
to construct and return a new MyToken.
Given that the signature includes the target token type type, custom type-specific token subclasses could be returned, each with their own custom methods.
Couple of issues with this, though. First, in practice, it is not typically needed: the assignment var is statically typed, so as in the the OP example,
options { TokenLabelType = "MyToken"; }
Integer i = myFields.uno.getInt(); // no cast required
If Integer is desired & expected, use getInt(). If Boolean ....
Second, ANTLR options allows setting a TokenLabelType to preclude the requirement to manually cast custom tokens. Use of only one token label type is supported. So, to use multiple token types, manual casting is required.
Another question on migrating code from v3 to v4:
For v3, I had a customized error reporting, using code like this (in the grammar file):
#members {
public void displayRecognitionError(String[] tokenNames,
RecognitionException e) {
String hdr = getErrorHeader(e);
String msg = getErrorMessage(e, tokenNames);
System.out.println("ERR:"+hdr+":"+msg);
errCount += 1;
}
}
In v4, when compiling the generated java files, I am getting the error:
MyParser.java:163: cannot find symbol
symbol : method getErrorMessage(org.antlr.v4.runtime.RecognitionException,java.lang.String[])
location: class MyParser
String msg = getErrorMessage(e, tokenNames);
^
Is this function replaced by some other function in v4? (I saw some questions and answers on ANTLRErrorListener, but I could not get how to use it for my situation.)
The displayRecognitionError method was removed in ANTLR 4, so even if you correct the body of that method it will not do anything. You need to remove the method from your grammar entirely, and implement ANTLRErrorListener instead. The documentation includes a list of classes that implement the interface, so you can reference those and/or extend one of them to produce the desired functionality.
Once you have an instance of an ANTLRErrorListener, you can use the following code to attach it to a Parser instance.
// remove the default error listener
parser.removeErrorListeners();
// add your custom error listener
parser.addErrorListener(listener);
I have upgraded from Antlr 3 to Antlr 4. I was using this code to catch exceptions using this code. But this is not working for Antlr 4.
partial class XParser
{
public override void ReportError(RecognitionException e)
{
base.ReportError(e);
Console.WriteLine("Error in Parser at line " + ":" + e.OffendingToken.Column + e.OffendingToken.Line + e.Message);
}
}
This is the error that appears
'Parser.ReportError(Antlr4.Runtime.RecognitionException)': no suitable method found to override
In Antlr 4 what is the expected way of accumulating errors that occurs in the input stream. I was unable to find a way to achieve this on the net. Please provide me some guidelines.
EDIT:
I have implemented the XParser as below
partial class XParser : IAntlrErrorListener<IToken>
{
public void SyntaxError(IRecognizer recognizer, IToken offendingSymbol, int line, int charPositionInLine, string msg, RecognitionException e)
{
Console.WriteLine("Error in parser at line " + ":" + e.OffendingToken.Column + e.OffendingToken.Line + e.Message);
}
}
As you said I can extend this parser class using any of the mentioned classes. But I was unable to register this listener, in the main program I am confused with passing argument as the listener. Please help me with the registering.
As I can see these classes has the capability of producing more meaningful error messages don't they?
You need to implement IAntlrErrorListener<IToken>. If all you want to is report errors like you have above, then you should focus on the SyntaxError method. Several base classes are available if you want to extend one.
ConsoleErrorListener
BaseErrorListener
DiagnosticErrorListener
The error listener is attached to the parser instance by calling parser.AddErrorListener(listener).
Edit: You need to create a new class which implements the error listener interface. You then attach the listener to the parser. The parser itself will not implement the error listener interface.
I checked SO for the xmlpullparser exception but it's giving me others questions with Android and SOUP. I am using J2me and normal HTTPrequest to get my XML and I am using kXMl to parser the xml text. Below is the code that I am working on. And above it is more parsing code and they work perfectly.
if (parser.getName().equals("comments")) {
event = parser.next();
boolean flag = false;
if (parser.getName().equals("comment")) {
flag = true;
System.out.println("Flag is true");
}
while (flag) {
event = parser.next();
Questioncomments.addComponent(new Label(parser.nextText()));
event = parser.next();
System.out.println("Inside the While");
if (!parser.getName().equals("comment")) {
flag = false;
System.out.println("Flag is false");
}
}
Questioncomments.repaint();
}
XML I am sending this side - <comments><comment>Awesome Question #dulitha<idComment></idComment></comment></comments>
The error is -
org.xmlpull.v1.XmlPullParserException: precondition: START_TAG
(position:TEXT Awesome Question...#1:399 in
java.io.InputStreamReader#f828ed68)
at org.kxml2.io.KXmlParser.exception(+47)
at org.kxml2.io.KXmlParser.nextText(+14)
at
com.petmill.mobile.view.qanda.QuestionCanvas.setData(QuestionCanvas.java:189)
at
com.petmill.mobile.view.qanda.QuestionsList$5$1$1.actionPerformed(QuestionsList.java:119)
The error comes up at the line where I am trying to get the text - parser.nextText(). How can I parse the xml to get the data required... Thanks in advance.
It looks like you are not on the START_TAG event when you call parser.nextText(). Check that you are on a START_TAG event when you call parser.nextText() with the parser.getEventType(). I suspect that you have some whitespace between <comments> and <comment> tag and therefore your parser is not at the event that you expect it to be.
Perhaps you should also consider a safer approach for parsing this xml.
<comments>
<comment>Awesome Question #dulitha
<idComment></idComment>
</comment>
</comments>
this is not valid xml