数据结构算术表达式求值魔王语言解释.docx
《数据结构算术表达式求值魔王语言解释.docx》由会员分享,可在线阅读,更多相关《数据结构算术表达式求值魔王语言解释.docx(14页珍藏版)》请在冰豆网上搜索。
![数据结构算术表达式求值魔王语言解释.docx](https://file1.bdocx.com/fileroot1/2023-1/3/ad68c817-0cde-485b-93a3-b8015c40626e/ad68c817-0cde-485b-93a3-b8015c40626e1.gif)
数据结构算术表达式求值魔王语言解释
一.实验目的
1.深入了解栈和队列的特性,以便在实际问题背景下灵活运用他们,同时还将巩固对栈和队列这两种结构的构造方法的理解。
2.加深对mfc的理解。
3.加深对浮点型,字符型,整型之间的转换的熟悉。
二.实验内容
1.表达式求值:
表达式计算是实现程序设计语言的基本问题,也是栈的应用之一。
设计一个程序,演示用算符优先法对算术表达式求值过程。
2.魔王语言解释:
有一个魔王总是使用自己的一种非常精练而抽象的语言讲话,没有人能听得懂,但他的语言是可以逐步解释承认能听懂的语言,因为他的语言是有以下两种形式的规则由人的语言逐步抽象上去的:
(1)α→β1β2…βm
(2)(θδ1δ2…δn)→θδnθδn-1…θδ1θ
在这两种形式中,从左到右均表示解释。
试写一个魔王语言的解释系统,把他的话解释成人能听得懂的话。
三.实验步骤(可选)
一.表达式求值:
此次实验我用了mfc来做,实现了计算器界面的仿真,拓展了程序的功能,使到该程序不仅可以计算整型,还可以计算浮点型,负数;有判断键入的表达式格式的正误,删除错误输入,清除结果的功能;拓展了运算符,增加了平方的运算,分数化的运算,还有说明界面,计算结果序列化、读取序列化结果的功能。
1.定义栈数据类型;
2.定义栈的操作,初始化,出栈,入栈;
3.编写运算符优先比较函数precede;
4.编写计算表达式的函数express;
5.编写序列化函数archieve;
6.设计计算器仿真界面;
7.添加关联变量,编写相关函数。
具体代码如下:
//栈定义
typedefstruct{
char*base;
char*top;
intstacksize;
}stack;
voidinitstack(stack&s)
{
s.base=(char*)malloc(sizeof(char)*100);
s.top=s.base;
s.stacksize=100;
}
chargettop(stacks)
{
chare;
e=*(s.top-1);
returne;
}
voidpush(stack&s,chare)
{
*s.top++=e;
}
voidpop(stack&s,char&e)
{
e=*--s.top;
}
boolstackisempty(stacks)//empty?
{
if(s.top==s.base)
return1;
elsereturn0;
}
charprecede(chara,charb)//比较优先级函数
{
switch(a)
{
case'+':
switch(b)
{
case'+':
case'-':
case'#':
case')':
return'>';
case'*':
case'/':
case'^':
//s
case'(':
return'<';
}
case'-':
switch(b)
{
case'+':
case'-':
case'#':
case')':
return'>';break;
case'*':
case'/':
case'^':
//s
case'(':
return'<';break;
}
case'*':
switch(b)
{
case'#':
case'+':
case'-':
case')':
case'*':
case'/':
return'>';
case'^':
//s
case'(':
return'<';
}
case'/':
switch(b)
{
case'#':
case'+':
case'-':
case')':
case'*':
case'/':
return'>';
case'^':
//s
case'(':
return'<';
}
case'(':
if(b==')')
return'=';
else
return'<';
case')':
return'>';
case'#':
if(b!
='#')return'<';
elsereturn'=';
case'^':
//s
switch(b)
{
case'(':
return'<';
default:
return'>';
}
}
}
floatoperate(floata,chars,floatb)//运算符操作结果函数
{
floatres=0;
switch(s)
{
case'+':
res=a+b;break;
case'-':
res=a-b;break;
case'*':
res=a*b;break;
case'/':
res=a/b;break;
case'^':
res=a*a;break;
}
returnres;
}
intcheck(CStringstr)
{
intlf=0,rg=0;
for(intn=0;n{
if(str[n]=='(')
lf++;
if(str[n]==')')
rg++;
if(rg>lf)
return1;
if(nif(!
isnum(str[n])&&!
isnum(str[n+1])&&str[n+1]!
='-'&&str[n+1]!
='('&&str[n]!
=')')//两个操作符相连
return2;
}
if(lf!
=rg)
return1;//括号不匹配
if(!
isnum(str[str.GetLength()-1])&&str[str.GetLength()-1]!
=')'||(!
isnum(str[0])&&str[0]!
='('&&str[0]!
='-'))//最后一个或第一个是操作付
return2;
return0;//正确返回零
}
floatexpression(CStrings)//求值函数
{
stackshu;//数字栈
stackfu;//操作符栈
initstack(shu);
initstack(fu);
intn=0;//表达式索引
intoc=0;//字符变浮点控制变量
floata=0,b=0;//a暂存操作数1,b暂存操作数2,c暂存操作结果
c=0;
chartem1,tem2,tem3;//弹出中间变量
CStringst;//把浮点型变成字符型
push(fu,'#');//标志表达式开始
push(shu,'a');//a标志数的分隔
for(;gettop(fu)!
='#'||s[n]!
='#';oc=0)
{
if(s[n]>=48&&s[n]<=57||s[n]=='.'||(s[n]=='-'&&n==0))//字符为数字或点则入数字栈
{
push(shu,s[n]);
if(nn++;
}//if
else
if(s[n]=='-')//判断—是减号还是负号
switch(s[n-1])
{
case'+':
case'-':
case'*':
case'/':
case'(':
push(shu,s[n]);//s【n-1】是以上结果的话,“—”则是负号,入数字栈
if(nn++;
break;
default:
//其他为负号
gotoyouxian;//去比较优先级
}//switch
else
youxian:
switch(precede(gettop(fu),s[n]))//比较优先级
{
case'<':
push(fu,s[n]);
if(s[n]!
='(')
push(shu,'a');
if(nn++;
break;
case'=':
pop(fu,tem1);
if(nn++;
break;
case'>':
pop(fu,tem1);a=0;
for(pop(shu,tem2);tem2!
='a';pop(shu,tem2))//字符转换成浮点
{
if(tem2=='-')
a=0-a;
else
if(tem2=='.')
{a=a/pow(10,oc);oc=0;}
else
a=(tem2-48)*pow(10,oc++)+a;
}//for
oc=0;b=0;
for(pop(shu,tem3);tem3!
='a';pop(shu,tem3))//字符转换成浮点
{
if(tem3=='-')
b=0-b;
else
if(tem3=='.')
{b=b/pow(10,oc);oc=0;}
else
b=(tem3-48)*pow(10,oc++)+b;
}//for
c=operate(b,tem1,a);
if(a==0&&tem1=='/')
{
MessageBox(NULL,"除数不能为0!
",0,0);
c=0;zero=1;
return0;
}
st.Format("%g",c);
if(st.GetLength()>=5&&st[st.GetLength()-5]=='e')//科学计数法则要转换
change(st);
push(shu,'a');
oc=0;
for(;ocpush(shu,st[oc]);
}//switch
}//maxfor
c=0;oc=0;
for(pop(shu,tem2);tem2!
='a';pop(shu,tem2))//字符转换成浮点
{
st.Format("%g",c);
//MessageBox(NULL,st,0,0);
if(tem2=='-')
c=0-c;
else
if(tem2=='.')
{c=c/pow(10,oc);oc=0;}
else
c=(tem2-48)*pow(10,oc++)+c;
}//for
returnc;
}
二.魔王语言解释:
(mfc实现)
1.定义栈数据类型;
2.定义栈的操作,初始化,出栈,入栈;
3.编写魔王语言解释函数及将小写字母和中文建立一一对应关系;
4.运行调试。
具体实现代码:
typedefstruct{
char*base;
char*top;
intsize;
}Stack;
voidinitstack(Stack&s)
{
s.base=(char*)malloc(100*sizeof(char));
s.top=s.base;
s.size=100;
}
voidgettop(Stacks,char&p)
{
if(s.top==s.base)
;
else
p=*(s.top-1);
}
voidpush(Stack&s,charp)
{
*s.top++=p;
}
voidpop(Stack&s,char&p)
{
if(s.base==s.top)
;
else
p=*--s.top;
}
boolisempty(Stacks)
{
if(s.base==s.top)
return1;
elsereturn0;
}
voidCMyDlg:
:
OnBUTTONtrans()
{
UpdateData(true);
CStrings;
Stacksk;
initstack(sk);
chart,tem;
for(intn=0;n{
if(m_a[n]=='B')
s+="tsaedsae";
if(m_a[n]=='A')
s+="sae";
if(m_a[n]=='(')
{
n++;
t=m_a[n++];
while(m_a[n]!
=')')
push(sk,m_a[n++]);
while(!
isempty(sk))
{pop(sk,tem);
s=s+t+tem;}//while
s+=t;
}//if
}//for
m_b=s;
m_c.Empty();
for(n=0;n{
switch(m_b[n])
{
case't':
m_c+="天";
break;
case'd':
m_c+="地";
break;
case's':
m_c+="上";
break;
case'a':
m_c+="一只";
break;
case'e':
m_c+="鹅";
break;
case'z':
m_c+="追";
break;
case'g':
m_c+="赶";
break;
case'x':
m_c+="下";
break;
case'n':
m_c+="蛋";
break;
case'h':
m_c+="恨";
break;
}//switch
}//for
UpdateData(false);
}
四.实验的结果及分析。
1.表达式求值:
计算器仿真界面:
上行显示算术表达式,下行显示结果,可输入整型,浮点型,负数。
Frac表示结果分数化,save指序列化结果。
当输入表达式有误时,提示错误信息。
2.魔王语言解释:
输入魔王语言,点击开始翻译,可得结果。
五.实验中出现的问题、解决方法和心得体会
1.通过本次实验,我对栈的运算有了更深刻的理解,知道了栈的出栈,入栈的方法。
2.对mfc有了更深的认识,知道了怎么加载位图,添加,播放音乐文件,调用模态对话框,怎么实现文件的存储和读取。
3.当数值大于1000000时,数据的表示会变成科学计数法,使得程序计算出错,后来我加了一个转换函数,当数值是科学计数法时,将他转换成正常的表示方式,才使得计算正确。
4.分数化的时候当数太大是会产生溢出,后来,加上了一个判断溢出语句。
5.开始时分不清负号和减号,使得负号也进入了运算符栈,导致错误,后来加上判断语句解决问题。
6.格式化浮点型的时候,用了%f,使得结果精确度欠缺,后来换成%g。
7.做魔王解释语言的时候,发现少了最后一个字母的解释,经调试,发现问题出在,字符数组最后元素的索引为n-1,而我在循环变量小于n-1时就退出,因而少了最后一个。
后来把n-1改为n。