编译原理(中间代码生成)-逆波兰表示(后缀表达式)

1.需求

1、编制一个中间代码生成程序,能将算术表达式等翻译成逆波兰形式, 即从中缀表达式转换成后缀表达式
2、程序具有通用性,即能接受各种不同的算术表达式等语法成分。
3、对于语法正确的算术表达式,能生成逆波兰表示,并输出结果;

1+2, 是中缀表达式. 后缀表达式即运算符在后面的表达式.
逆波兰表达式,它的语法规定,表达式必须以逆波兰表达式的方式给出。逆波兰表达式又叫做后缀表达式,下面是一些具体的例子:
正常的表达式 逆波兰表达式
a+b —> a,b,+
a+(b-c) —> a,b,c,-,+
a+(b-c)d —> a,b,c,-,d,,+
a+d*(b-c)—>a,d,b,c,-,*,+
a=1+3 —> a=1,3 +

2.算法

从左到右遍历中缀表达式:
1.遇到操作数,直接输出;
2.栈为空时,遇到运算符,入栈;
3.遇到左括号,将其入栈;
4.遇到右括号,执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出;
5.遇到其他运算符’+”-”*”/’时,弹出所有优先级大于或等于该运算符的栈顶元素(即除了 ’ ( ',然后将该运算符入栈;
6.最终将栈中的元素依次出栈,输出。

流程图:
举例:a+b * c+(d * e+f)* g ———> abc+de * f+g*+

遇到a,直接输出:编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第1张图片
遇到+,此时栈为空,入栈:
编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第2张图片
遇到b,直接输出:
编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第3张图片
遇到*,优先级大于栈顶符号优先级,入栈; 遇到c, 直接输出:
编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第4张图片
遇到+, 栈内的符号优先级都大于等于它, 所以先弹出栈内的符号, 再i压入+:
编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第5张图片

遇到(,将其入栈:
编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第6张图片

遇到d,直接输出:
编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第7张图片
遇到*,由于的优先级高于处在栈中的(,因此入栈:
编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第8张图片
遇到e,直接输出:
编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第9张图片
遇到+,栈顶*的优先级高于+,但是栈内的(低于+,将栈顶输出,+入栈:
编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第10张图片
遇到f,直接输出:
编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第11张图片

遇到),弹出栈顶元素并且输出(上面算法第4条),直到弹出(才结束,在这里也就是弹出+输出,弹出(但不输出:
编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第12张图片

遇到*,优先级高于栈顶+,将*入栈:
编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第13张图片

遇到g,直接输出:
编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第14张图片

此时已经没有新的字符了,依次出栈并输出操作直到栈为空:
编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第15张图片

将中缀表达式转换成后缀表达式的算法如下图所示:
编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第16张图片
转换为后缀表达式之后,对逆波兰表达式的计算:
编译原理(中间代码生成)-逆波兰表示(后缀表达式)_第17张图片

3.代码

#include
using namespace std;

char st[1000]; //保存符号的堆栈数组(模拟栈)
int top = -1; //堆栈指针
string ss = ""; //保存结果逆波兰式

int main(){
	printf("%s", "Input:");
	string s;
	
	cin>>s;
	int L = s.length();
	for(int i =  0;i < L; ++i){
		if(s[i]=='+'||s[i]=='-'){
			if(top==-1){ //栈为空, 遇到运算符,入栈
				st[++top] = s[i]; //将+,-入栈
			}else
			{
				while (st[top]!='(' && top > -1) //遇到其他运算符’+”-”*”/’时,弹出所有优先级大于或等于该运算符的栈顶元素(即除了 ' ( '
				{
					ss.push_back(st[top]);
					top--;
				}
				st[++top] = s[i]; //然后将该运算符入栈
			}
		}else if(s[i]=='*'||s[i]=='/'){
			if(top==-1){ //栈为空, 遇到运算符,入栈
				st[++top] = s[i]; //入符号栈
			}else{
				while (st[top]!='('&&(st[top]=='*'||st[top]=='/')) //同L20处, 不过st[top]不能为=或-,否则无法输出
				{
					ss.push_back(st[top]);
					top--;
				}
				st[++top] = s[i]; 
			}
		}else if(s[i]==')'){ //遇到右括号将左括号之前全部入栈,加入逆波兰式
			while(st[top]!='('){ //遇到右括号,执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出
				ss.push_back(st[top]);
				top--;
			}
			top--; //左括号出栈但不加入逆波兰式
		}else{ 
			ss.push_back(s[i]); //操作数直接加入逆波兰式
		}
	} 

	//最后将堆栈中全部元素加入波兰式
	while(top>-1){
		ss.push_back(st[top]);
		top--;
	}
	printf("%s","逆波兰式为: ");
	cout<<ss<<endl;
	return 0;
} 

输入Input:2+3*5

输出:逆波兰式为: 235*+

你可能感兴趣的:(算法,编译原理,C++,c++)