编译原理-逆波兰式的产生及计算

合集下载

c++逆波兰式计算

c++逆波兰式计算

c++逆波兰式计算C++逆波兰式计算是一种基于后缀表达式的计算方法。

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

下面我会从多个角度来解释逆波兰式计算。

1. 逆波兰式的转换:将中缀表达式转换为逆波兰式的过程称为逆波兰式的转换。

这个过程可以通过使用栈来实现。

具体步骤如下:从左到右扫描中缀表达式的每个元素。

如果遇到操作数,则直接输出到逆波兰式。

如果遇到操作符,则与栈顶操作符比较优先级。

如果栈顶操作符优先级高于当前操作符,则将栈顶操作符输出到逆波兰式,然后将当前操作符入栈;否则将当前操作符入栈。

如果遇到左括号,则将其入栈。

如果遇到右括号,则将栈顶操作符输出到逆波兰式,直到遇到左括号。

左括号出栈,但不输出到逆波兰式。

扫描结束后,将栈中剩余的操作符依次输出到逆波兰式。

2. 逆波兰式的计算:逆波兰式计算是通过对逆波兰式进行求值来得到结果的过程。

这个过程同样可以使用栈来实现。

具体步骤如下:从左到右扫描逆波兰式的每个元素。

如果遇到操作数,则入栈。

如果遇到操作符,则从栈中弹出两个操作数,进行相应的运算,并将结果入栈。

扫描结束后,栈中的唯一元素即为最终的结果。

3. C++实现逆波兰式计算:在C++中,可以使用栈来实现逆波兰式的计算。

具体步骤如下:定义一个栈来存储操作数。

从左到右扫描逆波兰式的每个元素。

如果遇到操作数,则将其转换为数字并入栈。

如果遇到操作符,则从栈中弹出两个操作数,进行相应的运算,并将结果入栈。

扫描结束后,栈中的唯一元素即为最终的结果。

总结:逆波兰式是一种基于后缀表达式的计算方法,可以通过转换中缀表达式得到。

逆波兰式计算可以使用栈来实现,通过扫描逆波兰式的每个元素,根据操作数和操作符进行相应的操作,最终得到计算结果。

在C++中,可以使用栈来实现逆波兰式的计算。

希望以上解释能够满足你的需求。

Java实现《编译原理》中间代码生成-逆波兰式生成与计算-程序解析

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");}}}}}测试:。

逆波兰表达式

逆波兰表达式

逆波兰表达式逆波兰表达式表达式⼀般由操作数(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、将运算结果重新压⼊堆栈。

逆波兰式(后缀表达式)的计算

逆波兰式(后缀表达式)的计算

逆波兰式(后缀表达式)的计算输⼊:后缀表达式(可带浮点数)输出:double型的计算结果代码:#include <stdio.h>#include <stdlib.h>#include <malloc.h>#define ElemType double#define Stack_Init_Size 100#define Increase_Size 10#define MaxBuffer 10typedef struct sqStack{ElemType *top;ElemType *base;int initSize;}sqStack;typedef struct sqStack *LinkStack;//初始化void InitStack( sqStack *s ){s->base = (LinkStack)malloc(Stack_Init_Size * sizeof(ElemType));if(!s->base){printf("存储空间分配失败······\n");return;}s->top = s->base;s->initSize = Stack_Init_Size;}//进栈void Push(sqStack *s,ElemType e){if(s->top - s->base >= s->initSize - 1){s->base = (LinkStack)realloc(s->base,(s->initSize + Increase_Size) * sizeof(ElemType));//第⼀个s->base是增加后的存储空间块的地址,第⼆个是增加空间之前的存储空间块地址,后⾯是增加过的存储空间块的⼤⼩ if(!s->base){printf("增加存储空间失败······\n");return;}s->initSize = Increase_Size + Stack_Init_Size;}*(s->top) = e;(s->top)++;}//出栈void Pop(sqStack *s,ElemType *e){if(s->top == s->base){printf("栈已空,⽆法进⾏出栈操作······\n");return;}s->top--;*e = *s->top;}//求栈的长度int StackLen(sqStack s){return (s.top - s.base);}//逆波兰计算器:输⼊逆波兰式(后缀表达式)输出结果int main(){int i = 0,j,len;double m,n,t;char c;struct sqStack s;char str[MaxBuffer];InitStack(&s);printf("请输⼊您要计算的后缀表达式,按Enter键结束(两个不同的字符之间⽤空格隔开):\n");scanf("%c",&c);while(c != '\n'){while( (c >= '0'&&c <= '9') || c == '.'){str[i] = c;i++;// str[i] = '\0';if(i >= 10){printf("\n输⼊的数字过⼤导致出错\n"); return -1;}scanf("%c",&c);if( c == ' '){t = atof(str);// printf("\nt is %f\n",t);Push(&s,t);i = 0;for(j = 0;j < MaxBuffer;j++){str[j] = '\0';}break;}}switch( c ){case '+':Pop(&s,&m);Pop(&s,&n);Push(&s,n+m);break;case '-':Pop(&s,&m);Pop(&s,&n);Push(&s,n-m);break;case '*':Pop(&s,&m);Pop(&s,&n);Push(&s,n*m);break;case '/':Pop(&s,&m);Pop(&s,&n);if( m == 0){printf("\n除数为0,出错\n");return -1;}else{Push(&s,n/m);break;}}scanf("%c",&c);}Pop(&s,&t);printf("\n最终的计算结果为:%f \n",t);return 0;}。

逆波兰公式

逆波兰公式

逆波兰公式(实用版)目录1.逆波兰公式的定义与概念2.逆波兰公式的求解方法3.逆波兰公式的应用实例4.逆波兰公式的优缺点分析正文1.逆波兰公式的定义与概念逆波兰公式,又称逆波兰表达式,是一种用于表示算术表达式的方式。

与常见的中缀表达式和中括号表达式不同,逆波兰表达式将运算符写在运算数的后面,从而形成了一种特殊的表达式形式。

这种表达式的求解方式也有所不同,需要采用逆波兰算法来完成。

2.逆波兰公式的求解方法逆波兰算法是一种基于栈的数据结构算法,其基本思想是将表达式中的运算符和运算数依次压入栈中,然后在栈顶进行运算。

具体步骤如下:(1)初始化一个空栈。

(2)从左到右遍历表达式,遇到运算数时,将其压入栈中;遇到运算符时,弹出栈顶的两个运算数进行运算,并将结果压入栈中。

(3)当遍历完整个表达式后,栈顶的元素即为最终的结果。

3.逆波兰公式的应用实例逆波兰公式在计算机科学中有广泛的应用,尤其在表达式求值、四则运算等方面有着重要的作用。

例如,对于表达式“2 + 3 * 4”,采用逆波兰算法可以得到如下的求解过程:(1)将数字 2 压入栈中。

(2)将数字 3 压入栈中。

(3)将运算符“*”压入栈中。

(4)弹出栈顶的数字 3 和数字 2,进行乘法运算,得到结果 6,并将其压入栈中。

(5)弹出栈顶的数字 6 和数字 4,进行加法运算,得到结果 10,即为最终结果。

4.逆波兰公式的优缺点分析逆波兰公式的优点在于其简洁明了的表达方式,可以直观地反映算术表达式的运算顺序。

此外,逆波兰算法的求解过程较为简单,容易实现,且具有较高的效率。

然而,逆波兰公式也存在一定的局限性。

由于逆波兰表达式中运算符位于运算数的后面,可能导致运算顺序不够明确,容易产生歧义。

c语言逆波兰表

c语言逆波兰表

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

编译原理实验三 逆波兰式的产生及计算

编译原理实验三     逆波兰式的产生及计算

实验三逆波兰式的产生及计算一、实验目的:将用中缀式表示的算术表达式转换为用逆波兰式表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。

二、实验内容:1.定义部分:定义常量、变量、数据结构。

2.初始化:设立算符优先分析表、初始化变量空间(包括堆栈、结构体、数组、临时变量等);3.控制部分:从键盘输入一个表达式符号串;4.利用算符优先分析算法进行表达式处理:根据算符优先分析表对表达式符号串进行堆栈(或其他)操作,输出分析结果,如果遇到错误则显示错误信息。

5.对生成的逆波兰式进行计算。

三、实验要求:输入如下:21+((42-2)*15+6 )-18#输出如下:原来表达式:21+((42-2)*15+6 )- 18#后缀表达式:21&42&2&-15&*6&++18&-计算结果:609四、实验源程序:#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("算数表达式:");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++; /*stack[]为运算符ω栈*/}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++; /*ex[ ]中存放逆波兰式*/ch=str[i];i++; /*str[ ]中存放中缀表达式*/}i--;ex[t]='&';t++;break; }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;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;case '/':if(stack[top]!=0)stack[top-1]=stack[top-1]/stack[top];else{printf("\n\t除零错误!\n");break; /*异常退出*/}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]);}void main(){trans();compvalue();}五、实验运行结果:。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

编译原理上机报告名称:逆波兰式的产生及计算学院:信息与控制工程学院专业:计算机科学与技术班级:计算机1401班姓名:叶达成2016年11月4日一、上机目的通过设计、编制、调试一个典型的语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,进一步掌握常用的语法分析方法。

1、选择最有代表性的语法分析方法,如LL(1) 语法分析程序、算符优先分析程序和LR分析分析程序,并至少完成两个题目。

2、选择对各种常见程序语言都用的语法结构,如赋值语句(尤指表达式)作为分析对象,并且与所选语法分析方法要比较贴切。

⑴实验前的准备按实验的目的和要求,编写语法分析程序,同时考虑相应的数据结构。

⑵调试调试例子应包括符合语法规则的算术表达式,以及分析程序能够判别的若干错例。

⑶输出对于所输入的算术表达式,不论对错,都应有明确的信息告诉外界。

⑷扩充有余力的同学,可适当扩大分析对象。

譬如:①算术表达式中变量名可以是一般标识符,还可含一般常数、数组元素、函数调用等等。

②除算术表达式外,还可扩充分析布尔、字符、位等不同类型的各种表达式。

③加强语法检查,尽量多和确切地指出各种错误。

二、基本原理和上机步骤基本原理:将运算对象写在前面,而把运算符号写在后面。

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

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

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

上机步骤:(1)构造一个栈,存放运算对象。

(2)读入一个用逆波兰式表示的简单算术表达式。

(3)自左至右扫描该简单算术表达式并判断该字符,如果该字符是运算对象,则将该字符入栈。

若是运算符,如果此运算符是二目运算符,则将对栈顶部的两个运算对象进行该运算,将运算结果入栈,并且将执行该运算的两个运算对象从栈顶弹出。

如果该字符是一目运算符,则对栈顶部的元素实施该运算,将该栈顶部的元素弹出,将运算结果入栈。

(4)重复上述操作直至扫描完整个简单算术表达式的逆波兰式,确定所有字符都得到正确处理,我们便可以求出该简单算术表达式的值。

三、上机结果程序清单:#include<iostream>#include<stdio.h>#include<stdlib.h>#include<algorithm>#include<cctype>#include<cstring>using namespace std;char str[50]; //用于存放原来的表达式int top; //栈顶指针char stack[50]; //定义栈,用于计算逆波兰式char ex[50]; //存放后缀表达式double _stack[50]; //定义栈,用于计算逆波兰式子int flag[50]; //用于区分+、-号的含义,0表示运算符,1表示正负号//生成逆波兰式void NiBolan(){memset(flag,0,sizeof(flag)); //flag初始值设为0char ch=str[0];int i=1,t=0;top=0;while(ch!='#'){switch(ch){case '(':top++;stack[top]=ch;break;case ')':while(stack[top]!='('){ex[t]=stack[top];top--;t++;}top--;break;case '^':while(stack[top]=='^') //设置^运算符优先级为最高{ex[t]=stack[top];top--;t++;}top++;stack[top]=ch;break;case '+':case '-'://当ch为+、-号是,若前面相邻字符不是')'或数字且后面相邻字符是数字时表示正负号if(isdigit(str[i]) && !isdigit(str[i-2]) && str[i-2]!=')'){flag[t]=1; //标记符号为正负号ex[t++]=ch;ch=str[i++];while((ch>='0'&&ch<='9')||(ch>='a'&&ch<='z')||ch=='.'||ch=='+') //判别小数点{ex[t]=ch;t++;ch=str[i];i++; }i--;ex[t]='&';t++;}else{ while(top!=0&&stack[top]!='('){ex[t]=stack[top];top--;t++;}top++;stack[top]=ch;}break;case '*':case '/':while(stack[top]=='*'||stack[top]=='/'||stack[top]=='^') //运算符^优先级高于*和/{ex[t]=stack[top];top--;t++; }top++;stack[top]=ch;break;case ' ':break;default:while((ch>='0'&&ch<='9')||(ch>='a'&&ch<='z')||ch=='.') //判别小数点{ex[t]=ch;t++;ch=str[i];i++; }i--;ex[t]='&';t++;}ch=str[i]; i++; }while(top!=0)if(stack[top]!='('){ex[t]=stack[top];t++;top--;}else{printf("error");top--;exit(0); }ex[t]='#';ex[t+1]='\0';printf("逆波兰式为:%s\n",ex);}void Calculate(){char ch=ex[0];int t=0;top=-1;while(ch!='#'){if(ch=='&'){ch=ex[++t];continue; }switch(ch) {case '+':if(flag[t]) //'+'表示正号{ch=ex[++t];double d=0;while(ch>='0'&&ch<='9'){d=10.0*d+double(ch-'0');ch=ex[++t];}if(ch=='.') //判断是否为小数{ch=ex[++t];double k=1.0;while(ch>='0'&&ch<='9'){d=d+double(ch-'0')/(10.0*k);k=k+1.0;ch=ex[++t];} }top++;_stack[top]=d;} else{_stack[top-1]=_stack[top-1]+_stack[top];top--;t++; }break;case '-':if(flag[t]) //'-'表示负号{ch=ex[++t];double d=0;while(ch>='0'&&ch<='9'){d=10.0*d+double(ch-'0');ch=ex[++t];} if(ch=='.') {ch=ex[++t];double k=1.0;while(ch>='0'&&ch<='9'){d=d+double(ch-'0')/(10.0*k);k=k+1.0;ch=ex[++t]; } }top++;_stack[top]=-d;} else {_stack[top-1]=_stack[top-1]-_stack[top];top--;t++; }break;case '^': //运算符为'^'if(_stack[top]==0){_stack[top-1]=1;}else{int temp;temp=_stack[top-1];while(--_stack[top]){_stack[top-1]*=temp; } } top--;t++;break;case '*':_stack[top-1]=_stack[top-1]*_stack[top];top--;t++;break;case '/':if(_stack[top]!=0)_stack[top-1]=_stack[top-1]/_stack[top];else{printf("\n\tchu0error!\n");exit(0);}top--;t++;break;default:double d=0;while(ch>='0'&&ch<='9'){d=10.0*d+double(ch-'0');ch=ex[++t]; }if(ch=='.') //判断是否为小数{ch=ex[++t];double k=1.0;while(ch>='0'&&ch<='9'){d=d+double(ch-'0')/(10.0*k);k=k+1.0;ch=ex[++t];}}top++;_stack[top]=d;}ch=ex[t];}cout<<"计算结果:"<<_stack[top]<<endl; //printf("计算结果:%lf\n",_stack[top]); }int main(){printf("请输入中缀表达式:");scanf("%s",&str); //输入原表达式printf("原表达式为:%s\n",str);NiBolan(); //生成逆波兰式Calculate(); //计算逆波兰式return 0;}屏幕截图:四、讨论与分析通过这次的实验,知道了算符优先文法的概念以及这个文法的简单应用。

相关文档
最新文档