451 lines
9.0 KiB
C++
451 lines
9.0 KiB
C++
/*
|
|
Copyright 2010 Grégory Soutadé
|
|
|
|
This file is part of KissCount.
|
|
|
|
KissCount is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
KissCount is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with KissCount. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <iostream>
|
|
|
|
#include "ParseExp.h"
|
|
|
|
/*
|
|
Algorithm
|
|
The idea of this parser is very simple : Create a binary tree with an operator, a left and a right operand.
|
|
Leafs are constants to be computed. This structure is more flexbile than a simple stack and very easy to parse
|
|
(for resultat computation).
|
|
A simple expression (3+4) will be represented by :
|
|
+
|
|
3 4
|
|
Another example (3+4+5) :
|
|
+
|
|
3 +
|
|
4 5
|
|
|
|
If an operator is less prioritary than his father we have to do a transformation.
|
|
Example with 3*4+5.
|
|
in first instance we may have this tree :
|
|
*
|
|
3 +
|
|
4 5
|
|
So we must reverse the tree into something like :
|
|
+
|
|
* 5
|
|
3 4
|
|
|
|
At each step the parser must read one operand and one operator,
|
|
fill a node with the operator and left operand and recurse on right
|
|
operand. Finally we stop with a constant (a leaf).
|
|
Operations in parenthesis must be computed separatly and filled into
|
|
the tree like constants.
|
|
*/
|
|
|
|
/* Less to most prioritary */
|
|
enum {CST, ADD, SUB, MUL, DIV, MOD, EXP};
|
|
|
|
enum {DOUBLE_POINTED=1, INVALID_CHAR, INVALID_PARENTHESIS, INVALID_OPERATION};
|
|
|
|
|
|
#ifdef DEBUG
|
|
#define P(x) x
|
|
#else
|
|
#define P(x)
|
|
#endif
|
|
|
|
double atof(char* s, int size)
|
|
{
|
|
int neg = 0;
|
|
double res = 0;
|
|
|
|
for (; size--; s++)
|
|
{
|
|
if (*s == '.')
|
|
{
|
|
neg = 10;
|
|
continue;
|
|
}
|
|
|
|
if (neg > 0)
|
|
{
|
|
res += (double) (*s - '0') / (double)neg;
|
|
neg *= 10;
|
|
}
|
|
else
|
|
{
|
|
res *= 10;
|
|
res += *s - '0';
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
void ParseExp(char** expr, struct parse_opt* root, bool needParenthesis)
|
|
{
|
|
char* temp;
|
|
bool pointed = false;
|
|
struct parse_opt* l, *r, *op, *op_tmp;
|
|
char type = -1;
|
|
bool negative = false, number = false;
|
|
l = r = op = op_tmp = NULL;
|
|
|
|
if (!**expr) return;
|
|
|
|
for (temp=*expr; **expr; (*expr)++)
|
|
{
|
|
if (**expr == '(')
|
|
{
|
|
op_tmp = new struct parse_opt;
|
|
op_tmp->type = CST;
|
|
op_tmp->root = root;
|
|
op_tmp->l = op_tmp->r = NULL;
|
|
(*expr)++;
|
|
ParseExp(expr, op_tmp, true);
|
|
l = op_tmp;
|
|
root->l = l;
|
|
continue;
|
|
}
|
|
|
|
if (**expr == ')')
|
|
{
|
|
if (!needParenthesis)
|
|
throw INVALID_PARENTHESIS;
|
|
|
|
if ((*expr-temp) == 0)
|
|
throw INVALID_OPERATION;
|
|
break;
|
|
}
|
|
|
|
if (**expr >= '0' && **expr <= '9')
|
|
continue;
|
|
|
|
if (**expr == '.')
|
|
{
|
|
if (!pointed)
|
|
pointed = true;
|
|
else
|
|
throw DOUBLE_POINTED;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (type != -1)
|
|
throw INVALID_OPERATION;
|
|
|
|
switch(**expr)
|
|
{
|
|
case '+':
|
|
type = ADD;
|
|
break;
|
|
case '-':
|
|
if (temp == *expr)
|
|
{
|
|
if (negative)
|
|
throw INVALID_OPERATION;
|
|
temp++;
|
|
negative = true;
|
|
continue;
|
|
}
|
|
type = SUB;
|
|
break;
|
|
case '/':
|
|
type = DIV;
|
|
break;
|
|
case '*':
|
|
type = MUL;
|
|
break;
|
|
// case '%':
|
|
// type = MOD;
|
|
// break;
|
|
default:
|
|
throw INVALID_CHAR;
|
|
}
|
|
|
|
number= true;
|
|
|
|
if (!l)
|
|
{
|
|
if ((*expr-temp) == 0)
|
|
throw INVALID_OPERATION;
|
|
l = new struct parse_opt;
|
|
l->type = CST;
|
|
l->root = root;
|
|
l->l = NULL; l->r = NULL;
|
|
l->value = atof(temp, *expr-temp);
|
|
if (negative)
|
|
l->value *= -1.0;
|
|
root->l = l;
|
|
}
|
|
|
|
// Here [temp..expr] must be left operand + operator
|
|
if (root->root && root->root->type >= type)
|
|
{
|
|
// Reverse tree
|
|
op = new parse_opt;
|
|
op->root = root->root;
|
|
op->type = root->root->type;
|
|
op->r = l;
|
|
op->l = root->root->l;
|
|
op->l->root = op;
|
|
root->root->l = op;
|
|
root->root->type = type;
|
|
|
|
root->type = CST;
|
|
root->value = 0.0;
|
|
root->l = NULL ; root->r = NULL;
|
|
|
|
(*expr)++;
|
|
ParseExp(expr, root, needParenthesis);
|
|
break;
|
|
temp=*expr;
|
|
}
|
|
else
|
|
{
|
|
// Recurse on right operand
|
|
root->type = type;
|
|
// atof
|
|
r = new struct parse_opt;
|
|
r->type = CST;
|
|
r->root = root;
|
|
r->l = NULL; r->r = NULL;
|
|
r->value = 0.0;
|
|
root->r = r;
|
|
|
|
(*expr)++;
|
|
ParseExp(expr, r, needParenthesis);
|
|
break;
|
|
temp=*expr;
|
|
}
|
|
|
|
}
|
|
|
|
if (needParenthesis && **expr != ')')
|
|
throw INVALID_PARENTHESIS;
|
|
|
|
if (!number)
|
|
{
|
|
if ((*expr-temp) == 0)
|
|
throw INVALID_OPERATION;
|
|
|
|
if (op_tmp)
|
|
*root = *op_tmp;
|
|
else
|
|
{
|
|
root->type = CST;
|
|
root->l = NULL; root->r = NULL;
|
|
root->value = atof(temp, *expr-temp);
|
|
if (negative)
|
|
root->value *= -1.0;
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
double EvaluateExpr(struct parse_opt* root, bool del)
|
|
{
|
|
double l, r;
|
|
char type;
|
|
|
|
type = root->type;
|
|
|
|
if (root->type != CST)
|
|
{
|
|
l = EvaluateExpr(root->l, del);
|
|
r = EvaluateExpr(root->r, del);
|
|
}
|
|
else
|
|
l = root->value;
|
|
|
|
if (del)
|
|
{
|
|
if (root->l) delete root->l;
|
|
if (root->r) delete root->r;
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
case ADD:
|
|
P(std::cout << l << " + " << r << std::endl);
|
|
return l+r;
|
|
case SUB:
|
|
P(std::cout << l << " - " << r << std::endl);
|
|
return l+r;
|
|
case MUL:
|
|
P(std::cout << l << " * " << r << std::endl);
|
|
return l*r;
|
|
case DIV:
|
|
P(std::cout << l << " / " << r << std::endl);
|
|
return l/r;
|
|
// case MOD:
|
|
// return EvaluateExpr(root->l) % EvaluateExpr(root->r);
|
|
case EXP:
|
|
P(std::cout << l << " ^ " << r << std::endl);
|
|
return l*r;
|
|
case CST:
|
|
return l;
|
|
default:
|
|
return 0.0;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
int main()
|
|
{
|
|
char* e1 = new char[100] ;
|
|
char* e = e1;
|
|
struct parse_opt root, *r;
|
|
|
|
try
|
|
{
|
|
memset(&root, 0, sizeof(root));
|
|
r = &root;
|
|
strcpy(e1, "4*3");
|
|
ParseExp(&e1, r, false);
|
|
std::cout << e << " = " << EvaluateExpr(&root, true) << "\n";
|
|
|
|
e1 = e;
|
|
memset(e1, 0, 100);
|
|
strcpy(e1, "4*3+5");
|
|
memset(&root, 0, sizeof(root));
|
|
r = &root;
|
|
ParseExp(&e1, r, false);
|
|
std::cout << e << " = " << EvaluateExpr(&root, true) << "\n";
|
|
|
|
e1 = e;
|
|
memset(e1, 0, 100);
|
|
strcpy(e1, "3+3+3");
|
|
memset(&root, 0, sizeof(root));
|
|
r = &root;
|
|
ParseExp(&e1, r, false);
|
|
std::cout << e << " = " << EvaluateExpr(&root, true) << "\n";
|
|
|
|
e1 = e;
|
|
memset(e1, 0, 100);
|
|
strcpy(e1, "3+3+3+3");
|
|
memset(&root, 0, sizeof(root));
|
|
r = &root;
|
|
ParseExp(&e1, r, false);
|
|
std::cout << e << " = " << EvaluateExpr(&root, true) << "\n";
|
|
|
|
e1 = e;
|
|
memset(e1, 0, 100);
|
|
strcpy(e1, "4+3*5");
|
|
memset(&root, 0, sizeof(root));
|
|
r = &root;
|
|
ParseExp(&e1, r, false);
|
|
std::cout << e << " = " << EvaluateExpr(&root, true) << "\n";
|
|
|
|
e1 = e;
|
|
memset(e1, 0, 100);
|
|
strcpy(e1, "-4+3*5/2");
|
|
memset(&root, 0, sizeof(root));
|
|
r = &root;
|
|
ParseExp(&e1, r, false);
|
|
std::cout << e << " = " << EvaluateExpr(&root, true) << "\n";
|
|
|
|
e1 = e;
|
|
memset(e1, 0, 100);
|
|
strcpy(e1, "5+-4");
|
|
memset(&root, 0, sizeof(root));
|
|
r = &root;
|
|
ParseExp(&e1, r, false);
|
|
std::cout << e << " = " << EvaluateExpr(&root, true) << "\n";
|
|
|
|
e1 = e;
|
|
memset(e1, 0, 100);
|
|
strcpy(e1, "5--4");
|
|
memset(&root, 0, sizeof(root));
|
|
r = &root;
|
|
ParseExp(&e1, r, false);
|
|
std::cout << e << " = " << EvaluateExpr(&root, true) << "\n";
|
|
|
|
e1 = e;
|
|
memset(e1, 0, 100);
|
|
strcpy(e1, "4*(3+2)");
|
|
memset(&root, 0, sizeof(root));
|
|
r = &root;
|
|
ParseExp(&e1, r, false);
|
|
std::cout << e << " = " << EvaluateExpr(&root, true) << "\n";
|
|
|
|
e1 = e;
|
|
memset(e1, 0, 100);
|
|
strcpy(e1, "(3+2)*4");
|
|
memset(&root, 0, sizeof(root));
|
|
r = &root;
|
|
ParseExp(&e1, r, false);
|
|
std::cout << e << " = " << EvaluateExpr(&root, true) << "\n";
|
|
|
|
e1 = e;
|
|
memset(e1, 0, 100);
|
|
strcpy(e1, "4*(3+2)+5");
|
|
memset(&root, 0, sizeof(root));
|
|
r = &root;
|
|
ParseExp(&e1, r, false);
|
|
std::cout << e << " = " << EvaluateExpr(&root, true) << "\n";
|
|
|
|
e1 = e;
|
|
memset(e1, 0, 100);
|
|
strcpy(e1, "5+(3+2)*4");
|
|
memset(&root, 0, sizeof(root));
|
|
r = &root;
|
|
ParseExp(&e1, r, false);
|
|
std::cout << e << " = " << EvaluateExpr(&root, true) << "\n";
|
|
|
|
e1 = e;
|
|
memset(e1, 0, 100);
|
|
strcpy(e1, "3+(3+(3+3))");
|
|
memset(&root, 0, sizeof(root));
|
|
r = &root;
|
|
ParseExp(&e1, r, false);
|
|
std::cout << e << " = " << EvaluateExpr(&root, true) << "\n";
|
|
|
|
e1 = e;
|
|
memset(e1, 0, 100);
|
|
strcpy(e1, "3+(3+(3+(3+3)))*5");
|
|
memset(&root, 0, sizeof(root));
|
|
r = &root;
|
|
ParseExp(&e1, r, false);
|
|
std::cout << e << " = " << EvaluateExpr(&root, true) << "\n";
|
|
|
|
e1 = e;
|
|
memset(e1, 0, 100);
|
|
strcpy(e1, "5+(3/(6+8--5)*9)*4");
|
|
memset(&root, 0, sizeof(root));
|
|
r = &root;
|
|
ParseExp(&e1, r, false);
|
|
std::cout << e << " = " << EvaluateExpr(&root, true) << "\n";
|
|
|
|
e1 = e;
|
|
memset(e1, 0, 100);
|
|
strcpy(e1, "5+(3*(6+8--5)/9)*4");
|
|
memset(&root, 0, sizeof(root));
|
|
r = &root;
|
|
ParseExp(&e1, r, false);
|
|
std::cout << e << " = " << EvaluateExpr(&root, true) << "\n";
|
|
}
|
|
catch (int e)
|
|
{
|
|
std::cout << "Error " << e << std::endl;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|