一個極簡編譯器的實現(xiàn)
一篇文章 : https://github.com/jamiebuilds/the-super-tiny-compiler/blob/master/the-super-tiny-compiler.js
文章里實現(xiàn)了一個簡單的編譯器郎楼,將LISP代碼編譯為C代碼:
數(shù)學(xué)算式 | LISP | C |
---|---|---|
2 + (4 - 2) | (add 2 (subtract 4 2)) | add(2, subtract(4, 2)) |
代碼編譯通常經(jīng)過三個階段:
- Parsing
- Transformation
- Code Generation
Parsing
源碼
(add 2 (subtract 4 2))
Lexical Analysis Result
[
{ type: 'paren', value: '(' },
{ type: 'name', value: 'add' },
{ type: 'number', value: '2' },
{ type: 'paren', value: '(' },
{ type: 'name', value: 'subtract' },
{ type: 'number', value: '4' },
{ type: 'number', value: '2' },
{ type: 'paren', value: ')' },
{ type: 'paren', value: ')' },
]
Syntactic Analysis Result
{
type: 'Program',
body: [{
type: 'CallExpression',
name: 'add',
params: [{
type: 'NumberLiteral',
value: '2',
}, {
type: 'CallExpression',
name: 'subtract',
params: [{
type: 'NumberLiteral',
value: '4',
}, {
type: 'NumberLiteral',
value: '2',
}]
}]
}]
}
Transformation
- 深度優(yōu)先遍歷舊AST嗓蘑,作出相應(yīng)的修改湃交,生成新AST
修改
創(chuàng)建Visitor對象,定義遍歷經(jīng)過每一種節(jié)點時的行為
遍歷
實現(xiàn)深度優(yōu)先遍歷的方法
Code Generation
將AST重新序列化坑夯,組成目標(biāo)代碼
JavaScript中的AST
Babel
babel/babylon
npm install @babel/parser --save-dev
const code = `const text = 'Hello World';`;
const ast = require("@babel/parser").parse(code);
console.log("ast", ast);
babel/traverse
npm install @babel/traverse --save-dev
const code = `const text = 'Hello World';`;
const ast = require("@babel/parser").parse(code);
require("@babel/traverse").default(ast, {
enter(path) {
console.log("path type is ", path.type);
},
});
//path type is Program
//path type is VariableDeclaration
//path type is VariableDeclarator
//path type is Identifier
//path type is StringLiteral
const code = `const text = 'Hello World';`;
const ast = require("@babel/parser").parse(code);
require("@babel/traverse").default(ast, {
enter(path) {
if (path.node.type === "StringLiteral" && path.node.value) {
path.node.value = `${path.node.value} new!`;
}
},
});
babel/generator
npm install @babel/traverse --save-dev
const code = `const text = 'Hello World';`;
const ast = require("@babel/parser").parse(code);
require("@babel/traverse").default(ast, {
enter(path) {
if (path.node.type === "StringLiteral" && path.node.value) {
path.node.value = `${path.node.value} new!`;
}
},
});
const output = require("@babel/generator").default(ast, {});
console.log(output.code);
參考資料:
https://cloud.tencent.com/developer/doc/1260
https://www.zcfy.cc/article/347