Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
How can I throw the custom error message from the grammar file to the java class(where the parsing and lexing are defined)?
<----------Parser Grammar----------->
parser grammar EParser;
#members {
public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
String hdr = getErrorHeader(e);
String msg = getErrorMessage(e, tokenNames);
System.out.println("hdr and msg...."+hdr+">>>>>>"+msg);
throw new RuntimeException(hdr + ":" + msg);
}
}
prog
: stat+
;
stat
: expr SEMI
| ID EQU expr SEMI
;
expr
: multExpr ((PRM) multExpr)*
;
multExpr
: atom (MUL atom)*
;
atom
:INT| OPEN expr CLS
;
<-------------------Java code--------------->
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
public class TestE {
public static void main(String[] args) throws Exception {
ELexer lexer = new ELexer(new ANTLRStringStream("a=9+8;"));
EParser parser = new EParser(new CommonTokenStream(lexer));
try
{
parser.prog();
System.out.println("Parsing successfully...");
}
catch (Exception e)
{
System.out.println("Other exception : " + e.toString());
}
}
}
<------------------Lexer grammar-------------->
lexer grammar ELexer;
tokens
{
ID;
INT;
WS;
EQU;
PRM;
OPEN;
CLS;
SEMI;
MUL;
}
#members {
Stack<String> paraphrase = new Stack<String>();
}
ID :('a'..'z'|'A'..'Z')+ ;
INT : '0'..'9'+ ;
EQU:'=';
PRM:'+'|'-';
OPEN:'(';
SEMI:';';
CLS :')';
MUL:'*';
WS : (' '|'\t'|'\n'|'\r')+ {skip();} ;
Here my input is a=9+8.
When I miss 8 it must give the error message as "Expecting an integer", and when I miss ; it must say "Missing semicolon".
Like this I have to produce the error message (I don't want the default error message that was produced by the antlr, I need my own error msgs).
How can I achieve this? Whether I have to write the error messages in the grammar file? Or the java code?
You don't need to throw custom errors in your grammar. Instead you install your custom error handler and handle exceptions in there. I have written a fairly complete error handling (however, for the ANTLR3 C target). It might give you some hints what you can use to construct your own error messages.
For Java target, you might want to override one or more of these methods:
org.antlr.runtime.BaseRecognizer.getErrorHeader()
creates error header (where in the input the error occurred)
org.antlr.runtime.BaseRecognizer.getErrorMessage()
creates the error message itself (what happened)
org.antlr.runtime.BaseRecognizer.emitErrorMessage()
displays the error (by default on error output / console)
org.antlr.runtime.BaseRecognizer.displayRecognitionError()
glues it all together:
public void displayRecognitionError(String[] tokenNames,
RecognitionException e)
{
String hdr = getErrorHeader(e);
String msg = getErrorMessage(e, tokenNames);
emitErrorMessage(hdr+" "+msg);
}
You can override them in #members section of the grammar as you already did with displayRecognitionError(), or if it's longer code it's more convenient to subclass the org.antlr.runtime.Parser and put superClass = MyParser; in the grammar's options section (note that to do it this way for lexer errors as well, you'll have to create a subclass of org.antlr.runtime.Lexer as well for the lexer to use).
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I'm very new to the coding space and was wondering if someone could help me start a .jar file. BTW This is using C#. My issue is this wont run the file. I got it to work with .txt files though, so I'm just a bit confused.
private void button1_Click(object sender, EventArgs e)
{
Process.Start("java" , "server.jar");
}
In short, for the answer, add -jar right before the JAR file name.
The accepted answer is not 100% correct for several reasons: it does not recognize whitespace-delimited and whitespace-containing arguments, and may mess up with quote characters that must be passed (therefore properly escaped) to the delegated Java app. In short, do not use Arguments if the string is not known to be a constant (having spaces will require manual escaping anyway), but merely prefer ArgumentList that handles each argument properly.
Here is an example Java application to deal with command line arguments:
public final class SayHello {
private SayHello() {}
public static void main(final String... names) {
for ( final String name : names ) {
System.out.printf("hello %s!\n", name);
}
}
}
The manifest for the JAR file:
Manifest-Version: 1.0
Main-Class: SayHello
Making a JAR file out of it is simple:
javac SayHello.java
jar cfm SayHello.jar MANIFEST.MF SayHello.class
Example of use:
java -jar SayHello.jar 'John Doe' Anonymous
that gives:
hello John Doe!
hello Anonymous!
Now, an example C# program that passes the -jar argument to the java process so that it recognizes the given file as a JAR file and demonstrates what can go wrong with Arguments if passed as a string.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
</Project>
using System.Diagnostics;
public static class SayHello {
public static void Main() {
// interprets 3 names: John, Doe, Anonymous (wrong)
RunJavaJarBadly1("SayHello.jar", "John Doe Anonymous");
// interprets 1 name: John Doe Anonymous (wrong)
RunJavaJarBadly2("SayHello.jar", "John Doe Anonymous");
// interprets 2 names: John Doe, Anonymous (correct, but bad: requires the first name to be quoted at the call-site)
RunJavaJarBadly1("SayHello.jar", "\"John Doe\" Anonymous");
// interprets 1 name: "John Doe" Anonymous (wrong: interprets everything as a single name)
RunJavaJarBadly2("SayHello.jar", "\"John Doe\" Anonymous");
// interprets 2 names, no ambiguous call, each name is recognized properly, does not require quoting at the call site
RunJavaJar("SayHello.jar", "John Doe", "Anonymous");
}
private static void RunJavaJarBadly1(string jarPath, string argumentsFortheJarFile) {
var process = new Process();
process.StartInfo.FileName = "java";
process.StartInfo.Arguments = #"-jar "+ jarPath +" " + argumentsFortheJarFile;
process.Start();
process.WaitForExit();
}
private static void RunJavaJarBadly2(string jarPath, string jarArgs) {
var process = new Process();
process.StartInfo = new ProcessStartInfo("java") {
ArgumentList = { "-jar", jarPath, jarArgs }
};
process.Start();
process.WaitForExit();
}
private static void RunJavaJar(string jarPath, params string[] jarArgs) {
var process = new Process();
process.StartInfo = new ProcessStartInfo("java") {
ArgumentList = { "-jar", jarPath }
};
foreach ( var jarArg in jarArgs ) {
process.StartInfo.ArgumentList.Add(jarArg);
}
process.Start();
process.WaitForExit();
}
}
The code above produces (no legend in the output, but added for explanation):
hello John! \_ #1/1: incorrect, the space is ignored
hello Doe! /
hello Anonymous! -- #1/2: correct, no spaces in-between
hello John Doe Anonymous! -- #2/1|2: incorrect
hello John Doe! -- #3/1: correct, but requires the call site to escape the argument
hello Anonymous! -- #3/2: correct, no need to escape, thanks to no spaces
hello "John Doe" Anonymous! -- #4/1|2: incorrect, similar to #2/1|2
hello John Doe! -- #5/1: correct, let the framework do its job
hello Anonymous! -- #5/2: correct, let the framework do its job
In order to get it to work, the file name needs to be "java" and contain the file location in the arguments.
System.Diagnostics.Process clientProcess = new Process();
clientProcess.StartInfo.FileName = "java";
clientProcess.StartInfo.Arguments = #"-jar "+ jarPath +" " + argumentsFortheJarFile;
clientProcess.Start();
clientProcess.WaitForExit();
int code = clientProcess.ExitCode;
Taken from similar question here
Optional way using ArgumentList:
System.Diagnostics.Process clientProcess = new Process();
var info = new System.Diagnostics.ProcessStartInfo("java.exe")
{
ArgumentList = {
"-jar",
jarPath,
jarArgs
}
};
info.FileName = "java";
clientProcess.StartInfo = info;
clientProcess.Start();
clientProcess.WaitForExit();
int code = clientProcess.ExitCode;
Here are some options for you to check out.
Also similar question with a working result: here
Paraphrasing from links:
In order to get it to work, the file name needs to be "java" and contain the file location in the arguments.
System.Diagnostics.Process clientProcess = new Process();
clientProcess.StartInfo.FileName = "java";
clientProcess.StartInfo.Arguments = #"-jar "+ jarPath +" " + argumentsFortheJarFile;
clientProcess.Start();
clientProcess.WaitForExit();
int code = clientProcess.ExitCode;
I'm trying to use the xQuery API for java s9api, however when I try to declare a namespace and run a simple rule to test it I restore the error "XPST0003: XQuery syntax error in
# ... if (funcJavaDict: CheckString #
Unexpected token "if (" beyond end of query "
Acretido is an easy error to solve, but I'm not getting to the solution,
The Java code snippet is:
//Declara namespace de funções java para usar nas regras
comp.declareNamespace ("funcJavaDict", "java:Rastreamento.retratos.DictionaryTerms");
comp.declareNamespace ("xmi", "http://www.omg.org/XMI");
//compila regra do arquivo
XQueryExecutable exp = null;
try {
exp = comp.compile("return /n"+
"if ( funcJavaDict:CheckString("em andamento","EM Andamento") ) then /n" +
" String("são iguais") /n"
"else /n"+
" String("são diferente") ");
}catch (SaxonApiException e) {
e.printStackTrace();
}
//carrega e executa regra
XQueryEvaluator Eval = exp.load();
XdmValue rs = null;
try {
rs = Eval.evaluate();
} catch (SaxonApiException e) {
e.printStackTrace();
}
the code is very simple is just to check if two string's are equivalent.
Firstly, I'm puzzled by your Java snippet because it won't compile (because of the nested quotes), so I don't see how you get as far as Saxon reporting an XQuery syntax error. Also I imagine that the '/n' should really be '\n'. So let's suppose the Java actually says:
comp.compile("return \n"+
"if ( funcJavaDict:CheckString('em andamento','EM Andamento') ) then \n" +
" String('são iguais') \n"
"else \n"+
" String('são diferente') ");
XQuery keywords are recognized only if they appear in the right context. "return" at the start of an expression is not recognized as a keyword, so it is interpreted as a path expression meaning child::element(return).
(In fact recent Saxon releases will often report a warning if you use a keyword incorrectly like this, but it's not catching this particular case).
So "return" is a complete expression that selects child elements named return, and the only thing that can come after a complete expression is either the end of the input, or an infix operator such as and or union. The keyword if is not either of these things, so the compiler reports a syntax error. The solution is to remove the return keyword.
But that's not the only thing wrong with your query. There is no function named String. You could change it to string and the query would work, but writing string('xyz') is just a long-winded way of writing 'xyz', so better to drop the function call entirely.
I would like to have a printed usage help message, when option which is specified as an program argument is not valid (not available in predefined options list).
CommandLineParser parser = new BasicParser();
try {
CommandLine line = parser.parse(getOptions(), args);
}
catch( ParseException exp ) {
getLogger().info("Invalid command line option name. "+exp.getMessage());
HelpFormatter hf = new HelpFormatter();
hf.printHelp("destDir", getOptions());
return false;
}
return true;
I type as an parameter 'Test' string. I was thinking, that invalid options cause parser to throw ParseException, however it's not. How can I achieve that behaviour ? Is it possible with this library at all ? Now it just ommit paremeters which are not valid.
UPDATE
Actually it throws exception when option has a '-' prefix. So '-Test' cause throwing exception, but 'Test' not. My question anyway is still valid, how to force parser to throw exception on invalid parameter
Command lines have two types of entry other than the program name, Options (which are specified with a - or --) and what I will call parameters (which probably have a better name but I don't know what it is!) which don't have a prefix. For example, for ls:
ls -la foo
The options are -l and -a, and parameter is foo (the directory to list). When you parse a command line with commons-cli it only cares about the options, it ignores everything else. Which is why it doesn't fail if you add Test (not an option) but does if you add -Test.
Although answer provided by adamreeve is really fine and I accept it, I've decided to extend default parser capabilities to prevent typing invalid option even without '-' or '--' symbols. I made my own custom parser :
public class StrictParser extends Parser {
#Override
protected String[] flatten(Options opts, String[] arguments, boolean stopAtNonOption) {
return arguments;
}
#Override
public CommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException {
CommandLine cmd = null;
List<String> tokenList = Arrays.asList(flatten(getOptions(), arguments, stopAtNonOption));
ListIterator<String> iterator = tokenList.listIterator();
boolean eatTheRest = false;
setOptions(options);
cmd = super.parse(options, arguments, stopAtNonOption);
while (iterator.hasNext()) {
String token = (String) iterator.next();
if (!token.startsWith("--") && !token.startsWith("-")) {
if (stopAtNonOption) {
throw new UnrecognizedOptionException("Unrecognized option: " + token +". Every option must start with '--' or '-'", token);
}
} else {
eatTheRest = true;
}
if (eatTheRest) {
iterator.next();
}
}
return cmd;
}
}
In this solution any cli parameters typed without '--' or '-' throw UnrecognizedOptionException. This is no perfect solution, but it show how it can be done, and can be a good starting point to other solutions. For instance we could accept options without '--' and '-' but check if that option is correct. Then we need to change
if (stopAtNonOption) {
throw new UnrecognizedOptionException("Unrecognized option: " + token +". Every option must start with '--' or '-'", token);
}
to
if (stopAtNonOption) {
if(!getOptions().hasOption(token)){
throw new UnrecognizedOptionException(
"Unrecognized option: " + token, token);
}
}
(ignore this ugly three nested ifs ;))
This also accepts only one argument per option,but as I've mentioned it's only starting point to implement other modifications to default parser
Yes you can , you have to create custom Exception like:
public class ParseException extends Exception{
ParseException(String msg){
super(msg);
}
}
And into code :
CommandLineParser parser = new BasicParser();
try {
CommandLine line = parser.parse(getOptions(), args);
}
catch( Exception exp ) {
throw new ParseException("Invalid Arguments");
}
return true;
And above method should throw
throws ParseException
So its caller if pass invalid argument will get ParseException
I am trying to develop a new language with Antlr. Here is my grammar file :
grammar test;
program : vr'.' to'.' e
;
e: be
| be'.' top'.' be
;
be: 'fg'
| 'fs'
| 'mc'
;
to: 'n'
| 'a'
| 'ev'
;
vr: 'er'
| 'fp'
;
top: 'b'
| 'af'
;
Whitespace : [ \t\r\n]+ ->skip
;
Main.java
String expression = "fp.n.fss";
//String expression = "fp.n.fs.fs";
ANTLRInputStream input = new ANTLRInputStream(expression);
testLexer lexer = new testLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
testParser parser = new testParser(tokens);
//remove listener and add listener does not work
ParseTree parseTree = parser.program();
Everything is good for valid sentences. But I want to catch unrecognized tokens and invalid sentences in order to return meaningful messages. Here are two test cases for my problem.
fp.n.fss => anltr gives this error token recognition error at: 's' but i could not handle this error. There are same example error handler class which use BaseErrorListener but in my case it does not work.
fp.n.fs.fs => this sentence is invalid for my grammar but i could not catch. How can i catch invalidations like this sentence?
Firstly welcome to SO and also to the ANTLR section! Error handling seems to be one of those topics frequently asked about, theres a really good thread here about handling errors in Java/ANTLR4.
You most likely wanted to extend the functionality of the defaultErrorStrategy to handle the particular issues and handle them in a way differently that just printing the error line 1:12 token recognition error at: 's'.
To do this you can implement your own version of the default error strategy class:
Parser parser = new testParser(tokens);
parser.setErrorHandler(new DefaultErrorStrategy()
{
#Override
public void recover(Parser recognizer, RecognitionException e) {
for (ParserRuleContext context = recognizer.getContext(); context != null; context = context.getParent()) {
context.exception = e;
}
throw new ParseCancellationException(e);
}
#Override
public Token recoverInline(Parser recognizer)
throws RecognitionException
{
InputMismatchException e = new InputMismatchException(recognizer);
for (ParserRuleContext context = recognizer.getContext(); context != null; context = context.getParent()) {
context.exception = e;
}
throw new ParseCancellationException(e);
}
});
parser.program(); //back to first rule in your grammar
I would like to also recommend splitting your parser and lexer grammars up, if not for readability but also because many tools used to analyse the .g4 file (ANTLRWORKS 2 particularly) will complain about implicity declarations.
For your example it can be modified to the following structure:
grammar test;
program : vr DOT to DOT e
;
e: be
| be DOT top DOT be
;
be: FG
| FS
| MC
;
to: N
| A
| EV
;
vr: ER
| FP
;
top: B
| AF
;
Whitespace : [ \t\r\n]+ ->skip
;
DOT : '.'
;
A: 'A'|'a'
;
AF: 'AF'|'af'
;
N: 'N'|'n'
;
MC: 'MC'|'mc'
;
EV:'EV'|'ev'
;
FS: 'FS'|'fs'
;
FP: 'FP'|'fp'
;
FG: 'FG'|'fg'
;
ER: 'ER'|'er'
;
B: 'B'|'b'
;
You can also find all the methods available for the defaultErrorStrategy Class here and by adding those methods to your "new" error strategy implementation handle whatever exceptions you require.
Hope this helps and Good luck with your project!
I'm making a JavaCC program to accept a certain language. I've done this but cannot understand how to use a generated ParseException to determine the issue in the input, and customise the output error message.
So far my code looks like:
try {
task parser = new task(System.in);
parser.start();
System.out.println("YES"); // If accepted print YES.
} catch (ParseException e) {
System.out.println("NO"); // If rejected print NO.
switch (e) {
case 1:
System.err.println("Some error case")
case 2:
...
}
}
Some sources I've looked at are the documentation for ParseException and the JavaCC error handling pages. Neither have helped me understand much better.
If anyone could help/hint I would be really thankful.
You can always throw a ParseException with a custom string. For example
void Primary() : {}
{
<INT>
|
"("
|
{throw new ParseException("At "+getCoords()
+" there was \""+ getToken(1).image
+ "\", but the parser expected either"
+ " a \"(\" or an integer literal.");}
}
If you are willing to go to enough effort, it should be possible to create a parser that never throws a ParseException that doesn't have a custom message.