实验二 表达式求值
院 、系 |
海师计教系 |
班级 |
计本二班 |
学 号 |
200624101101 |
姓名 |
杨振平 |
完成日期 |
2007-10-10 |
源程序名 |
expression.cpp |
一、题目
编制一个表达式求值的程序。
二、需求分析
本程序在Windows环境下用用Visual C++编写,要把一个表达式翻译成正确求值的一个机器指令序列,或者直接对表达式求值
首先要了解算术四则运算的规则。即:
1)先乘除,后加减;
2)从左算到右;
3)先括号内,后括号外。
算符优先法就是根据这个运算优先关系的规定来实现对表达式的编译或解释执行的。
任何一个表达式都是由操作数(operand)、运算符(operator)和界限符(delimiter)组成的,我们称它们为单词。一般地,操作数既可以是常数也可以是被说明为变量或常量的标识符;运算符可以分为算术运算符、关系运算符和逻辑运算符等三类;基本界限符有左右括号和表达式结束符等。为了叙述的简洁,我们仅讨论简单算术表达式的求值问题。这种表达式只含加、减、乘、除等四种运算符。
我们把运算符和界限符统称为算符,它们构成的集合命名为OP。根据上述三条运算规则,在运算的每一步中,任意两个相继出现的算符op1和op2之间的优先关系至多是下面三种关系之一:
op1<op2 opl的优先权低于op2
op1=op2 op1的优先权等于op2
op1>op2 op1的优先权高于op2
由规则3),+、- 、*和/为op1时的优先性均低于‘(’但高于“)”,由 规则2),当op1=op2时,令op1>op2,‘#’是表达式的结束符。为了算法简洁,在表达式的最左边也虚设一个‘#’构成整个表达式的一对括号。‘)’与‘(’、‘#’与‘)’以及‘(’与‘#’之间无优先关系,这是因为表达式中不允许它们相继出现,一旦遇到这种情况,则可以认为出现了语法错误。
为实现算符优先算法,可以使用两个工作栈。一个称做OPTR,用以寄存运算符;另一个称做OPND,用以寄存操作数或运算结果。
算法的基本思想是:
1)首先置操作数栈为空栈,表达式起始符“#”为运算符栈的栈底元素;
2)依次读入表达式中每个字符,若是操作数则进OPND栈,若是运算符,则和OPTR栈的栈顶运算符比较优先权后作相应操作,直至整个表达式求值完毕(即OPTR栈的栈顶元素和当前读入的字符均为“#”)。
二、概要设计
1)为了实现上述程序功能,需要定义单链表的抽象数据类型:
ADT LinkList {
数据对象:D={ai|ai∈IntegerSet,i=0,1,2,…,n,n≥0}
数据关系:R={<ai,ai+1>|ai,ai+1 ∈D}
基本操作:
Status InitStack(SqStack &S)//初始化栈
Status Push(SqStack &S,SElemType e) //入栈
char GetTop(SqStack S)//取栈顶元素
int Pop(SqStack &S)//出栈
int FindOpOrd(char op,char TestOp[])//查找取得的字符对应运算符表中的位置
char precede(char op1, char op2)//判断优先级并返回对应字符
int Operate(int a,int theta,int b)//字符解释计算函数
Status In(char Test,char TestOp[])//判断输入字符是否在运算符集合中
OperandType EvaluateExpression()// 算术表达式求值的算符优先算法。
2)本程序包含7个函数:
① 主函数main()
②运算符栈出栈初始化栈函数Status InitStack(SqStack &S)
③入栈函数Status Push(SqStack &S,SElemType e)
④入栈取栈顶元素函数char GetTop(SqStack S)
⑤出栈函数int Pop(SqStack &S)
⑥取得的字符对应运算符表中的位置函数int FindOpOrd(char op,char TestOp[])
⑦判断优先级并返回对应字符函数char precede(char op1, char op2)
⑧字符解释计算函数函数int Operate(int a,int theta,int b)
⑨判断输入字符是否在运算符集合中函数Status In(char Test,char TestOp[])
⑩算术表达式求值的算符优先算法函数OperandType EvaluateExpression()
各函数间关系如下:
main() |
EvaluateExpression() |
InitStack(SqStack &S) |
Push(SqStack &S,SElemType e) |
GetTop(SqStack S) |
Pop(SqStack &S) |
In(char Test,char TestOp[]) |
Operate(int a,int theta,int b) |
FindOpOrd(charop,charTestOp[])
|
precede(char op1, char op2) |
三、详细设计
为了实现概要设计中定义的所有的数据类型,对每个操作伪码算法;对主程序和其他模块也都需要写出伪码算法;画出系统结构图
1) 该程序的功能是实现顺序栈的定义和操作。该程序包括定义的栈结构类型以及对每一种栈操作的具体的函数定义和主函数。
#define STACK_INIT_SIZE 100
#define STACK_INIT_LENGTH 10
#define STACKINCREMENT 10
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define OPSIZE 7
typedef int SElemType;
typedef int Status;
typedef char OperandType;
unsigned char Prior[7][7] = {
'>','>','<','<','<','>','>',
'>','>','<','<','<','>','>',
'>','>','>','>','<','>','>',
'>','>','>','>','<','>','>',
'<','<','<','<','<','=',' ',
'>','>','>','>',' ','>','>',
'<','<','<','<','<',' ','=',
};//定义优先级表
char OP[OPSIZE]={'+' , '-' , '*' , '/' ,'(' , ')' , '#'};//定义运算符集合
typedef struct StackChar
{
int *base;
int *top;
int stacksize;
}SqStack;
四、测试结果
1+2#
3
2+3#
5
五、调试分析
在表达式求值函数中清楚了:getchar()在<stdio.h>中定义为int型
因此c=getchar();c-48可以自动转化为字符型
经过反复的调试终于成功了!
六、 源程序(带注释)
#include "malloc.h"
#include "conio.h"
#include "stdlib.h"
#include "stdio.h"
#define STACK_INIT_SIZE 100
#define STACK_INIT_LENGTH 10
#define STACKINCREMENT 10
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define OPSIZE 7
typedef int SElemType;
typedef int Status;
typedef char OperandType;
unsigned char Prior[7][7] = {
'>','>','<','<','<','>','>',
'>','>','<','<','<','>','>',
'>','>','>','>','<','>','>',
'>','>','>','>','<','>','>',
'<','<','<','<','<','=',' ',
'>','>','>','>',' ','>','>',
'<','<','<','<','<',' ','=',
};//定义优先级表
char OP[OPSIZE]={'+' , '-' , '*' , '/' ,'(' , ')' , '#'};//定义运算符集合
typedef struct StackChar
{
int *base;
int *top;
int stacksize;
}SqStack;
Status InitStack(SqStack &S)//初始化栈
{
S.base=(SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType ));
if(!S.base) exit (OVERFLOW);
S.top=S.base;
S.stacksize=STACK_INIT_SIZE;
return OK;
}
Status Push(SqStack &S,SElemType e) //入栈
{
if(S.top-S.base>=S.stacksize)
{
S.base=(SElemType *)realloc(S.base,(S.stacksize+STACKINCREMENT)*sizeof(SElemType ));
if(!S.base) exit(OVERFLOW);
S.top=S.base+S.stacksize;
S.stacksize+=STACKINCREMENT;
}
*(S.top)=e;S.top++;
return OK;
}
char GetTop(SqStack S)//取栈顶元素
{
if(S.top==S.base) return ERROR;
return *(S.top-1); ;
}
int Pop(SqStack &S)//出栈
{
if(S.top==S.base) return ERROR;
return *--S.top;
}
int FindOpOrd(char op,char TestOp[])//查找取得的字符对应运算符表中的位置
{
int j;
for(int i=0;i<OPSIZE;i++)
if(op==TestOp[i]) j=i;
return j;
}
char precede(char op1, char op2)//判断优先级并返回对应字符
{
return Prior[FindOpOrd(op1,OP)][FindOpOrd(op2,OP)];
}
int Operate(int a,int theta,int b)//字符解释计算函数
{
switch(theta)
{
case '+': return a+b;break;
case '-': return a-b;break;
case '*': return a*b;break;
case '/': return a/b;break;
default : return 0;
}
}
Status In(char Test,char TestOp[])//判断输入字符是否在运算符集合中
{
int Find=ERROR;
for (int i=0;i<OPSIZE;i++)
{
if(Test==TestOp[i]) Find=OK;
}
return Find;
}
OperandType EvaluateExpression()
{// 算法3.4
// 算术表达式求值的算符优先算法。
// 设OPTR和OPND分别为运算符栈和运算数栈,OP为运算符集合
int a,b,c,theta;
SqStack OPTR,OPND;
InitStack(OPTR);
Push(OPTR,'#' );
InitStack(OPND);
c=getchar();
while(c!='#'||GetTop(OPTR)!='#')
{
if(!In(c,OP)) // 不是运算符则进栈
{
Push(OPND,c-48);
c=getchar();
}
else
switch(precede(GetTop(OPTR),c))//判断优先级
{
case'<':Push(OPTR,c);c=getchar();break; // 栈顶元素优先权低
case'=':Pop(OPTR);c=getchar();break; // 脱括号并接收下一字符
case'>':theta=Pop(OPTR);b=Pop(OPND);a=Pop(OPND);Push(OPND,Operate(a,theta,b));break; // 退栈并将运算结果入栈
}
}
return GetTop(OPND);
}
void main()
{
printf(“"请输入语法正确、不含有变量的整数表达式(表达式中的数字限为单位数)(以#结束):/n"”);
int e=EvaluateExpression();
printf("%d/n",e);
}