编译原理 逆波兰式 c++
c++逆波兰式计算
c++逆波兰式计算C++逆波兰式计算是一种基于后缀表达式的计算方法。
逆波兰式也称为后缀表达式,其中操作符位于操作数之后。
下面我会从多个角度来解释逆波兰式计算。
1. 逆波兰式的转换:将中缀表达式转换为逆波兰式的过程称为逆波兰式的转换。
这个过程可以通过使用栈来实现。
具体步骤如下:从左到右扫描中缀表达式的每个元素。
如果遇到操作数,则直接输出到逆波兰式。
如果遇到操作符,则与栈顶操作符比较优先级。
如果栈顶操作符优先级高于当前操作符,则将栈顶操作符输出到逆波兰式,然后将当前操作符入栈;否则将当前操作符入栈。
如果遇到左括号,则将其入栈。
如果遇到右括号,则将栈顶操作符输出到逆波兰式,直到遇到左括号。
左括号出栈,但不输出到逆波兰式。
扫描结束后,将栈中剩余的操作符依次输出到逆波兰式。
2. 逆波兰式的计算:逆波兰式计算是通过对逆波兰式进行求值来得到结果的过程。
这个过程同样可以使用栈来实现。
具体步骤如下:从左到右扫描逆波兰式的每个元素。
如果遇到操作数,则入栈。
如果遇到操作符,则从栈中弹出两个操作数,进行相应的运算,并将结果入栈。
扫描结束后,栈中的唯一元素即为最终的结果。
3. C++实现逆波兰式计算:在C++中,可以使用栈来实现逆波兰式的计算。
具体步骤如下:定义一个栈来存储操作数。
从左到右扫描逆波兰式的每个元素。
如果遇到操作数,则将其转换为数字并入栈。
如果遇到操作符,则从栈中弹出两个操作数,进行相应的运算,并将结果入栈。
扫描结束后,栈中的唯一元素即为最终的结果。
总结:逆波兰式是一种基于后缀表达式的计算方法,可以通过转换中缀表达式得到。
逆波兰式计算可以使用栈来实现,通过扫描逆波兰式的每个元素,根据操作数和操作符进行相应的操作,最终得到计算结果。
在C++中,可以使用栈来实现逆波兰式的计算。
希望以上解释能够满足你的需求。
逆波兰表达式
逆波兰表达式逆波兰表达式表达式⼀般由操作数(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语言逆波兰表达式简介一、什么是逆波兰表达式逆波兰表达式,也被称为后缀表达式,是一种不需要括号来标识操作符优先级的数学表达式表示方法。
在逆波兰表达式中,操作符位于操作数之后,因此也被称为后缀表达式。
二、逆波兰表达式的优势1. 不需要括号,减少了人为输入错误的概率。
2. 操作符的位置固定,使得计算机在计算逆波兰表达式时更加简单高效。
3. 逆波兰表达式可以通过栈来实现计算,使得计算逻辑更加清晰。
三、逆波兰表达式的转换将常见的中缀表达式转换为逆波兰表达式有两种方法:中缀转后缀法和中缀转前缀法。
这里我们主要介绍中缀转后缀的方法。
1. 创建一个空栈和一个空字符串作为结果。
2. 从左到右遍历中缀表达式的每个字符。
3. 如果当前字符是操作数,则直接将其添加到结果字符串中。
4. 如果当前字符是操作符,则判断其与栈顶操作符的优先级:a. 如果栈为空,则直接将操作符入栈。
b. 如果栈不为空,且栈顶操作符的优先级大于等于当前操作符,则将栈顶操作符弹出并添加到结果字符串中,直到栈为空或栈顶操作符的优先级小于当前操作符,然后将当前操作符入栈。
5. 如果当前字符是左括号"(",则直接入栈。
6. 如果当前字符是右括号")",则将栈中的操作符弹出并添加到结果字符串中,直到遇到左括号为止。
此时将左括号弹出,但不添加到结果字符串中。
7. 遍历完中缀表达式后,将栈中剩余的操作符依次弹出并添加到结果字符串中。
四、逆波兰表达式的计算计算逆波兰表达式可以利用栈来实现。
具体步骤如下:1. 创建一个空栈。
2. 从左到右遍历逆波兰表达式的每个字符。
3. 如果当前字符是操作数,则将其转换为数值并入栈。
4. 如果当前字符是操作符,则从栈中弹出两个操作数进行计算,并将计算结果入栈。
5. 遍历完逆波兰表达式后,栈中只剩下一个元素,即为最终的计算结果。
五、逆波兰表达式的应用逆波兰表达式在编程语言解析、数学计算和计算器等领域有着广泛的应用。
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",¬ation);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]!='('&¬ation[i]!=')'&¬ation[i]!='+'&¬ation[i]!='-'&¬ation[i]!='*'&¬ation[i]!='/'&&!isdigit(notation[i])&¬ation[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]!='('&¬ation[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]=='.'&¬ation[i+1]!='\0'&¬ation[i+2]!='\0'&¬ation[i+3]!='\0'&¬ation[i+4]!='\0'&¬ation[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])&¬ation[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&¬ation[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&¬ation[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本身。
逆波兰运算c语言实现
逆波兰运算c语言实现以逆波兰运算C语言实现为标题逆波兰表达式(Reverse Polish Notation,简称RPN)是一种数学表达式的书写方式,也是一种计算机科学中常用的运算方式。
在逆波兰表达式中,操作符位于操作数的后面,这样可以避免使用括号,使得表达式更加简洁明了。
本文将介绍如何使用C语言实现逆波兰运算。
1. 逆波兰表达式的基本概念逆波兰表达式的基本原则是将操作符放在操作数的后面,以此来表示运算顺序。
例如,将中缀表达式"3 + 4"转换为逆波兰表达式的结果为"3 4 +"。
在逆波兰表达式中,每个操作数和操作符之间都用空格分隔开。
2. 实现逆波兰表达式的算法为了实现逆波兰表达式的计算,我们可以使用栈来存储操作数和操作符。
遍历逆波兰表达式的每一个元素,如果是操作数,就将其入栈;如果是操作符,就从栈中弹出两个操作数进行运算,并将结果再次入栈。
最后,栈中剩下的元素即为最终的计算结果。
3. C语言实现逆波兰表达式的代码下面是一个简单的C语言实现逆波兰表达式的代码示例:```c#include <stdio.h>#include <stdlib.h>#include <string.h>#define MAX_STACK_SIZE 100typedef struct {int top;int stack[MAX_STACK_SIZE];} Stack;void push(Stack *s, int value) {if (s->top < MAX_STACK_SIZE) { s->stack[s->top++] = value; } else {printf("Stack Overflow\n"); exit(1);}}int pop(Stack *s) {if (s->top > 0) {return s->stack[--s->top]; } else {printf("Stack Underflow\n");exit(1);}}int calculate(int a, int b, char operator) { switch (operator) {case '+':return a + b;case '-':return a - b;case '*':return a * b;case '/':return a / b;default:printf("Invalid Operator\n");exit(1);}}int evaluateRPN(char *rpn) {Stack s;int len = strlen(rpn);for (int i = 0; i < len; i++) {if (isdigit(rpn[i])) {push(&s, rpn[i] - '0');} else if (rpn[i] == ' ') {continue;} else {int b = pop(&s);int a = pop(&s);int result = calculate(a, b, rpn[i]); push(&s, result);}}return pop(&s);}int main() {char rpn[] = "3 4 +";int result = evaluateRPN(rpn);printf("The result is: %d\n", result);}```4. 运行结果分析以上代码中的逆波兰表达式为"3 4 +",表示的是3加4。
编译原理(逆波兰表达式)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++程序波兰式、逆波兰式、中缀计算1. 引言1.1 概述在计算机科学和编程领域中,数学表达式的计算是一项基本任务。
而波兰式、逆波兰式和中缀计算是常见的用于表示和计算数学表达式的方法。
这些方法都有各自独特的优势和应用场景。
1.2 文章结构本文将对波兰式、逆波兰式和中缀计算进行详细介绍和分析。
首先,在“2. 波兰式计算”部分,我们将探讨波兰式的定义、原理以及如何将中缀表达式转化为后缀形式。
接下来,在“3. 逆波兰式计算”部分,我们将介绍逆波兰式的定义、原理,以及如何将中缀表达式转化为前缀形式。
最后,在“4. 中缀计算”部分,我们将深入讨论中缀表达式的定义、原理以及如何将其转化为逆波兰式形式。
文章最后,“5. 结论”部分将对整个内容进行总结与分析,并讨论这些方法在实际应用中的优点与局限性。
1.3 目的本文旨在阐述波兰式、逆波兰式和中缀计算的概念、原理以及它们在实际应用中的优缺点。
读者将通过本文了解到这些不同的表达式形式如何表示和计算数学表达式,并能根据具体需求选择合适的方法进行计算。
无论是初学者还是有一定编程经验的人,本文都将为他们提供一个全面而清晰的介绍,帮助他们更好地理解和应用波兰式、逆波兰式和中缀计算。
2. 波兰式计算:2.1 定义和原理:波兰式(Polish Notation)是一种用前缀表达式表示数学运算的方法。
在波兰式中,操作符位于操作数之前,通过这种形式来消除了括号对优先级的影响。
例如,表达式"3 + 4" 可以用波兰式表示为"+ 3 4"。
波兰式的原理是利用栈这一数据结构进行计算。
我们将表达式从右到左遍历,如果遇到一个数字,则将其压入栈中;如果遇到一个操作符,则弹出栈顶的两个数字进行计算,并将结果再次压回栈中。
重复这个过程直到整个表达式被处理完毕,并返回最终结果。
2.2 转化为后缀表达式:要将中缀表达式转化为后缀表达式(也称为逆波兰式),我们可以使用以下步骤:1. 创建一个空栈和一个空结果列表。
(编译原理)逆波兰式算法的源代码
(编译原理)逆波兰式算法的源代码一.实验目的1.深入理解算符优先分析法2.掌握FirstVt和LastVt集合的求法有算符优先关系表的求法3.掌握利用算符优先分析法完成中缀表达式到逆波兰式的转化二.实验内容及要求将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。
程序输入/输出示例:输出的格式如下:(1)(2)输入一以#结束的中缀表达式(包括+—*/()数字#)(3)(4)逆波兰式备注:(1)在生成的逆波兰式中如果两个数相连则用&分隔,如28和68,中间用&分隔;串。
注意:1.表达式中允许使用运算符(+-*/)、分割符(括号)、数字,结束符#;2.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好);3.对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。
同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;三.实验过程1、逆波兰式定义将运算对象写在前面,而把运算符号写在后面。
用这种表示法表示的表达式也称做后缀式。
逆波兰式的特点在于运算对象顺序不变,运算符号位置反映运算顺序。
采用逆波兰式可以很好的表示简单算术表达式,其优点在于易于计算机处理表达式。
2、产生逆波兰式的前提中缀算术表达式3、逆波兰式生成的实验设计思想及算法(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。
(2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。
(3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。
(4)如果不是数字,该字符则是运算符,此时需比较优先关系。
做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。
如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。
中缀表达式转换成逆波兰式数据结构c语言
中缀表达式转换成逆波兰式数据结构c语言在计算机科学领域,中缀表达式和逆波兰式是两种常见的数学表达方式。
中缀表达式是我们日常生活中最为熟悉的数学表达方式,通常是由运算符和操作数构成的代数表达式,比如:(3 + 4) * 5。
而逆波兰式则是将操作符置于操作数之后的一种数学表达方式,比如:“3 4 + 5 *”。
在本文中,我们将深入探讨中缀表达式如何转换成逆波兰式,并结合数据结构和C语言编程,来实现这一转换过程。
通过这样的方式,我们不仅能够更深入地理解中缀表达式和逆波兰式的本质及其在计算机科学领域中的重要性,同时也能够加深对数据结构和C语言编程的理解。
1. 中缀表达式和逆波兰式的概念让我们简单回顾一下中缀表达式和逆波兰式的概念。
在中缀表达式中,操作符位于操作数之间,例如:3 + 4 * 5。
而逆波兰式则采用后缀表达方式,操作符位于操作数之后,例如:3 4 5 * +。
2. 数据结构的选择在将中缀表达式转换成逆波兰式的过程中,我们需要选择合适的数据结构来存储中间结果和最终结果。
在这里,我们选择使用栈这一数据结构。
栈是一种后进先出的数据结构,非常适合处理中缀表达式转换成逆波兰式的过程。
3. 中缀表达式转换成逆波兰式的算法接下来,我们将介绍中缀表达式转换成逆波兰式的算法。
该算法主要通过遍历中缀表达式,并使用栈来处理操作符的优先级和操作数的顺序。
具体的转换过程可以分为以下几个步骤: 1. 从左至右遍历中缀表达式的每个元素 2. 如果是操作数,则直接输出 3. 如果是左括号,则将其压入栈中 4. 如果是操作符,则比较其与栈顶操作符的优先级,如果栈顶操作符优先级较高,则将栈顶操作符弹出并输出,直到栈为空或者遇到了左括号 5. 如果是右括号,则将栈中左括号之前的所有操作符全部弹出并输出 6. 遍历完毕后,将栈中剩余的所有操作符依次弹出并输出4. 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语言-回复什么是波兰表达式?波兰表达式,又称逆波兰表达式(Reverse Polish Notation,简称RPN),是一种数学表达式的表示方式。
它通过将运算符放在操作数的后面,而不是中间,来改变传统的中缀表达式的形式。
波兰表达式的一个主要优点是不需要括号来指定运算符的优先级,从而避免了歧义,并且可以通过简单的堆栈操作进行计算。
如何将中缀表达式转换为波兰表达式?中缀表达式转换为波兰表达式的过程可以通过以下步骤完成:1. 创建一个空的栈,用于保存运算符。
2. 遍历中缀表达式中的每个字符。
3. 如果当前字符是操作数(数字),则将其添加到输出中。
4. 如果当前字符是左括号,将其压入栈中。
5. 如果当前字符是右括号,则从栈中弹出运算符,并将其添加到输出中,直到遇到左括号。
然后将左括号从栈中丢弃。
6. 如果当前字符是运算符(加号、减号、乘号、除号等),则将其与栈顶运算符进行比较。
a. 如果栈为空,或栈顶为左括号,则将当前运算符压入栈中。
b. 否则,重复以下步骤,直到栈为空、栈顶为左括号,或栈顶运算符的优先级低于当前运算符:1) 弹出栈顶运算符,并将其添加到输出中。
2) 将当前运算符压入栈中。
7. 重复步骤2至步骤6,直到遍历完中缀表达式中的所有字符。
8. 如果栈中还有运算符,依次弹出并添加到输出中。
如何计算波兰表达式的值?计算波兰表达式的值可以通过以下步骤完成:1. 创建一个空的栈,用于保存操作数。
2. 遍历波兰表达式中的每个字符。
3. 如果当前字符是操作数(数字),则将其转换为数值,并压入栈中。
4. 如果当前字符是运算符(加号、减号、乘号、除号等),则从栈中弹出两个操作数,进行相应的运算,并将结果压入栈中。
5. 重复步骤2至步骤4,直到遍历完波兰表达式中的所有字符。
6. 栈中最终的元素即为计算结果。
波兰表达式的使用场景和优势是什么?波兰表达式在计算机科学和数学领域有广泛的应用,其主要优势包括: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;}五、算法思想有三个数组分别存放的是符号、变量、优先级、之后输入字符,进行判断是什么东西,之后再对他们进行进出符号,变量直接进,判断优先级(老师上课所讲的逆波兰式如何生成),最后显示出其逆波兰式。
编译原理实验报告6逆波兰式的翻译和计算
实验6 逆波兰式的翻译和计算一、实验目的通过实验加深对语法指导翻译原理的理解,掌握算符优先分析的方法,将语法分析所识别的表达式变换成中间代码的翻译方法。
二、实验内容设计一个表示能把普通表达式(中缀式)翻译成后缀式,并计算出结果的程序。
三、实验要求1、给出文法如下:G[E]E->T|E+T;T->F|T*F;F->i(E);对应的转化为逆波兰式的语义动作如下: E-> E (1)op E (2) {E.CODE:= E (1).CODE||E (2).CODE||op} E->(E (1)) { E.CODE := E (1).CODE}E->id { E.CODE := id}2、利用实验5中的算符优先分析算法,结合上面给出的语义动作实现逆波兰式的构造;3、利用栈,计算生成的逆波兰式,步骤如下:1) 中缀表达式,从文本文件读入,每一行存放一个表达式,为了降低难度,表达式采用常数表达式;2) 利用结合语法制导翻译的算符优先分析,构造逆波兰式;3) 利用栈计算出后缀式的结果,并输出;四、实验环境PC 微机DOS 操作系统或 Windows 操作系统Turbo C 程序集成环境或 Visual C++ 程序集成环境五、实验步骤1、了解语法制导翻译的方法,学习后缀式构造的语义动作;2、结合实验5的算符优先程序,设计程序构造后缀式;3、利用栈,编程实现后缀式的计算;4、测试程序运行效果:从文本文件中读表达式,在屏幕上输出,检查输出结果。
六、测试数据输入数据:编辑一个文本文文件expression.txt,在文件中输入如下内容:正确结果:(1)1+2;输出:1,2,+ 3(2)(1+2)*3;输出:1,2,+,3,* 9(3)(10+20)*30+(50+60*70)输出:10,20,+30,*50,60,70,*,+,+ 5150七、实验报告要求实验报告应包括以下几个部分:1、构造逆波兰式的语义动作;2、结合算符优先分析构造逆波兰式的算法和过程;3、语法制导翻译的运行方法;4、程序的测试结果和问题;5、实验总结。
实验报告_编译原理_表达式翻译程序(逆波兰式)(后缀表达式)的设计与实现
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++;}}。
Java实现《编译原理》中间代码生成-逆波兰式生成与计算-程序解析
Java实现《编译原理》中间代码⽣成-逆波兰式⽣成与计算-程序解析Java 实现《编译原理》中间代码⽣成 -逆波兰式⽣成与计算 - 程序解析编译原理学习笔记(⼀)逆波兰式是什么?逆波兰式(Reverse Polish notation,RPN,或逆波兰记法),也叫后缀表达式(将运算符写在操作数之后)⼀般的表达式⼜称中缀表达式,这种表达式的⼆元运算符放在两个运算量之间。
⽽逆波兰表达式⼜称后缀表达式,这种表达式把运算符放在运算量后⾯。
⽐如如 a+b 的逆波兰式表⽰为 ab+注意:逆波兰式是⼀个⽆括号表达式;逆波兰式的运算符出现的顺序就是原表达式的运算顺序。
(⼆)逆波兰式编译原理有什么关系?逆波兰式,三元式,四元式等是编译原理 - 中间代码⽣成阶段的常见的中间代码形式。
(三)本篇任务通过设计,使⽤ Java 语⾔编写⼀个逆波兰式⽣成程序,测试效果:(四)Java 源代码package com.java997.analyzer.rpn;import java.util.HashMap;import java.util.Map;import java.util.Scanner;import java.util.Stack;/*** <p>* 逆波兰式** @author XiaoPengwei* @since 2019-06-19*/public class RpnMain {/*** 检查算术表达术括号是否匹配, 语法是否正确** @param s 算术表达术* @return boolean*/public boolean isMatch(String s) {//括号符号栈Stack<Character> charStack = new Stack<>();//将表达式的字符串转换成数组char[] charArray = s.toCharArray();//遍历数组for (char aChar : charArray) {if (aChar == '(') {charStack.push(aChar);} else if (aChar == ')') {//如果是 ) , 且栈为空则返回 falseif (charStack.isEmpty()) {return false;} else {//如果是 ) , 且栈不为空则返回 false//peek() 是返回栈顶的值, 不做其他操作if (charStack.peek() == '(') {//把栈顶的值删除charStack.pop();}}}}//⾛到这⾥, 栈为空则表达式正确return charStack.empty();}/*** 判断是否为操作符 + - * /** @param charAt* @return boolean*/public boolean isOperator(char charAt) {return charAt == '+' || charAt == '-' || charAt == '*' || charAt == '/'; }/*** 根据正确的表达式, 获取逆波兰式** @param input* @return ng.String*/public StringBuilder getRpn(String input) {//结果StringBuilder sb = new StringBuilder();sb.append("The RPN is: ");//运算符栈Stack<Character> opStack = new Stack();//运算符优先级Map<Character, Integer> opMap = new HashMap(5);opMap.put('(', 0);opMap.put('+', 1);opMap.put('-', 1);opMap.put('*', 2);opMap.put('/', 2);//处理字符串for (int i = 0; i < input.length(); i++) {//如果是'('直接压栈if (input.charAt(i) == '(') {opStack.push('(');} else if (new RpnMain().isOperator(input.charAt(i))) {//如果是运算符char curOp = input.charAt(i);//如果运算符栈是空,就直接压栈if (opStack.isEmpty()) {opStack.push(curOp);} else if (opMap.get(curOp) > opMap.get(opStack.peek())) {//运算符栈不为空,且当当前运算符的优先级⽐站内第⼀个运算符的优先级⾼的时候,压栈 opStack.push(curOp);} else {//栈不为空,且运算符的优先级⼩于等于栈顶元素for (int j = 0; j <= opStack.size(); j++) {//弹出栈内第⼀个元素char ch = opStack.pop();sb.append(ch);if (opStack.isEmpty()) {opStack.push(curOp);break;} else if (opMap.get(curOp) > opMap.get(opStack.peek())) {opStack.push(curOp);break;}}}} else if (input.charAt(i) == ')') {//如果是')'就把站内'('上的元素都弹出栈for (int j = 0; j < opStack.size(); j++) {char c = opStack.pop();if (c == '(') {break;} else {sb.append(c);}}} else if ('A'<=input.charAt(i)&&input.charAt(i)<='Z'){//如果是字母就直接添加sb.append(input.charAt(i));}else if ('a'<=input.charAt(i)&&input.charAt(i)<='z'){//如果是字母就直接添加sb.append(input.charAt(i));}else if (Character.isDigit(input.charAt(i))){//如果是数字sb.append(input.charAt(i));}else {return new StringBuilder("But the expression contains unrecognizable characters");}}//把栈内剩余的运算符都弹出站for (int i = 0; i <= opStack.size(); i++) {sb.append(opStack.pop());}return sb;}public static void main(String[] args) {RpnMain rpnMain = new RpnMain();Scanner sc = new Scanner(System.in);while (true) {System.out.println("==========================\nPlease input an expression:");String input = sc.nextLine();if ("q".equals(input)) {sc.close();return;} else {if (rpnMain.isMatch(input)) {System.out.println("The expression's brackets are matched");// 获取逆波兰式System.out.println(rpnMain.getRpn(input));} else {System.out.println("Error: The expression's brackets are not matched! Enter 'q' to exit");}}}}}测试:。
编译原理报告四逆波兰式
逆波兰式的产生及计算一、目的与要求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#实现逆波兰式运⽤⼤众例⼦:所谓的逆波兰表⽰法(Reverse Polish notation,RPN,或逆波兰记法),是⼀种数学表达式⽅式,在逆波兰记法中,所有操作符置于操作数的后⾯,因此也被称为后缀表⽰法。
逆波兰记法不需要括号来标识操作符的优先级。
(摘⾃维基)我们平时长写的数学公式被称为中缀表达式,即:(a+b)*c,⽤逆波兰式为ab+c*,再如:(a+b)*c-(a+b)/e,逆波兰式为ab+c*ab+e/-,⾸先理解下转化成逆波兰式的⼏个步骤:算法实现(选⾃百度):⾸先需要分配2个栈,⼀个作为临时存储运算符的栈S1(含⼀个结束符号),⼀个作为输⼊逆波兰式的栈S2(空栈),S1栈可先放⼊优先级最低的运算符#,注意,中缀式应以此最低优先级的运算符结束。
可指定其他字符,不⼀定⾮#不可。
从中缀式的左端开始取字符,逐序进⾏如下步骤:(1)若取出的字符是,则分析出完整的运算数,该操作数直接送⼊S2栈(2)若取出的字符是,则将该运算符与S1栈栈顶元素⽐较,如果该⼤于S1栈栈顶运算符优先级,则将该运算符进S1栈,否则,将S1栈的栈顶运算符弹出,送⼊S2栈中,直⾄S1栈栈顶运算符低于(不包括等于)该运算符优先级,最后将该运算符送⼊S1栈。
(3)若取出的字符是“(”,则直接送⼊S1栈顶。
(4)若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个,依次送⼊S2栈,此时抛弃“(”。
(5)重复上⾯的1~4步,直⾄处理完所有的输⼊字符(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送⼊S2栈。
最后出来的S2需要逆序处理下,便是逆波兰表达式了。
看着定义,然后粗略了实现了下⾯的代码:主⽅法:static void Main(string[] args){while (true){Console.WriteLine("输⼊计算公式:");//输⼊公式string formula = Console.ReadLine();//定义临时计算符栈Stack<string> opStack = new Stack<string>();opStack.Push("#");Stack<string> numStack = new Stack<string>();for (int i = 0; i < formula.Length;){int opNum = GetOperationLevel(formula[i].ToString());if (opNum == 0){int index = GetCompleteValue(formula.Substring(i, formula.Length - i));numStack.Push(formula.Substring(i, index));i = (i + index);}//为操作数,获取完整else{if (formula[i] == '('){opStack.Push(formula[i].ToString());}else if (formula[i] == ')'){MoveOperator(opStack, numStack);}else{if (opStack.Peek() == "("){opStack.Push(formula[i].ToString());}else{JudgeOperator(opStack, numStack, formula[i].ToString());}}i++;}}if (opStack.Count != 0){while (opStack.Count != 0 && opStack.Peek() != "#"){numStack.Push(opStack.Pop());}}StringBuilder strBuild = new StringBuilder();foreach (string s in numStack){strBuild.Insert(0,s);}Console.WriteLine(strBuild.ToString());}}获取运算符等级:///<summary>///获取运算符等级///</summary>///<param name="c">当前字符</param>///<returns></returns>private static int GetOperationLevel(string c){switch (c){case"+": return1;case"-": return1;case"*": return2;case"/": return2;case"#": return -1;case"(": return -1;case")": return -1;default: return0;}}获取完整操作数///<summary>///获取完整数值///</summary>///<param name="formula">公式</param>///<returns></returns>private static int GetCompleteValue(string formula){int index = formula.Length;for (int i = 0; i < formula.Length; i++){int num = GetOperationLevel(formula[i].ToString());if (num != 0){index = i;break;}}return index;}移动运算符:///<summary>///移动运算符///</summary>///<param name="opStack"></param>///<param name="numStack"></param>private static void MoveOperator(Stack<string> opStack, Stack<string> numStack) {string s = opStack.Pop();if (s == "("){return;}else{numStack.Push(s);MoveOperator(opStack, numStack);return;}}判断运算符:///<summary>///判断运算符///</summary>///<param name="opStack"></param>///<param name="numStack"></param>///<param name="x"></param>private static void JudgeOperator(Stack<string> opStack, Stack<string> numStack, string x){int xNum = GetOperationLevel(x);int opNum = GetOperationLevel(opStack.Peek());if (xNum > opNum || numStack.Peek() == "("){opStack.Push(x);return;}else{string opStr = opStack.Pop();numStack.Push(opStr);JudgeOperator(opStack, numStack, x);return;}}代码运⾏效果:接下来就是计算公式的值,思路是新建⼀个栈R⽤来放结果,依次取出表达式的栈F,1.如果取出的值为操作数,则放⼊栈R,2.如果取出的值为运算符,则取出栈R顶的两个,进⾏运算,运算结果在存放⼊栈R 最后R顶的元素,即为计算的值下⾯为代码,⽬前只做了+,-,*,///numStack为逆波兰表达式Stack<string> rpnFormula = new Stack<string>();foreach (string s in numStack){rpnFormula.Push(s);}Console.WriteLine(CalcRPNFormula(rpnFormula));=private static string CalcRPNFormula(Stack<string> rpnFormula){Stack<string> resultStack = new Stack<string>();foreach (string s in rpnFormula){int num = GetOperationLevel(s);if (num == 0){resultStack.Push(s);}else{CalcResult(resultStack,s);}}return resultStack.Pop();}private static void CalcResult(Stack<string> resultStack, string operatorStr){if (resultStack.Count >= 2){double num2 = Convert.ToDouble(resultStack.Pop());double num1 = Convert.ToDouble(resultStack.Pop());if (operatorStr == "+"){resultStack.Push(Convert.ToString(num1 + num2));}else if (operatorStr == "-"){resultStack.Push(Convert.ToString(num1 - num2));}else if (operatorStr == "*"){resultStack.Push(Convert.ToString(num1 * num2));}else if (operatorStr == "/"){resultStack.Push(Convert.ToString(num1 / num2));}}}因为适应⾃⼰的项⽬,需要做到⽀持“”^”,"arctan", "sqrt", "sin", "cos", "tan", "arcsin", "arccos"的计算⽅式,在查看上⾯⽣成的逆波兰式的时候,发现^会后置,其他的都是前置,然后就投机取巧了以下,遇到^取前两位,遇到其他特殊符号,则取后⼀位,所以增加了以下内容,测试了下例⼦:2^3+sqrt(9)+sin(45)+1 通过之前的代码转换为后缀表达式为23^sqrt9+sin45+1+(正确应为23^9sqrt+45sin+1+),然后根据上述的进⾏计算,加了这⼏个特许计算后,可能与原来的后缀表达式有点背道⽽驰,没有对特殊字符进⾏后置处理,但⽬前为了先实现计算,所以投机取巧了下,后期会进⾏修改///<summary>///特殊字符///</summary>private static List<string> m_SpecialOp = new List<string>() { "arctan", "sqrt", "sin", "cos", "tan", "arcsin", "arccos" };///<summary>///获取运算符等级///</summary>///<param name="c">当前字符</param>///<returns></returns>private static int GetOperationLevel(string c){//sin(cos(tan(arcsin(arccos(arctan(switch (c){case"+": return1;case"-": return1;case"*": return2;case"/": return2;case"^": return2;case"arctan": return10;case"sqrt": return10;case"sin": return10;case"cos": return10;case"tan": return10;case"arcsin": return10;case"arccos": return10;case"#": return -1;case"(": return -1;case")": return -1;default: return0;}}///<summary>///计算逆波兰式///</summary>///<param name="rpnFormula"></param>///<returns></returns>private static string CalcRPNFormula(Stack<string> rpnFormula){Stack<string> resultStack = new Stack<string>();while (rpnFormula.Count > 0){string rpnStr = rpnFormula.Pop();int num = GetOperationLevel(rpnStr);if (num == 0){resultStack.Push(rpnStr);}else if (num == 10){SpecialCalc(resultStack, rpnStr, rpnFormula.Pop());}else{CalcResult(resultStack, rpnStr);}}return resultStack.Pop();}///<summary>///特殊计算///</summary>///<param name="resultStack"></param>///<param name="operatorStr"></param>///<param name="calcValue"></param>private static void SpecialCalc(Stack<string> resultStack, string operatorStr, string calcValue) {if (m_SpecialOp.Contains(operatorStr)){double num = Convert.ToDouble(calcValue);if (operatorStr == "sqrt"){resultStack.Push(Math.Sqrt(num).ToString("#0.000"));}else if (operatorStr == "sin"){resultStack.Push(Math.Sin(num).ToString("#0.000"));}else if (operatorStr == "cos"){resultStack.Push(Math.Cos(num).ToString("#0.000"));}else if (operatorStr == "tan"){resultStack.Push(Math.Tan(num).ToString("#0.000"));}else if (operatorStr == "arcsin"){resultStack.Push(Math.Asin(num).ToString("#0.000"));}else if (operatorStr == "arccos"){resultStack.Push(Math.Acos(num).ToString("#0.000"));}else if (operatorStr == "arctan"){resultStack.Push(Math.Atan(num).ToString("#0.000"));}}}///<summary>///计算结果///</summary>///<param name="resultStack"></param>///<param name="operatorStr"></param>private static void CalcResult(Stack<string> resultStack, string operatorStr){if (resultStack.Count >= 2){double num2 = Convert.ToDouble(resultStack.Pop());double num1 = Convert.ToDouble(resultStack.Pop());if (operatorStr == "+"){resultStack.Push(Convert.ToString(num1 + num2));}else if (operatorStr == "-"){resultStack.Push(Convert.ToString(num1 - num2));}else if (operatorStr == "*"){resultStack.Push(Convert.ToString(num1 * num2));}else if (operatorStr == "/"){resultStack.Push(Convert.ToString(num1 / num2));}else if (operatorStr == "^"){resultStack.Push(Math.Pow(num1, num2).ToString());}}}。
编译原理系列之九中间代码生成
编译原理系列之九中间代码⽣成
中间代码⽣成
中间代码也与机器⽆关。
常见中间表⽰形式:
1. 逆波兰式:
逆波兰式
中缀表达式转逆波兰式:按照算术表达式的计算顺序根据操作数1、(操作数2)、运算符的顺序化成⼀个部分的后缀式,将这个后缀式在算术表达式中看成⼀个操作数继续按照上⾯⽅法分析。
逆波兰式转中缀表达式:根据逆波兰式的序列从左向右找运算符,找到后从这个运算符开始向前找出紧邻的操作数2、操作数1并化成算术表达式,将这个算术表达式看成⼀个操作数,继续往后寻找操作符,重复以上步骤。
注意:操作数均由⼀个字母表⽰。
1. 抽象语法树AST:
抽象语法树中每⼀个⼦树的根结点都对应⼀种动作或运算,它的所有⼦结点对应该动作或运算的参数或运算数。
参数或运算数也可以是另⼀⼦树,代表另⼀动作或运算。
将AST中相同的⼦树合并,这种改进的AST叫做有向⽆环图DAG;
AST与DAG
1. 三地址码TAC
x=y op z或者四元组的形式(op,y,z,x)
TAC
其他TAC语句
常⽤语句的语法制导翻译 :
语义过程GEN表⽰产⽣⼀个TAC或四元式,并且填⼊TAC或四元式表中。
语义过程Newtemp表⽰⽣成⼀个临时变量,每调⽤⼀次,⽣成⼀新的临时变量。
语义变量E. place,⽤来存放 E 的值的存储位置。
语义变量id.place , id 对应的存储位置。
1. 简单赋值语句的翻译 :
赋值语句
1. 布尔表达式的翻译 :
布尔表达式
拉链与回填:
拉链与回填
=拉链与回填。
逆波兰转换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、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#include<iostream>
#include<string>
using namespace std;
#define MAX 100;//表达式的最大长度
char read[100];//中缀表达式
char temp[100];//暂存数组
char out[100];//逆波兰式(后缀表达式)
void Translation();//中缀表达式换成后缀表达式
int main()
{
Translation();
return 0;
}
void Translation()
{
cout<<"请输入要转换的表达式以#号结束"<<endl;
int i=1,t=1,k=0;//t用来指向out数组k用来指向temp数组i用来指向read数组
do{ //输入表达式
cin>>read[i];
i++;
}while(read[i-1]!='#'&&i!=100);
int total=i-1;
i=1;
char r=read[i];
while(r!='#')
{
switch(r) //若取出的字符是“(”,则直接送入temp栈栈顶。
{
case '(':
{
k++;
temp[k]=r;
break;
}
case')'://若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
{
while(temp[k]!='(')
{
out[t]=temp[k];
k--;
t++;
}
k--; //去掉'('
break;
}
case'+':
case'-':
{
while(k!=0&&temp[k]!='(')
{
out[t]=temp[k];
k--;
t++;
}
k++;
temp[k]=r;
break;
}
case'*':
case'/':
{
while(temp[k]=='*'||temp[k]=='/')
{
out[t]=temp[k];
k--;
t++;
}
k++;
temp[k]=r;
break;
}
default:
while(r>='0'&&r<='9')
{
out[t]=r;
t++;
i++;
r=read[i];
}
i--;
}
i++;
r=read[i];
}
while(k!=0)
{
out[t]=temp[k];
k--;
t++;
}
for(int j=1;j<=total;j++)
{
cout<<out[j]<<" ";
}
}
/*
(1)若取出的字符是操作数,则分析出完整的运算数,该操作数直接送入S2栈;若取出的是运算符,并且当前S1栈顶为(,
则当前运算符直接入S1栈。
(2)若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,如果该运算符优先级大于S1栈栈顶运算符优先级,
则将该运算符进S1栈,否者,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符低于(不包括等于)该运算符优先级,
则将该运算符送入S1栈。
(3)若取出的字符是“(”,则直接送入S1栈栈顶。
(4)若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
(5)重复上面的1~4步,直至处理完所有的输入字符
(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。
2+3*(4-5)-6/7#
*/。