Skip to content

Instantly share code, notes, and snippets.

@paxbun
Created November 18, 2019 04:20
Show Gist options
  • Select an option

  • Save paxbun/decf250fbbce297a156dc27871fdc2fd to your computer and use it in GitHub Desktop.

Select an option

Save paxbun/decf250fbbce297a156dc27871fdc2fd to your computer and use it in GitHub Desktop.
Advanced calculator
* {
font-size: large;
}
#input {
padding: 4px;
min-width: 10px;
border-bottom: 1px;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="index.css">
<script src="index.js"></script>
</head>
<body>
<span contenteditable="true" id="input"></span>
<span id="output"></span>
</body>
</html>
const ops = "+-*/^()";
const nums = "0123456789";
function split(expr) {
let rtn = [];
let stack = '';
for (let i = 0; i < expr.length; ++i) {
if (ops.includes(expr[i])) {
if (stack.length != 0)
rtn.push(stack);
rtn.push(expr[i]);
stack = '';
} else if (nums.includes(expr[i])) {
stack = stack + expr[i];
} else {
return undefined;
}
}
if (stack.length != 0)
rtn.push(stack);
return rtn;
}
function in2pre(expr) {
let precedence = {
'(' : 0,
')' : 0,
'^' : 1,
'*' : 2,
'/' : 2,
'+' : 3,
'-' : 3
};
let stack = [];
let result = [];
for (let i = 0; i < expr.length; ++i) {
if ("+-*/^".includes(expr[i])) {
let pre = precedence[expr[i]];
if (stack.length == 0 || stack[stack.length - 1][1] > pre) {
stack.push([expr[i], precedence[expr[i]]]);
} else {
while (stack.length != 0
&& stack[stack.length - 1][0] != '('
&& stack[stack.length - 1][1] <= pre)
result.push(stack.pop()[0]);
stack.push([expr[i], pre]);
}
} else if (expr[i] == '(') {
stack.push([expr[i], 0]);
} else if (expr[i] == ')'){
if (stack.length == 0)
return undefined;
while (stack[stack.length - 1][0] != '(')
result.push(stack.pop()[0]);
stack.pop();
}
else {
result.push(expr[i]);
}
}
for (let i = stack.length - 1; i >= 0; --i) {
result.push(stack[i][0]);
}
return result;
}
function calc(expr) {
if (expr == undefined)
return undefined;
function calc_internal(beg) {
if (beg < 0)
return undefined;
if (ops.includes(expr[beg])) {
let right = calc_internal(beg - 1);
if (right == undefined)
return undefined;
let left = calc_internal(right[1]);
if (left == undefined)
return undefined;
let op = {
'^' : (x, y) => Math.pow(x, y),
'*' : (x, y) => x * y,
'/' : (x, y) => x / y,
'+' : (x, y) => x + y,
'-' : (x, y) => x - y
}
return [op[expr[beg]](Number(left[0]), Number(right[0])), left[1]];
} else {
return [Number(expr[beg]), beg - 1];
}
}
let result = calc_internal(expr.length - 1);
if (result == undefined)
return undefined;
else
return result[0];
}
function run() {
let input_dom = document.getElementById('input');
let output_dom = document.getElementById('output');
const input = input_dom.innerHTML;
if (input.length == 0)
output_dom.innerHTML = '';
const result = calc(in2pre(split(input)));
if (result != undefined && !isNaN(result))
output_dom.innerHTML = '=' + result;
}
window.onload = function() {
document.getElementById('input').addEventListener('input', run);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment