How Would You Write A Dynamic Text Input Calculator?

Started by
23 comments, last by ajm113 12 years ago
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.
Check out my open source code projects/libraries! My Homepage You may learn something.
Advertisement
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

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.

I would use Flex and Bison.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

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:
#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.
I did this as the example program for my parsing library

This topic is closed to new replies.

Advertisement