那么针对上一节编译器就拥有了经过处理后的抽象语法树,此时需要做的当然是将所谓的树形结构的抽象语法树转化成为新的代码。
这一步通常我们成为生成阶段(Code Generation) :我们通过抽象语法树反向转化成为生成的代码,此时最新的代码是根据修改后的 AST 生成的代码。
在生成阶段本质上就是遍历抽象语法树,根据抽象语法树上每个节点的类型和属性递归调用从而生成对应的字符串代码。比如:
(add 2 (subtract 4 2)) 变化为 add(2, subtract(4, 2));
export function codegen(node) {
switch (node.type) {
case "Program":
return node.body.map(codegen).join("")
case "ExpressionStatement":
return codegen(node.expression) + ";"
case "NumberListeral":
return node.value;
case "CallExpression":
return node.callee.name + "(" + node.arguments.map(codegen).join(", ") + ")"
default:
break;
}
}
这里我们实现一个compiler函数,总的来说,这个函数里面就包括我们前面几节里面所有的步骤, 比如将源代码(add 2 (subtract 4 2))通过compiler函数处理之后变为目标代码add(2, subtract(4, 2));
那这里就是对前面几节的一个复盘
1.首先通过tokenizer生成对应的tokens
2.通过parser生成ast
3.通过遍历ast树,并生成target ast
4.调用codegen函数实现target code
import { tokenizer } from "./tokenizer";
import { parser } from "./ast"
import { transform } from "./transformer";
import { codegen } from "./codegen";
export function compiler(code: string) {
const tokens = tokenizer(code)
const ast = parser(tokens)
const transformedAST = transform(ast)
return codegen(transformedAST)
}