Created
May 8, 2017 13:27
-
-
Save DanCouper/09a1ec47b227e07ce7acaee20c94472a to your computer and use it in GitHub Desktop.
Calculator using Shunting Yard Algorithm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<body> | |
<span id="inpos"> | |
<span id="inpbox"> | |
<input id="inp" type="text" placeholder="0"> | |
<span id="close">X</span> | |
</span> | |
<span id="enter">ENTER</span> | |
</span> | |
<div id="res"></div> | |
</body> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function queue(q) { | |
this.q = q; | |
this.len = function() { | |
return q.length; | |
} | |
this.push = function(ite) { | |
q.splice(0, 0, ite); | |
} | |
this.pop = function() { | |
return q.splice(0, 1)[0]; | |
} | |
this.top = function() { | |
return q[0]; | |
} | |
this.print = function() { | |
var s = ""; | |
for (var i = 0; i < this.q.length; i++) { | |
s += q[i]; | |
} | |
return s; | |
} | |
} | |
//used for displaying | |
function rev(q) { | |
var res = []; | |
for (var i = q.length - 1; i >= 0; i--) { | |
res.push(q[i]); | |
} | |
return res; | |
} | |
//list of precedences and associativities | |
var ops = { | |
'+': { | |
prec: 2, | |
ass: 'l' | |
}, | |
'-': { | |
prec: 2, | |
ass: 'l' | |
}, | |
'*': { | |
prec: 3, | |
ass: 'l' | |
}, | |
'/': { | |
prec: 3, | |
ass: 'l' | |
}, | |
'^': { | |
prec: 4, | |
ass: 'r' | |
} | |
} | |
function getPrec(ite) { | |
return ops[ite].prec; | |
} | |
function getAss(ite) { | |
return ops[ite].ass; | |
} | |
//-1 = op1 < op2; 0 = op1 == op2; 1 = op1>op2 | |
function precomp(op1, op2) { | |
if (getPrec(op1) < getPrec(op2)) | |
return -1; | |
else if (getPrec(op1) == getPrec(op2)) | |
return 0; | |
else | |
return 1; | |
} | |
function isNum(ite) { | |
return !isNaN(ite); | |
} | |
function isOp(ite) { | |
return (ite == '+') || (ite == '-') || (ite == '*') || (ite == "/") || (ite == "^") | |
} | |
function isUnary(op) { | |
return false; | |
} | |
function isBinary(op) { | |
return (op == "+") || (op == "-") || (op == "*") || (op == "/") || (op == "^"); | |
} | |
function doOp(op, num1, num2) { | |
if (num2 != undefined) { | |
if (op == "+") | |
return parseFloat(num1) + parseFloat(num2); | |
else if (op == "-") | |
return parseFloat(num2) - parseFloat(num1); | |
else if (op == "*") | |
return parseFloat(num1) * parseFloat(num2); | |
else if (op == "/") | |
return parseFloat(num2) / parseFloat(num1); | |
else if (op == "^") | |
return Math.pow(parseFloat(num2), parseFloat(num1)); | |
} | |
} | |
function isParen(ite) { | |
return (ite == "(") || (ite == ")"); | |
} | |
function isRightParen(ite) { | |
return ite == ")"; | |
} | |
function isLeftParen(ite) { | |
return ite == "("; | |
} | |
//------------------------------------------------------- | |
function getTks(teststr) { | |
teststr = teststr.replace(/ /g,''); | |
var tks = []; | |
while (teststr.length > 0) { | |
var numreg = /^\d+\.?\d*|^\(-\d+\.?\d*(?=\))/; | |
var opreg = /^[+\-*/\^]/; | |
var parreg = /^[\(\)]/; | |
var r = "", | |
r2 = "", | |
r3 = ""; | |
r = numreg.exec(teststr); | |
r2 = opreg.exec(teststr); | |
r3 = parreg.exec(teststr); | |
// var r = parseFloat(teststr); | |
if (r != null) { | |
if (r[0][0] == '(') { | |
tks.push(snip(r[0], '(')) | |
teststr = snip(teststr, r[0] + ')'); | |
} else { | |
tks.push(r[0]); | |
teststr = snip(teststr, r[0]); | |
} | |
} else { | |
var op = teststr.charAt(0); | |
tks.push(op); | |
teststr = snip(teststr); | |
} | |
} | |
return tks; | |
} | |
function snip(teststr, r) { | |
var s = ""; | |
if (r == undefined) { | |
for (var i = 1; i < teststr.length; i++) { | |
s += teststr[i]; | |
} | |
return s; | |
} else { | |
var l = String(r).length; | |
for (var i = l; i < teststr.length; i++) { | |
s += teststr[i]; | |
} | |
return s; | |
} | |
} | |
function regtest() { | |
var numreg = /^\d+\.?\d*|^(?=\()-\d+\.?\d*(?=\))/; | |
var opreg = /^[+\-*/\^]/; | |
var parreg = /^[\(\)]/; | |
var teststr = "3+5"; | |
var exp = "3", | |
res = numreg.exec(teststr); | |
if (res == null) | |
console.log('FAIL: numreg.exec("' + teststr + '") is null') | |
else if (res[0] == exp) | |
console.log('PASS: numreg.exec("' + teststr + '")[0] == "' + exp) | |
else | |
console.log('FAIL: numreg.exec("' + teststr + '")[0] == "' + exp + '"; should be ' + exp + ', got ' + res[0]) | |
teststr = "(-3)+5"; | |
exp = "-3" | |
res = numreg.exec(teststr); | |
if (res == null) | |
console.log('FAIL: numreg.exec("' + teststr + '") is null') | |
else if (res[0] == exp) | |
console.log('PASS: numreg.exec("' + teststr + '")[0] == "' + exp) | |
else | |
console.log('FAIL: numreg.exec("' + teststr + '")[0] == "' + exp + '"; should be ' + exp + ', got ' + res[0]) | |
teststr = "(-3)+5"; | |
exp = "-3" | |
res = numreg.exec(teststr); | |
if (res == null) | |
console.log('FAIL: numreg.exec("' + teststr + '") is null') | |
else if (res[0] == exp) | |
console.log('PASS: numreg.exec("' + teststr + '")[0] == "' + exp) | |
else | |
console.log('FAIL: numreg.exec("' + teststr + '")[0] == "' + exp + '"; should be ' + exp + ', got ' + res[0]) | |
} | |
function getRpn(expr) { | |
var tks = getTks(expr); | |
var q = new queue(tks); | |
var buf1 = new queue([]); | |
var buf2 = new queue([]); | |
while (q.len() > 0) { | |
if (isNum(q.top())) { | |
buf1.push(q.pop()) | |
} else if (isOp(q.top())) { | |
if ((buf2.len() > 0) && (isOp(buf2.top())) && ((precomp(q.top(), buf2.top()) <= 0 && getAss(q.top()) == 'l') || (precomp(q.top(), buf2.top()) == -1 && getAss(q.top()) == 'r'))) { | |
while ((buf2.len() > 0) && (isOp(buf2.top())) && ((precomp(q.top(), buf2.top()) <= 0 && getAss(q.top()) == 'l') || (precomp(q.top(), buf2.top()) == -1 && getAss(q.top()) == 'r'))) { | |
buf1.push(buf2.pop()); | |
} | |
buf2.push(q.pop()) | |
} else { | |
buf2.push(q.pop()); | |
} | |
} else if (isParen(q.top())) { | |
if (isRightParen(q.top())) { | |
while (!isLeftParen(buf2.top())) //until the top of the op stack is left paren... | |
{ | |
buf1.push(buf2.pop()) //pop tokens off the op stack | |
} | |
buf2.pop() | |
q.pop(); | |
} else { | |
buf2.push(q.pop()); //if left paren, push onto op stack | |
} | |
} else //don't need this | |
{ | |
console.log("dont know") | |
q.pop() | |
} | |
} | |
while (buf2.len() > 0) { | |
buf1.push(buf2.pop()) | |
} | |
return buf1 | |
} | |
function calc(rpn) { | |
var stk = new queue([]); | |
console.log(rpn.q) | |
while (rpn.len() > 0) { | |
if (isNum(rpn.top())) { | |
console.log("h" + rpn.top()) | |
stk.push(rpn.pop()) | |
} | |
if (isOp(rpn.top())) { | |
if (isUnary(rpn.top())) { | |
var num = stk.pop(); | |
var op = rpn.pop(); | |
var res = doOp(op, num); | |
stk.push(res) | |
} else if (isBinary(rpn.top())) { | |
var num1 = stk.pop(); | |
var num2 = stk.pop(); | |
var op = rpn.pop(); | |
res = doOp(op, num1, num2); | |
stk.push(res) | |
} | |
} | |
} | |
console.log(stk.q) | |
return stk; | |
} | |
//-------------------------------------------------------------------------------------------- | |
var teststr3 = "(1+6)+(-4)" | |
var teststr = "(3+1)*(-2)"; | |
var teststr2 = "3 + 4 * 2 / (1 - 5) * 2 * 3" | |
var testarr2 = ['3', '+', '4', '*', '2', '/', '(', '1', '+', '-5', ')', '^', '2', '^', '3'] | |
var testarr = ['(', '3', '+', '1', ')', '*', '(', '-2', ')']; | |
var but = document.getElementById('enter'); | |
var x = document.getElementById('close'); | |
var inp = document.getElementById('inp'); | |
$('#inp').keyup(function(){ | |
var curv = $("#inp").val(); | |
if(curv == "") { | |
var res = document.getElementById("res"); | |
res.innerHTML = ""; | |
} | |
}) | |
//submit | |
but.addEventListener('click', function() { | |
var inp = document.getElementById('inp').value | |
var res = document.getElementById('res'); | |
inp = rev(getRpn(inp).q); //extract array of queue(stack) structure | |
var inp = new queue(inp); | |
console.log(inp) | |
res.innerHTML = calc(inp).print(); | |
}) | |
x.addEventListener('click', function(){ | |
$('#inp').val("") | |
var res = document.getElementById("res"); | |
res.innerHTML = ""; | |
}) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html, | |
body { | |
height: 100%; | |
overflow: hidden; | |
-webkit-transition: all .500s; | |
transition: all .500s; | |
} | |
html { | |
background: #282E33; | |
} | |
body { | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
font-size:5em; | |
} | |
span#inpbox { | |
display: inline-block; | |
border: 2px solid #5E6C77; | |
border-radius: 0.5em; | |
padding: 0px 10px 0px; | |
color: #5E6C77; | |
border-radius: .25em; | |
background: transparent; | |
} | |
span#close { | |
font-family: Helvetica; | |
cursor:pointer; | |
} | |
span#inpbox > input { | |
border: none; | |
background: none; | |
} | |
#enter { | |
background: #222; | |
color: white; | |
cursor:pointer; | |
border:1px solid black; | |
padding:0px 5px; | |
border-radius:6px; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment