#include "parser.h"
using namespace std;
Parser::Parser()
{
expr[0] = '\0';
e = NULL;
token[0] = '\0';
token_type = NOTHING;
}
char* Parser::parse(const char new_expr[])
{
try
{
if (strlen(new_expr) > EXPR_LEN_MAX)
{
throw Error(row(), col(), 200);
}
strcpy(expr, new_expr); e = expr; ans = 0;
getToken();
if (token_type == DELIMETER && *token == '\0')
{
throw Error(row(), col(), 4);
}
ans = parse_level1();
if (token_type != DELIMETER || *token != '\0')
{
if (token_type == DELIMETER)
{
throw Error(row(), col(), 101, token);
}
else
{
throw Error(row(), col(), 5, token);
}
}
user_var.add("Ans", ans);
snprintf(ans_str, sizeof(ans_str), "Ans = %g", ans);
}
catch (Error err)
{
if (err.get_row() == -1)
{
snprintf(ans_str, sizeof(ans_str), "Error: %s (col %i)", err.get_msg(), err.get_col());
}
else
{
snprintf(ans_str, sizeof(ans_str), "Error: %s (ln %i, col %i)", err.get_msg(), err.get_row(), err.get_col());
}
}
return ans_str;
}
bool isMinus(const char c)
{
if (c == 0) return 0;
return c == '-';
}
bool isWhiteSpace(const char c)
{
if (c == 0) return 0;
return c == 32 || c == 9; }
bool isDelimeter(const char c)
{
if (c == 0) return 0;
return strchr("&|<>=+/*%^!", c) != 0;
}
bool isNotDelimeter(const char c)
{
if (c == 0) return 0;
return strchr("&|<>=+-/*%^!()", c) != 0;
}
bool isAlpha(const char c)
{
if (c == 0) return 0;
return strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ_", toupper(c)) != 0;
}
bool isDigitDot(const char c)
{
if (c == 0) return 0;
return strchr("0123456789.", c) != 0;
}
bool isDigit(const char c)
{
if (c == 0) return 0;
return strchr("0123456789", c) != 0;
}
void Parser::getToken()
{
token_type = NOTHING;
char* t; t = token; *t = '\0'; while (*e == ' ' || *e == '\t') {
e++;
}
if (*e == '\0')
{
token_type = DELIMETER;
return;
}
if (*e == '-')
{
token_type = DELIMETER;
*t = *e;
e++;
t++;
*t = '\0'; return;
}
if (*e == '(' || *e == ')')
{
token_type = DELIMETER;
*t = *e;
e++;
t++;
*t = '\0';
return;
}
if (isDelimeter(*e))
{
token_type = DELIMETER;
while (isDelimeter(*e))
{
*t = *e;
e++;
t++;
}
*t = '\0'; return;
}
if (isDigitDot(*e))
{
token_type = NUMBER;
while (isDigitDot(*e))
{
*t = *e;
e++;
t++;
}
if (toupper(*e) == 'E')
{
*t = *e;
e++;
t++;
if (*e == '+' || *e == '-')
{
*t = *e;
e++;
t++;
}
while (isDigit(*e))
{
*t = *e;
e++;
t++;
}
}
*t = '\0';
return;
}
if (isAlpha(*e))
{
while (isAlpha(*e) || isDigit(*e))
{
*t = *e;
e++;
t++;
}
*t = '\0'; char* e2 = NULL;
e2 = e;
while (*e2 == ' ' || *e2 == '\t') {
e2++;
}
if (*e2 == '(')
{
token_type = FUNCTION;
}
else
{
token_type = VARIABLE;
}
return;
}
token_type = UNKNOWN;
while (*e != '\0')
{
*t = *e;
e++;
t++;
}
*t = '\0';
throw Error(row(), col(), 1, token);
return;
}
double Parser::parse_level1()
{
if (token_type == VARIABLE)
{
char* e_now = e;
TOKENTYPE token_type_now = token_type;
char token_now[NAME_LEN_MAX+1];
strcpy(token_now, token);
getToken();
if (strcmp(token, "=") == 0)
{
double ans;
getToken();
ans = parse_level2();
if (user_var.add(token_now, ans) == false)
{
throw Error(row(), col(), 300);
}
return ans;
}
else
{
e = e_now;
token_type = token_type_now;
strcpy(token, token_now);
}
}
return parse_level2();
}
double Parser::parse_level2()
{
int op_id;
double ans;
ans = parse_level3();
op_id = get_operator_id(token);
while (op_id == AND || op_id == OR || op_id == BITSHIFTLEFT || op_id == BITSHIFTRIGHT)
{
getToken();
ans = eval_operator(op_id, ans, parse_level3());
op_id = get_operator_id(token);
}
return ans;
}
double Parser::parse_level3()
{
int op_id;
double ans;
ans = parse_level4();
op_id = get_operator_id(token);
while (op_id == EQUAL || op_id == UNEQUAL || op_id == SMALLER || op_id == LARGER || op_id == SMALLEREQ || op_id == LARGEREQ)
{
getToken();
ans = eval_operator(op_id, ans, parse_level4());
op_id = get_operator_id(token);
}
return ans;
}
double Parser::parse_level4()
{
int op_id;
double ans;
ans = parse_level5();
op_id = get_operator_id(token);
while (op_id == PLUS || op_id == MINUS)
{
getToken();
ans = eval_operator(op_id, ans, parse_level5());
op_id = get_operator_id(token);
}
return ans;
}
double Parser::parse_level5()
{
int op_id;
double ans;
ans = parse_level6();
op_id = get_operator_id(token);
while (op_id == MULTIPLY || op_id == DIVIDE || op_id == MODULUS || op_id == XOR)
{
getToken();
ans = eval_operator(op_id, ans, parse_level6());
op_id = get_operator_id(token);
}
return ans;
}
double Parser::parse_level6()
{
int op_id;
double ans;
ans = parse_level7();
op_id = get_operator_id(token);
while (op_id == POW)
{
getToken();
ans = eval_operator(op_id, ans, parse_level7());
op_id = get_operator_id(token);
}
return ans;
}
double Parser::parse_level7()
{
int op_id;
double ans;
ans = parse_level8();
op_id = get_operator_id(token);
while (op_id == FACTORIAL)
{
getToken();
ans = eval_operator(op_id, ans, 0.0);
op_id = get_operator_id(token);
}
return ans;
}
double Parser::parse_level8()
{
double ans;
int op_id = get_operator_id(token);
if (op_id == MINUS)
{
getToken();
ans = parse_level9();
ans = -ans;
}
else
{
ans = parse_level9();
}
return ans;
}
double Parser::parse_level9()
{
char fn_name[NAME_LEN_MAX+1];
double ans;
if (token_type == FUNCTION)
{
strcpy(fn_name, token);
getToken();
ans = eval_function(fn_name, parse_level10());
}
else
{
ans = parse_level10();
}
return ans;
}
double Parser::parse_level10()
{
if (token_type == DELIMETER)
{
if (token[0] == '(' & token[1] == '\0')
{
getToken();
double ans = parse_level2();
if (token_type != DELIMETER || token[0] != ')' || token[1] || '\0')
{
throw Error(row(), col(), 3);
}
getToken();
return ans;
}
}
return parse_number();
}
double Parser::parse_number()
{
double ans = 0;
switch (token_type)
{
case NUMBER:
ans = strtod(token, NULL);
getToken();
break;
case VARIABLE:
ans = eval_variable(token);
getToken();
break;
default:
if (token[0] == '\0')
{
throw Error(row(), col(), 6);
}
else
{
throw Error(row(), col(), 7);
}
break;
}
return ans;
}
int Parser::get_operator_id(const char op_name[])
{
if (!strcmp(op_name, "&")) {return AND;}
if (!strcmp(op_name, "|")) {return OR;}
if (!strcmp(op_name, "<<")) {return BITSHIFTLEFT;}
if (!strcmp(op_name, ">>")) {return BITSHIFTRIGHT;}
if (!strcmp(op_name, "=")) {return EQUAL;}
if (!strcmp(op_name, "<>")) {return UNEQUAL;}
if (!strcmp(op_name, "<")) {return SMALLER;}
if (!strcmp(op_name, ">")) {return LARGER;}
if (!strcmp(op_name, "<=")) {return SMALLEREQ;}
if (!strcmp(op_name, ">=")) {return LARGEREQ;}
if (!strcmp(op_name, "+")) {return PLUS;}
if (!strcmp(op_name, "-")) {return MINUS;}
if (!strcmp(op_name, "*")) {return MULTIPLY;}
if (!strcmp(op_name, "/")) {return DIVIDE;}
if (!strcmp(op_name, "%")) {return MODULUS;}
if (!strcmp(op_name, "||")) {return XOR;}
if (!strcmp(op_name, "^")) {return POW;}
if (!strcmp(op_name, "!")) {return FACTORIAL;}
return -1;
}
double Parser::eval_operator(const int op_id, const double &lhs, const double &rhs)
{
switch (op_id)
{
case AND: return static_cast<int>(lhs) & static_cast<int>(rhs);
case OR: return static_cast<int>(lhs) | static_cast<int>(rhs);
case BITSHIFTLEFT: return static_cast<int>(lhs) << static_cast<int>(rhs);
case BITSHIFTRIGHT: return static_cast<int>(lhs) >> static_cast<int>(rhs);
case EQUAL: return lhs == rhs;
case UNEQUAL: return lhs != rhs;
case SMALLER: return lhs < rhs;
case LARGER: return lhs > rhs;
case SMALLEREQ: return lhs <= rhs;
case LARGEREQ: return lhs >= rhs;
case PLUS: return lhs + rhs;
case MINUS: return lhs - rhs;
case MULTIPLY: return lhs * rhs;
case DIVIDE: return lhs / rhs;
case MODULUS: return static_cast<int>(lhs) % static_cast<int>(rhs); case XOR: return static_cast<int>(lhs) ^ static_cast<int>(rhs);
case POW: return pow(lhs, rhs);
case FACTORIAL: return factorial(lhs);
}
throw Error(row(), col(), 104, op_id);
return 0;
}
double Parser::eval_function(const char fn_name[], const double &value)
{
try
{
char fnU[NAME_LEN_MAX+1];
toupper(fnU, fn_name);
if (!strcmp(fnU, "ABS")) {return abs(value);}
if (!strcmp(fnU, "EXP")) {return exp(value);}
if (!strcmp(fnU, "SIGN")) {return sign(value);}
if (!strcmp(fnU, "SQRT")) {return sqrt(value);}
if (!strcmp(fnU, "LOG")) {return log(value);}
if (!strcmp(fnU, "LOG10")) {return log10(value);}
if (!strcmp(fnU, "SIN")) {return sin(value);}
if (!strcmp(fnU, "COS")) {return cos(value);}
if (!strcmp(fnU, "TAN")) {return tan(value);}
if (!strcmp(fnU, "ASIN")) {return asin(value);}
if (!strcmp(fnU, "ACOS")) {return acos(value);}
if (!strcmp(fnU, "ATAN")) {return atan(value);}
if (!strcmp(fnU, "FACTORIAL")) {return factorial(value);}
}
catch (Error err)
{
throw Error(col(), row(), err.get_id(), err.get_msg());
}
throw Error(row(), col(), 102, fn_name);
return 0;
}
double Parser::eval_variable(const char var_name[])
{
char varU[NAME_LEN_MAX+1];
toupper(varU, var_name);
if (!strcmp(varU, "E")) {return 2.7182818284590452353602874713527;}
if (!strcmp(varU, "PI")) {return 3.1415926535897932384626433832795;}
double ans;
if (user_var.get_value(var_name, &ans))
{
return ans;
}
throw Error(row(), col(), 103, var_name);
return 0;
}
int Parser::row()
{
return -1;
}
int Parser::col()
{
return e-expr-strlen(token)+1;
}