返回

用 JavaScript 实现一个 Lisp 解释器的第二步:求值

前端

// 简单实现 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);