mirror of
https://github.com/osmarks/website
synced 2024-11-08 20:29:55 +00:00
158 lines
3.2 KiB
JavaScript
Executable File
158 lines
3.2 KiB
JavaScript
Executable File
// Reads the input box for a RPN expression
|
|
// Calculates result
|
|
// Outputs it as nicely formatted boxes.
|
|
function calculateFromInput() {
|
|
var expr = document.getElementById("input").value;
|
|
var output = document.getElementById("output")
|
|
|
|
var result = calculateRPN(expr.split(" "));
|
|
|
|
output.innerHTML = ""; // Clear the output div
|
|
|
|
result.stack.forEach(function(num) {
|
|
num = num.toString().replace("NaN", "Error");
|
|
var box = createBox(num);
|
|
box.style["max-width"] = num.length + "em";
|
|
output.appendChild(box);
|
|
});
|
|
|
|
if (result.errors.length > 0) { // If errors exist output them separated by line breaks.
|
|
result.errors.forEach(error => {
|
|
output.appendChild(document.createTextNode(error.toString()))
|
|
output.appendChild(document.createElement("br"))
|
|
})
|
|
}
|
|
}
|
|
|
|
function add(x, y) {
|
|
return x + y;
|
|
}
|
|
|
|
function multiply(x, y) {
|
|
return x * y;
|
|
}
|
|
|
|
function divide(x, y) {
|
|
return x / y;
|
|
}
|
|
|
|
function flip(x, y) {
|
|
return [y, x];
|
|
}
|
|
|
|
function subtract(x, y) {
|
|
return x - y;
|
|
}
|
|
|
|
function sum(vals) {
|
|
var acc = 0;
|
|
|
|
vals.forEach(function(el) {
|
|
acc += el;
|
|
});
|
|
|
|
return acc;
|
|
}
|
|
|
|
function range(low, high) {
|
|
var r = [];
|
|
|
|
for (var i = low; i <= high; i++) {
|
|
r.push(i);
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
function createBox(contents) {
|
|
var el = document.createElement("div");
|
|
el.setAttribute("class", "stack-box");
|
|
|
|
el.innerText = contents;
|
|
|
|
return el;
|
|
}
|
|
|
|
// Takes a two-argument function and lifts it to a binary stack op
|
|
function binaryOp(fun) {
|
|
return function(stack) {
|
|
var x = stack.pop();
|
|
var y = stack.pop();
|
|
|
|
stack.push(fun(y, x));
|
|
return stack;
|
|
}
|
|
}
|
|
|
|
// Takes a function and lifts it to a unary op using a stack. Returns new stack.
|
|
function unaryOp(fun) {
|
|
return function(stack) {
|
|
var x = stack.pop();
|
|
|
|
stack.push(fun(x));
|
|
return stack;
|
|
}
|
|
}
|
|
|
|
// Takes a function and lifts it to an op which takes the entire stack and reduces it to one value. Returns new stack.
|
|
function greedyOp(fun) {
|
|
return function(stack) {
|
|
return [fun(stack)];
|
|
}
|
|
}
|
|
|
|
// Lifs to an operator which takes two values and adds an array of them to the stack. Returns a new stack.
|
|
function binaryMultioutOp(fun) {
|
|
return function(stack) {
|
|
var x = stack.pop();
|
|
var y = stack.pop();
|
|
|
|
return stack.concat(fun(y, x));
|
|
}
|
|
}
|
|
|
|
function calculateRPN(tokens) {
|
|
var stack = [];
|
|
var errors = [];
|
|
|
|
for (var i = 0; i < tokens.length; i++) {
|
|
var token = tokens[i];
|
|
|
|
switch (token) {
|
|
case "+":
|
|
stack = binaryOp(add)(stack);
|
|
break;
|
|
case "*":
|
|
stack = binaryOp(multiply)(stack);
|
|
break;
|
|
case "/":
|
|
stack = binaryOp(divide)(stack);
|
|
break;
|
|
case "-":
|
|
stack = binaryOp(subtract)(stack);
|
|
break;
|
|
case "range":
|
|
stack = binaryMultioutOp(range)(stack);
|
|
break;
|
|
case "flip":
|
|
stack = binaryMultioutOp(flip)(stack);
|
|
break;
|
|
case "sum":
|
|
stack = greedyOp(sum)(stack);
|
|
break;
|
|
case "": // This may be entered by accident.
|
|
break;
|
|
default:
|
|
var parsed = parseFloat(token);
|
|
|
|
if (parsed === parsed) { // check for NaNs from a failed parse
|
|
stack.push(parsed);
|
|
} else {
|
|
errors.push("Token '" + token + "' (#" + (i + 1) + ")" + " invalid");
|
|
}
|
|
}
|
|
}
|
|
|
|
return {stack: stack, errors: errors};
|
|
}
|