返回
用 JavaScript 实现一个 Lisp 解释器的第二步:求值
前端
2023-10-27 00:44:53
// 简单实现 lisp 解释器的第二步:实现求值
// 实现 eval 函数: 将代码从字符串转换成值
// 代码可以被看作一个列表,例如:(+ 1 2)
const eval = (code) => {
// 如果代码是原子(数字或字符串),则直接返回该值
if (isAtom(code)) {
return code;
}
// 如果代码是一个列表,则取出列表中的第一个元素作为函数名
const funcName = code[0];
// 根据函数名调用对应的函数
if (funcName === "+") {
return add(code);
} else if (funcName === "-") {
return sub(code);
} else if (funcName === "*") {
return mul(code);
} else if (funcName === "/") {
return div(code);
} else {
throw new Error(`不支持函数:${funcName}`);
}
};
// 将代码从字符串转换成列表
const parse = (code) => {
// 去掉代码中的空格
code = code.replace(/\s/g, "");
//将代码分割成一个列表
const tokens = code.split("");
// 使用栈来解析代码
const stack = [];
let list = [];
for (let i = 0; i < tokens.length; i++) {
const token = tokens[i];
// 如果是 "(",则创建一个新的列表
if (token === "(") {
list = [];
stack.push(list);
}
// 如果是 ")",则将列表从栈中弹出并返回该列表
else if (token === ")") {
list = stack.pop();
stack[stack.length - 1].push(list);
}
// 如果是数字,则将其添加到当前列表中
else if (/\d/.test(token)) {
list.push(parseInt(token));
}
// 如果是运算符,则将其添加到当前列表中
else if (token === "+" || token === "-" || token === "*" || token === "/") {
list.push(token);
}
}
// 返回栈中剩下的列表
return stack[0];
};
// 检查给定的代码是否是一个原子(数字或字符串)
const isAtom = (code) => {
return typeof code === "number" || typeof code === "string";
};
// 执行加法运算
const add = (code) => {
const args = code.slice(1);
let sum = 0;
for (let i = 0; i < args.length; i++) {
sum += eval(args[i]);
}
return sum;
};
// 执行减法运算
const sub = (code) => {
const args = code.slice(1);
let difference = eval(args[0]);
for (let i = 1; i < args.length; i++) {
difference -= eval(args[i]);
}
return difference;
};
// 执行乘法运算
const mul = (code) => {
const args = code.slice(1);
let product = 1;
for (let i = 0; i < args.length; i++) {
product *= eval(args[i]);
}
return product;
};
// 执行除法运算
const div = (code) => {
const args = code.slice(1);
let quotient = eval(args[0]);
for (let i = 1; i < args.length; i++) {
quotient /= eval(args[i]);
}
return quotient;
};
// 输入代码并计算结果
const input = "(+ (* 2 3) (- 6 2))";
const result = eval(parse(input));
console.log(result);