Reputation: 43
I have the following problem: I have an input string that looks something like this: string s ="87635+23754*ar+ar*var*0.895+(ar-var)+ar*ar+var*var";
I want to split this string and execute each operation i.e I want to read in all the values, perform the mathematical operations and output the final answer in C++. How do I do it? getline command can split only one type of delimiter. How do I solve this problem?
Thanks
Nita
Upvotes: 2
Views: 2070
Reputation: 171263
The "correct" answer is to write a parser for your mini-language, but it might be simpler to use string::find_first_of
and/or string::find_first_not_of
to tokenize it into numbers, operators and named variables
Upvotes: 2
Reputation: 517
You must write a parser. Don't be scared of the "correct" solution, it's correct for a good reason; it works. The shortcuts offered by others won't make your task any easier.
I have included a basic solution that you can use as a starting point. You should build test cases to make sure it is correct and handle error cases more thoroughly.
Hopefully by studying this code you will get the general idea of a recursive decent parser. We split up the parsing problem by using separate functions for the different levels of operator precedence. These functions call each other in a top down fashion, making this type of parser easier to understand.
I have coded it in such a way as to be brief. If you believe 'goto' is evil, use a while loop instead. Furthermore, convert the parsing functions into a Parser class to get rid of the global variables.
Good luck and happy parsing :)
#include <string>
#include <map>
#include <iostream>
#include <sstream>
using namespace std;
stringstream ss;
map<string,double> variables;
string err_string = "";
double parse_add_exp();
int main()
{
// get the expression and variables
ss << "87635+23754*ar+ar*var*0.895+(ar-var)+ar*ar+var*var";
variables["ar"] = -4.5;
variables["var"] = 141.26f;
try
{
// calculate the result
double result = parse_add_exp();
if( result == INFINITY )
cout<<"Runtime error: Division by zero"<<endl;
else
cout<<"Result = "<<result<<endl; // prints 'Result = 1.95143'
}
catch (const char * error)
{
cout<<"Invalid expression: "<<error<<endl;
}
return 0;
}
double parse_number()
{
double f;
if( !(ss>>f) )
throw "Expected number";
return f;
}
double parse_operand()
{
string var("");
while( isalpha(ss.peek()) )
var += ss.get();
if( !var.size() )
return parse_number();
if( variables.find(var) == variables.end() )
throw "Variable is undefined";
return variables[var];
}
double parse_parenthesis()
{
if( ss.peek() != '(' )
return parse_operand();
ss.get();
double f = parse_add_exp();
if( ss.get() != ')' )
throw "Expected closing parenthesis";
return f;
}
double parse_mul_exp()
{
double product = parse_parenthesis();
PEEKOP:
switch( ss.peek() )
{
case '*': ss.get(); product *= parse_parenthesis(); goto PEEKOP;
case '/': ss.get(); product /= parse_parenthesis(); goto PEEKOP;
default: return product;
}
}
double parse_add_exp()
{
double sum = parse_mul_exp();
PEEKOP:
switch( ss.peek() )
{
case '+': ss.get(); sum += parse_mul_exp(); goto PEEKOP;
case '-': ss.get(); sum -= parse_mul_exp(); goto PEEKOP;
default: return sum;
}
}
Upvotes: 1
Reputation: 462
Take a look at std::stringstream. You can put a string into the stream and read from it just like from std::cin!
For example:
#include <iostream>
#include <sstream>
int main()
{
std::stringstream stream(std::stringstream::in | std::stringstream::out);
stream << "22+2";
int operand1, operand2;
char op;
stream >> operand1;
stream >> op;
stream >> operand2;
std::cout << operand1 << " " << op << " " << operand2 << std::endl;
return 0;
}
For a more complex example look at the dc-clone I did a while ago: gist.github.com/ae6ebe58a286d6cfd847. Especially look at the lines 467-522 (in main).
Upvotes: 1