Parsing an arithmetic expression and building a tree from it in Java
The "Five minute introduction to ANTLR" includes an arithmetic grammar example. It's worth checking out, especially since antlr is open source (BSD license).
Create a binary tree from an algebraic expression
Tree construction for prefix expressions
def insert
Insert each token in the expression from left to right:
(0) If the tree is empty, the first token in the expression (must
be an operator) becomes the root
(1) Else if the last inserted token is an
operator, then insert the token as the left child of the last inserted
node.
(2) Else if the last inserted token is an operand, backtrack up the
tree starting from the last inserted node and find the first node with a NULL
right child, insert the token there. **Note**: don't insert into the last inserted
node.
end def
Let's do an example: + 2 + 1 1
Apply (0).
+
Apply (1).
+
/
2
Apply (2).
+
/ \
2 +
Apply (1).
+
/ \
2 +
/
1
Finally, apply (2).
+
/ \
2 +
/ \
1 1
This algorithm has been tested against - * / 15 - 7 + 1 1 3 + 2 + 1 1
So the Tree.insert
implementation is those three rules.
insert(rootNode, token)
//create new node with token
if (isLastTokenOperator)//case 1
//insert into last inserted's left child
else { //case 2
//backtrack: get node with NULL right child
//insert
}
//maintain state
lastInsertedNode = ?, isLastTokenOperator = ?
Evaluating the tree is a little funny, because you have to start from the bottom-right of the tree. Perform a reverse post-order traversal. Visit the right child first.
evalPostorder(node)
if (node == null) then return 0
int rightVal = evalPostorder(node.right)
int leftVal = evalPostorder(node.left)
if(isOperator(node.value))
return rightVal <operator> leftVal
else
return node.value
Given the simplicity of constructing a tree from a prefix expression, I'd suggest using the standard stack algorithm to convert from infix to prefix. In practice you'd use a stack algorithm to evaluate an infix expression.
Parsing of math expression gives wrong tree
Yes I would parse the equation, it just looks like you miss a key part of the order of operations/parsing. You need to include an additional check for double negatives.
The key factor here is that: In a situation with two identical operators then the left most operation is always carried out first.
First lets narrow down the issue.
This 1-5*(-2)+3
is equal to 1--10+3
.
Now for our purposes lets assign a positive to the first operator because it helps illustrate a point:
1--10+3
is the same as +1--10+3
Now if we where to run +1--10+3
through a correct parser we would know that this --
is equal to +
but only when used in the following situation:
+X--Y
= X+Y
So now our parser has turned the original expression of 1--10+3
into 1+10+3
and we know that is equal to 14.
So all up: Yes you need a parser, but pay special attention to how +X--Y and X+Y work.
Also take a look at this answer: https://stackoverflow.com/a/26227947/1270000
Algorithm to build a tree that represent a prefix expression
Actually, you parse the String from left to right:
public class Parser {
private final String prefix;
int pos = 0;
public Parser(String prefix) {
this.prefix = prefix;
}
public Noeud parse() {
char c = prefix.charAt(pos);
pos++;
String token = Character.toString(c);
if (Character.isDigit(c)) {
return new Noeud(token);
}
return new Noeud(token, parse(), parse());
}
}
The basic algorithm to read a Node is:
- read a character (the next token).
- if that character is a digit, then return a new leaf node.
- otherwise read two more nodes, and construct a new node with those as left and right child.
Your constructTree
function would be this:
public static Noeud constructTree(String prefix) {
return new Parser(prefix).parse();
}
Techniques needed to write an arithmetic expression parser
Without knowledge of compilation techniques it would be ugly. But there is no need to learn a ton of compilation for an introductory example like this.
Look at something like http://www.codeproject.com/Articles/345888/How-to-write-a-simple-interpreter-in-JavaScript and see if it makes sense to you.
Related Topics
Firebase Firestore Get Data from Collection
Place Cursor at the End of Text in Edittext
Noclassdeffounderror in Eclipse
How to Change Color of the Back Arrow in the New Material Theme
How to Find Java Heap Size and Memory Used (Linux)
How Can One Detect Airplane Mode on Android
Firebaseapp with Name [Default] Doesn't Exist
Error: Unable to Run Mksdcard Sdk Tool
Running Java Program from Command Line Linux
Variable Is Accessed Within Inner Class. Needs to Be Declared Final
Android-Java- How to Sort a List of Objects by a Certain Value Within the Object
How to Use Vectordrawable in Buttons and Textviews Using Android:Drawableright
Kafka - Unable to Send a Message to a Remote Server Using Java
Keep Broadcast Receiver Running After Application Is Closed
Android Library Gradle Release Jar