(编译原理)逆波兰式算法的源代码
逆波兰表达式计算 java
逆波兰表达式计算 java逆波兰表达式是一种将运算符写在操作数之后的表示方法,计算逆波兰表达式可以使用栈来实现。
下面是一个使用Java实现逆波兰表达式计算的例子:```javaimport java.util.Stack;public class RPNCalculator {public static double evaluateRPN(String[] tokens) {Stack<Double> stack = new Stack<>();for (String token : tokens) {if (isOperator(token)) {double operand2 = stack.pop();double operand1 = stack.pop();double result = calculate(token, operand1, operand2);stack.push(result);} else {stack.push(Double.parseDouble(token));}}return stack.pop();}private static boolean isOperator(String token) {return token.equals("+") || token.equals("-") ||token.equals("*") || token.equals("/");}private static double calculate(String operator, double operand1, double operand2) {switch (operator) {case "+":return operand1 + operand2;case "-":return operand1 - operand2;case "*":return operand1 * operand2;case "/":return operand1 / operand2;default:throw new IllegalArgumentException("Unknown operator: " + operator);}}public static void main(String[] args) {String[] tokens = {"2", "1", "+", "3", "*"};double result = evaluateRPN(tokens);System.out.println("Result: " + result);String[] tokens2 = {"4", "13", "5", "/", "+"};double result2 = evaluateRPN(tokens2);System.out.println("Result: " + result2);}}```这个例子演示了如何使用栈来计算逆波兰表达式。
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");}}}}}测试:。
编译原理(逆波兰表达式)C语言版
中国计量学院《编译原理设计》课程论文题目:中缀表达式的逆波兰表示学生姓名:学号:学生专业:班级:二级学院:一、摘要编译原理是计算机科学与技术专业最重要的一门专业基础课程,内容庞大,涉及面广,知识点多。
由于该课程教、学难度都非常大,往往费了大量时间而达不到预期教学效果俗语说:学习的最好方法是实践。
本课程设计正是基于此,力求为学生提供一个理论联系实际的机会,通过布置一定难度的课题,要求学生独立完成。
我们这次课程设计的主要任务是编程实现对输入合法的中缀表达式进行词法分析、语法分析,构造相应的逆波兰式,计算后缀表达式的值输出结果。
逆波兰式也叫后缀表达式,即将运算符写在操作数之后。
通过实践,建立系统设计的整体思想,锻炼编写程序、调试程序的能力,学习文档编写规范,培养独立学习、吸取他人经验、探索前言知识的习惯,树立团队协作精神。
同时,课程设计可以充分弥补课堂教学及普通实验中知识深度与广度有限的缺陷,更好地帮助学生从全局角度把握课程体系。
关键字:逆波兰式;语法分析;中缀表达式二、实验综述在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,所以,这种表示法也称为中缀表示。
对中缀表达式的计值,并非按运算符出现的自然顺序来执行其中的各个运算,而是根据算符间的优先关系来确定运算的次序,此外,还应顾及括号规则。
因此,要从中缀表达式直接产生目标代码一般比较麻烦。
相对的,逆波兰式在计算机看来却是比较简单易懂的结构。
因为计算机普遍采用的内存结构是栈式结构,它执行先进后出的顺序。
三、实验意义对于实现逆波兰式算法,难度并不大,但为什么要将看似简单的中缀表达式转换为逆波兰式,原因就在于这个简单是相对人类的思维结构来说的,对计算机而言中缀表达式是非常复杂的结构。
相对的,逆波兰式在计算机看来却是比较简单易懂的结构。
因为计算机普遍采用的内存结构是栈式结构,它执行四、系统分析词法分析基本原理:词法分析程序完成的是编译第一阶段的工作。
逆波兰式(后缀表达式)的计算
逆波兰式(后缀表达式)的计算输⼊:后缀表达式(可带浮点数)输出: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;}。
实验4.1-目标代码生成-逆波兰
实验4.1 目标代码生成-逆波兰式一、实验目的结合课堂上理论知识,将算术表达式首先转化为逆波兰式(后缀表达式),然后再转化为目标代码(即假想栈式汇编代码),以此来了解编译器工作的原理。
二、实验环境1.常用微机一台。
2.c++编译环境(常见如vc6.0)。
三、实验要求将逆波兰直接转化为目标代码并输出。
不考虑生成的目标代码质量,并且忽略机器的特性的细节。
变量寄存器使用R0-R7,对于MOV指令,左边为源操作数,右边为目的操作数。
对于其他运算指令,目的操作数和源操作数进行运算,结果保存在存储源操作数的寄存器中,如ADD 3 4,汇编代码为MOV 3 R0 ADD 4 R0。
四、实验过程1.实验算法1.1逆波兰式生成算法首先设一个运算符栈,当从左到右扫描一个表达式时,若扫描到运算分量,将其保存在数组中。
若扫描到运算符,若运算符栈为空,则该运算符入栈,若栈不为空,则比较运算符的优先级,若当前运算符优先级小于等于栈顶运算符优先级,则将栈顶运算符保存到数组中,并且出栈,继续比较当前运算符和栈顶符号的优先级。
若当前运算符优先级大于栈顶优先级,则当前运算符入栈。
只要碰到’(‘,就进栈,当表达式已扫描完,将栈中的运算依次存入数组中,并出栈。
最后打印出数组的值,’(‘和’)’不存入数组中,所以不输出。
1.2目标代码生成算法首先设一个运算分量栈,开始扫描生成的逆波兰式。
若扫描的是运算分量,则将运算分量入栈。
若扫描到运算符,则按给定的运算符是几目运算(本程序并没有考虑一目运算符,所有的运算符都是二目),将运算分量栈中栈顶元素保存在一个字符数组变量中,并出栈,然后将字符串变量和栈顶元素生成该运算符的目标代码。
最后把运算结果的寄存器入栈,直到扫描完逆波兰式。
2.程序主要函数说明(1)string Apoland(string expre):将表达式转化为逆波兰式输出。
(2)int top(string ch):本程序中所使用的寄存器为通用寄存器R0-R7,用单字符@,#,<,>,[,],{,}来代替8个寄存器入栈,函数返回的是寄存器的号,如R0,@代替其进栈,栈顶为@时,则返回0。
逆波兰表达式求值(实验报告及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),所以时间的复杂度主要取决于字符串的长度,空间也同样取决于字符串长度。
逆波兰算法-python代码实现
逆波兰算法-python代码实现1,逆波兰算法简介假定给定⼀个只 包含 加、减、乘、除,和括号的算术表达式,你怎么编写程序计算出其结果?问题是:在表达式中,括号,以及括号的多层嵌套 的使⽤,运算符的优先级不同等因素,使得⼀个算术表达式在计算时,运算顺序往往因表达式的内容⽽定,不具规律性。
这样很难编写出统⼀的计算指令。
使⽤逆波兰算法可以轻松解决这个问题。
他的核⼼思想是将普通的中缀表达式转换为后缀表达式。
什么是中缀表达式?例如a+b,运算符在两个操作数的中间。
这是我们从⼩学开始学习数学就⼀直使⽤的表达式形式。
什么是后缀表达式?例如a b + ,运算符在两个操作数的后⾯。
后缀表达式虽然看起来奇怪,不利于⼈阅读,但利于计算机处理。
转换为后缀表达式的好处是:1、去除原来表达式中的括号,因为括号只指⽰运算顺序,不是实际参与计算的元素。
2、使得运算顺序有规律可寻,计算机能编写出代码完成计算。
2,逆波兰算法原理逆波兰算法的核⼼步骤就2个:1、将中缀表达式转换为后缀表达式,例如输⼊的原始表达式是 3*(5+7) ,转换得到 3 5 7 + *2、根据后缀表达式,按照特定的计算规则得到最终计算结果下⾯详细介绍这个2步的操作。
中缀表达式转换为后缀表达式你需要设定⼀个栈SOP,和⼀个线性表 L 。
SOP⽤于临时存储运算符和左括号分界符( ,L⽤于存储后缀表达式。
遍历原始表达式中的每⼀个表达式元素(1)如果是操作数,则直接追加到 L中。
只有 运算符 或者 分界符( 才可以存放到 栈SOP中(2)如果是分界符Ⅰ 如果是左括号 ( , 则 直接压⼊SOP,等待下⼀个最近的 右括号 与之配对。
Ⅱ 如果是右括号),则说明有⼀对括号已经配对(在表达式输⼊⽆误的情况下)。
不将它压栈,丢弃它,然后从SOP中出栈,得到元素e,将e依次追加到L⾥。
⼀直循环,直到出栈元素e 是 左括号 ( ,同样丢弃他。
(3)如果是运算符(⽤op1表⽰)Ⅰ如果SOP栈顶元素(⽤op2表⽰) 不是运算符,则⼆者没有可⽐性,则直接将此运算符op1压栈。
C语言实现逆波兰式实例
C语⾔实现逆波兰式实例复制代码代码如下:#include<stdio.h>#include<string.h>typedef struct{char s[20][20];int top;}SQ;void copystr(char *a,char *b){int i=0;do{b[i]=a[i];i++;}while(a[i]!='\0');b[i]='\0';}void voidSQ(SQ *s){s->top=-1;}int ifempty(SQ *s){return(s->top==-1);}void push(SQ *S,char *c){if(S->top==19)printf("over flow\n");else{S->top++;copystr(c,S->s[S->top]);}}char *pop(SQ *S){if(ifempty(S)){printf("over flow!\n");return(NULL);}elsereturn(S->s[S->top--]);}int judge(char *c){if(c[1]=='\0')switch(c[0]){case '+':return(3);case '-':return(3);case '*':return(2);case '/':return(2);default:return(1);}elsereturn(1);}void write(char *a,char *b,char *c){strcat(a,c);strcat(a,b);}int seek(char *c,int start){int signal=1;for(start=start++;c[start]!='\0'&&signal!=0;start++) {if(c[start]==')')signal--;else if(c[start]=='(')signal++;}if(signal==0)return(start-1);else{printf("输⼊⽆效式⼦\n");return(-1);}}void FB(SQ *A,SQ *B){for(;!ifempty(A);){push(B,A->s[A->top]);pop(A);}}char *rewrite(char *A){SQ front;SQ back;int i,j,k,flag=0;char *result;char mid[20];voidSQ(&front);voidSQ(&back);for(i=0;A[i]!='\0';){if(A[i]=='('){j=seek(A,i);for(k=i+1;k<j;k++){mid[k-i-1]=A[k];}mid[j-i-1]='\0';copystr(rewrite(mid),mid);push(&back,mid);i=j+1;}else if(A[i]!='(')mid[0]=A[i];mid[1]='\0';push(&back,mid);i++;}}FB(&back,&front);for(;front.top>=2;){flag=0;for(i=0;i<=front.top;i++){if(judge(front.s[i])==2){flag=1;break;}}if(flag==1){for(;front.top>=2;){if(judge(front.s[front.top])==1&&judge(front.s[front.top-1])==2&&judge(front.s[front.top-2])==1) {write(front.s[front.top],front.s[front.top-1],front.s[front.top-2]);push(&back,front.s[front.top]);pop(&front);pop(&front);pop(&front);}else{push(&back,front.s[front.top]);pop(&front);}}FB(&front,&back);FB(&back,&front);}else{for(;front.top>=2;){if(judge(front.s[front.top])==1&&judge(front.s[front.top-1])==3&&judge(front.s[front.top-2])==1) {write(front.s[front.top],front.s[front.top-1],front.s[front.top-2]);push(&back,front.s[front.top]);pop(&front);pop(&front);pop(&front);}else{push(&back,front.s[front.top]);pop(&front);}}FB(&front,&back);FB(&back,&front);}result=front.s[front.top];return(result);}typedef struct{char c[20];int top;}sq; int execute(char a,char b,char c) {switch(a){case('+'):return((c-48)+(b-48)); case('-'):return((c-48)-(b-48));case('*'):return((c-48)*(b-48));case('/'):return((c-48)/(b-48));}}void voidsq(sq *s){s->top=-1;}int ifsqempty(sq *s){return(s->top==-1);}void pushsq(sq *s,char x){if(s->top==19)printf("over flow!\n");else{s->top=s->top+1;s->c[s->top]=x;}}void popsq(sq *s){if(ifsqempty(s))printf("over flow!\n");elses->top--;}int just(char c){switch(c){case ('+'):return(0);case ('-'):return(0);case ('*'):return(0);case ('/'):return(0);default:return(1);}}void restread(sq *a,sq *b){for(;!ifsqempty(a);){pushsq(b,a->c[a->top]);popsq(a);}}int calculate(char *c){sq rest,read;int i,re;voidsq(&rest);voidsq(&read);for(i=0;c[i]!='\0';i++)pushsq(&read,c[i]);for(;read.top>=2;){for(;read.top>=2;){if(just(read.c[read.top])==0&&just(read.c[read.top-1])==1&&just(read.c[read.top-2]) ==1) {re=execute(read.c[read.top],read.c[read.top-1],read.c[read.top-2]);pushsq(&rest,re+48);popsq(&read);popsq(&read);popsq(&read);}else{pushsq(&rest,read.c[read.top]);popsq(&read);}}restread(&read,&rest);restread(&rest,&read);}return(read.c[0]-48);}void main(){char re[20];char a[20];printf("请输⼊算式:\n");scanf("%s",a);copystr(rewrite(a),re);printf("逆波兰式:\n%s\n",re);printf("求值结果:\n%d\n",calculate(re));}。
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语言版
中国计量学院《编译原理设计》课程论文题目:中缀表达式的逆波兰表示学生姓名:学号:学生专业:班级:二级学院:一、摘要编译原理是计算机科学与技术专业最重要的一门专业基础课程,内容庞大,涉及面广,知识点多。
由于该课程教、学难度都非常大,往往费了大量时间而达不到预期教学效果俗语说:学习的最好方法是实践。
本课程设计正是基于此,力求为学生提供一个理论联系实际的机会,通过布置一定难度的课题,要求学生独立完成。
我们这次课程设计的主要任务是编程实现对输入合法的中缀表达式进行词法分析、语法分析,构造相应的逆波兰式,计算后缀表达式的值输出结果。
逆波兰式也叫后缀表达式,即将运算符写在操作数之后。
通过实践,建立系统设计的整体思想,锻炼编写程序、调试程序的能力,学习文档编写规范,培养独立学习、吸取他人经验、探索前言知识的习惯,树立团队协作精神。
同时,课程设计可以充分弥补课堂教学及普通实验中知识深度与广度有限的缺陷,更好地帮助学生从全局角度把握课程体系。
关键字:逆波兰式;语法分析;中缀表达式二、实验综述在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,所以,这种表示法也称为中缀表示。
对中缀表达式的计值,并非按运算符出现的自然顺序来执行其中的各个运算,而是根据算符间的优先关系来确定运算的次序,此外,还应顾及括号规则。
因此,要从中缀表达式直接产生目标代码一般比较麻烦。
相对的,逆波兰式在计算机看来却是比较简单易懂的结构。
因为计算机普遍采用的内存结构是栈式结构,它执行先进后出的顺序。
三、实验意义对于实现逆波兰式算法,难度并不大,但为什么要将看似简单的中缀表达式转换为逆波兰式,原因就在于这个简单是相对人类的思维结构来说的,对计算机而言中缀表达式是非常复杂的结构。
相对的,逆波兰式在计算机看来却是比较简单易懂的结构。
因为计算机普遍采用的内存结构是栈式结构,它执行四、系统分析词法分析基本原理:词法分析程序完成的是编译第一阶段的工作。
(编译原理)逆波兰式算法的源代码
一.实验目的1.深入理解算符优先分析法2.掌握FirstVt和LastVt集合的求法有算符优先关系表的求法3.掌握利用算符优先分析法完成中缀表达式到逆波兰式的转化二.实验内容及要求将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。
程序输入/输出示例:输出的格式如下:(1)逆波兰式的生成及计算程序,编制人(2)输入一以#结束的中缀表达式(包括+—*/()数字#)(3)(4)逆波兰式备注:(1)在生成的逆波兰式中如果两个数相连则用&分隔,如28和68,中间用&分隔;(注意:1。
表达式中允许使用运算符(+-*/)、分割符(括号)、数字,结束符#;2。
如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好);3.对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。
同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;三.实验过程1、逆波兰式定义将运算对象写在前面,而把运算符号写在后面。
用这种表示法表示的表达式也称做后缀式。
逆波兰式的特点在于运算对象顺序不变,运算符号位置反映运算顺序。
采用逆波兰式可以很好的表示简单算术表达式,其优点在于易于计算机处理表达式。
2、产生逆波兰式的前提中缀算术表达式3、逆波兰式生成的实验设计思想及算法(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。
(2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”.(3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。
(4)如果不是数字,该字符则是运算符,此时需比较优先关系。
做法如下:将该字符与运算符栈顶的运算符的优先关系相比较.如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈.倘若不是的话,则将此运算符栈顶的运算符从栈中弹出,将该字符入栈。
c语言实现逆波兰表达式!
}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++;
编译原理报告四逆波兰式
逆波兰式的产生及计算一、目的与要求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的属性。
对逆波兰式计算的程序设计
数据结构作业报告逆波兰式的计算一题目内容逆波兰式也叫后缀表达式(将运算符写在操作数之后)如:我们平时写a+b,这是中缀表达式,写成后缀表达式就是:ab+(a+b)*c-(a+b)/e的后缀表达式为:(a+b)*c-(a+b)/e→((a+b)*c)((a+b)/e)-→((a+b)c*)((a+b)e/)-→(ab+c*)(ab+e/)-→ab+c*ab+e/-计算给出的逆波兰式(假设条件:逆波兰表达式由单字母变量和双目四则运算符构成,以’#‘作为结束标志)。
二题目分析逆波兰式即后缀表达式,运算符置于两个操作数之后。
运算实应从前往后依次读出两个运算数,与这两个运算数之后的运算符进行计算,然后再从前往后提取两个操作数,再从之后提取对应的运算符,直到计算完毕。
这与栈的功能相一致,建立一个栈结构,将表达式的各个字符依次读取,若是数字则放入栈中,,若是操作符则从栈中提取两个数字进行运算,将运算结果加入到栈中,直至运算完毕。
三程序描述首先定义相关数值,建立栈结构的数据类型typedef struct{SElemType *base;SElemType *top;int stacksize;}SqStack;之后是各个对栈的操作函数Status InitStack(SqStack &S){S.base=(SElemType*)malloc(STACK_INIT_SIZE*sizeof(SElem Type));if(!S.base)exit(OVERFLOW);S.top=S.base;S.stacksize=STACK_INIT_SIZE;return OK;}//建立空栈Status Push(SqStack &S,SElemType e){if(S.top-S.base>=S.stacksize){S.base=(SElemType*)malloc(S.base,(S.stacksize+STACKINCREME NT)*sizeof(SElemTYpe));if(!S.base)exit(OVERFLOW);S.top=S.base+S.stacksize;S.stacksize+=STACKINCREMENT;}*S.top++=e;return OK;}//将栈顶元素输出到元素e之中Status Pop(SqStack &S,SElemType e) {if(S.top==S.base)return ERROR;e=*--S.top;return OK;}//将元素e加入到栈之中程序最重要的操作函数如下(进行计算操作):char CalVal_InverPoland(char Buffer[]){Stack Opnd;InitStack(Opnd);int i=0;char c;ElemType e1,e2;while(Buffer[i]!='#'){if(!IsOperator(Buffer[i])){Push(Opnd,Buffer[i]);}else{Pop(Opnd,e2);Pop(Opnd,e1);c=Cal(e1,Buffer[i],e2);Push(Opnd,c);}i++;}return c;}while循环中是对表达式各字符的判断和计算过程,如果是数字则加入栈中,是操作符则从栈中提取两数据进行计算,之后将计算结果加入到栈中,直至遇到表达式结束标志’#’则结束运算,栈中数字则为计算结果。
(编译原理)逆波兰式算法的源代码
(编译原理)逆波兰式算法的源代码一.实验目的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)⾸先对输⼊的中缀表达式合法性进⾏判断,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 }。
(编译原理)逆波兰式算法地源代码
一.实验目的1.深入理解算符优先分析法2.掌握FirstVt和LastVt集合的求法有算符优先关系表的求法3.掌握利用算符优先分析法完成中缀表达式到逆波兰式的转化二.实验内容及要求将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。
程序输入/输出示例:输出的格式如下:(1)(2)输入一以#结束的中缀表达式(包括+—*/()数字#)(3)(4)逆波兰式备注:(1)在生成的逆波兰式中如果两个数相连则用&分隔,如28和68,中间用&分隔;注意:1.表达式中允许使用运算符(+-*/)、分割符(括号)、数字,结束符#;2.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好);3.对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。
同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;三.实验过程1、逆波兰式定义将运算对象写在前面,而把运算符号写在后面。
用这种表示法表示的表达式也称做后缀式。
逆波兰式的特点在于运算对象顺序不变,运算符号位置反映运算顺序。
采用逆波兰式可以很好的表示简单算术表达式,其优点在于易于计算机处理表达式。
2、产生逆波兰式的前提中缀算术表达式3、逆波兰式生成的实验设计思想及算法(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。
(2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。
(3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。
(4)如果不是数字,该字符则是运算符,此时需比较优先关系。
做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。
如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。
倘若不是的话,则将此运算符栈顶的运算符从栈中弹出,将该字符入栈。
python实现逆波兰计算表达式的代码
python实现逆波兰计算表达式的代码如下资料是关于python实现逆波兰计算表达式的代码。
symbol_priority = {}symbol_priority[0] = ['#']symbol_priority[1] = ['(']symbol_priority[2] = ['+', '-']symbol_priority[4] = [')']def comparePriority(symbol, RPN_stack, symbol_stack):'''Compare priority between two symbols'''global symbol_priorityif len(symbol_stack) > 0:symbol_pop = symbol_stack.pop()else:returnfor list in symbol_priority.values():if (symbol in list) and (symbol_pop in list):'''same priority'''symbol_stack.append(symbol_pop)symbol_stack.append(symbol)returnelif symbol in list:'''symbol is smaller'''RPN_stack.append(symbol_pop)#recusion callcomparePriority(symbol, RPN_stack, symbol_stack)returnelif symbol_pop in list:'''symbol is bigger'''symbol_stack.append(symbol_pop)symbol_stack.append(symbol)returnelse:continuesymbol_stack.append(symbol_pop)returndef scanEveryone(input_string, RPN_stack, symbol_stack):for ch in input_string:if ch.isdigit():RPN_stack.append(ch)else:if len(symbol_stack) > 0:if ch == '(':symbol_stack.append(ch)elif ch == ')':while True:symbol_pop = symbol_stack.pop()if symbol_pop == '(':breakelse:RPN_stack.append(symbol_pop)else:comparePriority(ch, RPN_stack, symbol_stack)else:symbol_stack.append(ch)def scanInput(RPN_stack, symbol_stack):input_string = raw_input()input_string += '#'scanEveryone(input_string, RPN_stack, symbol_stack)def calRPN(RPN_stack):value_stack = []RPN_stack.append('#')for value in RPN_stack:if value == '#':return value_stack.pop()breakif value.isdigit():value_stack.append(value)else:right_value = value_stack.pop()left_value = value_stack.pop()cal_string = left_value + value + right_valuevalue_stack.append(str(eval(cal_string)))def main():RPN_stack = []symbol_stack = []scanInput(RPN_stack, symbol_stack)print calRPN(RPN_stack)if name == 'main':main()calRPN.pysymbol_priority = {}symbol_priority[0] = ['#']symbol_priority[1] = ['(']symbol_priority[2] = ['+', '-']symbol_priority[4] = [')']def comparePriority(symbol, RPN_stack, symbol_stack): '''Compare priority between two symbols'''global symbol_priorityif len(symbol_stack) > 0:symbol_pop = symbol_stack.pop()else:returnfor list in symbol_priority.values():if (symbol in list) and (symbol_pop in list):'''same priority'''symbol_stack.append(symbol_pop)symbol_stack.append(symbol)returnelif symbol in list:'''symbol is smaller'''RPN_stack.append(symbol_pop)#recusion callcomparePriority(symbol, RPN_stack, symbol_stack)returnelif symbol_pop in list:'''symbol is bigger'''symbol_stack.append(symbol_pop)symbol_stack.append(symbol)returnelse:continuesymbol_stack.append(symbol_pop)returndef scanEveryone(input_string, RPN_stack, symbol_stack): for ch in input_string:if ch.isdigit():RPN_stack.append(ch)else:if len(symbol_stack) > 0:if ch == '(':symbol_stack.append(ch)elif ch == ')':while True:symbol_pop = symbol_stack.pop()if symbol_pop == '(':breakelse:RPN_stack.append(symbol_pop)else:comparePriority(ch, RPN_stack, symbol_stack)else:symbol_stack.append(ch)def scanInput(RPN_stack, symbol_stack):input_string = raw_input()input_string += '#'scanEveryone(input_string, RPN_stack, symbol_stack) def calRPN(RPN_stack):value_stack = []RPN_stack.append('#')for value in RPN_stack:if value == '#':return value_stack.pop()breakif value.isdigit():value_stack.append(value)else:right_value = value_stack.pop()left_value = value_stack.pop()cal_string = left_value + value + right_valuevalue_stack.append(str(eval(cal_string)))def main():RPN_stack = []symbol_stack = []scanInput(RPN_stack, symbol_stack)print calRPN(RPN_stack)if name == 'main':main()。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一.实验目的
1.深入理解算符优先分析法
2.掌握FirstVt和LastVt集合的求法有算符优先关系表的求法
3.掌握利用算符优先分析法完成中缀表达式到逆波兰式的转化
二.实验内容及要求
将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。
程序输入/输出示例:
输出的格式如下:
(1)
(2)输入一以#结束的中缀表达式(包括+—*/()数字#)
(3)
(4)逆波兰式
备注:(1)在生成的逆波兰式中如果两个数相连则用&分隔,如28和68,中间用&分隔;
注意:1.表达式中允许使用运算符(+-*/)、分割符(括号)、数字,结束符#;
2.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好);
3.对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。
同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;
三.实验过程
1、逆波兰式定义
将运算对象写在前面,而把运算符号写在后面。
用这种表示法表示的表达式也称做后缀式。
逆波兰式的特点在于运算对象顺序不变,运算符号位置反映运算顺序。
采用逆波兰式可以很好的表示简单算术表达式,其优点在于易于计算机处理表达式。
2、产生逆波兰式的前提
中缀算术表达式
3、逆波兰式生成的实验设计思想及算法
(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。
(2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。
(3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。
(4)如果不是数字,该字符则是运算符,此时需比较优先关系。
做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。
如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。
倘若不是的话,则将此运算符栈顶的运算
符从栈中弹出,将该字符入栈。
(5)重复上述操作(1)-(2)直至扫描完整个简单算术表达式,确定所有字符都得到正确处
理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。
3、逆波兰式计算的实验设计思想及算法
(1)构造一个栈,存放运算对象。
(2)读入一个用逆波兰式表示的简单算术表达式。
(3)自左至右扫描该简单算术表达式并判断该字符,如果该字符是运算对象,则将
该字符入栈。
若是运算符,如果此运算符是二目运算符,则将对栈顶部的两个运算对象进行该运算,将运算结果入栈,并且将执行该运算的两个运算对象从栈顶弹出。
如果该字符是一目运算符,则对栈顶部的元素实施该运算,将该栈顶部的元素弹出,将运算结果入栈。
(4)重复上述操作直至扫描完整个简单算术表达式的逆波兰式,确定所有字符都得
到正确处理,我们便可以求出该简单算术表达式的值。
4.实验的源程序代码如下:
#include<stdio.h>
#include<math.h>
#define max 100
char 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;
case '/':
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();
}
5.程序的运行结果如下:
四.实验总结(心得)
通过本实验的学习,主要掌握了逆波兰式算法的含义,结合书本知识,让我更加清楚此算法实现的主要过程,以及使用该算法的好处,通过对程序实现的分析,对于逆波兰式算法的细节了解的更加清楚,从中学到了很多的东西。