Files
geek-calc/rpn-calculator.js
snowprint 54f427ea21
Some checks failed
Deploy to GitHub Pages / build-and-deploy (push) Has been cancelled
init geek calc
2025-10-04 10:53:41 +08:00

141 lines
4.4 KiB
JavaScript

// RPN (Reverse Polish Notation) calculator module
const RPNCalculator = (function() {
class RPNCalculator {
constructor() {
this.clear();
}
// Push a number onto the stack
push(value) {
if (typeof value === 'number' || !isNaN(parseFloat(value))) {
this.stack.push(parseFloat(value));
}
}
// Pop a number from the stack
pop() {
if (this.stack.length > 0) {
return this.stack.pop();
}
return undefined;
}
// Perform an operation on stack values
operate(operator) {
if (this.stack.length < 2) {
return 'Error'; // Need at least 2 values for binary operations
}
const b = this.pop();
const a = this.pop();
let result;
switch (operator) {
case '+':
result = a + b;
break;
case '-':
result = a - b;
break;
case '*':
result = a * b;
break;
case '/':
if (b === 0) {
result = Infinity;
} else {
result = a / b;
}
break;
case '^':
case '**':
result = Math.pow(a, b);
break;
default:
return 'Error'; // Unknown operator
}
// Check for invalid results
if (isNaN(result) || !isFinite(result)) {
this.push('Error');
return 'Error';
}
this.push(result);
return result;
}
// Clear the entire stack
clear() {
this.stack = [];
}
// Get current stack state
getStack() {
return [...this.stack]; // Return a copy to prevent external modification
}
// Execute RPN expression (e.g., "3 4 +")
evaluate(rpnExpression) {
try {
// Split the expression into tokens
const tokens = rpnExpression.trim().split(/\s+/);
this.clear(); // Clear the stack before evaluation
for (const token of tokens) {
if (['+', '-', '*', '/', '^', '**'].includes(token)) {
// It's an operator
const result = this.operate(token);
if (result === 'Error') {
return 'Error';
}
} else {
// It's a number
const num = parseFloat(token);
if (isNaN(num)) {
return 'Error'; // Invalid token
}
this.push(num);
}
}
// Return the top of the stack if there's a result
if (this.stack.length === 1) {
return this.stack[0];
} else if (this.stack.length === 0) {
return 0; // Empty stack, return 0
} else {
return this.stack[this.stack.length - 1]; // Return top of stack
}
} catch (error) {
return 'Error';
}
}
// Process a single RPN input token
processInput(token) {
if (['+', '-', '*', '/', '^', '**'].includes(token)) {
// Operator
return this.operate(token);
} else if (token === 'ENTER' || token === 'E') {
// ENTER doesn't do anything in implementation, just pushes numbers that were already processed
return this.getStack();
} else if (token === 'C' || token === 'CE') {
this.clear();
return 0;
} else {
// Number
const num = parseFloat(token);
if (!isNaN(num)) {
this.push(num);
return num;
} else {
return 'Error';
}
}
}
}
return { RPNCalculator };
})();