Solution: This is a workaround, but if you store a boolean 'cancel' field within your listener class, and, at the top of any exit methods, check this value and throw an exception if True, this successfully throws the ParseCancellationException.
Note that this must be done individually for each exit listener; exitEveryRule
always executes after each rule.
I believe that the reason this works and other approaches do not is due to Antlr4's error recovery attempts; upon encountering an error it attempts to rerun the visitor method multiple times, even if you have set a BailErrorStrategy
or other custom strategy.
Thank you for everyone's help, I will attach my solution as a comment below this post.
I'm working on a mini compiler project, and I was attempting to throw a ParseCancellationException
in a parseListener
class or similar exception to halt parsing upon encountering a fatal error, however this simply gets ignored during execution.
I was wondering if anyone knew a way to successfully halt parsing upon throwing an exception.
I have verified through debugging that the exception is in fact thrown, though it seems to be ignored. I have also attempted throwing RuntimeExceptions
instead, to no avail.
My program uses a stack
to store results of expressions, and for some reason EmptyStackExceptions
seem to successfully halt parsing.
Here is the code of my method I am experiencing issues with:
@Override
public void exitAddExpr(BasicLangParser.AddExprContext ctx) {
Util.Value left = stack.pop();
Util.Value right = stack.pop();
if (left.datatype==right.datatype) {
String result = switch (left.datatype) {
case INT, FLOAT -> String.valueOf((Double)left.getValue() + (Double)right.getValue());
case STRING, CHAR -> (String)left.getValue() + (String)right.getValue();
default -> throw new ParseCancellationException("Addition Error - Invalid Datatype ("+left.datatype.toString()+","+right.datatype.toString()+")");
};
stack.push(Util.Value.newValue(result));
} else {
throw new ParseCancellationException("Addition Error - Mismatched Datatypes ("+left.datatype.toString()+","+right.datatype.toString()+")");
}
super.exitAddExpr(ctx);
}
Because this code does in fact throw an exception, the 12th line stack.push()
does not run, and so later in my program I encounter the aforementioned empty stack exception.
Edit:
I am not currently attempting to catch the ParseCancellationException
within my code for now; I simply caught this exception using Intellij's debugger and enabling exception breakpoints.
I'm working on a single threaded application, so the exception is definitely not thrown on the UI thread.
I have not blocked exception propagation within my code, though I am unaware as to whether Antlr4 does this, hence my question.
The only other exception is a caught exception where I attempt to parse a String as a double in order to determine whether it is numeric.
Solution: This is a workaround, but if you store a boolean 'cancel' field within your listener class, and, at the top of any exit methods, check this value and throw an exception if True, this successfully throws the ParseCancellationException.
Note that this must be done individually for each exit listener; exitEveryRule
always executes after each rule.
I believe that the reason this works and other approaches do not is due to Antlr4's error recovery attempts; upon encountering an error it attempts to rerun the visitor method multiple times, even if you have set a BailErrorStrategy
or other custom strategy.
Thank you for everyone's help, I will attach my solution as a comment below this post.
I'm working on a mini compiler project, and I was attempting to throw a ParseCancellationException
in a parseListener
class or similar exception to halt parsing upon encountering a fatal error, however this simply gets ignored during execution.
I was wondering if anyone knew a way to successfully halt parsing upon throwing an exception.
I have verified through debugging that the exception is in fact thrown, though it seems to be ignored. I have also attempted throwing RuntimeExceptions
instead, to no avail.
My program uses a stack
to store results of expressions, and for some reason EmptyStackExceptions
seem to successfully halt parsing.
Here is the code of my method I am experiencing issues with:
@Override
public void exitAddExpr(BasicLangParser.AddExprContext ctx) {
Util.Value left = stack.pop();
Util.Value right = stack.pop();
if (left.datatype==right.datatype) {
String result = switch (left.datatype) {
case INT, FLOAT -> String.valueOf((Double)left.getValue() + (Double)right.getValue());
case STRING, CHAR -> (String)left.getValue() + (String)right.getValue();
default -> throw new ParseCancellationException("Addition Error - Invalid Datatype ("+left.datatype.toString()+","+right.datatype.toString()+")");
};
stack.push(Util.Value.newValue(result));
} else {
throw new ParseCancellationException("Addition Error - Mismatched Datatypes ("+left.datatype.toString()+","+right.datatype.toString()+")");
}
super.exitAddExpr(ctx);
}
Because this code does in fact throw an exception, the 12th line stack.push()
does not run, and so later in my program I encounter the aforementioned empty stack exception.
Edit:
I am not currently attempting to catch the ParseCancellationException
within my code for now; I simply caught this exception using Intellij's debugger and enabling exception breakpoints.
I'm working on a single threaded application, so the exception is definitely not thrown on the UI thread.
I have not blocked exception propagation within my code, though I am unaware as to whether Antlr4 does this, hence my question.
The only other exception is a caught exception where I attempt to parse a String as a double in order to determine whether it is numeric.
Share Improve this question edited Feb 16 at 17:51 Willo678 asked Feb 16 at 5:45 Willo678Willo678 77 bronze badges New contributor Willo678 is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct. 3- The exception is being caught higher up the stack. Find the catch by stepping through after your exception in debug mode. Once you have than you may have more to work with. – John Williams Commented Feb 16 at 13:10
- According to the Antlr4 documentation, this error should not be caught by the library I am using, and should instead propagate up to my own code. My question is regarding the unintended behaviour of the exception. – Willo678 Commented Feb 16 at 16:15
- So, lets find out where it's getting caught and take it from there. – John Williams Commented Feb 16 at 16:21
1 Answer
Reset to default -1This is a workaround, but if you store a boolean 'cancel' field within your listener class, and, at the top of any exit methods, check this value and throw an exception if True, this successfully throws the ParseCancellationException.
Note that this must be done individually for each exit listener; exitEveryRule always executes after each rule, which will not meet needs if an overridden method would throw its own exception.
I believe that the reason this works and other approaches do not is due to Antlr4's error recovery attempts; upon encountering an error it attempts to rerun the visitor method multiple times, even if you have set a BailErrorStrategy or other custom strategy.
The solution is as follows:
private boolean stopping = false;
private void attemptStop() {
stopping = true;
}
private void quitIfStopping() {
if (stopping) {throw new ParseCancellationException();}
}
@Override
public void exitAddExpr(BasicLangParser.AddExprContext ctx) {
quitIfStopping();
if (condition) {
String result = "example result";
stack.push(Util.Value.newValue(result));
} else {
attemptStop();
}
super.exitAddExpr(ctx);
}
`