/**
* This is a program for solve mathematical expression. Just like:
* "1+4*3/2+22*(3+2*(3-4))"
*
* To solve this problem, Let us see it by a view of priority. The rules as following:
* 1). the priority of plus sign is 1, and minus sign too.
* 2). the priority of product sign and sign of division is 2.
* 3). the priority of bracket is 3.
*
* so, we can convert the expression above to:
*
*
* [1]
* .
* -------------
* [2] . .
* [1] . . .
* . . . .
* --------------------------------
* [2] [2] [2] . .
* [1] . . [1] . . .
* . . . . . . .
* " 1 + 4 * 3 / 2 + 22 * ( 3 + 2 * ( 3 - 4 ) ) "
*
* It is easy to know, we can‘t compute a sign in rising edge. And on the other way, we could dispose those brackets by a special way. that‘s means we could get a more
* simple expression without bracket
*
* [1] [2] [2] [1] [2] [4] [5] [7]
* " 1 + 4 * 3 / 2 + 22 * 3 + 2 * 3 - 4"
*
* and then what we should to do is just as follow:
*
* step 1: get a operator .
* step 2: compare the priority with it‘s last one‘s.
* -- ‘>=‘ , compute it.
* -- ‘<‘ , return to the step above.
*
* if arrvied the end , we will get a new expression. The priority of totally expression is increase by degree.
*
* [1] [1] [2] [4] [5] [7]
* " 1 + 6 + 22 * 3 + 2 * 3 - 4 "
*
* In the last, what we need is compute all operator by inverted order.
*
*/
#include <iostream>
#include <stdio.h>
#include "../stack.h"
#define NUMS_DEP 20
#define SYMS_DEP 20
/**
* All input symbol must be one of the types. we will deal those symbol
* with a corresponding operation. Need to say, number is also belong to
* symbol.
*/
enum SYMBOL {
S_NUM,
S_PLUS,
S_SUB,
S_MUL, //multiply
S_DIV, //division
S_BRAL, //left bracket
S_BRAR, //right bracket
S_INVAID,
S_END, // the end of expression
S_MAX,
};
/**
* All symbols have a priority for operation.
*/
enum SYM_PRI {
PR_NUM = 0,
PR_INVALID = 0,
PR_PLUS = 1,
PR_SUB = 1,
PR_MUL = 2,
PR_DIV = 2,
PR_MAX,
};
/**
* record information about symbol.
*/
struct OperatorS {
//what's type?
SYMBOL sym;
//priority
int prior;
//used to record the value of number.
int val;
};
class Calculater {
public:
Calculater( );
~Calculater( );
//initialize the environment
bool set( char *expr);
//solve
bool work( void);
//show the result
void show( void);
private:
//deal with symbol
bool dwItem( OperatorS &item);
//get a symbol from the expression string
bool getItem( OperatorS &item);
//deal with bracket,
bool adjustPri( OperatorS &item);
//modify the priority of a symbol
bool calcuPri( OperatorS &item);
//calculate the value of a symbol with its' corresponding values.
bool calcuSym( OperatorS &sym);
//convert a string to a interger
bool str2Inter( char *begin, int &val, int &len);
/*
* when deal with a symbol, we found it have a feature, first-in last-out.
* that is same as the feature of the stack.
*/
//stack for save symbol
STACK<OperatorS> sym_s;
//stack for save number
STACK<int> num_s;
//mathematical expression
char * expr;
//current position
int cur_ind;
/*
* current priority. if encounter a bracket, this value will change for
* revise the priority of symbol after it.
*/
int cur_pri;
// the result will be restore in here.
int sum;
};
Calculater::Calculater( ):num_s(NUMS_DEP),sym_s(SYMS_DEP)
{
this->expr = NULL;
this->cur_ind = 0;
this->cur_pri = 0;
this->sum = 0;
}
Calculater::~Calculater( )
{}
bool Calculater::set(char * expr)
{
this->expr = expr;
this->cur_ind = 0;
this->cur_pri = 0;
this->sum = 0;
return true;
}
/**
* core function, work for solve the mathematical expression.
*/
bool Calculater::work( void)
{
OperatorS item;
/*
* untill all of symbols be computed.
*/
while( ('\0'!=this->expr[this->cur_ind])
||(this->num_s.getEleNum( )!=1) )
{
//get a symbol
//Y: continue
//N: remain the last symbol
if( !this->getItem( item) )
return false;
//deal with symbol
this->dwItem( item);
}
this->num_s.pop( this->sum);
return true;
}
/**
* get a item from the string, and build a symbol.
*/
bool Calculater::getItem( OperatorS & item)
{
char firstc = this->expr[this->cur_ind];
this->cur_ind ++;
OperatorS tmp;
switch( firstc)
{
case '+':
tmp.sym = S_PLUS;
tmp.prior = PR_PLUS;
tmp.val = 0;
break;
case '-':
tmp.sym = S_SUB;
tmp.prior = PR_SUB;
tmp.val = 0;
break;
case '*':
tmp.sym = S_MUL;
tmp.prior = PR_MUL;
tmp.val = 0;
break;
case '/':
tmp.sym = S_DIV;
tmp.prior = PR_DIV;
tmp.val = 0;
break;
case '(':
tmp.sym = S_BRAL;
tmp.prior = PR_MAX;
tmp.val = 0;
break;
case ')':
tmp.sym = S_BRAR;
tmp.prior = PR_MAX;
tmp.val = 0;
break;
case '0'...'9':
{
int len = 0;
tmp.sym = S_NUM;
tmp.prior = PR_INVALID;
this->str2Inter( this->expr + this->cur_ind - 1, tmp.val, len);
this->cur_ind += len-1;
break;
}
/*
* when arrived the end, create a end sign.
*/
case '\0':
{
tmp.sym = S_END;
tmp.prior = PR_INVALID;
tmp.val = 0;
break;
}
default :
return false;
break;
}
item = tmp;
return true;
}
/**
* get a number from the string. if success, the value will
* be store in @val, and the length of reading will be store
* in @len.
*/
bool Calculater::str2Inter(char * begin,int & val,int & len)
{
int tmp_val = 0;
int tmp_len = 0;
while( (begin[tmp_len]>='0')
&&(begin[tmp_len]<='9'))
{
tmp_val = tmp_val*10 + begin[tmp_len] - '0';
tmp_len++;
}
val = tmp_val ;
len = tmp_len ;
return true;
}
//deal with symbol
bool Calculater::dwItem( OperatorS & item)
{
printf("sym: %x, prior: %x, val: %d\n", item.sym, item.prior, item.val);
switch( item.sym)
{
//case 1: symbol is a number.
//push in @num_s.
case S_NUM :
this->num_s.push( item.val);
break;
//case 2: symbol is a operator.
case S_END:
case S_PLUS...S_DIV :
{
//compute priority, cur + = ()
this->calcuPri( item);
//compare with the last operator.
// <= , compute the last operator with the last two numbers.
//do the compare above untill the new operator greater than the last one.
// > , do nothing.
// * , push the new operator in @sym_s.
//printf("sym: %x, prior: %x, val: %d\n", item.sym, item.prior, item.val);
OperatorS last;
do{
if(!this->sym_s.pop( last))
break; //there is no symbol
if( item.prior<=last.prior)
{
this->calcuSym( last);
continue;
}
this->sym_s.push( last);
}
while( item.prior <= last.prior);
this->sym_s.push( item);
break;
}
//deal with bracket
case S_BRAL...S_BRAR:
{
this->adjustPri( item);
break;
}
default :
return false;
}
return true;
}
bool Calculater::adjustPri(OperatorS & item)
{
switch( item.sym)
{
case S_BRAL:
this->cur_pri += item.prior;
break;
case S_BRAR:
this->cur_pri -= item.prior;
break;
default :
return false;
break;
}
return true;
}
/**
* compute the priority of this symbol.
*/
bool Calculater::calcuPri( OperatorS & item)
{
switch( item.sym)
{
case S_END:
break;
default :
item.prior += this->cur_pri;
break;
}
return true;
}
bool Calculater::calcuSym(OperatorS & sym)
{
int val1, val2, sum;
this->num_s.pop( val1);
this->num_s.pop( val2);
sum = 0;
switch( sym.sym)
{
case S_PLUS:
sum = val2 + val1;
break;
case S_SUB:
sum = val2 - val1;
break;
case S_MUL:
sum = val2 * val1;
break;
case S_DIV:
sum = val2/val1;;
break;
default :
return false;
break;
}
this->num_s.push( sum);
return true;
}
void Calculater::show(void)
{
printf(" %s = %d\n", this->expr, this->sum);
}
#define EXPR "1+24*3/12-4*(5+6-7*2*(2+3*4))*22"
int main()
{
Calculater cal;
cal.set( EXPR);
cal.work( );
cal.show( );
return 0;
}
原文地址:http://blog.csdn.net/u012301943/article/details/35559155