源语言 : 加法表达式语言,支持形如 1+1 、1+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生成如下的抽象语法树
然后对该二叉树进行后续遍历,按照如下的规则生成代码
- 遇到整数
n,则生成c.push(n) - 遇到操作符
+,则生成c.add() - 遍历完成整棵树以后,生成
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);
}
运行之后生成目标代码正确。