This isn't a school assignment or anything, but I realize it's a mostly academic question. But, what I've been struggling to do is parse 'math' text and come up with an answer.
For Example - I can figure out how to parse '5 + 5' or '3 * 5' - but I fail when I try to correctly chain operations together.
(5 + 5) * 3
It's mostly just bugging me that I can't figure it out. If anyone can point me in a direction, I'd really appreciate it.
EDIT Thanks for all of the quick responses. I'm sorry I didn't do a better job of explaining.
First - I'm not using regular expressions. I also know there are already libraries available that will take, as a string, a mathematical expression and return the correct value. So, I'm mostly looking at this because, sadly, I don't "get it".
Second - What I've tried doing (is probably misguided) but I was counting '(' and ')' and evaluating the deepest items first. In simple examples, this worked; but my code is not pretty and more complicated stuff crashes. When I 'calculated' the lowest level, I was modifying the string.
So... (5 + 5) * 3
Would turn into 10 * 3
Which would then evaluate to 30
But it just felt 'wrong'.
I hope that helps clarify things. I'll certainly check out the links provided.
@Rising Star [I hoped to add this as a comment, but the formatting failed]
It may seem counterintuitive, but a binary tree is both simpler and more flexible. A node, in this case, would be either a constant (number) or an operator. A binary tree makes life somewhat easier when you decide to extend the language with elements like control flow, and functions.
Example:
In the case above the scanner has been programmed to read '-' followed by a series of digits as a single number, so "-7" gets returned as the value component of the "number" token. '-' followed by whitespace is retured as a "minus" token. This makes the parser somewhat easier to write. It fails on the case where you want "-(x * y)", but you can easily change the expression to "0 - exp"
As many answers have already stated, the issue is that you need a
recursive parser
withassociativity rules
because you can end up with expressions like:and your parser needs to know that:
As you can imagine, writing a (good) parser is an art. The good thing is that there are several tools, called
parser generators
which allow you to easily define the grammar of your language, and the parsing rules. You may want to check the entries in Wikipedia for BNF, so that you can see how a grammar is defined.Finally, if you are doing this for learning experience, go ahead. If this is for production code, do not reinvent the wheel, and find an existing library, otherwise you risk spending 1000 lines of code to add 2+2.
I did something similar to what you describe. I use recursion to parse all the parenthesis. I then use a ternary tree to represent the different segments. The left branch is the left hand side of the operator. The center branch is the operator. The right branch is the right hand side of the operator.
Short Answer Recursion and ternary trees.
For anyone seeing this question nine years into the future from when this post was made: If you don't want to re-invent the wheel, there are many exotic math parsers out there.
There is one that I wrote years ago in Java, which supports arithmetic operations, equation solving, differential calculus, integral calculus, basic statistics, function/formula definition, graphing, etc.
Its called ParserNG and its free.
Evaluating an expression is as simple as:
Or using variables and calculating simple expressions:
Or using functions:
Or to evaluate the derivative at a given point(Note it does symbolic differentiation(not numerical) behind the scenes, so the accuracy is not limited by the errors of numerical approximations):
Which differentiates
x^3 * ln(x)
once at x=3. The number of times you can differentiate is 1 for now.or for Numerical Integration:
This parser is decently fast and has lots of other functionality.
DISCLAIMER: ParserNG is authored by me.
Did you ever take a class on formal languages in school? Effectively you need a grammar to parse by.
EDIT: Oh crap, Wikipedia says I'm wrong, but now I forget the correct name :( http://en.wikipedia.org/wiki/Formal_grammar
Ages ago when working on a simple graphing app, I used this algorithm (which is reasonably easy to understand and works great for simple math expressions like these) to first turn the expression into RPN and then calculated the result. RPN was nice and fast to execute for different variable values.
Of course, language parsing is a very wide topic and there are many other ways of going about it (and pre-made tools for it too)