Evaluating arithmetic expressions from string in C++
I think you're looking for a simple recursive descent parser.
Here's a very simple example:
const char * expressionToParse = "3*2+4*1+(4+9)*6";
char peek()
{
return *expressionToParse;
}
char get()
{
return *expressionToParse++;
}
int expression();
int number()
{
int result = get() - '0';
while (peek() >= '0' && peek() <= '9')
{
result = 10*result + get() - '0';
}
return result;
}
int factor()
{
if (peek() >= '0' && peek() <= '9')
return number();
else if (peek() == '(')
{
get(); // '('
int result = expression();
get(); // ')'
return result;
}
else if (peek() == '-')
{
get();
return -factor();
}
return 0; // error
}
int term()
{
int result = factor();
while (peek() == '*' || peek() == '/')
if (get() == '*')
result *= factor();
else
result /= factor();
return result;
}
int expression()
{
int result = term();
while (peek() == '+' || peek() == '-')
if (get() == '+')
result += term();
else
result -= term();
return result;
}
int _tmain(int argc, _TCHAR* argv[])
{
int result = expression();
return 0;
}
evaluate an arithmetic expression stored in a string (C#)
There's a javascript library you can reference, then just do something like:
var engine = VsaEngine.CreateEngine();
Eval.JScriptEvaluate(mySum, engine);
Edit;
Library is Microsoft.JScript
How to evaluate a mathematical expression using strings and arrays in C
Look into the shunting yard algorithm and convert the string into reverse polish notation.
It will help if you also separate out number detection from symbol detection by reading the string one character at a time instead of just jumping to the operators.
After that, it is rather easy to perform the computation, as the inputs are ordered in a manner that makes a stack based calculator easy to implement.
Yes, you could do a full fledged recursive descent parser; but, for the relatively simple matter of algebraic expressions, they are overkill.
--- Edited because I see that there's controversy over tools vs techniques ---
I see a lot of people mentioning lexx and yacc. They are great tools, they are also overkill for what you need. It's like saying to open a carpentry shop when you want to replace a board on your fence. You don't need to learn another language to handle your math language, and lexx and yacc will require you to learn their domain specific configuration language to build the parser for your domain specific language. That's a lot of languages for a simple, solved problem.
Lexx and Yacc are great if you want to build a mathematical tree of your data; however, RPN is a mathematical tree of your data stored in a list of two fundamental node types (data) and (operation).
(a)(b)(c) // three "data nodes"
(a)(b)(+) // two "data nodes" and one operation node.
This allows one to use a stack based machine (very easy to implement). The machine has an "instruction set" of
if (x is data) { push X onto the top of the stack }
if (x is operation) {
pop the operation's required parameters.
pass them to the operation.
push the result on the stack
}
so assuming you had a '+' operator, the expression 3 + 5 + 6
would convert to RPN 3 5 + 6 +
and the stack would look like (during processing)
<empty>
(3)
(3)(5)
(8)
(8)(6)
(14)
The primary reason to convert to RPN is not because it's necessary, it's because it makes the rest of your program much easier to implement. Imagine 3 + 5 * 7
converted to RPN, you have 3 5 7 * +
which means that you don't have to do anything special with evaluation "machine" language. Note that (3 + 5) * 7
converts to RPN 3 5 + 7 *
. In short, you reduce the complexity of the evaluation engine by massaging your input data to be less ambiguous.
Lexx and Yacc provide a lot of "configurability" to allow you to accomplish the same thing; however, you are not going to be configuring lexx and yacc to do anything special here, so the configurable interface doesn't buy you much. It's like having a multiple selection knob when you only need an on-off switch.
Now, if you want to build any kind of parser, where you are not aware of any kind of future rules which might be added; then definately choose lexx and yacc. But a simple algebraic expression parser is far too "solved" a problem to bring in the big guns. Use a shunting algorthim and break your problem down into
simple scanner to identify the main types of "tokens", NUMBER, +, -, /, *, (, and )
shunting algorithim to convert the "list" of tokens into a RPN list
a stack to hold the "memory" of the evaluation "machine"
the "machine" pull / push / evaluate loop
This has the added benefits of being able to develop the pieces independently, so you can verify each step without the entire framework being in place. Lexx and Yacc promote adding your code to their framework, so unless you take steps to do otherwise, you might have to debug the entire thing as one big piece.
What is the best way to evaluate mathematical expressions in C++?
Boost.Spirit is a C++ parser library.
Examples:
- in its distribution: classic version and current version (look for "calc");
- on Rosetta wiki;
- some applications using it.
(C++) Parse tree for evaluating simple arithmetic expressions returning incorrect value
The problem is that you are doing calculations with characters and not with integers. As you might know each character has a Ascii-code, a numerical representation of this character, which is used for calculations. Ascii codes for '5'
, '2'
and '7'
are 53, 50 and 55.
Thus '5' + '2' * '7'
is indeed 2083, because it's actually 53 + 50 * 55
.
A simple fix would be to replace
return tree -> get_root();
in eval_parse_tree
with
return tree -> get_root() - '0';
Related Topics
Initialization Order of Class Data Members
Two Different Values At the Same Memory Address
Why Does the Use of 'New' Cause Memory Leaks
Measuring Execution Time of a Function in C++
How to Implement Big Int in C++
Difference Between Static and Dynamic Arrays in C++
How to Call a Parent Class Function from Derived Class Function
Position of Least Significant Bit That Is Set
Operator Precedence VS Order of Evaluation
What Happens If I Assign a Negative Value to an Unsigned Variable
What Is the Purpose of the Most Vexing Parse
How to Pass a Unique_Ptr Argument to a Constructor or a Function
How to Get Current Time and Date in C++
Using Custom Std::Set Comparator
Array[N] VS Array[10] - Initializing Array With Variable VS Numeric Literal