// 程序基于C++之父的表达式计算例子改版为字符串流计算
#ifndef __EXPR__CALC__H__
#define __EXPR__CALC__H__
#include <iostream>
#include <map>
#include <string>
#include <sstream>
enum Token_value
{
NAME, NUMBER, END,
PLUS='+', MINUS='-', MUL='*', DIV='/',
PRINT=';', ASSIGN='=', LP='(',RP=')'
};
class ExprCalc
{
public:
ExprCalc() : curr_tok(PRINT),no_of_errors(0) {}
~ExprCalc() { ss.clear(); table.clear(); }
void operator << (const std::string &exp);
void set(const std::string &var, double val);
void set_table(std::map<std::string,double> &tab);
double calc();
bool get_error();
private:
Token_value get_token();
double term(bool get);
double expr(bool get);
double prim(bool get);
double error(const std::string& s);
private:
std::map<std::string,double> table;
std::stringstream ss;
std::string string_value;
double number_value;
int no_of_errors;
Token_value curr_tok;
};
#endif
#include "stdafx.h"
#include "ExprCalc.h"
Token_value ExprCalc::get_token()
{
char ch;
do{
if(!ss.get(ch))return curr_tok = END;
}while(ch!='\n' && isspace(ch));
switch(ch)
{
case ';':
case '\n':
return curr_tok = PRINT;
case '+':
case '-':
case '*':
case '/':
case '(':
case ')':
case '=':
return curr_tok = Token_value(ch);
case '0':case '1':case '2':case '3':case '4':
case '5':case '6':case '7':case '8':case '9':
case '.':
ss.putback(ch);
ss>>number_value;
return curr_tok = NUMBER;
default:
if(isalpha(ch))
{
string_value = ch;
while(ss.get(ch) && isalnum(ch))string_value.push_back(ch);
ss.putback(ch);
return curr_tok = NAME;
}
error("非法变量名");
return curr_tok = PRINT;
}
}
double ExprCalc::term(bool get)
{
double left = prim(get);
for(;;)
{
switch(curr_tok)
{
case MUL:
left *= prim(true);
break;
case DIV:
if(double d = prim(true))
{
left /= d;
break;
}
return error("除以0溢出");
default:
return left;
}
}
}
double ExprCalc::expr(bool get)
{
double left = term(get);
for(;;)
{
switch(curr_tok)
{
case PLUS:
left += term(true);
break;
case MINUS:
left -= term(true);
break;
default:
return left;
}
}
}
double ExprCalc::prim(bool get)
{
if(get)get_token();
switch(curr_tok)
{
case NUMBER:{
double v = number_value;
get_token();
return v;
}
case NAME: {
if(table.find(string_value) == table.end()){no_of_errors++;}
double& v = table[string_value];
if(get_token() == ASSIGN){v = expr(true);}
return v;
}
case MINUS: {return -prim(true);}
case LP: {
double e = expr(true);
if(curr_tok != RP){return error("没有匹配右括号");}
get_token();
return e;
}
default:
return error("初等项异常");
}
}
double ExprCalc::error(const std::string& s)
{
no_of_errors++;
printf("错误: %s \n", s.c_str());
return 1;
}
double ExprCalc::calc()
{
no_of_errors = 0;
double ret = 0;
while(!ss.eof())
{
get_token();
if(curr_tok == END)break;
if(curr_tok == PRINT)continue;
ret = expr(false);
}
ss.clear();
return ret;
}
void ExprCalc::set(const std::string &var, double val)
{
if(table.find(var)!=table.end())
{
table.erase(var);
}
table[var] = val;
}
void ExprCalc::operator << (const std::string &exp)
{
ss.clear();
ss << exp;
}
void ExprCalc::set_table(std::map<std::string,double> &tab)
{
table.clear();
table.swap(tab);
}
bool ExprCalc::get_error()
{
return (no_of_errors != 0);
}
#include "ExprCalc.h"
int main(int argc, char *argv[])
{
ExprCalc ec;
ec.set("a2",3);
ec.set("b3",2.5);
ec<<("a2*100 /b3");
printf("%lf\n",ec.calc());
ec<<(" a2 * ( b3 + 1 / 3 )");
printf("%lf\n",ec.calc());
ec.set("a2",4);
ec<<("a2 * (b3 +1 /3) -1/3");
printf("%lf\n",ec.calc());
return 0;
}