Precedence and Associativity - Grammar Mistake using JavaCC - grammar

I'm having a problem with my grammar and I don't really know how to solve it. I'm facing the issue with precedence and associativity in operations. I included the whole grammar but I avoided to put all the Tokens otherwise it'd be too long.
PARSER_BEGIN(UcParse)
Node Start() :
{
Node tree = new Node(Id.PROGRAM);
Node td;
}
{
( td = TopLevelDeclaration() { tree.add(td); }
)*
<EOF> { return tree; }
}
Node TopLevelDeclaration() :
{
Node n;
}
{
LOOKAHEAD(3)
n = Declaration() <SEMI> { return n; }
| n = Function() { return n; }
| n = IncludeFile() {return n; }
}
Node Function() :
{
Node tld = new Node(Id.FUNC);
Node bt;
Node dr;
Node body;
Node formals;
Node s;
}
{
bt = ReturnType() { tld.add(bt); }
Declarator(tld)
(
FunctionParameters(tld)
(
body = CompoundStatement() { tld.add(body); }
|
<SEMI>
)
| { }
)
{ return tld; }
}
//List FunctionParameters () :
void FunctionParameters (Node func) :
{
Node f;
}
{
<LPAREN>
(
<VOID> { func.add(new Node(Id.VOID)); }
|
f = Declaration() { func.add(f); }
( <COMMA>
f = Declaration() { func.add(f); }
)*
)
<RPAREN>
}
Node Declaration () :
{
Node d = new Node(Id.VARDEC);
Node bt;
Node dr;
}
{
bt = DeclarationType() { d.add(bt); }
Declarator(d) { return d; }
}
Node SimpleDeclaration () :
{
Node d = new Node(Id.VARDEC);
Node bt;
Node id;
}
{
bt = DeclarationType() { d.add(bt); }
id = Identifier() { d.add(id); }
<SEMI>
{ return d; }
}
Node ReturnType () :
{}
{
<CHAR> { return new Node(Id.CHAR); }
| <INT> { return new Node(Id.INT); }
| <VOID> { return new Node(Id.VOID); }
}
Node DeclarationType () :
{}
{
<CHAR> { return new Node(Id.CHAR); }
|
<INT> { return new Node(Id.INT); }
}
void Declarator (Node p) :
{
Node id;
Node r;
}
{
id = Identifier() { p.add(id); }
( <LBRACK>
( r = IntegerLiteral() { p.add(r); } ) *
<RBRACK>
|
{ }
)
}
Node CompoundStatement () :
{
Node cs = new Node(Id.COMPOUND_STMNT);
Node d;
Node s;
}
{
<LBRACE>
( d = Declaration() { cs.add(d); }
<SEMI>
)*
( s = Statement() { cs.add(s); }
)*
<RBRACE>
{ return cs; }
}
Node Statement() :
{
Node stmt = new Node(Id.STMNT);
Node s;
Token t;
Node c;
Node s1;
Node s2;
}
{
(s = SimpleCompoundStatement() { stmt.add(s); }
|
Expression(stmt)
<SEMI> // expr;
|
<SEMI> { stmt.add(new Node(Id.EMPTY_STMNT)); } //;
|
t = { s = new Node(Id.IF); stmt.add(s); }
<LPAREN>
Expression(s)
<RPAREN>
s1 = Statement() { s.add(s1); }
( LOOKAHEAD(1)
<ELSE>
s2 = Statement() { s.add(s2); } ) *
|
t = <WHILE> { s = new Node(Id.WHILE); stmt.add(s); }
<LPAREN>
Expression(s)
<RPAREN>
s2 = Statement() { s.add(s2); }
|
(Expression(stmt)) *
<SEMI>) //return expr*;
{ return stmt; }
}
Node SimpleCompoundStatement() :
{
Node scs = new Node(Id.SIMPLE_COMPOUND_STMNT);
Token left;
Token right;
Node s;
}
{
left = <LBRACE>
( s = Statement() { scs.add(s); }
)*
right = <RBRACE>
{ return scs; }
}
void Expression (Node e) :
{
Node exp;
Node id;
Node p;
Node op;
}
{
(
op = IntegerLiteral()
OperatorExpression(e, op)
|
exp = CharLiteral()
OperatorExpression(e, exp)
|
<LPAREN> { p = new Node(Id.PAREN); }
Expression(p)
<RPAREN>
OperatorExpression(e, p)
| id = Identifier()
( <LBRACK>
Expression(e)
<RBRACK>
| <LPAREN>
(
Expression(e)
( <COMMA>
Expression(e)
)*
| { } )
<RPAREN>
| { }
)
OperatorExpression(e, id)
|
exp = Unary()
Expression(e)
OperatorExpression(e, exp)
)
}
void OperatorExpression(Node par, Node op) :
{
Node n;
Node p;
}
{
( LOOKAHEAD(2)
n = BinaryMulDiv() { par.add(n); }
{ n.add(op); }
Expression(n)
| OperatorExpressionPlusMin(par, op) )
}
void OperatorExpressionPlusMin(Node par, Node op) :
{
Node n;
}
{
( LOOKAHEAD(2)
n = BinaryPlusMin() { par.add(n); }
{ n.add(op); }
Expression(n)
| OperatorExpressionComp(par, op))
}
void OperatorExpressionComp(Node par, Node op) :
{
Node n;
}
{
( LOOKAHEAD(2)
n = BinaryComp() { par.add(n); }
{ n.add(op); }
Expression(par)
| {} {par.add(op);} )
}
Node BinaryComp () :
{
Token t;
}
{
(t = <LT> // >
|
t = <GT> // // // >=
|
t = <EQ> // =
|
t = <EQEQ> // ==
|
t = <NOTEQ> // !=
|
t = <ANDAND> // &&
|
t = <OROR>) // ||
{return new Node(Id.BINARY, t.image); }
}
Node BinaryMulDiv () :
{
Token t;
}
{
(t = <MUL> // *
|
t = <DIV>) // /
{return new Node(Id.BINARY, t.image); }
}
Node BinaryPlusMin () :
{
Token t;
}
{
(t = <PLUS> // +
|
t = <MINUS>) // -
{return new Node(Id.BINARY, t.image); }
}
Node Unary() :
{
Token t;
}
{
t = <MINUS> { return new Node(Id.UNARY, t.image); }
|
t = <NOT> { return new Node(Id.UNARY, t.image); } // !
}
Node Identifier() :
{
Token t;
}
{
t = <IDENT> { return new Node(Id.IDENT, t.image); }
}
Node IntegerLiteral() :
{
Token t;
}
{
t = <INTEGER_LITERAL>
{ return new Node(Id.INTEGER_LITERAL, t.image); }
}
Node CharLiteral() :
{
Token t;
}
{
t = <CHAR_LITERAL>
{ return new Node(Id.CHAR_LITERAL, t.image); }
}
Node FileName() :
{
Token dot;
}
{
(<IDENT> <DOT> <IDENT>)
{ return new Node(Id.FILE_NAME); }
}
Node IncludeFile() :
{
Node include = new Node(Id.INCLUDE);
Node name;
Token incl;
Token lt;
Token gt;
}
{
incl = <INCLUDE>
lt = <LT>
name = FileName() { include.add(name); }
gt = <GT>
{ return include; }
}
This is the program I'm using for my tests.
int main(void) {
int i;
1!=!3;
4&&(6);
7* 8+10; // wrong tree
10+8*7; // right tree
(11-12)+(12/16);
17=27>28;
}
I guess that the part that doesn't work in my grammar is the OperatorExpression() because when I print the syntax tree for the code above, I obtain two different branches for those line I put a comment in.
Here the syntax tree
PROGRAM
FUNC
INT
IDENT ( main )
VOID
COMPOUND_STMNT
VARDEC
INT
IDENT ( i )
STMNT
BINARY ( != )
INTEGER_LITERAL ( 1 )
INTEGER_LITERAL ( 3 )
UNARY ( ! )
STMNT
BINARY ( && )
INTEGER_LITERAL ( 4 )
PAREN
INTEGER_LITERAL ( 6 )
STMNT
BINARY ( * )
INTEGER_LITERAL ( 7 )
BINARY ( + )
INTEGER_LITERAL ( 8 )
INTEGER_LITERAL ( 10 )
STMNT
BINARY ( + )
INTEGER_LITERAL ( 10 )
BINARY ( * )
INTEGER_LITERAL ( 8 )
INTEGER_LITERAL ( 7 )
STMNT
BINARY ( + )
PAREN
BINARY ( - )
INTEGER_LITERAL ( 11 )
INTEGER_LITERAL ( 12 )
PAREN
BINARY ( / )
INTEGER_LITERAL ( 12 )
INTEGER_LITERAL ( 16 )
STMNT
BINARY ( = )
INTEGER_LITERAL ( 25 )
BINARY ( > )
INTEGER_LITERAL ( 27 )
INTEGER_LITERAL ( 28 )
Any help is really appreciate! Thanks

There is a write up called Parsing Expressions by Recursive Descent, which outlines 3 approaches to getting precedence and associativity right in recursive descent parsers. All three techniques can be applied to JavaCC parsers. The second one (the "classic" algorithm) is probably simplest to use.

Related

How to implement an AST given a grammar with JJTree

I'm trying to implement a parser from LaTeX to HTML, to complete my exercise I need to write a JavaCC grammar, generate the Abstract syntax tree and implement a visitor to parse the code.
I've written my .jj grammar file, now I'm confused about how to use jjtree to generate the AST based on grammar file. Anyone can help me?
Here you are my grammar file, if it can help.
ArrayList<LaTeXObject> LaTeX() :
{
ArrayList<LaTeXObject> objects;
}
{
objects = ObjectList() <EOF>
{
return objects;
}
}
ArrayList<LaTeXObject> ObjectList() :
{
ArrayList<LaTeXObject> objects = new ArrayList<LaTeXObject>();
LaTeXObject object;
}
{
( object = Object() { objects.add(object); } )*
{
return objects;
}
}
LaTeXObject Object() :
{
LaTeXObject object;
}
{
(
object = Command()
|
object = Group()
|
object = String()
)
{
return object;
}
}
LaTeXCommand Command() :
{
String name;
}
{
<BACKSLASH>
(
name = Name() Whitespace()
|
name = SpecialCharacter()
|
name = NonSpecialCharacter()
)
{
return new LaTeXCommand(name);
}
}
String Name() :
{
StringBuilder sb = new StringBuilder();
Token token;
}
{
token = <ASCII_LETTER> { sb.append(token.image); } ( LOOKAHEAD( <ASCII_LETTER> ) token = <ASCII_LETTER> { sb.append(token.image); } )*
{
return sb.toString();
}
}
void Whitespace() :
{}
{
( LOOKAHEAD( WhitespaceCharacter() ) WhitespaceCharacter() )*
}
String WhitespaceCharacter() :
{
Token token;
}
{
token = <WHITESPACE>
{
return token.image;
}
}
String SpecialCharacter() :
{
Token token;
}
{
(
token = <BACKSLASH>
|
token = <LBRACE>
|
token = <RBRACE>
|
token = <SPECIAL>
)
{
return token.image;
}
}
String NonSpecialCharacter() :
{
Token token;
}
{
token = <NON_SPECIAL>
{
return token.image;
}
}
LaTeXGroup Group() :
{
ArrayList<LaTeXObject> objects;
}
{
<LBRACE> objects = ObjectList() <RBRACE>
{
return new LaTeXGroup(objects);
}
}
LaTeXString String() :
{
StringBuilder sb = new StringBuilder();
String string;
}
{
string = TextCharacter() { sb.append(string); } ( LOOKAHEAD( TextCharacter() ) string = TextCharacter() { sb.append(string); } )*
{
return new LaTeXString(sb.toString());
}
}
String TextCharacter() :
{
Token token;
}
{
(
token = <WHITESPACE>
|
token = <NON_SPECIAL>
|
token = <SPECIAL>
|
token = <ASCII_LETTER>
|
token = <ASCII_DIGIT>
|
token = <LATIN_SUPPLEMENT>
|
token = <UNICODE_LETTER>
)
{
return token.image;
}
}
So what you have now does build an abstract syntax tree. If you are happy with that, you don't need JJTree at all.
If you really want to use JJTree, you should strip out all the code that makes LatexObjectobjects. Just make all your nonterminal productions return void. Also rename the file from .jj to .jjt. Now run JJTree with your .jjt files as input. Low and behold you'll have a new .jj file that builds an abstract syntax tree. Now fiddle with the .jjt file until the abstract syntax tree it produces is one you are happy with.

how to find the first and follow values of grammar

i have the following grammar and i would like to create the First & follow table. if i have a case that the first of non terminal is epsilon should i take also all the terminals that came after this non terminal from is rule?
S-> ABC
A->Aa/aB
B->Bb/epsilon
C->Cc/epsilon
and my question is:
in the first of C i need to get First(C) = {epsilon,c) and First(B) = {epsilon,b)?
i got the following results but still i think i have problems:
|first|follow
S |a |$
A |a |a
B |eps,b|b,a,$
C |eps,c|$
Finding the FIRST and Follow of a Grammar written in txt FILE:
#include<stdio.h>
#include<string.h>
#define size 10
int i,j,l,m,n=0,o,p,nv,z=0,x=0;
char str[size],temp,temp2[size],temp3[20],*ptr;
struct prod
{
char left_of_non_term[size],right_of_nonTerm[size][size],first[size],fol[size];
int n;
}pro[size];
int main()
{
FILE *f;
for(i=0;i<size;i++)
pro[i].n=0;
f=fopen("lab6.txt","r");
while(!feof(f))
{
fscanf(f,"%s",pro[n].left_of_non_term);
if(n>0)
{
if( strcmp(pro[n].left_of_non_term,pro[n-1].left_of_non_term) == 0 )
{
pro[n].left_of_non_term[0]='\0';
fscanf(f,"%s",pro[n-1].right_of_nonTerm[pro[n-1].n]);
pro[n-1].n++;
continue;
}
}
fscanf(f,"%s",pro[n].right_of_nonTerm[pro[n].n]);
pro[n].n++;
n++;
}
printf("\nGiven Grammar");
printf("\n-------------\n");
for(i=0;i<n;i++)
for(j=0;j<pro[i].n;j++)
printf("%s = %s\n",pro[i].left_of_non_term,pro[i].right_of_nonTerm[j]);
pro[0].first[0]='#';
for(i=0;i<n;i++)
{
for(j=0;j<pro[i].n;j++)
{
if( pro[i].right_of_nonTerm[j][0]<65 || pro[i].right_of_nonTerm[j][0]>90 )
{
pro[i].first[strlen(pro[i].first)]=pro[i].right_of_nonTerm[j][0];
}
else if( pro[i].right_of_nonTerm[j][0]>=65 && pro[i].right_of_nonTerm[j][0]<=90 )
{
temp=pro[i].right_of_nonTerm[j][0];
if(temp=='S')
pro[i].first[strlen(pro[i].first)]='#';
findter();
}
}
}
printf("-------------");
printf("\n\nFIRST\n");
for(i=0;i<n;i++)
{
printf("\n%s -> { ",pro[i].left_of_non_term);
for(j=0;j<strlen(pro[i].first);j++)
{
for(l=j-1;l>=0;l--)
if(pro[i].first[l]==pro[i].first[j])
break;
if(l==-1)
printf("%c ",pro[i].first[j]);
}
printf("}");
}
for(i=0;i<n;i++)
temp2[i]=pro[i].left_of_non_term[0];
pro[0].fol[0]='$';
for(i=0;i<n;i++)
{
for(l=0;l<n;l++)
{
for(j=0;j<pro[i].n;j++)
{
ptr=strchr(pro[l].right_of_nonTerm[j],temp2[i]);
if( ptr )
{
p=ptr-pro[l].right_of_nonTerm[j];
if(pro[l].right_of_nonTerm[j][p+1]>=65 && pro[l].right_of_nonTerm[j][p+1]<=90)
{
for(o=0;o<n;o++)
if(pro[o].left_of_non_term[0]==pro[l].right_of_nonTerm[j][p+1])
strcat(pro[i].fol,pro[o].first);
}
else if(pro[l].right_of_nonTerm[j][p+1]=='\0')
{
temp=pro[l].left_of_non_term[0];
if(pro[l].right_of_nonTerm[j][p]==temp)
continue;
if(temp=='S')
strcat(pro[i].fol,"$");
findfol();
}
else
pro[i].fol[strlen(pro[i].fol)]=pro[l].right_of_nonTerm[j][p+1];
}
}
}
}
printf("\n\n\n");
for(i=0;i<n;i++)
{
printf("\nFOLLOW (%s) -> { ",pro[i].left_of_non_term);
for(j=0;j<strlen(pro[i].fol);j++)
{
for(l=j-1;l>=0;l--)
if(pro[i].fol[l]==pro[i].fol[j])
break;
if(l==-1)
printf("%c",pro[i].fol[j]);
}
printf(" }");
}
printf("\n");
//getch();
}
void findter()
{
int k,t;
for(k=0;k<n;k++)
{
if(temp==pro[k].left_of_non_term[0])
{
for(t=0;t<pro[k].n;t++)
{
if( pro[k].right_of_nonTerm[t][0]<65 || pro[k].right_of_nonTerm[t][0]>90 )
pro[i].first[strlen(pro[i].first)]=pro[k].right_of_nonTerm[t][0];
else if( pro[k].right_of_nonTerm[t][0]>=65 && pro[k].right_of_nonTerm[t][0]<=90 )
{
temp=pro[k].right_of_nonTerm[t][0];
if(temp=='S')
pro[i].first[strlen(pro[i].first)]='#';
findter();
}
}
break;
}
}
}
void findfol()
{
int k,t,p1,o1,chk;
char *ptr1;
for(k=0;k<n;k++)
{
chk=0;
for(t=0;t<pro[k].n;t++)
{
ptr1=strchr(pro[k].right_of_nonTerm[t],temp);
if( ptr1 )
{
p1=ptr1-pro[k].right_of_nonTerm[t];
if(pro[k].right_of_nonTerm[t][p1+1]>=65 && pro[k].right_of_nonTerm[t][p1+1]<=90)
{
for(o1=0;o1<n;o1++)
if(pro[o1].left_of_non_term[0]==pro[k].right_of_nonTerm[t][p1+1])
{
strcat(pro[i].fol,pro[o1].first);
chk++;
}
}
else if(pro[k].right_of_nonTerm[t][p1+1]=='\0')
{
temp=pro[k].left_of_non_term[0];
if(pro[l].right_of_nonTerm[j][p]==temp)
continue;
if(temp=='S')
strcat(pro[i].fol,"$");
findfol();
chk++;
}
else
{
pro[i].fol[strlen(pro[i].fol)]=pro[k].right_of_nonTerm[t]
[p1+1];
chk++;
}
}
}
if(chk>0)
break;
}
}
Also Make a text File named it lab6.txt . and put grammers like below
S ABCDE
A a|0
B b|0
C c
D d|0
E e|0
Here space after NonTerminal Indicates the -> this sign and 0 indicates epsilon.

Deleting node from BST without using generics

I can't seem to find the correct logic to delete node from binary search tree.
public void delete(int key){
node current=root;
int flag=0;
if(current.data==key){
System.out.println(key+" is deleted");
current.rightchild=null;
current.leftchild=null;
current=null;
}
else{
while(true){
if(current.data>key){
current=current.leftchild;
if(current==null){
flag=1;
break;
}
if(current.data==key){
System.out.println(key+" is deleted");
current.leftchild=null;
current.rightchild=null;
current=null;
break;
}
}
else{
current=current.rightchild;
if(current==null){
flag=1;
break;
}
if(current.data==key){
System.out.println(key+" is deleted");
current.leftchild=null;
current.rightchild=null;
current=null;
break;
}
}
}
}
if(flag==1){`enter code here`
System.out.println(key+" Not Found");
}
}
I use these functions to delete a node in a BST, try it...note that my functions are templated to 3 elements, 1 for ID and 2 for Data.....
template <class T, class U,class V> class Node
{
public:
T ID;
U data1;
V data2;
Node *left;
Node *right;
Node() { left = right = NULL; }
Node(T ID, U data1, V data2)
{
this->ID = ID;
this->data1 = data1;
this->data2 = data2;
left = right = NULL;
}
V getActors()
{
return data2;
}
~Node()
{
delete left;
delete right;
}
};
void Delete(T ID)
{
root = delete_helper(root, ID);
}
Node<T, U,V>* delete_helper(Node<T, U,V>* N, T ID)
{
if (ID < N->ID)
{
N->left = delete_helper(N->left, ID);
return N;
}
else if (ID > N->ID)
{
N->right = delete_helper(N->right, ID);
return N;
}
return Separate(N, ID);
}
Node<T, U,V>* Separate(Node<T, U,V>* N, T ID)
{
Node<T, U,V>* NewNode = NULL;
if ((N->left == NULL) && (N->right == NULL))
{
delete N;
}
else if (N->right == NULL)
{
NewNode = N->left;
delete N;
}
else if (N->left == NULL)
{
NewNode = N->right;
delete N;
}
else
{
NewNode = N;
Node<T, U,V>* R = getRightOf(N->left);
Node<T, U,V>* parent = Parent(R->ID);
N->ID = R->ID;
if (parent != N) {
parent->right = R->left;
}
else {
N->left = R->left;
}
delete R;
}
return NewNode;
}

Send different metadata to different target streams - PDI

I have two target streams (Matches and mismatches) defined as below:
#Override
public StepIOMetaInterface getStepIOMeta() {
StepMeta stepMeta = new StepMeta();
if (ioMeta == null) {
ioMeta = new StepIOMeta(true, false, false, false, false, true);
StreamInterface matchStream = new Stream(StreamType.TARGET, null, "Matches", StreamIcon.TARGET, null);
StreamInterface mismatchStream = new Stream(StreamType.TARGET, null, "Mismatches", StreamIcon.TARGET, null);
ioMeta.addStream(matchStream);
ioMeta.addStream(mismatchStream);
}
return ioMeta;
}
I want to send different meta data to these two targets. The meta data is received from the previous steps. For match, it needs to be a concatenation of both input streams and for mismatch just the first input stream.
I am stuck on how to define the metadata separately for the two target streams.
Appreciate your help.
List<StreamInterface> targets=getStepIOMeta().getTargetStreams();
List<StreamInterface> infos=getStepIOMeta().getInfoStreams();
if ( info != null )
{
if(targets!=null)
{
if(nextStep.getName().equals(targets.get(0).getStepname()))
{
if ( info != null ) {
for ( int i = 0; i < info.length; i++ ) {
if ( info[i] != null ) {
r.mergeRowMeta( info[i] );
}
}
}
}
if(nextStep.getName().equals(targets.get(1).getStepname()))
{
if ( info != null ) {
if ( info.length > 0 && info[0] != null ) {
r.mergeRowMeta( info[0] );
}
}
}
if(nextStep.getName().equals(targets.get(2).getStepname()))
{
if ( info != null ) {
if ( info.length > 0 && info[0] != null ) {
r.mergeRowMeta( info[1] );
}
}
}
}

Exporting a non public Type through public API

I am trying to follow Trees tutorial at: http://cslibrary.stanford.edu/110/BinaryTrees.html
Here is the code I have written so far:
package trees.bst;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/**
*
* #author sachin
*/
public class BinarySearchTree {
Node root = null;
class Node {
Node left = null;
Node right = null;
int data = 0;
public Node(int data) {
this.left = null;
this.right = null;
this.data = data;
}
}
public void insert(int data) {
root = insert(data, root);
}
public boolean lookup(int data) {
return lookup(data, root);
}
public void buildTree(int numNodes) {
for (int i = 0; i < numNodes; i++) {
int num = (int) (Math.random() * 10);
System.out.println("Inserting number:" + num);
insert(num);
}
}
public int size() {
return size(root);
}
public int maxDepth() {
return maxDepth(root);
}
public int minValue() {
return minValue(root);
}
public int maxValue() {
return maxValue(root);
}
public void printTree() { //inorder traversal
System.out.println("inorder traversal:");
printTree(root);
System.out.println("\n--------------");
}
public void printPostorder() { //inorder traversal
System.out.println("printPostorder traversal:");
printPostorder(root);
System.out.println("\n--------------");
}
public int buildTreeFromOutputString(String op) {
root = null;
int i = 0;
StringTokenizer st = new StringTokenizer(op);
while (st.hasMoreTokens()) {
String stNum = st.nextToken();
int num = Integer.parseInt(stNum);
System.out.println("buildTreeFromOutputString: Inserting number:" + num);
insert(num);
i++;
}
return i;
}
public boolean hasPathSum(int pathsum) {
return hasPathSum(pathsum, root);
}
public void mirror() {
mirror(root);
}
public void doubleTree() {
doubleTree(root);
}
public boolean sameTree(BinarySearchTree bst) { //is this tree same as another given tree?
return sameTree(this.root, bst.getRoot());
}
public void printPaths() {
if (root == null) {
System.out.println("print path sum: tree is empty");
}
List pathSoFar = new ArrayList();
printPaths(root, pathSoFar);
}
///-------------------------------------------Public helper functions
public Node getRoot() {
return root;
}
//Exporting a non public Type through public API
///-------------------------------------------Helper Functions
private boolean isLeaf(Node node) {
if (node == null) {
return false;
}
if (node.left == null && node.right == null) {
return true;
}
return false;
}
///-----------------------------------------------------------
private boolean sameTree(Node n1, Node n2) {
if ((n1 == null && n2 == null)) {
return true;
} else {
if ((n1 == null || n2 == null)) {
return false;
} else {
if ((n1.data == n2.data)) {
return (sameTree(n1.left, n2.left) && sameTree(n1.right, n2.right));
}
}
}
return false;
}
private void doubleTree(Node node) {
//create a copy
//bypass the copy to continue looping
if (node == null) {
return;
}
Node copyNode = new Node(node.data);
Node temp = node.left;
node.left = copyNode;
copyNode.left = temp;
doubleTree(copyNode.left);
doubleTree(node.right);
}
private void mirror(Node node) {
if (node == null) {
return;
}
Node temp = node.left;
node.left = node.right;
node.right = temp;
mirror(node.left);
mirror(node.right);
}
private void printPaths(Node node, List pathSoFar) {
if (node == null) {
return;
}
pathSoFar.add(node.data);
if (isLeaf(node)) {
System.out.println("path in tree:" + pathSoFar);
pathSoFar.remove(pathSoFar.lastIndexOf(node.data)); //only the current node, a node.data may be duplicated
return;
} else {
printPaths(node.left, pathSoFar);
printPaths(node.right, pathSoFar);
}
}
private boolean hasPathSum(int pathsum, Node node) {
if (node == null) {
return false;
}
int val = pathsum - node.data;
boolean ret = false;
if (val == 0 && isLeaf(node)) {
ret = true;
} else if (val == 0 && !isLeaf(node)) {
ret = false;
} else if (val != 0 && isLeaf(node)) {
ret = false;
} else if (val != 0 && !isLeaf(node)) {
//recurse further
ret = hasPathSum(val, node.left) || hasPathSum(val, node.right);
}
return ret;
}
private void printPostorder(Node node) { //inorder traversal
if (node == null) {
return;
}
printPostorder(node.left);
printPostorder(node.right);
System.out.print(" " + node.data);
}
private void printTree(Node node) { //inorder traversal
if (node == null) {
return;
}
printTree(node.left);
System.out.print(" " + node.data);
printTree(node.right);
}
private int minValue(Node node) {
if (node == null) {
//error case: this is not supported
return -1;
}
if (node.left == null) {
return node.data;
} else {
return minValue(node.left);
}
}
private int maxValue(Node node) {
if (node == null) {
//error case: this is not supported
return -1;
}
if (node.right == null) {
return node.data;
} else {
return maxValue(node.right);
}
}
private int maxDepth(Node node) {
if (node == null || (node.left == null && node.right == null)) {
return 0;
}
int ldepth = 1 + maxDepth(node.left);
int rdepth = 1 + maxDepth(node.right);
if (ldepth > rdepth) {
return ldepth;
} else {
return rdepth;
}
}
private int size(Node node) {
if (node == null) {
return 0;
}
return 1 + size(node.left) + size(node.right);
}
private Node insert(int data, Node node) {
if (node == null) {
node = new Node(data);
} else if (data <= node.data) {
node.left = insert(data, node.left);
} else {
node.right = insert(data, node.right);
}
//control should never reach here;
return node;
}
private boolean lookup(int data, Node node) {
if (node == null) {
return false;
}
if (node.data == data) {
return true;
}
if (data < node.data) {
return lookup(data, node.left);
} else {
return lookup(data, node.right);
}
}
public static void main(String[] args) {
BinarySearchTree bst = new BinarySearchTree();
int treesize = 5;
bst.buildTree(treesize);
//treesize = bst.buildTreeFromOutputString("4 4 4 6 7");
treesize = bst.buildTreeFromOutputString("3 4 6 3 6");
//treesize = bst.buildTreeFromOutputString("10");
for (int i = 0; i < treesize; i++) {
System.out.println("Searching:" + i + " found:" + bst.lookup(i));
}
System.out.println("tree size:" + bst.size());
System.out.println("maxDepth :" + bst.maxDepth());
System.out.println("minvalue :" + bst.minValue());
System.out.println("maxvalue :" + bst.maxValue());
bst.printTree();
bst.printPostorder();
int pathSum = 10;
System.out.println("hasPathSum " + pathSum + ":" + bst.hasPathSum(pathSum));
pathSum = 6;
System.out.println("hasPathSum " + pathSum + ":" + bst.hasPathSum(pathSum));
pathSum = 19;
System.out.println("hasPathSum " + pathSum + ":" + bst.hasPathSum(pathSum));
bst.printPaths();
bst.printTree();
//bst.mirror();
System.out.println("Tree after mirror function:");
bst.printTree();
//bst.doubleTree();
System.out.println("Tree after double function:");
bst.printTree();
System.out.println("tree size:" + bst.size());
System.out.println("Same tree:" + bst.sameTree(bst));
BinarySearchTree bst2 = new BinarySearchTree();
bst2.buildTree(treesize);
treesize = bst2.buildTreeFromOutputString("3 4 6 3 6");
bst2.printTree();
System.out.println("Same tree:" + bst.sameTree(bst2));
System.out.println("---");
}
}
Now the problem is that netbeans shows Warning: Exporting a non public Type through public API for function getRoot().
I write this function to get root of tree to be used in sameTree() function, to help comparison of "this" with given tree.
Perhaps this is a OOP design issue... How should I restructure the above code that I do not get this warning and what is the concept I am missing here?
The issue here is that some code might call getRoot() but won't be able to use it's return value since you only gave package access to the Node class.
Make Node a top level class with its own file, or at least make it public
I don't really understand why you even created the getRoot() method. As long as you are inside your class you can even access private fields from any other object of the same class.
So you can change
public boolean sameTree(BinarySearchTree bst) { //is this tree same as another given tree?
return sameTree(this.root, bst.getRoot());
}
to
public boolean sameTree(BinarySearchTree bst) { //is this tree same as another given tree?
return sameTree(this.root, bst.root);
}
I would also add a "short path" for the case you pass the same instance to this method:
public boolean sameTree(BinarySearchTree bst) { //is this tree same as another given tree?
if (this == bst) {
return true;
}
return sameTree(this.root, bst.root);
}