BYACCJ: How do I include line number in my error message? - java

This is my current error handling function:
public void yyerror(String error) {
System.err.println("Error: "+ error);
}
This is the default error function I found on the BYACC/J homepage. I can't find any way to add the line number. My question is similar to this question. But the solution to it doesn't work here.
For my lexer I am using a JFlex file.

It's not that different from the bison/flex solution proposed in the question you link. At least, the principle is the same. Only the details differ.
The key fact is that it is the scanner, not the parser, which needs to count lines, because it is the scanner which converts the input text into tokens. The parser knows nothing about the original text; it just receives a sequence of nicely-processed tokens.
So we have to scour the documentation for JFlex to figure out how to get it to track line numbers, and then we find the following in the section on options and declarations:
%line
Turns line counting on. The int member variable yyline contains the number of lines (starting with 0) from the beginning of input to the beginning of the current token.
The JFlex manual doesn't mention that yyline is a private member variable, so in order to get at it from the parser you need to add something like the following to your JFlex file:
%line
{
public int GetLine() { return yyline + 1; }
// ...
}
You can then add a call to GetLine in the error function:
public void yyerror (String error) {
System.err.println ("Error at line " + lexer.GetLine() + ": " + error);
}
That will sometimes produce confusing error messages, because by the time yyerror is called, the parser has already requested the lookahead token, which may be on the line following the error or even separated from the error by several lines of comments. (This problem often shows up when the error is a missing statement terminator.) But it's a good start.

Related

Having an issue with exceptions regarding input from a .txt file

Hi I'm currently creating a program which will allow me to input the path of a .txt file with a format of:
Home Name : Away Name : Home Score : Away Score
Liverpool : Chelsea : 2 : 1
Spurs : Fulham : 1 : 1
and it should output into the console in order. However, I am having trouble with my exceptions. I am trying to get it to display so that if either parameter is missing such as the delimiter, team name/score is missing it will output an error to the console. I want it so that it will display all missing parameters and not just one. For example, Home team name is missing. Away team name is missing. No field delimiter. Invalid home score, check it is a whole number.
Any help is highly appreciated. Thanks!
The current code which I have now is:
The error is cause the first line of your file is a header
Home Name : Away Name : Home Score : Away Score
And when you will try to parse the splitted text into int, it will failed to parse and will throw an error at the following line in your code
int homeScore = Integer.parseInt(splitText[2].trim());
I hope this gives you a direction to find a solution to your question. Although it's quite difficult to 'guess' the issue as there isn't any error stacktrace.
If you want to display all errors you shouldn't use exceptions. Those are meant to be used in case something unexpected happens. Instead you should do checks like that splitText[0].length() == 0 etc. and collect all the errors. That being said, the ArrayIndexOutOfBoundsException could be replaced by a check for splitText.length < 4 (and of course the following checks need to take that into consideration as well).
That NumberFormatException could be an exception for that rule because you'd either have to check whether the string is a number and then try to parse it or just try it and catch the exception to know it isn't a number.
Your code could then look like this:
List<String> errors = new LinkedList<>();
if( splitText.length < 4) {
errors.add("Fields might be missing")
}
//do other checks here
//if all fields are present, check the numbers (this could be done in some method)
int homeScore = -1;
try {
homeScore = Integer.parseInt(splitText[2].trim());
} catch( NumberFormatException e) {
errors.add("Homescore is not an integer");
}
//other checks and then finally:
if( errors.isEmpty() ) {
//everything ok
} else {
//print the collected errors
}
Note that some checks don't make sense if others already failed, i.e. parsing away score doesn't make sense if the length of the array is smaller than 4 or if the 4th element is an empty string (at least after trimming). That would have to be taken into account.

Find comma in the parameters of a function using regex

I need to find the occurrence of a chain call functions, but must include the case where there is more than one parameter passed as (programming in java):
Tower.getType(i,j).initialPrice(f,g);
Tower.getType().initialPrice();
So far only managed to make the regex when there is only one parameter or no one:
[\w]+([.]+[\w]+[(]+[\w]*+[)]){2,}+[;]
Like:
Tower.getType().initialPrice();
object.function().function2().function3().function4().function5();
I trying this, but its not working:
[\w] + ([\.] + [\w] + [(] + [\w]* + ([\,] + [\w])* + [)]) {2,} + [;]
My code:
public static void checksMessageChain (String s) {
if (s!=null && s.matches("[\\w]+([\\.]+[\\w]+[(]+[\\w]*+[)]){2,}+[;]")) {
System.out.println("\nIts Message Chain for "+s+"\n");
splitMessageChain(s); // {0,} equivale a *
} else if (s!=null && s.matches("[\\w] + ([\\.] + [\\w] + [(] + [\\w]* + ([\\,] + [\\w])* + [)]) {2,} + [;]")) {
System.out.println("\nIts Message Chain for "+s+"\n");
splitMessageChain(s);
} else {
System.out.println("\nIts not Message Chain for "+s+"\n");
} }
I wouldn't bother with specifying the parameters and just use this :
\\w+(?:\\.\\w+\\([^)]*\\)){2,};
Note that this will fail if one String parameter contains a closing parenthesis, and it doesn't handle multi-line expressions.
As is usual for such a complex language, you'd better use a specialized parser. I have never used one, but a quick search reveals javaparser available on Github.
You can try it on regex101.
Do not try to do this using Regex: you will get an headache and a program that will not cover all possible cases.
Just use JavaParser: it is opensource, it is lightweight, it does not have dependencies.
You can either parse the whole Java file and then navigate the Abstract Syntax Tree to find your function calls or you can directly parse the single expression you are interested into, if you have already identified that piece of source code.
In the first case you want to call parse, otherwise parseExpression
Once you get your MethodCallExpr if its parent is another MethodCallExpr then you have chained calls.
Disclaimer: I am a JavaParser contributor

Java code regex not working

I am trying to add a validation utility to a program I have already created. This utility will analyze a file to ensure it meets proper parameters. I have finished the analysis for the first line and am running into a problem regarding whitespaces. The file that I am using for testing includes this line:
1459875655257 05112345678945612345678941EMMAM BANK OF AMERICA, NA BAC
The block of code that tests this line and is generating the problem is as follows:
if(immediateDestName.isEmpty()){
JOptionPane.showMessageDialog(null,
"ERROR: File header immediate destination name is missing!");
} else {
if((sCurrentLine.substring(40,63)).matches("A-Za-z0-9 ]+")){
}else{
JOptionPane.showMessageDialog(null,
"ERROR: File header immediate destination name is invalid: "
+sCurrentLine.substring(40,63));
}
}
When I run the validation utility it pops open that JOptionPane, suggesting that the name is invalid. Just FYI the actual substring is EMMAM followed by a bunch of whitespaces (hence the problem).
Can someone please help me figure out why my program is flagging this alert even though from all I can see the substring matches the regex?
Use
if (sCurrentLine.substring(40,63).matches("[A-Za-z0-9 ]+")) { .. }
I believe you missed the first bracket. This will match any character that is A-Z, a-z, 0-9 or a space.

JSP: Pass Special Characters in response.setHeader?

I am getting stuck in a basic JSP Operation. I want to a new line so i have added \n in the end but it throws me an exception. If i remove \n everything works fine
Exception
java.lang.IllegalArgumentException: Invalid LF not followed by whitespace
Class File
StringBuilder junitLog = new StringBuilder();
junitLog.append("The class that is being executed : " + description.getClassName() +"\n");
junitLog.append("Number of testcases to execute : " + description.testCount()+"\n");
/**
* #return the junitLog
*/
public StringBuilder getJunitLog() {
return junitLog;
}
/**
* #param junitLog the junitLog to set
*/
public void setJunitLog(StringBuilder junitLog) {
this.junitLog = junitLog;
}
JSP:-
response.setHeader("finalJUNITReport",""+ junitListener.getJunitLog());
try Base64 encoding them before you set in headers and Base64 decoding them when you want to read them back.
As long as you think to it in the OO way, you can wonder why you couldn't put new line in your headers.
But as soon as you think that it will be transmitted using HTTP protocol, it becomes evident : a HTTP message (request or response) is nothing else than a sequential serie of bytes. For HTTP, the header section comes first and is composed of lines like that :
HEADER_NAME: header value
If you put a new line in a header value, anything that would follow would be considered as a new header. And if you put 2 consecutive new lines that would denote the end of the header section.
All you can do is to use "\n ", because a line beginning with a space if supposed to be a continuation line.
That's the reason of the error message Invalid LF not followed by whitespace, and hopefully it was there, because you would have send an incorrect header section what could be harder to detect ...
I howeva suceeded in my requirement. :)
As clearly stated by Serge Ballesta.
If you put a new line in a header value, anything that would follow would be considered as a new header..
So below is the logic i applied based on my requirement.
Below were my code changes:
junitLog.append("The class that is being executed : " + description.getClassName() +"?");
junitLog.append("Number of testcases to execute : " + description.testCount()+"?");
I added a question mark at the end of the string. THe string became something as mentioned below.
The class that is being executed : testCreateHaulier? Number of testcases to execute : 39?
I passed the String from JSP using response.setHeader Code as below:
response.setHeader("finalJUNITReport",""+ junitListener.getJunitLog());
and in my java class file i did something like this:
junitReportString=yc.getHeaderField("finalJUNITReport").toString();
System.out.println(junitReportString);
junitReportString=junitReportString.replaceAll("\\?", "\n");
System.out.println("Report Details ==============>"+junitReportString);
Using replaceAll i replaced all question marks to new line and my requirement was done.
Hope it helps others too.:)

ANTLR4 Lexer error reporting (length of offending characters)

I'm developing a small IDE for some language using ANTLR4 and need to underline erroneous characters when the lexer fails to match them. The built in org.antlr.v4.runtime.ANTLRErrorListener implementation outputs a message to stderr in such cases, similar to this:
line 35:25 token recognition error at: 'foo\n'
I have no problem understanding how information about line and column of the error is obtained (passed as arguments to syntaxError callback), but how do I get the 'foo\n' string inside the callback?
When a parser is the source of the error, it passes the offending token as the second argument of syntaxError callback, so it becomes trivial to extract information about the start and stop offsets of the erroneous input and this is also explained in the reference book. But what about the case when the source is a lexer? The second argument in the callback is null in this case, presumably since the lexer failed to form a token.
I need the length of unmatched characters to know how much to underline, but while debugging my listener implementation I could not find this information anywhere in the supplied callback arguments (other than extracting it from the supplied error message though string manipulation, which would be just wrong). The 'foo\n' string may clearly be obtained somehow, so what am I missing?
I suspect that I might be looking in the wrong place and that I should be looking at extending DefaultErrorStrategy where error messages get formed.
You should write your lexer such that a syntax error is impossible. In ANTLR 4, it is easy to do this by simply adding the following as the last rule of your lexer:
ErrorChar : . ;
By doing this, your errors are moved from the lexer to the parser.
In some cases, you can take additional steps to help users while they edit code in your IDE. For example, suppose your language supports double-quoted strings of the following form, which cannot span multiple lines:
StringLiteral : '"' ~[\r\n"]* '"';
You can improve error reporting in your IDE by using the following pair of rules:
StringLiteral : '"' ~[\r\n"]* '"';
UnterminatedStringLiteral : '"' ~[\r\n"]*;
You can then override the emit() method to treat the UnterminatedStringLiteral in a special way. As a result, the user sees a great error message and the parser sees a single StringLiteral token that it can generally handle well.
#Override
public Token emit() {
switch (getType()) {
case UnterminatedStringLiteral:
setType(StringLiteral);
Token result = super.emit();
// you'll need to define this method
reportError(result, "Unterminated string literal");
return result;
default:
return super.emit();
}
}

Categories

Resources