Introduction:
mathparser is a simple c++ program to parse math expressions.
The program is a modified version of math expression parser presented in the book: "C++ The Complete Reference" by H.Schildt.
It supports operators: +-*/^()
It supports math functions: SIN, COS, TAN, ASIN, ACOS, ATAN, SINH, COSH, TANH, ASINH, ACOSH, ATANH, LN, LOG, EXP, SQRT, SQR, ROUND, INT.
It supports variables A to Z.
Sample:
25*3+1.5*(-2^4*log(30)/3)
x=3
y=4
r=sqrt(x^2+y^2)
t=atan(y/x)
About:
mathparser version 1.0 by Hamid Soltani. (gmail: hsoltanim)
Code:
Download mathparser.cpp
/******************************************************************
Introduction:
mathparser is a simple c++ program to parse math expressions.
The program is a modified version of math expression parser
presented in the book : "C++ The Complete Reference" by H.Schildt.
It supports operators: + - * / ^ ( )
It supports math functions : SIN, COS, TAN, ASIN, ACOS, ATAN, SINH,
COSH, TANH, ASINH, ACOSH, ATANH, LN, LOG, EXP, SQRT, SQR, ROUND, INT.
It supports variables A to Z.
Sample:
25 * 3 + 1.5*(-2 ^ 4 * log(30) / 3)
x = 3
y = 4
r = sqrt(x ^ 2 + y ^ 2)
t = atan(y / x)
mathparser version 1.0 by Hamid Soltani. (gmail: hsoltanim)
Last modified: Aug. 2016.
*******************************************************************/
#include "stdafx.h"
#include < iostream >
#include < cstdlib >
#include < cctype >
#include < cstring >
#include < math.h >
#define PI 3.14159265358979323846
using namespace std;
enum types { DELIMITER = 1, VARIABLE, NUMBER, FUNCTION };
const int NUMVARS = 26;
class parser {
char *exp_ptr; // points to the expression
char token[256]; // holds current token
char tok_type; // holds token's type
double vars[NUMVARS]; // holds variable's values
void eval_exp1(double &result);
void eval_exp2(double &result);
void eval_exp3(double &result);
void eval_exp4(double &result);
void eval_exp5(double &result);
void eval_exp6(double &result);
void get_token();
public:
parser();
double eval_exp(char *exp);
char errormsg[64];
};
// Parser constructor.
parser::parser()
{
int i;
exp_ptr = NULL;
for (i = 0; i < NUMVARS; i++)
vars[i] = 0.0;
errormsg[0] = '\0';
}
// Parser entry point.
double parser::eval_exp(char *exp)
{
errormsg[0] = '\0';
double result;
exp_ptr = exp;
get_token();
if (!*token)
{
strcpy(errormsg, "No Expression Present"); // no expression present
return (double)0;
}
eval_exp1(result);
if (*token) // last token must be null
strcpy(errormsg, "Syntax Error");
return result;
}
// Process an assignment.
void parser::eval_exp1(double &result)
{
int slot;
char temp_token[80];
if (tok_type == VARIABLE)
{
// save old token
char *t_ptr = exp_ptr;
strcpy(temp_token, token);
// compute the index of the variable
slot = *token - 'A';
get_token();
if (*token != '=')
{
exp_ptr = t_ptr; // return current token
strcpy(token, temp_token); // restore old token
tok_type = VARIABLE;
}
else {
get_token(); // get next part of exp
eval_exp2(result);
vars[slot] = result;
return;
}
}
eval_exp2(result);
}
// Add or subtract two terms.
void parser::eval_exp2(double &result)
{
register char op;
double temp;
eval_exp3(result);
while ((op = *token) == '+' || op == '-')
{
get_token();
eval_exp3(temp);
switch (op)
{
case '-':
result = result - temp;
break;
case '+':
result = result + temp;
break;
}
}
}
// Multiply or divide two factors.
void parser::eval_exp3(double &result)
{
register char op;
double temp;
eval_exp4(result);
while ((op = *token) == '*' || op == '/')
{
get_token();
eval_exp4(temp);
switch (op)
{
case '*':
result = result * temp;
break;
case '/':
result = result / temp;
break;
}
}
}
// Process an exponent.
void parser::eval_exp4(double &result)
{
double temp;
eval_exp5(result);
while (*token == '^')
{
get_token();
eval_exp5(temp);
result = pow(result, temp);
}
}
// Evaluate a unary + or -.
void parser::eval_exp5(double &result)
{
register char op;
op = 0;
if ((tok_type == DELIMITER) && *token == '+' || *token == '-')
{
op = *token;
get_token();
}
eval_exp6(result);
if (op == '-')
result = -result;
}
// Process a function, a parenthesized expression, a value or a variable
void parser::eval_exp6(double &result)
{
bool isfunc = (tok_type == FUNCTION);
char temp_token[80];
if (isfunc)
{
strcpy(temp_token, token);
get_token();
}
if ((*token == '('))
{
get_token();
eval_exp2(result);
if (*token != ')')
strcpy(errormsg, "Unbalanced Parentheses");
if (isfunc)
{
if (!strcmp(temp_token, "SIN"))
result = sin(PI / 180 * result);
else if (!strcmp(temp_token, "COS"))
result = cos(PI / 180 * result);
else if (!strcmp(temp_token, "TAN"))
result = tan(PI / 180 * result);
else if (!strcmp(temp_token, "ASIN"))
result = 180 / PI*asin(result);
else if (!strcmp(temp_token, "ACOS"))
result = 180 / PI*acos(result);
else if (!strcmp(temp_token, "ATAN"))
result = 180 / PI*atan(result);
else if (!strcmp(temp_token, "SINH"))
result = sinh(result);
else if (!strcmp(temp_token, "COSH"))
result = cosh(result);
else if (!strcmp(temp_token, "TANH"))
result = tanh(result);
else if (!strcmp(temp_token, "ASINH"))
result = asinh(result);
else if (!strcmp(temp_token, "ACOSH"))
result = acosh(result);
else if (!strcmp(temp_token, "ATANH"))
result = atanh(result);
else if (!strcmp(temp_token, "LN"))
result = log(result);
else if (!strcmp(temp_token, "LOG"))
result = log10(result);
else if (!strcmp(temp_token, "EXP"))
result = exp(result);
else if (!strcmp(temp_token, "SQRT"))
result = sqrt(result);
else if (!strcmp(temp_token, "SQR"))
result = result*result;
else if (!strcmp(temp_token, "ROUND"))
result = round(result);
else if (!strcmp(temp_token, "INT"))
result = floor(result);
else
strcpy(errormsg, "Unknown Function");
}
get_token();
}
else
switch (tok_type)
{
case VARIABLE:
result = vars[*token - 'A'];
get_token();
return;
case NUMBER:
result = atof(token);
get_token();
return;
default:
strcpy(errormsg, "Syntax Error");
}
}
// Obtain the next token.
void parser::get_token()
{
register char *temp;
tok_type = 0;
temp = token;
*temp = '\0';
if (!*exp_ptr) // at end of expression
return;
while (isspace(*exp_ptr)) // skip over white space
++exp_ptr;
if (strchr("+-*/%^=()", *exp_ptr))
{
tok_type = DELIMITER;
*temp++ = *exp_ptr++; // advance to next char
}
else if (isalpha(*exp_ptr))
{
while (!strchr(" +-/*%^=()\t\r", *exp_ptr) && (*exp_ptr))
*temp++ = toupper(*exp_ptr++);
while (isspace(*exp_ptr)) // skip over white space
++exp_ptr;
tok_type = (*exp_ptr == '(') ? FUNCTION : VARIABLE;
}
else if (isdigit(*exp_ptr) || *exp_ptr == '.')
{
while (!strchr(" +-/*%^=()\t\r", *exp_ptr) && (*exp_ptr))
*temp++ = toupper(*exp_ptr++);
tok_type = NUMBER;
}
*temp = '\0';
if ((tok_type == VARIABLE) && (token[1]))
strcpy(errormsg, "Only first letter of variables is considered");
}
int main()
{
char expstr[256];
parser ob;
cout << "Math expression parser. Enter a blank line to stop.\n\n";
do
{
cout << "Enter expression: ";
cin.getline(expstr, 255);
double ans = ob.eval_exp(expstr);
if (*ob.errormsg)
cout << "Error: " << ob.errormsg << "\n\n";
else
cout << "Answer: " << ans << "\n\n";
} while (*expstr);
return 0;
}