编译原理(逆波兰表达式)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. 创建一个空栈和一个空结果列表。

编译原理逆波兰式

编译原理逆波兰式

内蒙古工业大学信息工程学院实验报告课程名称:编译原理实验名称:语法制导把表达式翻译成逆波兰式实验类型:验证性□ 综合性□ 设计性□实验室名称:电力大楼九楼东机房班级:计13-1学号:201320201045姓名:徐铭贝组别:同组人:成绩:实验日期:2016-6一)实验目的进一步掌握语法制导翻译的概念,理解中间语言,设计出错处理程序方法,掌握把表达式翻译成中间语言的算法。

(二)实验内容1.从左到右扫描中缀表达式,经语法分析找出中缀表达式出现的错误并给出错误的具体位置和类型。

一个运算符栈存放暂时不能出现的运算符,逆波兰区存放逆波兰表达式。

2.测试所编程序,给出正确和错误的结果。

(三)实验要求1.学生课前要认真阅读实验指导,理解实验内容与相关理论知识的关系,并完成预习报告2.用C语言或其它高级语言编写程序3.写出实验报告实验二语法制导把表达式翻译成逆波兰式一、实验名称语法制导把表达式翻译成逆波兰式二、实验目的通过上机实习加深对语法指导翻译原理的理解,进一步掌握语法制导翻译的概念,掌握运算符优先权的算法,将语法分析所识别的表达式变换成中间代码的翻译方法。

三、表达式生成逆波兰式的算法1、初始化△送到运算符栈。

2、扫描左括号“(”,把△送到运算符栈。

3、扫描到变量,把它送到逆波兰区。

4、扫描到运算符(1)栈内运算符比较a.栈内运算符>=栈外运算符,把栈内运算符送到逆波兰区。

b.栈内运算符<栈外运算符,把栈外运算符入栈。

( 2 ) 栈内是△把运算符入栈。

5、扫描右括号“)”。

( 1 )栈内是运算符,把栈内运算符送到逆波兰区。

( 2 )栈内是△则△退栈,读入下一个字符。

6、扫描到#(结束符)( 1 )栈内是运算符,把栈内运算符送到逆波兰区。

( 2 )栈内是△结束,否则继续分析。

四、程序清单#include<stdio.h>int jg[30];int fh[30];char fuhao[30][30]; //char fuhao1[30];int fuhao2[30];int number4=0;int number5=0;int bds[30];int number3=0; //表达式char fh1[6]={'(','+','-','*','/','^'}; //关系表int number1=0; //结果int number2=0; //符号int main(){int gx,gx1; //比较关系char aa; //字符int a,b,c=0,sum=0; //平常使用的while(1){c=0;while(1){scanf("%c",&aa);bds[number3]=aa;number3++;if(aa=='#'){for(a=number2-1;a>=0;a--){jg[number1]=fh[a];number1++;}break;}if(aa<='z'&&aa>='a'){jg[number1]=aa;number1++;// printf("aaa\n");}if(aa=='('){fh[number2]=aa;number2++;// printf("bbb\n");}if(aa=='+'||aa=='-'||aa=='*'||aa=='/'||aa=='^') // (<+=-<*=/<^<) {while(1){gx=0;gx1=0;for(a=0;a<6;a++){if(aa==fh1[a])gx=a;if(number2==0){break;}if(fh[number2-1]==fh1[a])gx1=a;}if(number2==0){fh[number2]=aa;number2++;break;}if(gx==1||gx==2){gx=1;}if(gx1==1||gx1==2){gx1=1;}if(gx==4||gx==3){gx=2;}if(gx1==4||gx1==3){gx1=2;}if(gx1>=gx){if(number2==0){// printf("ge2ge2ge2\n");fh[number2]=aa;number2++;break;}// printf("gege\n");jg[number1]=fh[number2-1];// printf("%c\n",fh[number2-1]);fh[number2-1]='\0';number1++;number2--;continue;}else{// printf("ge1ge1\n");fh[number2]=aa;number2++;break;}}}if(aa==')'){// printf(")))\n");for(a=number2-1;a>=0;a--){if(fh[a]=='('){fh[a]='\0';number2--;break;}else {jg[number1]=fh[a];number1++;fh[a]='\0';number2--;}}}}for(a=0;a<number1;a++){printf("%c",jg[a]);}printf("\n");for(a=0;a<number3-1;a++){if(bds[a]<='z'&&bds[a]>='a')if(bds[a+1]<='z'&&bds[a+1]>='a') {fuhao[number4][number5]=bds[a];number5++;}else{fuhao[number4][number5]=bds[a];fuhao2[number4]=number5+1;number5=0;fuhao1[number4]='a'+number4;number4++;}}printf("从前到后依次为:\n");for(a=0;a<number4;a++){printf("%c:::%s\n",fuhao1[a],fuhao[a]);}for(a=0;a<number4;a++){printf("%c",fuhao1[a]);sum=sum+fuhao2[a];for(;(jg[sum]<='z'&&jg[sum]>='a')!=1;sum++) { if(sum>=number1){break;}printf("%c",jg[sum]);}}printf("\n");for(a=0;a<30;a++){jg[a]='\0';fh[a]='\0';for(b=0;b<30;b++){fuhao[a][b]='\0';}}number1=0;number2=0;number3=0;number4=0;number5=0;sum=0;}return 0;}五、算法思想有三个数组分别存放的是符号、变量、优先级、之后输入字符,进行判断是什么东西,之后再对他们进行进出符号,变量直接进,判断优先级(老师上课所讲的逆波兰式如何生成),最后显示出其逆波兰式。

编译原理 逆波兰式 代码

编译原理 逆波兰式 代码

逆波兰式include<stdio.h>#include<math.h>#define max 100char ex[max]; /*存储后缀表达式*/void trans(){ /*将算术表达式转化为后缀表达式*/char str[max]; /*存储原算术表达式*/char stack[max]; /*作为栈使用*/char ch;int sum,i,j,t,top=0;printf("*****************************************"n");printf("*输入一个求值的表达式,以#结束。

*"n");printf("******************************************"n");printf("算数表达式:");i=0; /*获取用户输入的表达式*/do{i++;scanf("%c",&str[i]);}while(str[i]!='#' && i!=max);sum=i;t=1;i=1;ch=str[i];i++;while(ch!='#'){switch(ch){case '(': /*判定为左括号*/top++;stack[top]=ch;break;case ')': /*判定为右括号*/while(stack[top]!='('){ex[t]=stack[top];top--;t++;}top--;break;case '+': /*判定为加减号*/case '-':while(top!=0&&stack[top]!='('){ex[t]=stack[top];top--;t++;}top++;stack[top]=ch;break;case '*': /*判定为乘除号*/case '/':while(stack[top]=='*'||stack[top]=='/'){ex[t]=stack[top];top--;t++;top++;stack[top]=ch;break;case ' ':break;default:while(ch>='0'&&ch<='9'){ /*判定为数字*/ ex[t]=ch;t++;ch=str[i];i++;}i--;ex[t]='#';t++;}ch=str[i];i++;}while(top!=0){ex[t]=stack[top];t++;top--;}ex[t]='#';printf(""n"t原来表达式:");for(j=1;j<sum;j++)printf("%c",str[j]);printf(""n"t后缀表达式:",ex);for(j=1;j<t;j++)printf("%c",ex[j]);}void compvalue(){ /*计算后缀表达式的值*/ float stack[max],d; /*作为栈使用*/char ch;int t=1,top=0; /*t为ex下标,top为stack下标*/ch=ex[t];t++;while(ch!='#'){switch(ch){case '+':stack[top-1]=stack[top-1]+stack[top];top--;break;case '-':stack[top-1]=stack[top-1]-stack[top];top--;break;case '*':stack[top-1]=stack[top-1]*stack[top];top--;break;if(stack[top]!=0)stack[top-1]=stack[top-1]/stack[top];else{printf(""n"t除零错误!"n");exit(0); /*异常退出*/}top--;break;default:d=0;while(ch>='0'&&ch<='9'){d=10*d+ch-'0'; /*将数字字符转化为对应的数值*/ch=ex[t];t++;}top++;stack[top]=d;}ch=ex[t];t++;}printf(""n"t计算结果:%g"n",stack[top]);}main(){trans();compvalue();}。

C语言简单计算器原理——表达式求值(采用逆波兰表达式和栈结合)

C语言简单计算器原理——表达式求值(采用逆波兰表达式和栈结合)

C语⾔简单计算器原理——表达式求值(采⽤逆波兰表达式和栈
结合)
表达式的求解的关键是将其转换成逆波兰表达式(即后缀表达式,如1+2*3它的逆波兰表达式为123*+),在后缀表达式中已经考虑了运算符的优先级,
没有括号,只有操作数和运算符。

算术表达式转换成后缀表达式⽅法如下:
依次从键盘输⼊表达式的字符ch,对于每个ch:
(1)若ch为数字则直接将其放⼊后缀数组exp中并以#号标记数值串结束。

(2)若ch为"(",则直接将其压⼊字符栈op中。

(3)若ch为")",则将栈中"("以前的字符依次全部删除并将其放⼊后缀数组exp中,然后再将字符ch放⼊字符栈op中。

(4)若ch为"+"."-",则将栈中"("以前的运算符依次全部删除并将其放⼊后缀数组exp中,然后再将ch放⼊op栈中。

(5)若ch为"*"."/",则将栈顶连续的"*"."/"删除,并放⼊后缀数组exp中,然后将ch放⼊op栈中。

(6)若字符串str扫描完毕,则将栈中所有运算符删除并放⼊后缀数组exp,最后在后缀数组exp中便可得到后缀表达式。

在对后缀表达式求值时要⽤到⼀个数值栈st,在后缀数组exp中从头开始扫描,若是数字则将其放⼊数值栈中,
若遇到字符就进⾏两次退栈,并将运算结果再放⼊栈中,如此重复下去,最后当后缀数组扫描完后数值栈st的栈顶元素便是所要求的表达式的值。

(编译原理)逆波兰式算法的源代码

(编译原理)逆波兰式算法的源代码

(编译原理)逆波兰式算法的源代码一.实验目的1.深入理解算符优先分析法2.掌握FirstVt和LastVt集合的求法有算符优先关系表的求法3.掌握利用算符优先分析法完成中缀表达式到逆波兰式的转化二.实验内容及要求将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。

程序输入/输出示例:输出的格式如下:(1)(2)输入一以#结束的中缀表达式(包括+—*/()数字#)(3)(4)逆波兰式备注:(1)在生成的逆波兰式中如果两个数相连则用&分隔,如28和68,中间用&分隔;串。

注意:1.表达式中允许使用运算符(+-*/)、分割符(括号)、数字,结束符#;2.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好);3.对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。

同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;三.实验过程1、逆波兰式定义将运算对象写在前面,而把运算符号写在后面。

用这种表示法表示的表达式也称做后缀式。

逆波兰式的特点在于运算对象顺序不变,运算符号位置反映运算顺序。

采用逆波兰式可以很好的表示简单算术表达式,其优点在于易于计算机处理表达式。

2、产生逆波兰式的前提中缀算术表达式3、逆波兰式生成的实验设计思想及算法(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。

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

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

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

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

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

编译原理中间代码

编译原理中间代码
S if E then S1 | if E then S1 else S2 | while E do S1 ❖这些语句的代码结构示意图分别在图8.15中:
❖翻译的基本思路:对于E为a rop b的形式生成代码为: if a rop b goto E.true 和goto E.false 其中,使用E.true和E.false分别表示E的真假出口转移目标
§ 中间代码的形式
一.逆波兰式(后缀式)(后根遍历) ❖由波兰逻辑学家卢卡西维奇发明 ❖这种表示法将运算对象写在前面,把运算符号写在后面 ❖图8.11给出了程序设计语言中的逆波兰表示形式:
程序设计语言中的表示
a*b a*b+c a*(b+c/d) a*b+c*d
逆波兰表示
ab* ab*c+ abcd/+* ab*cd*+
❖为了直观,也把四元式的形式写成简单赋值形式:
(1)t1:=b*c
(2)t2:=b*d
(3)t3:=t1+t2
(4)a:=t3
(jump,-,-,L) goto L
(jrop,B,C,L) if B rop C goto L
❖例题:写出算术表达式: A+B*(C-D)+E/(C-D)↑N ①四元式 ②三元式 ③间接三元式 ④逆波兰 ⑤树形表示
{ E.place:=newtemp; emit(E.place ‘:=’ ‘uminus’ E1.place)} { E.place := E1.place) { p:=lookup(); if p≠nil then E.place:=p) else error}
❖图8.12中的第(3)条产生式及其有关语义描述如图8.13:
E→(E1) {E.place∶=E1.place}

逆波兰(加、减、乘、除、括号)表达式原理及C++代码实现

逆波兰(加、减、乘、除、括号)表达式原理及C++代码实现

逆波兰(加、减、乘、除、括号)表达式原理及C++代码实现当我们输⼊⼀个数学表达式,是中缀表达式,我们⾸先转换为后缀表达式(逆波兰表达式),然后再进⾏求值。

代码思路:(1)⾸先对输⼊的中缀表达式合法性进⾏判断,bool isStringLegal(const char* str); 函数实现。

(2)然后把中缀表达式转换为后缀表达式。

(3)根据后缀表达式求出结果,double getTheResult(vector<string> &vec);函数实现。

注意:表达式的运算符可以输⼊加、减、乘、除、括号,输⼊的数据为整形数据,计算结果为double型数据。

1 #include <iostream>2 #include <math.h>3 #include <map>4 #include <vector>5 #include <string.h>6 #include <memory>7 #include <string>8 #include <stdio.h>9 #include <stack>10 #include <stdlib.h>1112using namespace std;1314#define MAX_STRING_LENGTH 1001516/* 解析当前的整形数据,并把整形数据转换为string型 */17string analyData(const char* str, int &i);1819/* 根据逆波兰表达式求表达式的值 */20double getTheResult(vector<string> &vec);2122/* 判断该字符是否是 + - * / ( ) */23bool isCalChar(const char ch);2425/* 判断输⼊的中缀表达式是否合法 */26bool isStringLegal(const char* str);27282930/* 解析当前的整形数据,并把整形数据转换为string型 */31string analyData(const char* str, int &i)32 {33int temp = i++;34while(str[i] >= '0' && str[i] <= '9' && str[i] != '\0')35 {36 i++;37 }3839string s(str+temp,str+i);4041return s;42 }4344/* 根据逆波兰表达式求表达式的值 */45double getTheResult(vector<string> &vec)46 {47 vector<string>::iterator it;48 stack<double> sta;4950string strTemp;51double d = 0, d1 = 0, d2 = 0;5253for(it = vec.begin(); it != vec.end(); it++)54 {55 strTemp = (*it);5657if(strTemp == "+")58 {59 d1 = sta.top();60 sta.pop();6162 d2 = sta.top();63 sta.pop();6465 d = d1 + d2;66 sta.push(d);67 }68else if(strTemp == "-")69 {70 d1 = sta.top();71 sta.pop();7273 d2 = sta.top();74 sta.pop();7576 d = d2 - d1;77 sta.push(d);78 }79else if(strTemp == "*")80 {81 d1 = sta.top();82 sta.pop();8384 d2 = sta.top();85 sta.pop();8687 d = d2 * d1;88 sta.push(d);89 }90else if(strTemp == "/")91 {92 d1 = sta.top();93 sta.pop();9495 d2 = sta.top();96 sta.pop();9798 d = d2 / d1;99 sta.push(d);100 }101else102 {103const char *p = strTemp.c_str();104 d = atoi(p);105 sta.push(d);106 }107 }108return sta.top();109 }110111/* 判断该字符是否是 + - * / ( ) */112bool isCalChar(const char ch)113 {114if(ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')') 115 {116return true;117 }118119return false;120 }121/* 判断输⼊的中缀表达式是否合法 */122bool isStringLegal(const char* str)123 {124/* 判断是否是空串 */125if(NULL == str)126 {127return false;128 }129130int len = strlen(str);131int i = 0;132int flag = 0;133134/* 字符串的开头和末尾是否是数字 */135if(str[0] > '9' || str[0] < '0' || str[len-1] > '9' || str[len-1] < '0')136 {137return false;138 }139140141for(i = 0; str[i] != '\0'; i++)142 {143/* 是否有除了加减乘除括号之外的字符 */144if(isCalChar(str[i]) == false)145 {146return false;147 }148149/* 判断是否有两个连续的符号 */150if(i < len-1 && isCalChar(str[i]) == true)151 {152if(isCalChar(str[i+1]) == true)153 {154return false;155 }156157 }158159/* 判断括号是否成对 */160if(str[i] == '(')161 {162 flag++;163 }164else if(str[i] == ')')165 {166 flag--;167 }168169/* 判断是否出现 )( 这样的情况 */170if(flag < 0)171 {172return false;173 }174 }175176/* 判断括号是否匹配 */177if(flag != 0)178 {179return false;180 }181182return true;183 }184185int main(void)186 {187char str[MAX_STRING_LENGTH] = {0};188int i = 0;189string data;190191/* 存放运算符表达式的栈 */192 stack<char> oper_char;193194/* 存放后缀表达式 */195 vector<string> post_str;196197/* 输⼊中缀的表达式 */198 gets(str);199200/* 判断输⼊的中缀表达式是否合法 */201if(isStringLegal(str) != true)202 {203 cout << "This expression is not legal." << endl; 204 }205else206 {207/* 将中缀表达式转换为后缀表达式 */208for(i = 0; str[i] != '\0'; i++)209 {210/* 如果该字符为数字,解析该数字,并压⼊栈 */ 211if(str[i] >= '0' && str[i] <= '9')212 {213 data = analyData(str,i);214 post_str.push_back(data);215 i--;216 }217else if(str[i] == '(')218 {219 oper_char.push(str[i]);220 }221else if(str[i] == ')')222 {223char chtemp[2] = {0};224225 chtemp[0] = oper_char.top();226227while(chtemp[0] != '(')228 {229string strtemp(chtemp);230 post_str.push_back(strtemp);231 oper_char.pop();232233 chtemp[0] = oper_char.top();234 }235 oper_char.pop();236 }237else if(str[i] == '+' || str[i] == '-')238 {239char chtemp[2] = {0};240241/* 全部出栈,但是碰到 '('就要停⽌出栈 */242while(oper_char.size() != 0)243 {244 chtemp[0] = oper_char.top();245if(chtemp[0] == '(')246 {247break;248 }249250 oper_char.pop();251252string strtemp(chtemp);253 post_str.push_back(strtemp);254 }255256/*将当前的表达式符号⼊栈*/257 oper_char.push(str[i]);258 }259else if(str[i] == '*' || str[i] == '/')260 {261char chtemp[2] = {0};262while(oper_char.size() != 0)263 {264 chtemp[0] = oper_char.top();265if(chtemp[0] == '(' || chtemp[0] == '+' || chtemp[0] == '-') 266 {267break;268 }269else270 {271 oper_char.pop();272273string strtemp(chtemp);274 post_str.push_back(strtemp);275 }276 }277278/*将当前的表达式符号⼊栈*/279 oper_char.push(str[i]);280 }281 }282283/* 存放表达式的栈可能还有数据 */284while(!oper_char.empty())285 {286char chtemp[2] = {0};287 chtemp[0] = oper_char.top();288 oper_char.pop();289290string strtemp(chtemp);291 post_str.push_back(strtemp);292 }293294/* 把逆波兰表达式求值 */295 cout << getTheResult(post_str) << endl;296 }297298return0;299 }。

实验报告_编译原理_表达式翻译程序(逆波兰式)(后缀表达式)的设计与实现

实验报告_编译原理_表达式翻译程序(逆波兰式)(后缀表达式)的设计与实现

5.1目的和要求1、掌握表达式由中缀式转变成后缀式的过程。

2、学会用栈这种数据结构实现的方法。

5.2实验环境Windows XP + VC++6.05.3实验准备写出一个中缀式,分析可能得到的后缀式s=(a+b)*c 后缀式sab+c*=s<a 后缀式sa<a=b&c=d 后缀式ab=cd=&a>b|c=d 后缀式ab>cd=|5.4实验内容及步骤1、输入已给的文本格式的扫描程序biaoda.cpp文件,然后编译运行,检查修改错误。

2、编译成功后,提示输入表达式,用回车键查看输出的结果。

3、比较自己分析的结果和屏幕上的输出结果。

给出代码没有‘=’,‘<’,‘>’,‘&’,‘|’运算结果错误5.5实验小结1、得到的经验。

中缀表达式转换为后缀表达式2、遇到的主要问题。

运算符优先级不清楚,自行查找。

3、改进方案。

在原代码中加入有关‘=’,‘<’,‘>’,‘&’,‘|’的运算。

else if(str[i]=='&'|| str[i]=='|') {while((S.top!=S.base)&&(*(S.top-1)!='(')) {Pop(S,ch);exp[j]=ch;j++;}Push(S,str[i]);} else if(str[i]=='=') {while((*(S.top-1)=='=')){Pop(S,ch);exp[j]=ch;}Push(S,str[i]);} /* end of else if */else if(str[i]=='+'||str[i]=='-') {while((S.top!=S.base)&&(*(S.top-1)!='(')){Pop(S,ch);exp[j]=ch;j++;}Push(S,str[i]);} /* end of else if */else if(str[i]=='<'||str[i]=='>') {while((S.top!=S.base)&&(*(S.top-1)!='(')){Pop(S,ch);exp[j]=ch;j++;}Push(S,str[i]);} /* end of else if */else if (str[i]=='*'||str[i]=='/'){while((*(S.top-1)=='*')||(*(S.top-1)=='/')) {Pop(S,ch);exp[j]=ch;j++;}Push(S,str[i]);} /* end of else if */i++;} /* end of while */exp[j]='#';cout<<"\n\n输入的表达式";i=1;while(str[i+1]!='#'){cout<<str[i];} /* end of while */ cout<<"逆波兰表达式为:\n"; i=0;while(exp[i]!='#'){cout<<exp[i];i++;}}。

编译原理报告四逆波兰式

编译原理报告四逆波兰式

逆波兰式的产生及计算一、目的与要求1、目的通过上机实习,加深对语法制导翻译原理的理解,掌握将语法分析所识别的语法范畴变换为某种中间代码的语义翻译方法。

2、要求(1)选用目前世界上普遍采用的语义分析方法──语法制导翻译技术。

(2)语义分析对象重点考虑经过语法分析后已是正确的语法范畴,实习重点是语义子程序。

(3)中间代码选用比较常见的形式,例如四元式。

二、背景知识属性文法:A=(G,V,F),其中:G:一个CFG, 属性文法的基础。

V:有穷的属性集:每个属性与一个文法符号相关联,这些属性代表与文法符号相关的语义信息,如:类型、地址、值、代码、符号表内容等等。

属性与变量一样,可以进行计算和传递,属性加工的过程即是语义处理的过程。

属性加工与语法分析同时进行。

属性的表示:标始符(或数),写在相应文法的下边,点记法:E.Val,E.Place,E.Type…。

F:关于属性的属性断言或一组属性的计算规则(称为语义规则)。

断言或语义规则与一个产生式相联,只引用该产生式左端或右端的终结符或非终结符相联的属性。

属性有两类:综合属性:归约型属性,用于“自下而上”传递信息。

继承属性:推导型属性,用于“自上而下”传递信息。

综合属性的例子:非终结符E、T及F都有一个综合属性val,符号digit有一个综合属性,它的值由词法分析器提供。

与产生式L→E对应的语义规则仅仅是打印由E产生的算术表达式的值的一个过程,我们可认为这条规则定义了L的一个虚属性。

某些非终结符加上标是为了区分一个产生式中同一非终结符多次出现。

设表达式为3*5+4,则语义动作打印数值19。

3*5+4的带注释的分析树继承属性的例子:继承属性的自上而下定值(Real id1,id2,id3):Real id1,id2,id3的分析树L-属性文法:一个属性文法称为L-属性文法,如果对于每个产生式A→X1X2…Xn,满足:1、Xj(1≤j≤n)的继承属性仅依赖于下述属性值中的一种:A的继承属性或产生式右部位于Xj左边的符号X1,X2,…,Xj-1的属性。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

(编译原理)逆波兰式算法地源代码

(编译原理)逆波兰式算法地源代码

一.实验目的1.深入理解算符优先分析法2.掌握FirstVt和LastVt集合的求法有算符优先关系表的求法3.掌握利用算符优先分析法完成中缀表达式到逆波兰式的转化二.实验内容及要求将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。

程序输入/输出示例:输出的格式如下:(1)(2)输入一以#结束的中缀表达式(包括+—*/()数字#)(3)(4)逆波兰式备注:(1)在生成的逆波兰式中如果两个数相连则用&分隔,如28和68,中间用&分隔;注意:1.表达式中允许使用运算符(+-*/)、分割符(括号)、数字,结束符#;2.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好);3.对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。

同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;三.实验过程1、逆波兰式定义将运算对象写在前面,而把运算符号写在后面。

用这种表示法表示的表达式也称做后缀式。

逆波兰式的特点在于运算对象顺序不变,运算符号位置反映运算顺序。

采用逆波兰式可以很好的表示简单算术表达式,其优点在于易于计算机处理表达式。

2、产生逆波兰式的前提中缀算术表达式3、逆波兰式生成的实验设计思想及算法(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。

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

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

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

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

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

倘若不是的话,则将此运算符栈顶的运算符从栈中弹出,将该字符入栈。

逆波兰转换C语言(带注释)

逆波兰转换C语言(带注释)

#include <stdio.h>#include <malloc.h>struct stack{char letter;struct stack *next;};int rank(char a); ////////判断运算符优先级函数void push(char a,struct stack*s);char pop(struct stack *s);void main(){char element;int i=0,j=0;struct stack *s;s=(struct stack*)malloc(sizeof(struct stack)); ////////创建一个运算符栈s->next=NULL;push('@',s); ////////给栈一个起始值while(s->next->letter!='#') ////////以‘#’作为输出的结尾{element=getchar();if(element!='#') ////////当输入不为结尾标志时{if((element>'a'&& element<'z') || (element>'A' && element<'Z')) ////////若输入为字母,则直接输出printf("%c",element);else if(rank(element)>rank(s->next->letter))push(element,s);////////若不为字母,则判断该运算符的优先级else{while(rank(element)<=rank(s->next->letter) && s->next->letter!='@') ///////输入运算符的优先级高于栈顶运算符的优先级,进栈{printf("%c",pop(s));///////若优先级不高于栈顶运算符,则将栈顶弹出,并输出,}///////直到栈顶运算符的优先级严格小于输入运算符的优先级push(element,s);///////或者已经到达栈底,之后将该输入的运算符进栈}}else push(element,s);////////若为输入结尾标志符,直接进栈,跳出while循环}while(s->next->letter!='@')////////将栈中的剩余的运算符全部弹出,并依次输出‘#’和‘@’不输出{if(s->next->letter!='#')printf("%c",pop(s));elseelement=pop(s);}}void push(char a,struct stack*s){struct stack* temp;temp=(struct stack*)malloc(sizeof(struct stack));temp->letter=a;temp->next=s->next;s->next=temp;}char pop(struct stack *s){struct stack* temp;char a;a=s->next->letter;temp=s->next;s->next=s->next->next;free(temp);return a;}int rank(char a){if(a=='+'||a=='-')return 1;else if(a=='*'||a=='/')return 2;elsereturn 4;}。

  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);}。

相关文档
最新文档