【编译原理】中间代码生成的实现(实验报告+C/C++源程序)

一、实验目的

        通过设计、开发一个高级语言的中间代码生成程序,加深对相关课堂教学内容,包括语法制导翻译技术、类型确定、类型检查、常见可执行语句(如赋值语句)翻译技术的理解。

二、实验要求

        编写一个中间代码生成程序。

        要求输出四元式。

三、实验设备与环境

1.硬件:处理器:12th Gen Intel(R) Core(TM) i5-12500H(16 CPUs),~2.5GHZ

2.软件:dev c++

四、实验内容

五、实验步骤

        语法制导翻译的基本思想:为每个产生式配上一个语义子程序,(该子程序描述了一个产生式所对应的翻译工 作。这些工作包括:生成中间代码,查填有关的符号表,检查和报错,修改编译程序某些工作变量的值等)。在语法分析过程中,每当一个产生式用于推导(自顶向下分析)或归约(自底向上分析)时,就调用该产生式所对应的语义子程序,以完成既定的翻译任务。

        具体步骤

        首先输入表达式,进行词法分析,把词法分析的结果存在字符数组中,之后调用递归下降分析器中的表达式子程序进行分析,最后得到四元组并输出,最后判断程序的输入是否结束,如果没有结束,就再次输入表达式,重复上述步骤,如果结束,则程序退出。

        bool isAlpha(char s)  //判断扫描字符是否为字母

        string scan()  //扫描读取字符

        string F()  //文法F的调用程序

        string T()  //文法T的调用程序

        string E()  //文法E的调用程序

        void S()  //文法开始S的入口入口程序

        int main()  //主函数

六、实验结果及分析

测试一:  

测试二:  

测试三:

        先读取表达式,采用递归下降分析法进行分析,对输入字符进行移进、归约,产生四元式。对于测试一,读取表达式,依次调用函数S、E、T、F、E、T、F,再回退到E,产生四元式“+”操作,再依次调用...最后得到四元式序列。

        一组数据具有偶然性,测试多组数据,来保证程序的可用性,发现分析都较为准确。

七、实验小结和思考

        本次实验我学会了如何将语法分析器与词法分析器相结合设计出生成目标代码的过程,加深了对语法制导翻译技术、常见可执行语句(如赋值语句)翻译技术的理解。

        编写代码的时候,需要用到词法分析器和语法分析器的编写方法,用词法分析器的编写思想来读取表达式,用语法分析器的编写思想来进行递归调用,最后在特殊位置输出四元式结果。

        通过这次实验,从词法分析到语法分析到语义分析的知识点有了串联的整合,重点回顾了不同阶段的作用以及相关性。但还需要进一步优化自己的代码,改进指针移动位置,减少冗余代码,使代码变得简洁,提高执行效率。

八、源程序清单

#include<iostream>
#include<string>
using namespace std;
string s;
int i,j=1;  //i指向当前语句的位置,j表示当前表达式序号
string E();
bool isAlpha(char s){  //判断扫描字符是否为字母
	if((s>='a'&&s<='z')||(s>='A'&&s<='Z')) return true;
	else return false;
}
string scan(){  //扫描读取字符
	char token[50];
	int tem=0;
	if(isAlpha(s[i])){
		while(isAlpha(s[i])){
			token[tem++]=s[i++];
		}
		token[tem]='\0';
	}
	return token;
}
string F(){  //文法F的调用程序
	if(s[i]=='-'){
		i++;
		string t1=F();
		cout<<"(-,"<<t1<<",-,T"<<j<<")"<<endl;
		string j1=to_string(j);
		string t='T'+j1;
		j++;	
		return t;
	}
	else if(s[i]=='('){
		i++;
		string t=E();
		i++;
		return t;
	}
	else {
		string I3=scan();
		return I3;
	}
}
string T(){  //文法T的调用程序
	string t1=F();
	string t=t1;
	if(s[i]=='*'){
		i++;
		string t2=F();
		cout<<"(*,"<<t1<<","<<t2<<",T"<<j<<")"<<endl;
		string j1=to_string(j);
		string t='T'+j1;
		return t;
	}
	return t;
}
string E(){  //文法E的调用程序
	string t1=T();
	string t=t1;
	if(s[i]=='+'){
		i++;
		string t2=scan();
		cout<<"(+,"<<t1<<","<<t2<<",T"<<j<<")"<<endl;
		string j1=to_string(j);
		string t='T'+j1;
		j++;
		return t;
	}
	return t;
}
void S(){  /文法开始S的入口入口程序
	string t=scan();
	i+=2;
	string t1=E();
	cout<<"(:=,"<<t1<<",-,"<<t<<")"<<endl;
}
int main(){
	cout<<"请输入赋值语句:";
	cin>>s;
	cout<<"四元式序列为:"<<endl;
	S();
	return 0;
}

  • 42
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
中间代码生成是编译器的一个重要组成部分,它将源代码翻译为目标代码的中间表示形式,方便后面的代码优化和目标代码生成。下面是一个简单的中间代码生成实验代码,使用 C++ 实现。 假设我们有以下 C 语言代码: ``` int main() { int a = 1; int b = 2; int c = a + b; return c; } ``` 我们要将其翻译为三地址码的形式,每个指令只有三个操作数(源操作数1、源操作数2、目标操作数)。生成的三地址码如下: ``` 1. t1 = 1 2. t2 = 2 3. t3 = t1 + t2 4. return t3 ``` 其中,t1、t2、t3 是临时变量,用于存储中间结果。 下面是中间代码生成C++ 实现: ```cpp #include <iostream> #include <vector> #include <string> using namespace std; // 三地址码指令 struct TAC { string op; // 操作符 string arg1; // 源操作数1 string arg2; // 源操作数2 string result; // 目标操作数 TAC(string op, string arg1, string arg2, string result) { this->op = op; this->arg1 = arg1; this->arg2 = arg2; this->result = result; } }; // 符号表项 struct Symbol { string name; // 名称 string type; // 类型 string addr; // 地址 Symbol(string name, string type, string addr) { this->name = name; this->type = type; this->addr = addr; } }; // 符号表 vector<Symbol> symbolTable; // 生成新的临时变量 string newTemp() { static int count = 0; return "t" + to_string(++count); } // 查找符号表中的变量 Symbol* lookup(string name) { for (int i = 0; i < symbolTable.size(); i++) { if (symbolTable[i].name == name) { return &symbolTable[i]; } } return NULL; } // 添加符号表项 void addSymbol(string name, string type, string addr) { symbolTable.push_back(Symbol(name, type, addr)); } // 生成三地址码 vector<TAC> genCode(string op, string arg1, string arg2, string result) { vector<TAC> code; code.push_back(TAC(op, arg1, arg2, result)); return code; } int main() { // 生成三地址码 vector<TAC> code; string t1 = newTemp(); string t2 = newTemp(); string t3 = newTemp(); code.push_back(TAC("=", "1", "", t1)); code.push_back(TAC("=", "2", "", t2)); code.push_back(TAC("+", t1, t2, t3)); code.push_back(TAC("return", t3, "", "")); // 输出三地址码 for (int i = 0; i < code.size(); i++) { cout << code[i].result << " = " << code[i].arg1 << " " << code[i].op << " " << code[i].arg2 << endl; } // 生成符号表 addSymbol("a", "int", "0"); addSymbol("b", "int", "4"); addSymbol("c", "int", "8"); // 查找符号表 Symbol* s = lookup("a"); if (s != NULL) { cout << "Variable a found: type = " << s->type << ", address = " << s->addr << endl; } else { cout << "Variable a not found!" << endl; } return 0; } ``` 在这个例子中,我们定义了三个临时变量 t1、t2 和 t3,分别用于存储 1、2 和 a + b 的值。然后使用 genCode 函数生成三地址码。接着,我们定义了一个符号表,用于存储变量的类型和地址。使用 addSymbol 函数添加符号表项,使用 lookup 函数查找符号表中的变量。最后,我们输出了生成的三地址码和查找的符号表项信息。 注意,这只是一个简单的中间代码生成实验代码,实际的编译器中还需要考虑更多的情况,比如类型检查、控制流语句等等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值