一、实验说明
初代编译器功能描述
初代编译器将 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(我懒)。