编译原理(逆波兰表达式)C语言版

合集下载

后缀表达式的实现(逆波兰表达式)

后缀表达式的实现(逆波兰表达式)

课程名称:编译原理实验项目:后缀表达式的实现姓名:专业:班级:学号:计算机科学与技术学院20 年月日实验名称:消去C程序中的注释一、实验目的1、为了更好的配合《编译原理》有关词法分析章节的教学。

2、加深和巩固学生对于词法分析的了解和掌握。

3、使学生通过本实验能够初步的了解和掌握程序词法分析的整个过程。

4、提高学生的上机和编程过程中处理具体问题的能力。

二、实验要求设计、编制并调制一个程序,将中缀表达式改写为后缀表达式。

掌握中间语言的转换方法。

功能可以包括:1.后缀表达式求值后缀表达式也叫逆波兰表达式,其求值过程可以用到栈来辅助存储。

假定待求值的后缀表达式为:6 5 2 3 + 8 * + 3 + *,则其求值过程如下:1)遍历表达式,遇到的数字首先放入栈中,此时栈如下所示:2)接着读到“+”,则弹出3和2,执行3+2,计算结果等于5,并将5压入到栈中。

3)读到8,将其直接放入栈中。

4)读到“*”,弹出8和5,执行8*5,并将结果40压入栈中。

而后过程类似,读到“+”,将40和5弹出,将40+5的结果45压入栈...以此类推。

最后求的值288。

2.中缀表达式转后缀表达式规则:中缀表达式a + b*c + (d * e + f) * g,其转换成后缀表达式则为a b c * + d e * f + g * +。

转换过程需要用到栈,具体过程如下:1)如果遇到操作数,我们就直接将其输出。

2)如果遇到操作符,则我们将其放入到栈中,遇到左括号时我们也将其放入栈中。

3)如果遇到一个右括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为止。

注意,左括号只弹出并不输出。

4)如果遇到任何其他的操作符,如(“+”,“*”,“(”)等,从栈中弹出元素直到遇到发现更低优先级的元素(或者栈为空)为止。

弹出完这些元素后,才将遇到的操作符压入到栈中。

有一点需要注意,只有在遇到" ) "的情况下我们才弹出" ( ",其他情况我们都不会弹出" ( "。

逆波兰表达式

逆波兰表达式

逆波兰表达式逆波兰表达式表达式⼀般由操作数(Operand)、运算符(Operator)组成,例如算术表达式中,通常把运算符放在两个操作数的中间,这称为中缀表达式(Infix Expression),如A+B。

波兰数学家Jan Lukasiewicz提出了另⼀种数学表⽰法,它有两种表⽰形式:把运算符写在操作数之前,称为波兰表达式(Polish Expression)或前缀表达式(Prefix Expression),如+AB;把运算符写在操作数之后,称为逆波兰表达式(Reverse Polish Expression)或后缀表达式(Suffix Expression),如AB+;其中,逆波兰表达式在编译技术中有着普遍的应⽤。

算法:⼀、将中缀表达式转换成后缀表达式算法:1、从左⾄右扫描⼀中缀表达式。

2、若读取的是操作数,则判断该操作数的类型,并将该操作数存⼊操作数堆栈3、若读取的是运算符(1) 该运算符为左括号"(",则直接存⼊运算符堆栈。

(2) 该运算符为右括号")",则输出运算符堆栈中的运算符到操作数堆栈,直到遇到左括号为⽌。

(3) 该运算符为⾮括号运算符:(a) 若运算符堆栈栈顶的运算符为括号,则直接存⼊运算符堆栈。

(b) 若⽐运算符堆栈栈顶的运算符优先级⾼或相等,则直接存⼊运算符堆栈。

(c) 若⽐运算符堆栈栈顶的运算符优先级低,则输出栈顶运算符到操作数堆栈,并将当前运算符压⼊运算符堆栈。

4、当表达式读取完成后运算符堆栈中尚有运算符时,则依序取出运算符到操作数堆栈,直到运算符堆栈为空。

⼆、逆波兰表达式求值算法:1、循环扫描语法单元的项⽬。

2、如果扫描的项⽬是操作数,则将其压⼊操作数堆栈,并扫描下⼀个项⽬。

3、如果扫描的项⽬是⼀个⼆元运算符,则对栈的顶上两个操作数执⾏该运算。

4、如果扫描的项⽬是⼀个⼀元运算符,则对栈的最顶上操作数执⾏该运算。

5、将运算结果重新压⼊堆栈。

c语言逆波兰表

c语言逆波兰表

c语言逆波兰表C语言逆波兰表达式简介一、什么是逆波兰表达式逆波兰表达式,也被称为后缀表达式,是一种不需要括号来标识操作符优先级的数学表达式表示方法。

在逆波兰表达式中,操作符位于操作数之后,因此也被称为后缀表达式。

二、逆波兰表达式的优势1. 不需要括号,减少了人为输入错误的概率。

2. 操作符的位置固定,使得计算机在计算逆波兰表达式时更加简单高效。

3. 逆波兰表达式可以通过栈来实现计算,使得计算逻辑更加清晰。

三、逆波兰表达式的转换将常见的中缀表达式转换为逆波兰表达式有两种方法:中缀转后缀法和中缀转前缀法。

这里我们主要介绍中缀转后缀的方法。

1. 创建一个空栈和一个空字符串作为结果。

2. 从左到右遍历中缀表达式的每个字符。

3. 如果当前字符是操作数,则直接将其添加到结果字符串中。

4. 如果当前字符是操作符,则判断其与栈顶操作符的优先级:a. 如果栈为空,则直接将操作符入栈。

b. 如果栈不为空,且栈顶操作符的优先级大于等于当前操作符,则将栈顶操作符弹出并添加到结果字符串中,直到栈为空或栈顶操作符的优先级小于当前操作符,然后将当前操作符入栈。

5. 如果当前字符是左括号"(",则直接入栈。

6. 如果当前字符是右括号")",则将栈中的操作符弹出并添加到结果字符串中,直到遇到左括号为止。

此时将左括号弹出,但不添加到结果字符串中。

7. 遍历完中缀表达式后,将栈中剩余的操作符依次弹出并添加到结果字符串中。

四、逆波兰表达式的计算计算逆波兰表达式可以利用栈来实现。

具体步骤如下:1. 创建一个空栈。

2. 从左到右遍历逆波兰表达式的每个字符。

3. 如果当前字符是操作数,则将其转换为数值并入栈。

4. 如果当前字符是操作符,则从栈中弹出两个操作数进行计算,并将计算结果入栈。

5. 遍历完逆波兰表达式后,栈中只剩下一个元素,即为最终的计算结果。

五、逆波兰表达式的应用逆波兰表达式在编程语言解析、数学计算和计算器等领域有着广泛的应用。

逆波兰表达式求值(实验报告及C源码)

逆波兰表达式求值(实验报告及C源码)

逆波兰表达式求值一、需求分析1、从键盘中输入一个后缀表达式,该表示包括加减乘除等操作符,以及正整数作为操作数等。

2、用堆栈来实现3、测试数据输入:2 3 * 1 – #输出:2 3 * 1 -- =5二、概要设计抽象数据类型需要一个浮点数栈来存储还没有计算的浮点数或者运算的结果。

ADT Stack数据成员:int size; int top; //分别用于存储栈大小、栈顶位置float *listArray;//存储浮点型数字的数组成员函数:bool push(float it);bool pop(float& it);bool isEmpty(); //判断栈为空bool isOne();//判断栈是否只有一个元素算法的基本思想1. 逐一扫描字符串,用ascii码进行判断,如果该字符是数字,则利用x=x*10+str[i]-48将数据由字符类型转换为浮点型数据;2. 如果字符是‘.’,则将‘.’转化为小数点,并将‘.’后的数据转化为小数部分;3. 遇到空格前是数据的,将x押入栈;4. 如果该字符是’+’,’-’,’*’或’/’,判断栈里的元素是否少于两个个,如果少于两个,报错;如果大于等于两个,就弹出两个数据,并进行相应的计算;程序的流程输入字符串,程序对字符串依次扫描。

扫描一位,处理一位。

扫描完成后,判断栈里是不是只有一个数据,若是,得到正确结果;若不是,则表达式出错。

三、详细设计物理数据类型用浮点数类型的栈存储运算中要用的数据,需要入栈、出栈,故设计如下的浮点类型的栈:class Stack{private:int size;int top;float *listArray;public:Stack(int sz=20);~Stack();bool push(float it);//入栈bool pop(float& it);//出栈bool isEmpty();//判断栈是否为空bool isOne(); //判断栈里是否只有且仅有一个元素};成员函数的函数体Stack::Stack(int sz) //栈构造函数{size=sz;top=0;listArray=new float[size]; }bool Stack::push(float it) {if(top==size)return false;listArray[top++]=it;return true;}bool Stack::pop(float& it) {if(top==0)return false;it=listArray[--top];return true;}bool Stack::isEmpty() //判断站是否为空{if(top==0)return true;return false;}bool Stack::isOne(){if(top==1)return true;return false;}Stack::~Stack(){delete listArray;}算法的具体步骤用switch语句实现1. 逐一扫描字符串,用ascii码进行判断,如果该字符是数字,则利用x=x*10+str[i]-48将数据由字符类型转换为浮点型数据;2. 如果字符是‘.’,则将‘.’转化为小数点,并将‘.’后的数据转化为小数部分;3. 遇到空格前是数据的,将x押入栈;4. 如果该字符是’+’,’-’,’*’或’/’,判断栈里的元素是否少于两个个,如果少于两个,报错;如果大于等于两个,就弹出两个数据,并进行相应的计算;算法的时空分析因为入栈、出栈的时间复杂度均为Θ(1),所以时间的复杂度主要取决于字符串的长度,空间也同样取决于字符串长度。

C语言之逆波兰表达式完整代码(附算法)

C语言之逆波兰表达式完整代码(附算法)

C语言课程设计之逆波兰表达式//逆波兰表达式(后缀表达式)reverse polish notation//程序实现的功能是将中缀表达式转变为后缀表达式,再求出其值//主要运用的知识点有:isdigit函数,pow函数,system("cls")函数,堆栈,格式的强制转换#include<stdio.h>#include<ctype.h>#include<stdlib.h>#include<math.h>void shift( char notation[]); //中缀表达式转换为后缀表达式的转换函数float calculate(float a[][2],int k); //计算后缀表达式int judge(char notation[]); //判断输入的中缀表达式是否符合要求int grade(char a); //返回运算符的等级void display(float a[][2],int k); //在屏幕上显示后缀表达式//主函数void main(){char notation [100];char choice;do{printf("请输入正确的中缀表达式:\n");printf("例如:2*3+4/3-(2+1)\n");scanf("%s",&notation);if(judge(notation)){shift(notation);}elseprintf("你的表达式有错误,请仔细检查!\n");fflush(stdin);printf("\n你是否需要继续计算(是输入Y/y,否输入其他任意键)\n");scanf("%c",&choice);getchar();system("cls");}while(choice=='Y'||choice=='y');printf("\n程序结束,谢谢使用!\n");}//判定函数int judge(char notation[]){int i,m,num=1,p1=0,p2=0;for(i=0;notation[i]!='\0';i++) //排除表达式外的字符{if(notation[i]!='('&&notation[i]!=')'&&notation[i]!='+'&&notation[i]!='-'&&notation[i]!='*'&&notation[i]!='/'&&!isdigit(notation[i])&&notation[i]!='.') {num=0;return num;}}if(notation[0]=='*'||notation[0]=='/'||notation[0]==')'||notation[0]=='.') //排除第一个字符为*,/,),.{num=0;return num;}for(i=0;notation[i]!='\0';i++) //排除'+','-','*','/','.'之间的连续出现以及'+','-','*','/','.'后面直接加')'{if(notation[i]!='('&&notation[i]!=')'&&!isdigit(notation[i])){if(notation[i+1]!='('&&!isdigit(notation[i+1])){num=0;return num;}}if(notation[i]=='('&&(notation[i+1]==')'||notation[i+1]=='.'||notation[i+1]=='*'||notation[i+ 1]=='/')){ //排除'('和')','.','*','/'一起连用num=0;return num;}if(notation[i]==')'&&(notation[i+1]=='('||notation[i+1]=='.'))//排除')'和'(','.'一起连用{num=0;return num;}}for(i=0;notation[i]!='\0';i++) //小数位不得超过4位{if(notation[i]=='.'&&notation[i+1]!='\0'&&notation[i+2]!='\0'&&notation[i+3]!='\0'&&notation[i+4]!='\0'&&notation[i+5]!='\0'){if(isdigit(notation[i+1])&&isdigit(notation[i+2])&&isdigit(notation[i+3])&&isdigit(notation[i+ 4])&&isdigit(notation[i+5])){num=0;return num;}}}for(i=0;notation[i]!='\0';i++) //排除一个小数中有两个小数点的情况{if(notation[i]=='.'){i++;while(isdigit(notation[i])){i++;}if(notation[i]=='.'){num=0;return 0;}}}for(i=0;notation[i]!='\0';i++) //排除')'后面不可以直接跟数字以及'('前面不可以加数字{if(notation[i]==')'&&isdigit(notation[i+1])){num=0;return num;}if(isdigit(notation[i])&&notation[i+1]=='(' ){num=0;return num;}}for(i=0;notation[i]!='\0';i++) //约束数字的位数一共最多为七位{if(isdigit(notation[i])){m=0; //用来计数,数字的位数为7while(isdigit(notation[i])||notation[i]=='.'){i++;m++;if(notation[i]=='.'){m--;}}if(m>7){num=0;return num;}}}for(i=0;notation[i]!='\0';i++) //'('与')'需要配对存在{if(notation[i]=='(')p1++;if(notation[i]==')')p2++;if(p1!=p2){num=0;return num;}}return num;}//转换函数void shift( char notation[]){char s1[100];s1[0]='#';float s2[100][2]; //第一维放后缀表达式的元素,第二维表示小数点的位数以及是否是运算符int i=0,j=1,k=0,t=0;float sum,num1=0,num2=0; //num1为存储整数位num2为存储小数位while(notation[i]!='\0'){if(i==0&&notation[i]=='+') //第一位为正号的情况{if(isdigit(notation[++i])){num1=0; //整数部分while(isdigit(notation[i])){num1=num1*10+(notation[i]-'0'); //notation[i]-'0'可以将字符转换为整数0~9i++;}num2=0; //小数部分t=0;if(notation[i]=='.'){i++;while(isdigit(notation[i])){num2=float (num2+pow(0.1,++t)*(notation[i]-'0'));i++;}}s2[k++][0]=float(num1+num2);s2[k-1][1]=float(t);}}if(i==0&&notation[i]=='-') //第一位为负号的情况,代码与正号类似{if(isdigit(notation[++i])){num1=0;while(isdigit(notation[i])){num1=(-1)*num1*10+(-1)*(notation[i]-'0');i++;}num2=0;t=0;if(notation[i]=='.'){i++;while(isdigit(notation[i])){num2=float(num2+(-1)*pow(0.1,++t)*(notation[i]-'0'));i++;}}s2[k++][0]=float(num1+num2);s2[k-1][1]=float(t);}}if(isdigit(notation[i])) //当前字符为数字的情况与为正号的情况一样{num1=0;while(isdigit(notation[i])){num1=num1*10+(notation[i]-'0');i++;}num2=0;t=0;if(notation[i]=='.'){i++;while(isdigit(notation[i])){num2=float(num2+pow(0.1,++t)*(notation[i]-'0'));i++;}}s2[k++][0]=float(num1+num2);s2[k-1][1]=float(t);}if(notation[i]=='+'||notation[i]=='-'||notation[i]=='*'||notation[i]=='/'){ //当前的字符为操作符时,如果s1的站定为'('则将字符直接送入s1if(s1[j-1]=='('){s1[j++]=notation[i++];}}if(notation[i]=='+'||notation[i]=='-'||notation[i]=='*'||notation[i]=='/'){ //当前字符为操作符时的普通的情况if(grade(notation[i])>grade(s1[j-1])){s1[j++]=notation[i++];}else{s2[k++][0]=s1[--j];s2[k-1][1]=-1;s1[j++]=notation[i++];}}if(notation[i]=='(') //当前字符为'('的情况{s1[j++]=notation[i++];if(notation[i]=='+') //'('后跟正号的情况{if(isdigit(notation[++i])){num1=0;while(isdigit(notation[i])){num1=num1*10+(notation[i]-'0');i++;}num2=0;t=0;if(notation[i]=='.'){i++;while(isdigit(notation[i])){num2=float(num2+pow(0.1,++t)*(notation[i]-'0'));i++;}}s2[k++][0]=float(num1+num2);s2[k-1][1]=float(t);}}if(notation[i]=='-') //'('后跟负号的情况{if(isdigit(notation[++i])){num1=0;while(isdigit(notation[i])){num1=float((-1)*num1*10+(-1)*(notation[i]-'0'));i++;}num2=0;t=0;if(notation[i]=='.'){i++;while(isdigit(notation[i])){num2=float(num2+(-1)*pow(0.1,++t)*(notation[i]-'0'));i++;}}s2[k++][0]=float(num1+num2);s2[k-1][1]=float(t);}}}if(notation[i]==')') //当前字符为')'的情况{while(s1[--j]!='('){s2[k++][0]=s1[j];s2[k-1][1]=-1;}i++;}}while(j>0&&s1[--j]!='#') //依次将s1中的除了'#'外的所有操作符出栈,相当于最后的扫尾工作{s2[k++][0]=s1[j];s2[k-1][1]=-1;}printf("\n后缀表达式(逆波兰表达式):\n");display(s2,k-1);printf("\n表达式的值为:\n");sum=calculate(s2,k-1);printf("%7.4f",sum);}//计算函数float calculate(float a[][2],int k){int i,t=0,j=k;float b[100][2],c[100];for(i=k;i>=0;i--){b[i][0]=a[k-i][0];b[i][1]=a[k-i][1];}i=k;while(j>=0){if(b[i][1]!=-1){c[t]=float (b[i][0]);j--;i--;t++;}if(b[i][1]==-1) //每当遇到一个运算符则将栈最上面的两个数出栈进行运算,然后再入栈{if(int(b[i][0])=='+'){c[t-2]=float (c[t-2]+c[t-1]);}if(int(b[i][0])=='-'){c[t-2]=float (c[t-2]-c[t-1]);}if(int(b[i][0])=='*'){c[t-2]=float (c[t-2]*c[t-1]);}if(int(b[i][0])=='/'){c[t-2]= float (c[t-2]/c[t-1]);}j--;i--;t--;}}return c[0]; //运算到最后,栈中的元素即为结果}//等级函数int grade(char a) //按照运算符的优先级{if(a=='#')return 0;if(a=='(')return 1;if(a=='-'||a=='+')return 2;if(a=='*'||a=='/')return 3;if(a==')')return 4;elsereturn 5;}//显示函数void display(float a[][2],int k){int i;for(i=0;i<=k;i++){if(a[i][1]==0)printf(" %d",int(a[i][0]));if(a[i][1]==1)printf(" %7.1f",a[i][0]);if(a[i][1]==2)printf(" %7.2f",a[i][0]);if(a[i][1]==3)printf(" %7.3f",a[i][0]);if(a[i][1]==4)printf(" %7.4f",a[i][0]);if(a[i][1]==-1)printf(" %c",int (a[i][0]));}}算法实现一个表达式E的后缀形式可以如下定义:(1)如果E是一个变量或常量,则E的后缀式是E本身。

逆波兰表达式

逆波兰表达式

逆波兰表达式逆波兰表达式题⼲正常的表达式称为中缀表达式,运算符在中间,主要是给⼈阅读的,机器求解并不⽅便。

例如:3 + 5 * (2 + 6) - 1⽽且,常常需要⽤括号来改变运算次序。

相反,如果使⽤逆波兰表达式(前缀表达式)表⽰,上⾯的算式则表⽰为:- + 3 * 5 + 2 6 1不再需要括号,机器可以⽤递归的⽅法很⽅便地求解。

为了简便,我们假设:只有 + - * 三种运算符每个运算数都是⼀个⼩于10的⾮负整数下⾯的程序对⼀个逆波兰表⽰串进⾏求值。

其返回值为⼀个结构:其中第⼀元素表⽰求值结果,第⼆个元素表⽰它已解析的字符数。

public static int[] evaluate(String x){if(x.length() == 0) return new int[]{0,0};char c = x.charAt(0);if (c >= '0' && c <= '9')return new int[]{c - '0', 1};int[] v1 = evaluate(x.substring(1));int[] v2 = __________________________________;//填空位置int v = Integer.MAX_VALUE;if (c == '+') v = v1[0] + v2[0];if (c == '*') v = v1[0] * v2[0];if (c == '-') v = v1[0] - v2[0];return new int[]{v, 1 + v1[1] + v2[1]};}代码public class _06逆波兰表达式 {// int[]数组中// 其中第⼀元素表⽰求值结果,第⼆个元素表⽰它已解析的字符数。

public static int[] evaluate(String x){if(x.length() == 0) return new int[]{0,0}; //char c = x.charAt(0); //取到⾸字符if (c >= '0' && c <= '9') //如果是数字return new int[]{c - '0', 1};// 如果是下⾯的情况,说明是字符,虽然此处没有else但是所表达的意思就是上⾯if之外的情况,因为上⾯的if没有执⾏的话才能够运⾏到下⼀⾏代码int[] v1 = evaluate(x.substring(1));//这⾥是除去第⼀个字符不要的其他部分,第⼀个字符是运算符int[] v2 = evaluate(x.substring(1+v1[1]));//填空位置,猜测是截取上⼀次没有处理到的部分// v1[1]处理v1消耗的字符数量//int v = Integer.MAX_VALUE;if (c == '+') v = v1[0] + v2[0];if (c == '*') v = v1[0] * v2[0];if (c == '-') v = v1[0] - v2[0];return new int[]{v, 1 + v1[1] + v2[1]};}public static void main(String[] args) {// TODO Auto-generated method stubSystem.out.println(evaluate("-+3*5+261")[0]);}}总结1.观察代码,也是从第⼀个字符开始:如果是数字,那么直接返回;如果不是,说明遇到了⼀个操作符,那么v1从这个操作符的后⼀位字符开始递归,直到遇到数字返回;然后v2再进⾏⼀些操作;最后把v1和v2对应的值对于回溯时最近的那个操作符进⾏运算。

c语言实现逆波兰表达式!

c语言实现逆波兰表达式!
if(a[i] >= '0' && a[i] <= '9'){ double f = getSum(&i); operNum[top++] = f;
}else if(a[i] == ' '){ i++;
}else if(a[i] == '+'){ x1 = operNum[--top]; x2 = operNum[--top]; operNum[top++] = x1 + x2; i++;
博客园 用户登录 代码改变世界 密码登录 短信登录 忘记登录用户名 忘记密码 记住我 登录 第三方登录/注册 没有账户, 立即注册
c语 言 实 现 逆 波 兰 表 达 式 !
C语言实现逆波兰表达式 (栈的应用 )
#include<iostream> #include<cstdio> using namespace std; const int MAXSIZE = 110; char a[MAXSIZE]; double operNum[MAXSIZE]; ​ double getSum(int* i){//地址传递,可以在边求值时边改变i的原值。如若是值传递,会导致值的重复算
}else if(a[i] == '-'){ x1 = operNum[--top]; x2 = operNum[--top]; operNum[top++] = x2 - x1; i++;
}else if(a[i] == '*'){ x1 = operNum[--top]; x2 = operNum[--top]; operNum[top++] = x1 * x2; i++;

c++程序 波兰式、逆波兰式、中缀计算

c++程序 波兰式、逆波兰式、中缀计算

c++程序波兰式、逆波兰式、中缀计算1. 引言1.1 概述在计算机科学和编程领域中,数学表达式的计算是一项基本任务。

而波兰式、逆波兰式和中缀计算是常见的用于表示和计算数学表达式的方法。

这些方法都有各自独特的优势和应用场景。

1.2 文章结构本文将对波兰式、逆波兰式和中缀计算进行详细介绍和分析。

首先,在“2. 波兰式计算”部分,我们将探讨波兰式的定义、原理以及如何将中缀表达式转化为后缀形式。

接下来,在“3. 逆波兰式计算”部分,我们将介绍逆波兰式的定义、原理,以及如何将中缀表达式转化为前缀形式。

最后,在“4. 中缀计算”部分,我们将深入讨论中缀表达式的定义、原理以及如何将其转化为逆波兰式形式。

文章最后,“5. 结论”部分将对整个内容进行总结与分析,并讨论这些方法在实际应用中的优点与局限性。

1.3 目的本文旨在阐述波兰式、逆波兰式和中缀计算的概念、原理以及它们在实际应用中的优缺点。

读者将通过本文了解到这些不同的表达式形式如何表示和计算数学表达式,并能根据具体需求选择合适的方法进行计算。

无论是初学者还是有一定编程经验的人,本文都将为他们提供一个全面而清晰的介绍,帮助他们更好地理解和应用波兰式、逆波兰式和中缀计算。

2. 波兰式计算:2.1 定义和原理:波兰式(Polish Notation)是一种用前缀表达式表示数学运算的方法。

在波兰式中,操作符位于操作数之前,通过这种形式来消除了括号对优先级的影响。

例如,表达式"3 + 4" 可以用波兰式表示为"+ 3 4"。

波兰式的原理是利用栈这一数据结构进行计算。

我们将表达式从右到左遍历,如果遇到一个数字,则将其压入栈中;如果遇到一个操作符,则弹出栈顶的两个数字进行计算,并将结果再次压回栈中。

重复这个过程直到整个表达式被处理完毕,并返回最终结果。

2.2 转化为后缀表达式:要将中缀表达式转化为后缀表达式(也称为逆波兰式),我们可以使用以下步骤:1. 创建一个空栈和一个空结果列表。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

中国计量学院《编译原理设计》课程论文题目:中缀表达式的逆波兰表示学生姓名:学号:学生专业:班级:二级学院:一、摘要编译原理是计算机科学与技术专业最重要的一门专业基础课程,内容庞大,涉及面广,知识点多。

由于该课程教、学难度都非常大,往往费了大量时间而达不到预期教学效果俗语说:学习的最好方法是实践。

本课程设计正是基于此,力求为学生提供一个理论联系实际的机会,通过布置一定难度的课题,要求学生独立完成。

我们这次课程设计的主要任务是编程实现对输入合法的中缀表达式进行词法分析、语法分析,构造相应的逆波兰式,计算后缀表达式的值输出结果。

逆波兰式也叫后缀表达式,即将运算符写在操作数之后。

通过实践,建立系统设计的整体思想,锻炼编写程序、调试程序的能力,学习文档编写规范,培养独立学习、吸取他人经验、探索前言知识的习惯,树立团队协作精神。

同时,课程设计可以充分弥补课堂教学及普通实验中知识深度与广度有限的缺陷,更好地帮助学生从全局角度把握课程体系。

关键字:逆波兰式;语法分析;中缀表达式二、实验综述在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,所以,这种表示法也称为中缀表示。

对中缀表达式的计值,并非按运算符出现的自然顺序来执行其中的各个运算,而是根据算符间的优先关系来确定运算的次序,此外,还应顾及括号规则。

因此,要从中缀表达式直接产生目标代码一般比较麻烦。

相对的,逆波兰式在计算机看来却是比较简单易懂的结构。

因为计算机普遍采用的内存结构是栈式结构,它执行先进后出的顺序。

三、实验意义对于实现逆波兰式算法,难度并不大,但为什么要将看似简单的中缀表达式转换为逆波兰式,原因就在于这个简单是相对人类的思维结构来说的,对计算机而言中缀表达式是非常复杂的结构。

相对的,逆波兰式在计算机看来却是比较简单易懂的结构。

因为计算机普遍采用的内存结构是栈式结构,它执行四、系统分析词法分析基本原理:词法分析程序完成的是编译第一阶段的工作。

词法分析的作用是把符流的程序变为单词序列,输出在一个中间文件上,这个文件作为语法分析程序的输入而继续编译过程。

递归下降的原理由于时间和技术的限制,语法分析采用递归下降的方法。

递归下降法是语法分析中最易懂的一种方法。

它的主要原理是,对每个非终极符按其产生式结构构造相应语法分析子程序,其中终极符产生匹配命令,而非终极符则产生过程调用命令。

因为文法递归相应子程序也递归,所以称这种方法为递归子程序下降法或递归下降法。

其中子程序的结构与产生式结构几乎是一致的。

五、算法实现将一个普通的中序表达式转换为逆波兰表达式的一般算法是:1 、首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。

2 、读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。

3 、从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。

4、如果不是数字,该字符则是运算符,此时需比较优先关系。

做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。

如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。

5 、重复上述操作1-2直至扫描完整个简单算术表达式,确定所有字符都得正确处理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。

转换的基本思路:1 在表达式字符串的末尾加一个代表结束的辅助符,比如“#”。

2 从头开始扫描表达式,并判断当前的每一个字符。

3 取当前的一个字符,如果当前字符是代表数字,则进逆波兰式的栈,如果是运算符,则转入4,如果是“#”,则结束。

4 比较当前运算符与临时栈中的栈顶运算符,如果栈顶运算符比当前运算符优先级高,则弹出一个运算符放进逆波兰式栈中,并继续4。

否则把当前运算符进临时栈,转入2六、测试结果七、总结在这次的课程设计中,让我深深地体现到编程不是一件简单的事情,它需要设计者具有全面的专业知识、缜密的思维、严谨的工作态度以及较高的分析问题、解决问题的能力,而我在很多方面还有欠缺。

通过编程实现了预期的目标,尽管如此,在程序实现的过程中出现过许多没有想到的功能,原本设计的思路和方法,到真正的程序中运行的时候就达不到预想的效果。

因此,我感觉编程序实际操作是非常重要的,不亲自实践就不会发现问题,我们只有不断的发现问题,不断的解决问题,才能使一个程序尽可能的完善。

当我即将完成这个设计的时候我终于认清楚了以前老师经常提起的一个问题,那就是:一个软件开发的过程中编码不是重要的,重要的是对分析系统以及系统模型的建立。

有了一个好的系统模型之后,我们再将其划分成几个模块,那样做起来就会容易得多。

由于经验不足,时间有限,虽然在一周的时间里顺利的完成了系统的分析、设计和调试的工作,但是仍然有许多不足之处,我会在将来的软件设计过程中引以为戒。

在做课程设计期间,有目的的去学习一些将要用到的东西,仔细的考虑工作流程的规律和步骤,充分的利用手中的开发工具,使自己的开发在代码上实现少而精确,能够尽量简单的进行操作。

通过这个课程设计让我有了深刻的了解,增长了自己的动手能力,而且我认识到团队合作也十分重要。

通过这次课程设计不仅锻炼了我学习能力,在团队合作上也有很大提高附录:源代码#include<stdio.h>/*标准输入输出头文件*/#include<conio.h>/*控制台输入输出*/#include<math.h>/*数学库函数*/#include<stdlib.h>/*系统函数,分配、释放内存等*/#include<string.h>/*字符串处理*/#define MaxSize 99char calc[MaxSize],expr[MaxSize];int i,t;struct{char data[MaxSize];/*构造了一个字符串*/ int top;}Sym;/*符号*/struct{double data[MaxSize];/*构造一个双精度数组*/int top;}Num;/*数*/double ston(char x[],int *p)/*定义一函数*/{int j=*p+1,i;double n=0;char sign=x[*p];/*字符串*/if(sign=='+'||sign=='-') *p=*p+1; while(x[j]>='0'&&x[j]<='9'){j++;}for(i=*p;i<j;i++){n=n*10+(x[i]-'0');}if(x[j]=='.'){*p=++j;while(x[j]>='0'&&x[j]<='9'){j++;}for(i=*p;i<j;i++){n=n+pow(0.1,i-*p+1)*(x[i]-'0'); }}*p=j;if(sign=='-') return(-n);return(n);}void InitStack(){Sym.top=Num.top=-1;}void SymPush(){if(Sym.top<MaxSize-1){Sym.data[++Sym.top]=calc[i++]; }else{printf("Sym栈满\n");return;}}void SymPop(){if(Sym.top>=0){expr[++t]=Sym.data[Sym.top--]; }else{printf("Sym栈空\n");return;}}void NumPush(){if(Num.top<MaxSize-1){Num.data[++Num.top]=ston(expr,&i);}else{printf("Num栈满\n");return;}}void NumPop(){if(Num.top>=0){if(expr[i]!=' '){switch(expr[i]){case '+':Num.data[Num.top-1]=Num.data[Num.top-1]+Num.data[Num.top];break;case '-':Num.data[Num.top-1]=Num.data[Num.top-1]-Num.data[Num.top];break;case '*':Num.data[Num.top-1]=Num.data[Num.top-1]*Num.data[Num.top];break;case '/':Num.data[Num.top-1]=Num.data[Num.top-1]/Num.data[Num.top];break;case '%':Num.data[Num.top-1]=(int)(Num.data[(Num.top-1)])%(int)(Num.data[Num.top]);break;case '^':Num.data[Num.top-1]=pow(Num.data[Num.top-1],Num.data[Num.top]);break;}Num.top--;}}else{printf("Num栈空\n");return;}}int main(void){loop1:i=0,t=-1;system("cls");printf("********************************************\n"); printf("**********中缀表达式变逆波兰表达式**********\n");printf("********************************************\n"); printf("请输入中缀表达式:");InitStack(),gets(calc);while(calc[i]!='\0'&&calc[i]!='='){if(calc[i]>='0'&&calc[i]<='9'){while((calc[i]>='0'&&calc[i]<='9')||(calc[i]=='.')) {loop2:expr[++t]=calc[i++];}expr[++t]=' ';}else if(calc[i]=='('){SymPush();}else if(calc[i]==')'){while(Sym.data[Sym.top]!='('){SymPop();expr[++t]=' ';}Sym.data[Sym.top--]='\0';i++;}else if((calc[i]=='+'||calc[i]=='-')){if((i==0)||(!(calc[i-1]>='0'&&calc[i-1]<='9')&&calc[i-1]!=')')) goto loop2;while(Sym.top>=0 && Sym.data[Sym.top]!='('){SymPop();expr[++t]=' ';}SymPush();}else if(calc[i]=='*'||calc[i]=='/'||calc[i]=='%'){while(Sym.top>=0&&(Sym.data[Sym.top]=='*'||Sym.data[Sym.top]=='/'||Sy m.data[Sym.top]=='%'||Sym.data[Sym.top]=='^')){SymPop();expr[++t]=' ';}SymPush();}else if(calc[i]=='^'){while(Sym.top>=0&&Sym.data[Sym.top]=='^'){SymPop();expr[++t]=' ';}SymPush();}else{i++;}}while(Sym.top>=0){SymPop();expr[++t]=' ';}expr[++t]=Sym.data[++Sym.top]='\0';printf("后缀表达式:%s\n",expr);for(i=0;expr[i]!='\0';i++){if((expr[i]>='0'&&expr[i]<='9')||((expr[i]=='+'||expr[i]=='-')&&(expr[i+1]>='0'&&expr[i+1]<='9'))){NumPush();}else{NumPop();}}printf("运算结果为:%g\n",Num.data[0]); printf("Continue(y/n)?");switch(getch()){case 'y':{system("cls");goto loop1;} case 'n':default :exit(0);}getch();return(0);}。

相关文档
最新文档