编译器
编译器能够把一种源语言翻译为语义上等价的另一种目标语言。编译器又分为前端和后端两个部分。前端包括词法分析、语法分析、语义分析、中间代码生成,具有机器无关性。后端包括中间代码优化、目标代码生成,具有机器相关性。
本文实现的目标
主要使用JavaScript实现一个简单的编译器,我们的编译器主要包含词法分析、语法分析、语义分析以及目标代码生成。我们编译器的主要功能为将特定的表达式编译成算数表达式。
编译器的实现
我们首先定义表达式的规则:
- 函数: mul, sub, sum, div
- 每个字符串标记都被空格隔开
- 只支持自然数
表达式的功能为:
- sum 3 3 编译成 3 + 3
- sub 3 2 编译成 3 - 2
- sum 3 sub 3 2 编译成 3 + (3 - 2)
词法分析
词法分析是处理源程序的第一部分,主要任务是逐个扫描输入字符,转换为词法单元(Token)序列,传递给语法分析器进行语法分析。Token 是一个不可分割的最小单元。
根据我们定义的表达式的规则,我们可以得到用于语法分析的单词表
单词符号 | 编码 | 助记符 | 值 |
---|---|---|---|
mul | 1 | $mul | - |
sub | 2 | $sub | - |
sum | 3 | $sum | - |
div | 4 | $div | - |
自然数 | 5 | $num | 数值 |
根据单词表实现词法分析
// 定义单词表
const words = {
mul: {
type: '$mul', getValue: () => '-' },
sub: {
type: '$sub', getValue: () => '-' },
sum: {
type: '$sum', getValue: () => '-' },
div: {
type: '$div', getValue: () => '-' },
num: {
type: '$num', getValue: (val) => parseInt(val, 10) },
};
function tokenizer(input) {
// `current`变量类似指针,用于记录我们在代码字符串中的位置。
let current = 0;
// `tokens`数组是我们放置 token 的地方
const tokens = [];
// 首先我们创建一个 `while` 循环, `current` 变量会在循环中自增。
while (current < input.length) {
// 我们在这里储存了 `input` 中的当前字符
let char = input[current];
// 检查是不是空格
const WHITESPACE = /\s/;
if (WHITESPACE.test(char)) {
current++;
continue;
}
// 检查是不是数字
const NUMBERS = /[0-9]/;
if (NUMBERS.test(char