简单编译器

226 阅读1分钟

源语言 : 加法表达式语言,支持形如 1+11+2+3 …… 的运算

目标机器:栈式计算机,支持push(n)add() 两种操作(使用C++模拟)

构造一个栈式计算机

#include<iostream>

#define ERROR -9999;

using namespace std;

class StackComputer{
	private:
		int stack_arr[100]; // 操作数栈 
		int head = 0; 	 	// 栈顶指针 
		
		int pop() { 
			if(this->head < 1) return ERROR;
			
			this->head--;
			
			return this->stack_arr[this->head];
		}
	public:
		StackComputer() = default;
		void push(int n) {
			this->stack_arr[this->head] = n;
			
			this->head ++;
		}
		int add() {
			if(this->head < 2) return ERROR;
			
			int result = this->pop() + this->pop();
			
			this->push(result);
			
			return result;
		}
		void print() {   	// 打印结果 
			 if(this->head == 1) cout<<this->pop()<<endl;
		}
};

main函数如下


int main() {
	StackComputer c;
	
	c.push(1);
	c.push(10);
	c.add();
	c.push(100);
	c.add();
	
	c.print();  // 输出111 
}

现在我们编写一个编译器将1+10+100编译成:

	c.push(1);
	c.push(10);
	c.add();
	c.push(100);
	c.add();
	
	c.print(); 

编写编译器

步骤说明

首先将1+10+100生成如下的抽象语法树

抽象语法树

然后对该二叉树进行后续遍历,按照如下的规则生成代码

  1. 遇到整数n,则生成c.push(n)
  2. 遇到操作符+,则生成c.add()
  3. 遍历完成整棵树以后,生成c.print()

构造抽象语法树

#define MODE_NUM 0
#define MODE_CHAR 1

typedef struct AbsTree* BinTree;
struct AbsTree {
	int mode;
	int data;
	bool isRoot; // 标记当前节点是否为根节点 
	BinTree left, right;
}; // 一棵二叉树

BinTree genTree(int mode, int data) { // 生成二叉树结点的工具
	BinTree tree = (BinTree)malloc(sizeof(AbsTree));
	
	tree->left = NULL;
	tree->right = NULL;
	tree->isRoot = false;
	
	if(mode == MODE_NUM) tree->data = data;
	
	tree->mode = mode;
	
	return tree;
}

BinTree genAbsTree(char* lang) { // 生成抽象语法树并返回根节点
	BinTree root = NULL, left = NULL, right = NULL;
	 
	for(int i=0; i<strlen(lang); i++) {
		char elem = lang[i];
		
		bool isNum = isdigit(elem);
		
		if(isNum) { // 扫描到数字
			int num = elem - 48;

			 // 将字符串数字转化为数字[如 '123' -> 123]
			while(i+1 < strlen(lang) 
					&& isdigit(lang[i+1])) {
						
				num = num*10 + (lang[++i] - 48);	
			}
			
			
			if(left == NULL) {
				left = genTree(MODE_NUM, num);
			}
			else {
				right = genTree(MODE_NUM, num);
				root->right = right;
				root->left = left;
				left = root;
			}
		}
		else { // 扫描到非数字
			if (elem == ' ') continue;
			
			root = genTree(MODE_CHAR, -1);
			root->left = left;
		}
	}
	
	if (root!=NULL) root->isRoot = true; // 标记当前结点为根节点 

	return root; 
} 

生成目标代码

// 树的后序遍历生成目标代码
void genTargetCode(BinTree node) {
	if(node == NULL) return;
	genTargetCode(node->left);
	genTargetCode(node->right);
	
	if (node->mode == MODE_NUM) {
		printf("c.push(%d);\n", node->data);
	}
	else {
		printf("c.add();\n");
	}
	
	if(node->isRoot) printf("c.print();\n");
}

测试

int main() {
	char sum_exp[100] = "1 + 10 + 100";
	
	BinTree root = genAbsTree(sum_exp);
	
	genTargetCode(root);
} 

运行之后生成目标代码正确。