文档库 最新最全的文档下载
当前位置:文档库 › 计算器c++代码

计算器c++代码

//提供了开发者模式(debug模式),可以方便的随时查看各个关键变量的值(另外还包括标志位,链表,运算数数组)和部分错误提示
//不支持科学技术法的表示方法
//可以实现普通正负小数整数包含括号和+-*/的混合四则运算:形如((-1)+(1.1*1.2/3))=
//debug模式运算数上限为10,普通模式为180-------------老实说,我也不知道普通模式超过了还会不会计算正确
//运算数上限没有做防溢出处理
//增加运算符需要在四个地方进行补充:1,有效字符列表2,合法性3,有效化处理规则4,计算规则
//代码总量约500行,有50行左右的代码作为debug保留
//-------------------
#include

using std::endl;
using std::cout;
using std::cin;



//-------------------
//所有的类和所有的函数声明列表
//----------------------
class nums//存放运算数的类
{
private:
long double numstr[200];//存放算式中所有的算数(按顺序)
//上面为存储空间
protected:
nums():count(0){}
~nums(){};
int count;//计数器(顺序存储必须)
int numset(long double num)//顺序存储函数
{
numstr[count]=num;
count++;
return 0;
}
int numwrite(long double num,int b)//在指定位置写入数
{
numstr[b]=num;
return 0;
}
long double numread(int b)//读取指定位置的数
{
return numstr[b];
}
bool display();//显示所有存储的数值
};

class syms//符号标志类
{
protected:
int a;//'0'标志
int b;//'1-9'标志
int c;//'+-'标志
int d;//'*'标志
int e;//'/'标志
int f;//'('标志
int g;//')'标志
int h;//'.'标志
int i;//'='标志
int fc;//'('计数器
int gc;//')'计数器
//上面的为有效值
bool display();//显示所有的标志位状态
syms():a(0),b(0),c(0),d(0),e(0),f(0),g(0),h(0),i(0),fc(0),gc(0){}
~syms(){};
};



class computer:protected nums,protected syms//计算器的算式类
{
private:
char member;//顺序存放所有算式中的运算符号和算数编号(便于在nums类中查找)
computer *next;
protected:
bool build(computer **head_adr,int debug_model=0);//构建算式链表(初次判断合法性--防止未知字符)1,//有效字服列表
bool inlaw(computer *head,int debug_model=0);//算式合法性判断(保证算式有效)2,//过滤规则
bool deal(computer *head,computer **deal_head_adr,int debug_model=0);//数值有效化处理(字符串转浮点型)3,//有效话处理规则

bool comput(computer **comput_head_adr,int debug_model=0);//无括号算式计算(无容错处理)4,//计算规则
bool display(computer *head);//显示链表所有值
long double ltodf(computer *ch_head);//链表字符串转双精度浮点型(无容错处理)
public:
computer():next(NULL){}//构造函数
bool fun_control();//总控函数(算法),唯一的对外接口
~computer(){};
};





//------------------------
//所有的函数定义
//-------------------------
//跟计算器主体算法有关的函数是按照调用时的先后顺序来排序的
//其他的小功能函数是按照重要性来排序的
//-------------------------
//构建
bool computer::build(computer **head_adr,int debug_model)
{
char get[1000];
char *point;
int i;
computer *p,*cur;
cout<<"请输入要计算的算式,以'='号结束";
if(debug_model==1)
cout<<"(debug模式)"<else
cout<cin>>get;
for(point=get,p=NULL,*head_adr=cur=NULL;*point!='\n';point++)//依次读取字符串中的字符
{
switch(*point)
{
//case 000://空格
//case 030:break;//换行符
//可以直接过滤掉的字符
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '+':
case '-':
case '*':
case '/':
case '(':
case ')':p=new computer;
p->member=*point;
if(*head_adr==NULL)

*head_adr=p;
else
cur->next=p;
cur=p;
break;
case '=':p=new computer;
p->member=*point;
if(*head_adr==NULL)
*head_adr=p;
else
cur->next=p;
cur=p;
return true;//成功输入并结束
break;
default:cout<<"含有非法字符!请重新输入" <cout<<"\'"<<*point<<"\'不是数字或者运算符号,也可能是暂时不支持的运算类型"<return false;//输入失败
}
}
}


//有效性判断的算法:根据当前指向的字符的前一个字符可以出现的值来判断算式的合法性(“前继有效法”)
//比如*号前面必须存在数字或者括号,如果出现其他的就肯定不合法,即算式无效。
//而*号前面出现了数字,则数字的状态可以进行清空,因为数字状态已

经无法影响到后面世子的正确性判断了。
//另外,采用了一个标志类来记录算式当前的状态,可以很好的解决.()号等等不能在固定的位置进行判断的情况。
//不过,即使是这样,仍然不能包含所有可能出现的错误状态,所以,另外单独列出了两个可能会出现的错误情况
//一个是.后面不能跟任何运算符号,另外一个是括号数量不对等(根据“前继有效法”均不能排除掉)


//有效性判断
bool computer::inlaw(computer *head,int debug_model)
{
computer *p;
for(p=head;p!=NULL||i!=1;p=p->next)
{
if(p->member=='.')
if(p->next->member<'0'||p->next->member>'9')
if(debug_model)
{
cout<<".后继错误"<return false;
}

switch(p->member)
{
case '0':if(c+d+f==1||b==1||a+b+c+d+e+f+g+h+i==0||h==1)//0前面可出现:+-*(.或者数字或者什么都不出
{
a=1;
c=d=e=f=0;
}
else
{
if(debug_model)
cout<<"0错误"<return false;
}
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':if(c+d+e+f==1||b==1||a+b+c+d+e+f+g+h+i==0||h==1)//数字前面可出现:数字或者+-*/(.或者什么都不出
{
b=1;
a=c=d=e=f=0;
}
else
{
if(debug_model)
cout<<"1-9错误"<return false;
}

break;
case '+':
case '-':if(a+b>=1||f==1||g==1||a+b+c+d+e+f+g+h+i==0)//+-前面可出现:数字或者(或者)或者什么都不出
{
c=1;
a=b=f=g=h=0;
}
else
{
if(debug_model)
cout<<"+-错误"<return false;
}
break;
case '*':if(a+b>=1||g==1)//*前面可出现:数字或者)
{
d=d+1;
a=b=g=h=0;
}
else
{
if(debug_model)
cout<<"*错误"<return false;
}
break;




case '/':if(a+b>=1||g==1)///前面可出现:数字或者)
{
e=e+1;
a=b=h=0;
}
else
{
if(debug_model)
cout<<"/错误"<return false;
}
break;
case '(':if(c+d+e+f==1||a+b+c+d+e+f+g+h+i==0)//(前面可出现:+-*/(或者什么都不出
{
f=1;
fc=fc+1;
c=d=e=0;
}
else
{
if(debug_model)
cout<<"(错误"<return false;
}
break;

case ')':if(a+b>=1||g==1)//)前面可出现:数字或者)
{
g=1;
gc=gc+1;
a=b=h=0;
}
else
{
if(debug_model)
cout<<")错误"<return false;
}
break;
case '.':if(h>=1)//.超过两个必错
{
if(debug_model)
cout<<".超2"<return false;
}
else
{
if(a+b>=1)//.前面只能为数字
h=h+1;
else
{
if(debug_model)
cout<<".错误"<return false;
}
}
break;




default:if(a+b>=1||g==1)//=前面可出现:数字或者)
{
i=1;
a=b=g=0;
}
else
{
if(debug_model)
cout<<"=错误"<return false;
}

}
}
if(fc!=gc)
{
if(debug_model)
cout<<"括号数量不相等"<return false;
}
return true;
}


//数值有效化处理
bool computer::deal(computer *head,computer **deal_head_adr,int debug_model)
{
computer *p1,*p2,*q1=NULL,*q2=NULL;//p1,p2指针在原链表上,q1,q2在新链表上
int a;//标志位,0表示第一次出现数字,1表示不止一次
for(a=0,p1=p2=head;p1!=NULL;p1=p2)//p2后移保留地址,便于p1清理现场
{
if((p1->member>='0'&&p1->member<='9')||p1->member=='.')//数字,将

转换后的值防到类nums中,在链表中存入标号
{
if(a==0)//第一次出现数字
{
a=1;
numset(ltodf(p1));//转换并存入
q2=new computer;
if(debug_model)
q2->member=count-1+'0';//debug模式(运算数个数上限为10,超过会导致与运算符重叠)
else
q2->member=count+71;//存入标号(+71可以避开ASCII码前面的运算符号,使运算数的个数上限到180以上)
q2->next=NULL;
if(*deal_head_adr==NULL)
*deal_head_adr=q1=q2;
else
{
q1->next=q2;
q1=q2;//q1往后移动到q2;
}
}
p2=p2->next;//p2往后移动
delete p1;//释放掉p1指向的空间,并为后移做准备
}
else//运算符号保留
{
a=0;//清空标志
if(*deal_head_adr==NULL)//链表头
*deal_head_adr=q1=p1;
else//中间或后面
{
q1->next=p1;//接入
q1=q1->next;//后移
}
p2=p2->next;
}
}
return true;
}


//单层括号的计算
//第一种模式:'('作为算式的接入口,')'作为算式的结束符
//第二种模式:数字或者+-号接入,=号结束-------此处+-符号意为‘正’‘负’;
//任意两数的运算结果都保留在前一个运算数的空间上
bool computer::comput(computer **comput_head_adr,int debug_model)
{
int pm,p1m,p2m;//缓存,p->member,p1->member,p2->member的简写
computer *p1,*p2,*p;//p在释放空间时使用
//先遍历链表,将所有的*/运算出来,+-号保留,')'结束符表示是括号内算式,‘=’表示为不含括号的普通算式
for(p1=p2=*comput_head_adr,p=p1->next;p1->member!=')'&&p1->member!='=';p2=p1,p=p1->next)
{
if(p->member=='*'||p->member=='/')//当前指向为运算数,且后继运算符为*/
{
p2=p->next;
if(debug_model)
{
p1m=p1->member-48;
p2m=p2->member-48;
}
else
{
p1m=p1->member-72;
p2m=p2->member-72;
}
if(p->member=='*')
numwrite(numread(p1m)*numread(p2m),p1m);
else
numwrite(numread(p1m)/numread(p2m),p1m);
//接下来释放掉多余的运算数和运算符的空间,并将链表接好
p1->next=p2->next;
delete(p);//释放掉运算符
delete(p2);//释放掉运算数
}
else//其他情况

p1=p1->next;

}
for(p1=p2=*comput_head_adr,p=p1->next;p1->member!=')'&&p1->member!='=';p2=p1,p=p1->next)
{
if((*comput_head_adr)->member=='+'||(*comput_head_adr)->member=='-')//针对于直接以'+'-'开头的算式
{
if(debug_model)
pm=p->member-48;
else
pm=p->member-72;
if((*comput_head_adr)->member=='+')
numwrite((0+numread(pm)),pm);
else
numwrite((0-numread(pm)),pm);
*comput_head_adr=p1=p;
delete(p2);
}
else if(p->member=='+'||p->member=='-')
{
p2=p->next;
if(debug_model)
{
p1m=p1->member-48;
p2m=p2->member-48;
}
else
{
p1m=p1->member-72;
p2m=p2->member-72;
}
if(p1->member=='(')//特殊情况,正负数的转换
{
if(p->member=='+')

numwrite((0+numread(p2m)),p2m);
else
numwrite((0-numread(p2m)),p2m);
p1->next=p2;
p1=p2;
delete(p);
}
else//正常情况
{
if(p->member=='+')
numwrite((numread(p1m)+numread(p2m)),p1m);
else
numwrite((numread(p1m)-numread(p2m)),p1m);
p1->next=p2->next;
delete(p);
delete(p2);
}
}
else
p1=p1->next;
}
return true;
}


//链表转双精度浮点型
long double computer::ltodf(computer *ch_head)
{
computer *q=NULL;
long double a=0,b=0,x=0;//a为整数部分,b为小数部分,x为缓存
int c=0;//标志位
int m=0,n=0;//计数器
for(q=ch_head;(q->member>='0'&&q->member<='9')||q->member=='.';q=q->next)
{
if(q->member=='.')//判断小数和整数部分
c=1;
else
{
if(c==0)//整数部分的处理方式
a=a*10+(q->member-'0');
else//小数部分的处理方式
{
for(m=0,n++,x=(q->member-'0');mx=x/10;
b=b+x;
}
}
}
return a+b;
}

//-----------------
//总控函数
//计算器的主体啦。。。
bool computer::fun_control()//总控函数--计算器算法
{
int a=0;//debug开关
//cout<<"开启debug模式?(0/1)";
//cin>>a;
computer *head=NULL,*deal_head=NULL;//*head链表接收输入,*deal_head存储处理后的head
computer *p=NULL,*p1=NULL,*p2=NULL;//p2遍历

,遇到(括号就把地址交给p1,p在处理括号时使用
cout<<"计算器初版,目前支持的运算符号有+-*/()."<if(build(&head,a)==false)//构建算式链表(初步)
{
cout<<"存在非运算符号,或者是不支持的运算符号"<return false;
}
else
{
if(inlaw(head,a)==false)//有效性及算式合法性检测
{
cout<<"算式无效"<return false;
}
else
{
deal(head,&deal_head,a);//处理,构建链表deal_head,数字字符串转浮点型并存入数组,运算符保留,结束时销毁head
//准备工作完成,接下来是计算
for(p1=p2=deal_head;p2!=NULL;p2=p2->next)//计算从最里层括号开始
{
if(p2->member=='=')
//p2遍历完毕也没有找到前或后括号,那么说明算式已经成为了一个不含括号的简单算式了
{
comput(&deal_head);
break;//结束
}
else if(p2->next->member=='(')//p2的下一个是'(',则将p2指向的地址交给p1;
p1=p2;
else if(p2->member==')')
{
if(p1->next->member=='(')
//如果正好p1的下一个与p2分别指向前括号与后括号,则进行计算,计算完毕后删掉前后括号
//算式值保留在括号中的第一个数字上(也就是最后保留下来的唯一一个数值)
{
p=p1->next;
comput(&p);
p1->next=p->next;
delete(p);//删掉前括号
p=p1->next;
p->next=p2->next;
delete(p2);//删掉后括号
p2=p;
}
else
{
if(p1!=deal_head)
//p1不在头部,且p1下一个不是前括号,而p2却指向了后括号,则重新遍历
p2=p1=deal_head;
else
//与上面的情况恰好相对,处理方式:计算
{
comput(&deal_head);
deal_head=p1->next;
delete(p1);
p1=deal_head;
p1->next=p2->next;
delete(p2);
p2=p1->next;
}
}
}
}
cout<<"结果是"<return true;


}
}
}


//----------------------
//显示函数,依次为链表显示,符号显示,数组显示
//开发者使用(调试保留)
bool computer::display(computer *head)
{
computer *p;
cout<for(p=head;p!=NULL;p=p->next)
cout<member;
cout<return true;
}

bool syms::display()
{
cout<cout<<"符号状态值:a="<return true;
}

bool nums::display()
{
int i;
cout<cout<<"数组元素值:"<for(i=0;i<10;i++)
{
cout<if((i+1)%5==0)
cout<}
cout<return true;
}
//------------------------


//--------------------------
int main()
{
computer a;
a.fun_control();
return 0;
system("PAUSE");
}



//-----------收工----------

相关文档