Hello all, I was wondering how any of you would write a dynamic text input calculator. I.E Lets say you have a single line text input field where the user can type their formula. How would you go about figuring out how to do the correct math calculations from the variables collected in a string?
Lets say the current input field value is "2 + 2"
structure mathStep Vector
enum m_type;
var value;
cLine = removeSpacesInText
For Each Character in cLine Loop
if cLine Character Does Not Equal to any operator.
Add Character to tempString
Else
Convert tempString into correct variable type determining if the string has a period in it.
Then add the variable to the mathStep Vector
After adding it to the to do list then add the operator to the back of the list. Simply by changing the m_type to PLUS and add it to the vector.
End If
End For Loop
If float/double/int use the correct variable type for the result value variable.
For Each Element in mathStep
Add/Subtract/etc to result value
End If
Return Result
I had something like that in mind, I didn't write it in C++ yet, but I've been pondering if there are better ways and variable types to use then adding a bunch of variables in a struct if it's a float or int, a plus, minus, etc in the text we are figuring out what it result is.
How Would You Write A Dynamic Text Input Calculator?
One solution would be to first tokenize the input line using regular expressions. This would convert the input string "2 + 2" to a token list like { Value(2), Operator(+), Value(2) }. Next, perform a syntactic analysis which identifies and organizes (typically in some tree structure) the elements that need to be evaluated. Continuing with our "2 + 2" example this would create a tree from the token list with 3 nodes constituting a single addition expression: { Addition(Value(2),Value(2)) }. Lastly, evaluate the tree (or more specifically each node in the tree), which in our example would yield something like Value(4).
If you can get your hands one Bjarne's "The C++ Programming Language" book, he explains how to create a calculator. The source code can also be found at his site.
One solution would be to first tokenize the input line using regular expressions. This would convert the input string "2 + 2" to a token list like { Value(2), Operator(+), Value(2) }. Next, perform a syntactic analysis which identifies and organizes (typically in some tree structure) the elements that need to be evaluated. Continuing with our "2 + 2" example this would create a tree from the token list with 3 nodes constituting a single addition expression: { Addition(Value(2),Value(2)) }. Lastly, evaluate the tree (or more specifically each node in the tree), which in our example would yield something like Value(4).
The tree structure you would want happens to have a name as well
The tree structure you would want happens to have a name as well
Thanks, I haven't worked on a compiler since 1998 so I have admittedly forgotten about many of the data structures used in this branch of programming.
A couple of alternatives that haven't been mentioned:
- There is a well-known algorithm that converts infix notation (what you have) to reverse polish notation. Once you have the expression in RPN, computing the result is trivially achieved using a stack.
- You can also write your own recursive descent parser for the types of expressions that you expect. I think this is a good exercise to go through at some point.
I would second alvaro and suggest rolling a recursive descent parser - there are lots of examples and explanations around, and it is indeed a good fundamental excercise.
Here's a recursive descent parser I just hacked together. The hardest part is reporting meaningful errors, which I haven't been careful about:
EDIT: My code had some issues with unary + and - operators, but I fixed them.
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
void skip_white_space(char const *&s) {
while (isspace(*s))
++s;
}
double compute_expression(char const *&s);
double compute_non_signed_factor(char const *&s) {
double result;
if (isdigit(*s)) {
int n_characters_read;
std::sscanf(s, "%lg%n", &result, &n_characters_read);
s += n_characters_read;
skip_white_space(s);
}
else if (*s == '(') {
++s;
skip_white_space(s);
result = compute_expression(s);
if (*s != ')') {
std::cerr << "`)' expected\n";
std::exit(1);
}
++s;
skip_white_space(s);
}
else {
std::cerr << "Number or `(' expected\n";
std::exit(1);
}
return result;
}
double compute_factor(char const *&s) {
bool positive = true;
if (*s == '+')
positive = true, ++s, skip_white_space(s);
else if (*s == '-')
positive = false, ++s, skip_white_space(s);
return positive ? compute_non_signed_factor(s) : -compute_non_signed_factor(s);
}
double compute_term(char const *&s) {
double result = 1.0;
bool dividing = false;
while (1) {
result *= dividing ? 1.0 / compute_factor(s) : compute_factor(s);
if (*s == '*')
dividing = false, ++s, skip_white_space(s);
else if (*s == '/')
dividing = true, ++s, skip_white_space(s);
else break;
}
return result;
}
double compute_expression(char const *&s) {
double result = 0.0;
bool subtracting = false;
while (1) {
result += subtracting ? -compute_term(s) : compute_term(s);
if (*s == '+')
subtracting = false, ++s, skip_white_space(s);
else if (*s == '-')
subtracting = true, ++s, skip_white_space(s);
else break;
}
return result;
}
double compute(char const *s) {
skip_white_space(s);
double result = compute_expression(s);
if (*s != '\0') {
std::cerr << "End of line expected\n";
std::exit(1);
}
return result;
}
int main() {
std::cout << compute("2+2") << '\n';
}
EDIT: My code had some issues with unary + and - operators, but I fixed them.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement