JJTree Token Manager Declarations - java

Hi everyone I have the following code in my .jjt file for my abstract syntax tree for checking track if where the nodes are made within the file that is passed to it but I cannot access this variable from my semantic checker class.
The code is bellow and any help would be appreciated! I've tried everything and I'm losing hope at this stage.
This is the integer in the .jjt file i'd like to access
TOKEN_MGR_DECLS :
{
static int commentNesting = 0;
public static int linenumber = 0;
}
SKIP : /*STRUCTURES AND CHARACTERS TO SCAPE*/
{
" "
| "\t"
| "\n" {linenumber++;}
| "\r"
| "\f"
}
An example of one of my nodes
void VariableDeclaration() #VariableDeclaration : {Token t; String id; String type;}
{
t = <VARIABLE> id = Identifier() <COLON> type = Type()
}
My semantic checker class
public class SemanticCheckVisitor implements "My jjt file visitor" {
public Object visit(VariableDeclaration node, Object data) {
node.childrenAccept(this, data);
return data;
}
How would it be possible to get the linenumber which this node was declared?
Thanks everyone.
}

You can see an example of this in the Teaching Machine's Java parser, which is here.
First you need to modify your SimpleNode type to include a field for the line number. In the TM I added a declaration
private SourceCoords myCoords ;
where SourceCoords is a type that includes not only the line number, but also information about what file the line was in. You can just use an int field. Also in SimpleNode you need to declare some methods like this
public void setCoords( SourceCoords toSet ) { myCoords = toSet ; }
public SourceCoords getCoords() { return myCoords ; }
You might want to declare them in the Node interface too.
Over in your .jjt file, use the option
NODE_SCOPE_HOOK=true;
And declare two methods in your parser class
void jjtreeOpenNodeScope(Node n) {
((SimpleNode)n).setCoords( new SourceCoords( file, getToken(1).beginLine ) ) ;
}
void jjtreeCloseNodeScope(Node n) {
}
Hmm. I probably should have declared the methods in Node to avoid that ugly cast.
One more thing, you are keeping count of the lines yourself. It's better the get the line number from the token, like I did. Your counter will generally by one token ahead. But when the parser looks ahead, it could be several tokens ahead.
If the token manager isn't keeping count of the lines correctly, then use your own count, but communicate it to the parser through an extra added field in the Token class.
Generally it's a bad idea to compute anything in the token manager and then use it in the parser unless its information you store in the tokens.

Related

In ANTLR how to parse the nested function using java

I am new to ANTLR, I have a list of functions which are mostly of nested types.
Below are the examples for functions:
1. Function.add(Integer a,Integer b)
2. Function.concat(String a,String b)
3. Function.mul(Integer a,Integer b)
If the input is having:
Function.concat(Function.substring(String,Integer,Integer),String)
So by using ANTLR with Java program, how to define and validate whether the function names are correct and parameter count and datatypes are correct, which has to be recursive as the Function will be in deeply nested format?
validate test class:
public class FunctionValidate {
public static void main(String[] args) {
FunctionValidate fun = new FunctionValidate();
fun.test("FUNCTION.concat(1,2)");
}
private String test(String source) {
CodePointCharStream input = CharStreams.fromString(source);
return compile(input);
}
private String compile(CharStream source) {
MyFunctionsLexer lexer = new MyFunctionsLexer(source);
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MyFunctionsParser parser = new MyFunctionsParser(tokenStream);
FunctionContext tree = parser.function();
ArgumentContext tree1= parser.argument();
FunctionValidateVisitorImpl visitor = new FunctionValidateVisitorImpl();
visitor.visitFunction(tree);
visitor.visitArgument(tree1);
return null;
}
}
Visitor impl:
public class FunctionValidateVisitorImpl extends MyFunctionsParserBaseVisitor<String> {
#Override
public String visitFunction(MyFunctionsParser.FunctionContext ctx) {
String function = ctx.getText();
System.out.println("------>"+function);
return null;
}
#Override
public String visitArgument(MyFunctionsParser.ArgumentContext ctx){
String param = ctx.getText();
System.out.println("------>"+param);
return null;
}
}
System.out.println("------>"+param); this statement is not printing argument it is only printing ------>.
This task can be accomplished by implementing two main steps:
1) Parse given input and build an Abstract Syntax Tree (AST).
2) Traverse the tree and validate each function, each argument, one after another, using a Listener or a Visitor patterns.
Fortunately, ANTLR provides tools for implementing both steps.
Here's a simple grammar I wrote based on your example. It does recursive parsing and builds the AST. You may want to extend its functionality to meet your needs.
Lexer:
lexer grammar MyFunctionsLexer;
FUNCTION: 'FUNCTION';
NAME: [A-Z]+;
DOT: '.';
COMMA: ',';
L_BRACKET: '(';
R_BRACKET: ')';
WS : [ \t\r\n]+ -> skip;
Parser:
parser grammar MyFunctionsParser;
options {
tokenVocab=MyFunctionsLexer;
}
function : FUNCTION '.' NAME '('(argument (',' argument)*)')';
argument: (NAME | function);
Important thing to notice here: the parser does not make distinction between a valid (from your point of view) and invalid functions, arguments, number of arguments, etc.
So the function like Function.whatever(InvalidArg) is also a valid construction from parser's point of view. To further validate the input and test whether it meets your requirements (which is a predefined list of functions and their arguments), you have to traverse the tree using a Listener or a Visitor (I think Visitor fits here perfectly).
To get a better understanding of what it is I'd recommend reading this and this. But if you want to get deeper into the subject, you should definitely look at "The Dragons Book", which covers the topic exhaustively.

how many time the characters of string are to be found in another string

my professor gave me an exercise to find how many time the characters of string called "filter" are to be found in a second string called "query".
before I begin I am java noob and English isnt my native language.
example:
String filter="kjasd";
String query="kjg4t";
Output:2
getting how many times a char has been found in another string isnt my problem but the problem that the professor gave us some rules to stick with:
class filter. The class must be the following public
Provide interfaces:
public Filter (String letters) (→ Constructor of class)
The string representing the filter should be stored in the letters string
public boolean contains (char character)
Returns true if the passed character is contained in the query string, otherwise false
-public String toString ()
Returns an appropriate string representation of the class (just to be clear I have no clue about what does he means with this one!)
To actually determine the occurrences of the filter in the query, another class QueryResolver is to be created.
The class should be able to be used as follows:
QueryResolver resolver = new QueryResolver();
int count = resolver.where(query).matches(filter).count();
the filter and the query are given by the user.
(i couldnt understand this one! )The methods "where" and "matches" configure the "QueryResolver" to include a subsequent call of "count" the calculation based on the previously passed variables
"query" and "filter" performs.
The count method should use the filter's previously-created method.
The modifier static is not allowed to use!
I dunno if he means that we cant use static {} or we cant use public (static) boolean contains (char character){}
we are not allowed to use void
so the problems that encountered me
- I can not pass a char to the method contains as long as it is not static.
error "Non-static variable can not be referenced from a static context"
i did not understand what i should do with the method toStirng!
what I've done so far:
Approach Nr 1:
so I just wrote everything in the main method to check whether the principle of my code works or not and then I wanted to create that whole with constructor and other methods but unfortunately I did not succeed.
Approach Nr 2:
then I tried to write the code in small mthoden as in the exercise but I did not succeed !.
in both aprroaches i violated the exercise rules but i cant seem to be able to do it alone thats why i posted the question here.
FIRST APPROACH:
public class filter{
public filter(String letters) {
//constructor of the class
String filter;
int count;
}
public boolean contains (char character){
/*Subprogram without static!
*the problem that I can't pass any char to this method if it wasn't static
*and I will get the following error"Non-static variable cannot be referenced from a static context"
*I understand why I'm getting the error but I don't know how to get around it X( */
return true ;
}
public String toString (){
/*he told us to include it in the program but honestly, I don't know what shall I write in it -_-
*I make it to null because you have to return something and I don't know what to do yet
*so, for now, I let it null. */
return null;
}
public static void main(String[] args) {
Scanner in =new Scanner (System.in);
System.out.println("please enter the query string! ");
String query= in.next();
System.out.println("please enter the filter stirng!");
String filter= in.next();
System.out.println("the query string is : [" + query+ "]");
System.out.println("the filter string is : [" + filter+ "]");
int count=0;
// I initialized it temporarily because I wanted to print it!
//later I need to use it with the boolean contains as a public method
boolean contains=false;
//to convert each the query and the filter strings to chars
char [] tempArray=query.toCharArray();
char [] tempArray1=filter.toCharArray();
//to iterate for each char in the query string!
for (int i = 0; i < tempArray.length; i++) {
char cc = tempArray[i];
//to iterate for each char in the filter string!
for (int j = 0; j < tempArray1.length; j++) {
// if the value in the filter string matches the value in the temp array then increment the counter by one!
if(tempArray1[j] == cc){
count++;
contains=true;
}
}
}
System.out.println("the characters of the String ["+filter+"] has been found in the forworded string ["+query+"] exactly "+count+" times!" );
System.out.println("the boolean value : "+ contains);
in.close();
}
}
SECOND APPROACH
- But here too I violated the rules of the task quite brutally :(
- First, I used void and did not use the tostring method.
- Second, I did not use a constructor.
- I did not add comments because that's just the same principal as my first attempt.
public class filter2 {
public static void main(String[] args) {
Scanner in = new Scanner (System.in);
System.out.println("enter the filter string:");
String filterStr=in.next();
System.out.println("enter the query string:");
String querystr =in.next();
Filter(filterStr, querystr);
in.close();
}
public static void Filter(String filterstr , String querystr){
char [] tempArray1 = filterstr.toCharArray();
contains(tempArray1, querystr);
}
public static void contains(char[]tempArray1, String querystr){
boolean isThere= false ;
int counter=0;
char [] tempArray = querystr.toCharArray();
for (int i = 0; i < tempArray.length; i++) {
char cc = tempArray[i];
for (int j = 0; j < tempArray1.length; j++) {
if(tempArray1[j] == cc){
counter++;
isThere=true;
}
}
}
System.out.println("the letters of the filter string has been found in the query string exactly "+counter+" times!\nthus the boolean value is "+isThere);
}
/*
* sadly enough i still have no clue what is meant with this one nor whatshall i do
* public String toString (){
* return null;
* }
*
*/
}
Few hints and advice would be very useful to me but please demonstrate your suggestions in code because sometimes it can be difficult for me to understand what you mean by the given advice. ;)
Thank you in advance.
(sorry for the gramatical and the type mistakes; english is not my native language)
As already mentioned, it is important to learn to solve those problems yourself. The homework is not for punishment, but to teach you how to learn new stuff on your own, which is an important trait of a computer scientist.
Nonetheless, because it seems like you really made some effort to solve it yourself already, here is my solution, followed by some explanation.
General concepts
The first thing that I feel like you didn't understand is the concept of classes and objects. A class is like a 'blueprint' of an object, and the object is once you instanciated it.
Compared with something like a car, the class would be the description how to build a car, and the object would be a car.
You describe what a class is with public class Car { ... }, and instanciate an object of it with Car myCar = new Car();.
A class can have methods(=functions) and member variables(=data).
I just repeat those concepts because the code that you wrote looks like you didn't fully understand that concept yet. Please ask some other student who understood it to help you with that.
The Filter class
public class Filter{
String letters;
public Filter(String letters) {
this.letters = letters;
}
public boolean contains (char character){
for(int i = 0; i < letters.length(); i++) {
if(letters.charAt(i) == character)
return true;
}
return false;
}
public String toString (){
return "Filter(" + letters + ")";
}
}
Ok, let's brake that down.
public class Filter{
...
}
I guess you already got that part. This is where you describe your class structure.
String letters;
This is a class member variable. It is unique for every object that you create of that class. Again, for details, ask other students that understood it.
public Filter(String letters) {
this.letters = letters;
}
This is the constructor. When you create your object, this is the function that gets called.
In this case, all it does is to take an argument letters and stores it in the class-variable letters. Because they have the same name, you need to explicitely tell java that the left one is the class variable. You do this by adding this..
public boolean contains (char character){
for(int i = 0; i < letters.length(); i++) {
if(letters.charAt(i) == character)
return true;
}
return false;
}
This takes a character and looks whether it is contained in this.letters or not.
Because there is no name collision here, you can ommit the this..
If I understood right, the missing static here was one of your problems. If you have static, the function is class-bound and not object-bound, meaning you can call it without having an object. Again, it is important that you understand the difference, and if you don't, ask someone. (To be precise, ask the difference between class, object, static and non-static) It would take too long to explain that in detail here.
But in a nutshell, if the function is not static, it needs to be called on an object to work. Look further down in the other class for details how that looks like.
public String toString (){
return "Filter(" + letters + ")";
}
This function is also non-static. It is used whenever the object needs to be converted to a String, like in a System.out.println() call. Again, it is important here that you understand the difference between class and object.
The QueryResolver class
public class QueryResolver {
Filter filter;
String query;
public QueryResolver where(String queryStr) {
this.query = queryStr;
return this;
}
public QueryResolver matches(String filterStr) {
this.filter = new Filter(filterStr);
return this;
}
public int count() {
int result = 0;
for(int i = 0; i < query.length(); i++) {
if(filter.contains(query.charAt(i))){
result++;
}
}
return result;
}
}
Again, let's break that down.
public class QueryResolver {
...
}
Our class body.
Note that we don't have a constructor here. It is advisable to have one, but in this case it would be an empty function with no arguments that does nothing, so we can just leave it and the compiler will auto-generate it.
public QueryResolver where(String queryStr) {
this.query = queryStr;
return this;
}
This is an interesting function. It returns a this pointer. Therefore you can use the result of the function to do another call, allowing you to 'chain' multiple function calls together, like resolver.where(query).matches(filter).count().
To understand how that works requires you to understand both the class-object difference and what exactly the this pointer does.
The short version is that the this pointer is the pointer to the object that our function currently lives in.
public QueryResolver matches(String filterStr) {
this.filter = new Filter(filterStr);
return this;
}
This is almost the same as the where function.
The interesting part is the new Filter(...). This creates the previously discussed Filter-object from the class description and puts it in the QueryResolver object's this.filter variable.
public int count() {
int result = 0;
for(int i = 0; i < query.length(); i++) {
if(filter.contains(query.charAt(i))){
result++;
}
}
return result;
}
Iterates through the object's query variable and checks for every letter if it is contained in filter. It keeps count of how many times this happens and returns the count.
This function requires that filter and query are set. Therefore it is important that before someone calls count(), they previously call where(..) and matches(..).
In our case, all of that happens in one line, resolver.where(query).matches(filter).count().
The main function
I wrote two different main functions. You want to test your code as much as possible during development, therefore the first one I wrote was a fixed one, where you don't have to enter something manually, just click run and it works:
public static void main(String[] args) {
String filter="kjasd";
String query="kjg4t";
QueryResolver resolver = new QueryResolver();
int count = resolver.where(query).matches(filter).count();
System.out.println(count);
}
Once you understand the class-object difference, this should be straight forward.
But to repeat:
QueryResolver resolver = new QueryResolver();
This creates your QueryResolver object and stores it in the variable resolver.
int count = resolver.where(query).matches(filter).count();
Then, this line uses the resolver object to first call where, matches, and finally count. Again, this chaining only works because we return this in the where and matches functions.
Now finally the interactive version that you created:
public static void main(String[] args) {
Scanner in =new Scanner(System.in);
System.out.println("please enter the query string! ");
String query= in.next();
System.out.println("please enter the filter stirng!");
String filter= in.next();
System.out.println("the query string is : [" + query+ "]");
System.out.println("the filter string is : [" + filter+ "]");
QueryResolver resolver = new QueryResolver();
int count = resolver.where(query).matches(filter).count();
System.out.println("the characters of the String ["+filter+"] has been found in the forworded string ["+query+"] exactly "+count+" times!" );
in.close();
}

Sonarqube: How to get the expression string when writing custom java rules?

The target class is:
class Example{
public void m(){
System.out.println("Hello" + 1);
}
}
I want to get the full string of MethodInvocation "System.out.println("Hello" + 1)" for some regex check. How to write?
public class Rule extends BaseTreeVisitor implements JavaFileScanner {
#Override
public void visitMethodInvocation(MethodInvocationTree tree) {
//get the string of MethodInvocation
//some regex check
super.visitMethodInvocation(tree);
}
}
I wrote some code inspection rules using eclipse jdt and idea psi whose expression tree node has these attributes. I wonder why sonar's just has first and last token instead.
Thanks!
An old question, but I have a solution.
This works for any sort of tree.
#Override
public void visitMethodInvocation(MethodInvocationTree tree) {
int firstLine = tree.firstToken().line();
int lastLine = tree.lastToken().line();
String rawText = getRelevantLines(firstLine, lastLine);
// do your thing here with rawText
}
private String getRelevantLines(int startLine, int endLine) {
StringBuilder builder = new StringBuilder();
context.getFileLines().subList(startLine, endLine).forEach(builder::append);
return builder.toString();
}
If you want to refine further, you can also use firstToken().column or perhaps use the method name in your regex.
If you want more lines/bigger scope, just use the parent of that tree tree.parent()
This will also handle cases where the expression/params/etc span multiple lines.
There might be a better way... but I don't know of any other way. May update if I figure out something better.

Sorting by translated enum

I'm having a following problem: I have to sort entities by enum parameter. The thing is, that enum name is not equivalent to its translated name, for example, the enum values can be:
enum Sample {
Bus, Car, Train
}
However, let's say in my language, Bus corresponds to pks, Car to auto, and Train to ciuchcia, co their order should be:
Car, Train, Bus and not Bus, Car, Train. It's just an example, my problem involves something like 10 different values.
The problem is, I can't get all the data, then perform a sort in Java, because the data is paginated. I tried to solve this problem by doing this in SQL (the data is from database view):
(CASE sample WHEN 'Car' THEN 1 WHEN 'Train' THEN 2 WHEN 'Bus' THEN 3 ELSE 0 END)
I'm sorting by number, and this solution works. However, I feel like this can be done better, and doesn't need to be modified each time I want to add something. Any help would be very appreciated.
If you can hard-code or populate the translation in the enum you can make the enum generate the query.
enum Sample {
Bus("pks"), Car("auto"), Train("ciuchcia");
private final String localName;
Sample(String localName) {
this.localName = localName;
}
private static final List<Sample> inLocalOrder = Arrays.stream(values())
.sorted((a,b) -> a.localName.compareTo(b.localName))
.collect(Collectors.toList());
public static CharSequence inLocalOrder() {
StringBuilder sb = new StringBuilder("(CASE");
int i = 1;
inLocalOrder.stream().forEach(a -> sb.append(" WHEN '"+a.name()+"' THEN "+i));
sb.append(" ELSE 0 END)");
return sb;
}
}
public void test(String[] args) {
System.out.println(Sample.inLocalOrder());
}
prints:
(CASE WHEN 'Car' THEN 1 WHEN 'Train' THEN 2 WHEN 'Bus' THEN 3 ELSE 0 END)
If the translations happen later then a minor adjustment should suffice.
First things first. Why you're using an Enum to sort stuff? I can't agree with this feature, but it's ok if you really need it.
I really appreciate #OldCurmudgeon's answer, but I would have done something different.
Instead of using the property value as the column name, I would use a method to request the correct column name (obviously I'm supposing that you don't have the entities mapped inside your code, so you're using an Enum to sort them). This way:
enum Sample {
Bus, Car, Train;
public String getColumnName() {
// GET IT FROM SOME RESOURCE OR REQUEST IT FROM ANOTHER CONTEXT OR JUST RETURN IT THE WAY IT IS
// YOU CAN USE A RESOURCE FILE TO MAP YOUR COLUMN NAME, SO IF THE ENTITY CHANGES, YOU DON'T NEED
// TO UPDATE YOUR CODE...
return "";
}
public static String getSortSQL(Map<Sample, Integer> samples) {
StringBuilder sb = new StringBuilder("(CASE");
samples.forEach((sample, number) -> addSampleNumberSQL(sb, sample, number));
return sb.append(" ELSE 0 END)").toString();
}
private static StringBuilder addSampleNumberSQL(StringBuilder sb, Sample sample, Integer number) {
return sb.append(" WHEN '").append(sample.getColumnName()).append("' THEN ").append(number);
}
}
As you can see, you can request your column name from any resource you want. But this implementation still weak because if you need to sort by any new column, you will need to add another Enum value. So I would implement something more powerfull, like a properties reader that read each property from the resource and a method that receive an String (mean the property itself) and a number (to sort by the number) so I would do something like this:
public static String getSortSQL(Map<String, Integer> properties) {
StringBuilder sb = new StringBuilder("(CASE");
properties.forEach((prop, number) -> addSampleNumberSQL(sb, prop, number));
return sb.append(" ELSE 0 END)").toString();
}
private static StringBuilder addSampleNumberSQL(StringBuilder sb, String property, Integer number) {
return sb.append(" WHEN '").append(property).append("' THEN ").append(number);
}
Hope it helps you...

Searching an ArrayList

I currently have 3 classes, a main class containing a GUI, and the fnameTxtField, a customer class containing the data, and a customerList class which gathers the data from the customer class, and puts it into an array list.
Quick fix: Refactor your method to have the following signature public void searchCustomer(String text) { ... } and call it with
searchCustome(fnameTxtField.getText()).
Then you could use the variable "text" in your method, so the line
if (search.returnFamilyName().equals(fnameTxtField.getText))
changes to
if (search.returnFamilyName().equals(text))
(Or don't have any parameters at all and add the [probably] missing parentheses to fnameTxtField.getText)
Where you are using fnameTxtField.getText, Java is expecting you to declare a method parameter (kind of like declaring a variable). A parameter is information that your method is told about for one particular execution, instead of having to find out on its own.
So you are right in thinking you want something like this:
public void searchCustomer(String familyName) {
for (int i = 0; i < customer.returnID(); i++) {
customer search = search.get(i);
if (search.returnFamilyName().equals(familyName)) {
System.out.println("Index: " + i);
//removed return i;
return;
}
}
}
Then at the point of invocation (method call) specify that you want to use the value in your text field:
//...
searchCustomer(fnameTxtField.getText());

Categories