mirror of
https://github.com/osmarks/website
synced 2025-11-12 11:24:43 +00:00
initial commit
This commit is contained in:
15
experiments/rpncalc-v2/calc.css
Executable file
15
experiments/rpncalc-v2/calc.css
Executable file
@@ -0,0 +1,15 @@
|
||||
.stack-box {
|
||||
text-align: center;
|
||||
border: solid 1px black;
|
||||
min-width: 30vmin;
|
||||
max-width: 30vmin; /* will normally be dynamically set */
|
||||
line-height: 30vmin;
|
||||
height: 30vmin;
|
||||
font-size: 7vmin;
|
||||
margin: -1px; /* make edges join neatly */
|
||||
}
|
||||
|
||||
#input {
|
||||
width: 100%;
|
||||
font-size: 2em;
|
||||
}
|
||||
157
experiments/rpncalc-v2/calc.js
Executable file
157
experiments/rpncalc-v2/calc.js
Executable file
@@ -0,0 +1,157 @@
|
||||
// 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};
|
||||
}
|
||||
16
experiments/rpncalc-v2/index.html
Executable file
16
experiments/rpncalc-v2/index.html
Executable file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
title: RPNCalc v2
|
||||
slug: rpncalc2
|
||||
description: A Reverse Polish Notation (check wikipedia) calculator, version 2. Buggy and kind of unreliable. This updated version implements subtraction.
|
||||
---
|
||||
|
||||
<link rel="stylesheet" href="calc.css">
|
||||
|
||||
<center><div id="output"></div></center>
|
||||
|
||||
<hr>
|
||||
|
||||
<input type="text" id="input" default="Input RPN expression" oninput="calculateFromInput()">
|
||||
</div>
|
||||
|
||||
<script src="calc.js"></script>
|
||||
Reference in New Issue
Block a user