编译原理 实验5 中间代码生成(将算术表达式等翻译成逆波兰形式)

1 实验任务

编写一个中间代码生成程序,能将算术表达式等翻译成逆波兰、三元组或四元组形式(选择其中一种形式即可)。

2 实验内容

(1)实验要求
将算术表达式等翻译成逆波兰、三元组或四元组形式
(2)输入格式
包含各种算术表达式的文本文件。
(3)输出格式
程序能输出生成的逆波兰、三元组或四元组序列。

3 算法描述

人们常用的算术表达式是中序表达式,而逆波兰表达式是后续表达式,在计算机编程中,后续表达式更易于求得表达式结果。

此处实现的算法主要是对栈的应用,主要实现是先给+、-、*、/、(设定优先级,然后读入符号,若是数字则直接压入结果栈,若是左括号则压入符号栈,是右括号则弹结果栈直到遇到左括号。

其他情况则按优先级压入,若当前符号优先级大于栈顶,直接压入符号栈,否则弹出符号栈到结果栈,直到为空或者符号优先级大于栈顶再压入符号栈。
而逆波兰表达式的求值则较为简单,每次从结果栈弹出三个值,分别是两个操作数和一个操作符,然后进行运算后压栈,当栈内只剩一个元素时,那个元素往往就是运算结果。

对于出错处理部分,将它们分成了三个错误:

  1. 字符非法:通过遍历字符看起是否合法实现。
  2. 操作符连续:维护一个bool的变量记录上个字符是否代表操作符。
  3. 括号无法匹配:利用一个栈。若左括号就压栈,右括号时查看是否是左括号处于栈顶,是的话就弹栈,不是的话就出错。最后,如果这个栈有剩余的左括号,说明出错。

4 代码

主要包含四个函数:

  • Convert:将输入的中序表达式转化为结果栈的形式(这里用链表模拟栈)。
  • GetRes:以Convert的输出做输入,求得后序表达式的值。
  • CheckInput:查看输入是否有错误。
  • error:输出对应错误。
//将中序表达式转化为后序表达式
//并利用后序表达式计算结果
#include<iostream>
#include<list>
#include<cstdio>
#include<string.h>
#include<string>
#include<map>
using namespace std;

list<string> ope;			//运算符栈
list<string> res;			//结果栈
map<string,int> oper;		//存储算符优先级
list<int> container;		//运算栈
char invalidChar;
bool valid = true;
void error(int x){
    
    
	valid = false;
	switch(x){
    
    
		case 1://)(()
			cout<<"非法字符"<<invalidChar<<endl;
			break;
		case 2:
			cout<<"连续的操作符"<<invalidChar<<endl;
			break;
		case 3:
			cout<<"无法匹配括号"<<endl;
			break;
	}
	
}

void CheckInput(string s){
    
    
	list<char> bracketStack;
	bool lastOp = true;//记录上一个是否为运算符 
	for(int i = 0;i<s.length();i++){
    
    
		if(s[i]>='0'&&s[i]<='9'){
    
    
			lastOp = false;
		}
		else if(s[i]=='+'||s[i]=='-'||s[i]=='*'||s[i]=='/'){
    
    
			if(lastOp){
    
    
				invalidChar=s[i];
				error(2);
			}
			lastOp=true;
		}
		else if(s[i]=='('){
    
    
			bracketStack.push_back('(');
			lastOp=true;//左括号后不能直接出现运算符 
		}
		else if(s[i]==')'){
    
    
			if(bracketStack.empty()||bracketStack.back()!='('){
    
    //不匹配 
				error(3);
			}
			else{
    
    
				bracketStack.pop_back();
			}
			
		}
		else{
    
     
			lastOp = false;
			invalidChar=s[i];
			error(1);
		}
		
	}
	if(!bracketStack.empty())
		error(3);
}

string Convert(char s[])
{
    
    
	oper["+"] = 1;		//运算符优先级越低,oper越低
	oper["-"] = 1;
	oper["*"] = 2;
	oper["/"] = 2;
	oper["("] = 0;
	int i = 0;
	while(true)
	{
    
    
		if (i >= strlen(s)) 
			break;
		while (s[i]==' '||s[i]=='/t')//去除无效的空格
			++i;
		if(s[i]>='0'&&s[i]<='9')	//若为数字则获取
		{
    
    
			string num;
			while (s[i] >= '0'&&s[i] <= '9')
				num.push_back(s[i++]);			
			res.push_back(num);		//数字直接压入结果栈
			continue;
		}
		else if(s[i]=='(')
			ope.push_back("(");
		else if(s[i]==')')			//是右括号则匹配
		{
    
    
			while(true)
			{
    
    
				if(ope.back()=="(")
				{
    
    
					ope.pop_back();
					break;
				}
				res.push_back(ope.back());
				ope.pop_back();
			}
		}
		else
		{
    
    
			string num;
			num.push_back(s[i]);
			while(!ope.empty())
			{
    
    
				if(oper[num]>oper[ope.back()])//当前符号优先级大于栈顶,直接压入符号栈
				{
    
    
				   ope.push_back(num);
				   break;
				}
				res.push_back(ope.back());//否则弹出符号栈到结果栈,直到为空或者符号优先级大于栈顶再压入符号栈。
				ope.pop_back();
			}
			if(ope.empty())
				ope.push_back(num);
		}
		++i;
	}
	while(!ope.empty())//最后把符号栈的全部内容弹到结果栈
	{
    
    
		res.push_back(ope.back());
		ope.pop_back();
	}
   string result = "";
   while(!res.empty())//输出后序表达式
   {
    
    
      result+=res.front()+" ";
      res.pop_front();
   }
   return result;
}

int GetRes(string s)
{
    
    
   int res;
   int i = 0;
   while(true)
   {
    
    
		if (i >= s.length()-1) 
		{
    
    
			break;
		}
		while (s[i]==' '||s[i]=='/t')//去除无效的空格
			++i;
		if(s[i]>='0'&&s[i]<='9')
		{
    
    
			int num=0;
			while (s[i] >= '0'&&s[i] <= '9')
				num = num*10 + s[i++]-'0';
			container.push_back(num);
			continue;
		}
      else
      {
    
    
         int b = container.back();
         container.pop_back();
         int a = container.back();
         container.pop_back();
         int c;
         if(s[i]=='+')
            c = a+b;
         else if(s[i]=='-')
            c = a-b;
         else if(s[i]=='*')
            c = a*b;
         else if(s[i]=='/')
            c = a/b;
         container.push_back(c);
      }
	  ++i;
   }
   return container.back();
}

int main()
{
    
    
   char s[30];
   while (scanf("%s", &s) != EOF) {
    
    
		ope.clear();
		res.clear();			
		container.clear();
		valid = true;
		CheckInput(s);
		if(!valid)
			continue;
	  	string ansStr = Convert(s);				//把中序的算数表达式
      	cout<<ansStr<<endl;						//输出逆波兰表达式
      	cout<<"算数结果:"<<GetRes(ansStr)<<endl;	//输出算数结果
   }
}
//56+8130/(2+67)*8
//9+1/1-7*2+123+456/123+(98+87)
//56+(8130/((2+67)-6*5+7)*8)
//56-+8130/(*2+67)*8
//~45+a/5
//5+2)(

5 运行结果

(1)测试一:56+8130/(2+67)8
在这里插入图片描述
(2)测试二:9+1/1-7
2+123+456/123+(98+87)
在这里插入图片描述
(3)测试三:56+(8130/((2+67)-6*5+7)*8)
在这里插入图片描述
(4)测试四:对三种出错情况进行测试。
56-+8130/(*2+67)*8触发错误:连续的操作符
~45+a/5触发错误:非法字符
5+2)(触发错误:括号不匹配
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43399489/article/details/121524843
今日推荐