compiler lab 1 初代编译器

一、实验说明

初代编译器功能描述

        初代编译器将 C 语言顺序语句序列翻译为等价的汇编程序,所输出的汇编 程序符合 x86 汇编语言格式要求,能够被后续的汇编器翻译为可执行程序运行。

文法要求

        关键字 :int 、return

        标识符 :单个英文字母

        常量 :十进制整型

        操作符 :+ - * / = ( )

        分隔符 :;

输入输出

         输入:以文件形式

int a ;
int b ;
int d ;
a = 1 ;
b = 2 ;
d = a + b ;
return d ;
(预期返回值为 3)

        输出:std输出

 mov DWORD PTR [ebp-4], 0 # int a
 mov DWORD PTR [ebp-8], 0 # int b
 mov DWORD PTR [ebp-12], 0 # int d
 mov DWORD PTR [ebp-4], 1 # a = 1
 mov DWORD PTR [ebp-8], 2 # b = 2
 mov eax, DWORD PTR [ebp-4] # d = a + b
 push eax
 mov eax, DWORD PTR [ebp-8]
 push eax
 pop ebx
 pop eax
 add eax, ebx
 push eax
 pop eax
 mov DWORD PTR [ebp-12], eax
 mov eax, DWORD PTR [ebp-12] # return d

二、实现思路

分词:

        由于输入已经将不同的词分开了,所以根据空格和回车分开读就行

操作:

        只有三类操作 申请int类型的临时变量;赋值操作;return返回一个临时变量

        因此可以直接用string类型读入某个词,判断是int 或 return 或赋值操作

运算:

        对于读入的中缀表达式,我们可以将其转化为后缀表达式进行处理和运算,关于表达式的运算可以参考以下文章。

https://blog.csdn.net/Amentos/article/details/127182926

三、实现代码

#include<iostream>
#include<fstream>
#include<vector>
#include<map>
#include<sstream>
#include<stack>

using namespace std;

vector<string> ans;
map<char, int> i_table;
map<char, int> num_table;
map<char, int> op_table;
class Node {
public:
	string type = "";	// constant, variable, operator
	int num = 0;
	char name = '\0';
};

vector<Node> ve;
stack<char> op;
stack<Node> cal;


int s2i(string s) {
	int num = 0;
	for (int i = 0; i < s.size(); i++) {
		num = num * 10 + s[i] - '0';
	}
	return num;
}

void init() {
	op_table.emplace('=', 0);
	op_table.emplace('(', 1);
	op_table.emplace('+', 2);
	op_table.emplace('-', 2);
	op_table.emplace('*', 3);
	op_table.emplace('/', 3);
}

int main(int argc, char* argv[]) {
	fstream file(argv[1], fstream::in);
	init();
	string s;
	while (!file.eof()) {
		file >> s;
		ve.clear();
		while (s != ";") {
			//cout << s << endl;
			if (s == "int") {
				file >> s;
				i_table.emplace(s[0], i_table.size()+1);
				stringstream temp;
				temp << "mov DWORD PTR [ebp-" << i_table[s[0]] * 4 << "], 0" << endl;
				ans.push_back(temp.str());
			}
			else if (s == "return") {
				file >> s;

				stringstream temp;
				temp << "mov eax, DWORD PTR [ebp-" << i_table[s[0]] * 4 << "]" << endl;
				ans.push_back(temp.str());
			}
			else {
				//cout << s << endl;
				if (s == "+" || s == "-" || s == "*" || s == "/" || s == "=" ) {
					if (op.empty() || op_table[op.top()] < op_table[s[0]]) {
						op.push(s[0]);
					}
					else {
						Node temp_node;
						while (!op.empty() && op_table[op.top()] >= op_table[s[0]]) {
							temp_node.type = "operator";
							temp_node.name = op.top();
							op.pop();
							ve.push_back(temp_node);
						}
						op.push(s[0]);
					}
				}
				else if (s == "(" ) {
					op.push('(');
				}
				else if (s == ")") {
					while (op.top() != '(') {
						Node temp_node;
						temp_node.type = "operator";
						temp_node.name = op.top();
						op.pop();
						ve.push_back(temp_node);
					}
					op.pop();
				}
				else {
					Node temp_node;
					if ('0' <= s[0] && s[0] <= '9') {
						temp_node.type = "constant";
						temp_node.num = s2i(s);
						ve.push_back(temp_node);
					}
					else {
						temp_node.type = "variable";
						temp_node.name = s[0];
						ve.push_back(temp_node);
					}
				}
			}


			file >> s;
		}
		while (!op.empty()) {
			Node temp_node;
			temp_node.type = "operator";
			temp_node.name = op.top();
			op.pop();
			ve.push_back(temp_node);
		}
		for (int i = 0; i < ve.size(); i++) {
			if (i == 0) {
				cal.push(ve[i]);
				continue;
			}
			if (ve[i].type == "variable") {
				cal.push(ve[i]);
				stringstream temp;
				temp << "mov eax, DWORD PTR [ebp-" << i_table[ve[i].name] * 4 << "]" << endl;
				temp << "push eax" << endl;
				ans.push_back(temp.str());

			}
			else if (ve[i].type == "constant") {
				cal.push(ve[i]);
				stringstream temp;
				temp << "mov eax, " << ve[i].num << endl;
				temp << "push eax" << endl;
				ans.push_back(temp.str());
			}
			else {
				if (ve[i].name == '+') {
					stringstream temp;
					temp << "pop ebx" << endl << "pop eax" << endl;
					temp << "add eax, ebx" << endl;
					temp << "push eax" << endl;
					ans.push_back(temp.str());
					cal.pop();
					cal.pop();
					Node temp_node;
					temp_node.type = "constant";
					temp_node.num = 1;
					cal.push(temp_node);
				}
				else if (ve[i].name == '*') {
					stringstream temp;
					temp << "pop ebx" << endl << "pop eax" << endl;
					temp << "imul eax, ebx" << endl;
					temp << "push eax" << endl;
					ans.push_back(temp.str());
					cal.pop();
					cal.pop();
					Node temp_node;
					temp_node.type = "constant";
					temp_node.num = 1;
					cal.push(temp_node);
				}
				else if (ve[i].name == '-') {
					stringstream temp;
					temp << "pop ebx" << endl << "pop eax" << endl;
					temp << "sub eax, ebx" << endl;
					temp << "push eax" << endl;
					ans.push_back(temp.str());
					cal.pop();
					cal.pop();
					Node temp_node;
					temp_node.type = "constant";
					temp_node.num = 1;
					cal.push(temp_node);
				}
				else if (ve[i].name == '/') {
					stringstream temp;
					temp << "pop ebx" << endl << "pop eax" << endl;
					temp << "cdq" << endl;
					temp << "idiv ebx" << endl;
					temp << "push eax" << endl;
					ans.push_back(temp.str());
					cal.pop();
					cal.pop();
					Node temp_node;
					temp_node.type = "constant";
					temp_node.num = 1;
					cal.push(temp_node);
				}
				else {
					cal.pop();
					Node f = cal.top();
					cal.pop();
					stringstream temp;
					temp << "pop eax" << endl;
					temp << "mov DWORD PTR [ebp-" << i_table[f.name] * 4 << "], eax" << endl;
					ans.push_back(temp.str());
				}
			}
		}

	}
	file.close();

	//for (pair<char, int> n : i_table) {
	//	cout << n.first << ' ' << n.second << endl;
	//}
	for (string ss : ans) {
		cout << ss;
	}

	return 0;
}

        这段代码只是能够达到最基本的实验要求,其对于 = 也是和其他运算符一同处理的,所以即使是 a = 1 ; 这样的直接赋值操作也要通过栈传递参数,非常的sb(我懒)。

  • 21
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值