后缀表达式计算器变量输入错误排查及修复请求
基于栈的后缀表达式计算器变量处理问题修复
问题描述
我实现了一个基于栈的后缀表达式计算器,普通表达式如2 5 +可正常运行,但变量处理时出现错误,运行输出如下:
7 27
报错信息:
index.js:44 throw new Error(`Invalid token encountered: ${token}`); ^ Error: Invalid token encountered: A at PostfixCalculator.evaluate (index.js:44:19) at Object.<anonymous> (/runtime/javascript/3zxrd96tq_3zxykq39r/index.js:78:24) at Module._compile (node:internal/modules/cjs/loader:1103:14) at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10) at Module.load (node:internal/modules/cjs/loader:981:32) at Function.Module._load (node:internal/modules/cjs/loader:822:12) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12) at node:internal/main/run_main_module:17:47
附原代码:
class PostfixCalculator { constructor() { // Initialize an empty stack to hold operands and an empty symbol table for variables this.stack = []; this.symbolTable = {}; } // Method to evaluate postfix expressions evaluate(expression) { // Split the expression into tokens (operands, operators, or variables) using spaces const tokens = expression.split(' '); // Iterate through each token in the expression for (let token of tokens) { if (!isNaN(token)) { // If the token is a number, push it onto the stack as an operand this.stack.push(parseFloat(token)); // Push operands to the stack } else if (token in this.symbolTable) { // If the token is a known variable, push its corresponding value onto the stack this.stack.push(this.symbolTable[token]); // Push variable values to the stack } else { // If the token is an operator (+, -, *, /) or '=', perform the corresponding operation switch (token) { case '+': this.performOperation((a, b) => a + b); // Addition operation break; case '-': this.performOperation((a, b) => a - b); // Subtraction operation break; case '*': this.performOperation((a, b) => a * b); // Multiplication operation break; case '/': this.performOperation((a, b) => a / b); // Division operation break; case '=': // Perform variable assignment by popping value and variable name from the stack const value = this.stack.pop(); const variable = this.stack.pop(); this.symbolTable[variable] = value; // Store variable value in the symbol table break; default: // Throw an error for an invalid token encountered throw new Error(`Invalid token encountered: ${token}`); } } } // Check if the stack contains only one element after evaluation if (this.stack.length !== 1) { throw new Error('Invalid expression'); } // Return the final result by popping the last element from the stack return this.stack.pop(); // Result will be the only element in the stack } // Method to perform arithmetic operations on operands performOperation(operation) { // Pop the last two operands from the stack const operand2 = this.stack.pop(); const operand1 = this.stack.pop(); // Perform the specified operation on the operands const result = operation(operand1, operand2); // Push the result back onto the stack this.stack.push(result); } } // Example usage: const calculator = new PostfixCalculator(); // Evaluate postfix expressions console.log(calculator.evaluate('3 4 +')); // Output: 7 console.log(calculator.evaluate('3 4 5 + *')); // Output: 27 // Handle variable assignments console.log(calculator.evaluate('A 2 =')); // Setting variable A to 2 console.log(calculator.evaluate('B 3 =')); // Setting variable B to 3 console.log(calculator.evaluate('A B *')); // Output: 6 (Multiplication of variables A and B)
错误原因分析
- 赋值逻辑顺序错误:
- 后缀表达式的赋值规则是
值 变量名 =,但你写的A 2 =顺序颠倒,且代码中赋值时的栈弹出顺序也反了(先弹值再弹变量名,正确应该是先弹变量名再弹值)。
- 后缀表达式的赋值规则是
- 变量处理逻辑漏洞:
- 代码仅允许压入已存在的变量值,但赋值时变量名是目标标识符,此时还未定义,需要直接将变量名字符串压入栈,而不是判断是否存在于symbolTable中。
修复后的代码
class PostfixCalculator { constructor() { this.stack = []; this.symbolTable = {}; } // 解析栈中的元素,若是变量名则返回对应值,否则返回自身 resolveValue(item) { if (typeof item === 'string') { if (!(item in this.symbolTable)) { throw new Error(`Undefined variable: ${item}`); } return this.symbolTable[item]; } return item; } evaluate(expression) { // 每次计算前清空栈,避免残留数据影响结果 this.stack = []; const tokens = expression.split(' '); for (let token of tokens) { // 先判断是否是运算符 if (['+', '-', '*', '/', '='].includes(token)) { switch (token) { case '+': this.performOperation((a, b) => a + b); break; case '-': this.performOperation((a, b) => a - b); break; case '*': this.performOperation((a, b) => a * b); break; case '/': this.performOperation((a, b) => { if (b === 0) throw new Error('Division by zero'); return a / b; }); break; case '=': // 赋值:先弹出变量名,再弹出值 const variable = this.stack.pop(); const value = this.resolveValue(this.stack.pop()); // 确保变量名是字符串类型 if (typeof variable !== 'string') { throw new Error('Invalid variable name'); } this.symbolTable[variable] = value; // 赋值操作不返回结果,将变量值压回栈以便后续使用 this.stack.push(value); break; default: throw new Error(`Invalid token encountered: ${token}`); } } else if (!isNaN(token)) { // 是数字则转为浮点数压栈 this.stack.push(parseFloat(token)); } else { // 是变量名直接压栈(字符串) this.stack.push(token); } } if (this.stack.length !== 1) { throw new Error('Invalid expression'); } // 解析最终结果(可能是变量名) return this.resolveValue(this.stack.pop()); } performOperation(operation) { const operand2 = this.resolveValue(this.stack.pop()); const operand1 = this.resolveValue(this.stack.pop()); const result = operation(operand1, operand2); this.stack.push(result); } } // 修正后的示例用法 const calculator = new PostfixCalculator(); console.log(calculator.evaluate('3 4 +')); // 7 console.log(calculator.evaluate('3 4 5 + *')); // 27 // 正确的赋值表达式:值在前,变量名在后 console.log(calculator.evaluate('2 A =')); // 2(返回赋值后的值) console.log(calculator.evaluate('3 B =')); // 3 console.log(calculator.evaluate('A B *')); // 6
优化建议
- 变量名合法性检查:添加正则判断变量名是否符合标识符规则(比如不能以数字开头)。
- 错误信息细化:区分无效token、未定义变量、非法变量名等不同错误场景。
- 表达式验证:处理前检查表达式的token数量是否符合后缀表达式规则。
- 支持负数:修改token分割逻辑或判断规则,支持负数字面量(如
-5)。
内容的提问来源于stack exchange,提问作者itxfahad_
相关产品推荐
相关产品推荐

