js编译原理 自己实现
JavaScript 编译原理实现要点
实现一个简易的 JavaScript 编译器需要理解编译器的核心阶段:词法分析、语法分析、语义分析、代码生成和优化。以下是关键步骤和示例代码。

词法分析(Lexical Analysis)
词法分析器将源代码转换为标记(tokens)序列。每个标记包含类型和值。

const tokenTypes = {
NUMBER: 'NUMBER',
IDENTIFIER: 'IDENTIFIER',
OPERATOR: 'OPERATOR',
KEYWORD: 'KEYWORD',
PUNCTUATION: 'PUNCTUATION'
};
function tokenize(code) {
const tokens = [];
let pos = 0;
const regex = /\s*(=>|{|}|[(),;+\-*/%]|\d+|\w+)\s*/g;
let match;
while ((match = regex.exec(code)) !== null) {
const value = match[1].trim();
let type;
if (/^\d+$/.test(value)) type = tokenTypes.NUMBER;
else if (/^[+\-*/%]$/.test(value)) type = tokenTypes.OPERATOR;
else if (/^(if|else|function|return)$/.test(value)) type = tokenTypes.KEYWORD;
else if (/^[(){},;]$/.test(value)) type = tokenTypes.PUNCTUATION;
else type = tokenTypes.IDENTIFIER;
tokens.push({ type, value });
}
return tokens;
}
语法分析(Parsing)
语法分析器根据标记生成抽象语法树(AST)。可使用递归下降解析法。
function parse(tokens) {
let pos = 0;
function walk() {
let token = tokens[pos];
if (token.type === tokenTypes.NUMBER) {
pos++;
return { type: 'NumberLiteral', value: token.value };
}
if (token.type === tokenTypes.IDENTIFIER) {
pos++;
return { type: 'Identifier', name: token.value };
}
if (token.type === tokenTypes.OPERATOR) {
pos++;
return { type: 'BinaryExpression', operator: token.value, left: walk(), right: walk() };
}
throw new Error(`Unknown token: ${token.type}`);
}
return walk();
}
代码生成(Code Generation)
将 AST 转换为目标代码(如机器码或中间代码)。以下示例生成伪汇编代码。
function generate(ast) {
switch (ast.type) {
case 'NumberLiteral':
return `PUSH ${ast.value}`;
case 'Identifier':
return `LOAD ${ast.name}`;
case 'BinaryExpression':
const left = generate(ast.left);
const right = generate(ast.right);
return `${left}\n${right}\n${ast.operator}`;
}
}
完整流程示例
const code = '1 + 2 * 3';
const tokens = tokenize(code);
const ast = parse(tokens);
const output = generate(ast);
console.log(output); // 输出伪汇编指令序列
进阶扩展
- 语义分析:添加变量作用域检查和类型推导。
- 优化:实现常量折叠(如将
1 + 2替换为3)。 - 目标平台:扩展为生成 WebAssembly 或 LLVM IR。
工具推荐
- ANTLR:可生成词法/语法分析器。
- Babel:参考其插件机制实现转换步骤。
- LLVM:用于生成优化后的机器码。
通过分阶段实现,可以逐步构建一个功能完整的编译器原型。实际项目中建议结合现有工具链(如 Babel 插件)简化开发。






