Created
December 14, 2019 16:53
-
-
Save n4o847/a0c3d2010ca09362cba076c77b00c4b3 to your computer and use it in GitHub Desktop.
This file contains 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
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | |
<title>Document</title> | |
<style> | |
#disp { | |
padding: 20px; | |
} | |
#disp * { | |
transition: all 1000ms; | |
} | |
.par::before { | |
content: "("; | |
} | |
.par::after { | |
content: ")"; | |
} | |
.num { | |
display: inline-block; | |
border: solid 2px #ccc; | |
border-radius: 10%; | |
background-color: #eee; | |
} | |
.op { | |
border: solid 2px rgb(149, 125, 206); | |
border-radius: 10%; | |
background-color: rgb(177, 165, 206); | |
} | |
</style> | |
</head> | |
<body> | |
<input type="text" id="expr"> | |
<button id="go">Go</button> | |
<button id="eval">Eval</button> | |
<div id="disp"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> |
This file contains 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
const $expr = document.getElementById("expr"); | |
const $go = document.getElementById("go"); | |
const $eval = document.getElementById("eval"); | |
const $disp = document.getElementById("disp"); | |
/* | |
expr = term ("+" term)* | |
term = atom ("*" atom)* | |
atom = num | "(" expr ")" | |
*/ | |
function parse(text) { | |
let pos = 0; | |
const parseExpr = () => { | |
let $1 = parseTerm(); | |
while (text[pos] === "+" || text[pos] === "-") { | |
const op = text[pos]; | |
pos++; | |
const $2 = parseTerm(); | |
$1 = { type: op, $1, $2 }; | |
} | |
return $1; | |
}; | |
const parseTerm = () => { | |
let $1 = parseAtom(); | |
while (text[pos] === "*" || text[pos] === "/") { | |
const op = text[pos]; | |
pos++; | |
const $2 = parseAtom(); | |
$1 = { type: op, $1, $2 }; | |
} | |
return $1; | |
}; | |
const parseAtom = () => { | |
if (text[pos] === "(") { | |
pos++; | |
const $1 = parseExpr(); | |
if (text[pos] === ")") { | |
pos++; | |
return { type: "()", $1 }; | |
} else { | |
throw new SyntaxError(); | |
} | |
} | |
return parseNum(); | |
}; | |
const parseNum = () => { | |
let ret = ""; | |
while (/\d/.test(text[pos])) { | |
ret += text[pos]; | |
pos++; | |
} | |
// 任意精度有理数? | |
return ret === "" ? null : { type: "num", $1: +ret }; | |
}; | |
return parseExpr(text); | |
} | |
const size = (val) => { | |
// 10より小さい場合は? | |
// シグモイド関数っぽくしたほうが良さそう | |
return Math.log10(val) * 100; | |
}; | |
const render = (tree) => { | |
if (tree.type === "num") { | |
const val = tree.$1; | |
return `<span class="num" style="width:${size(val)}px;height:${size(val)}px">${val}</span>`; | |
} | |
if (tree.type === "()") { | |
return `<span class="par">${render(tree.$1)}</span>`; | |
} | |
return ` | |
<span class="gr"> | |
${render(tree.$1)} | |
<span class="op">${tree.type}</span> | |
${render(tree.$2)} | |
</span> | |
`; | |
}; | |
$expr.value = `(12+34)*56-78`; | |
let expr = null; | |
$go.addEventListener("click", () => { | |
// $disp.textContent = JSON.stringify(parse($expr.value)); | |
expr = parse($expr.value); | |
$disp.innerHTML = render(expr); | |
}); | |
$eval.addEventListener("click", () => { | |
// expr = evaluate(expr); | |
// $disp.innerHTML = render(expr); | |
evaluateDOM($disp.children[0]); | |
}); | |
const evaluate = (tree) => { | |
if (tree.type === "num") { | |
return tree; | |
} | |
if (tree.$1.type !== "num") { | |
return { ...tree, $1: evaluate(tree.$1) }; | |
} | |
if (tree.type === "()") { | |
return tree.$1; | |
} | |
if (tree.$2.type !== "num") { | |
return { ...tree, $2: evaluate(tree.$2) }; | |
} | |
return { | |
type: "num", | |
$1: eval(`${tree.$1.$1} ${tree.type} ${tree.$2.$1}`), | |
}; | |
}; | |
const evaluateDOM = (tree) => { | |
if (tree.className === "num") { | |
return; | |
} | |
if (tree.children[0].className !== "num") { | |
evaluateDOM(tree.children[0]); | |
return; | |
} | |
if (tree.className === "par") { | |
tree.style.opacity = 0; | |
setTimeout(() => { | |
tree.parentNode.replaceChild(tree.children[0], tree); | |
tree.style.opacity = 1; | |
}, 1000); | |
return; | |
} | |
if (tree.children[2].className !== "num") { | |
evaluateDOM(tree.children[2]); | |
return; | |
} | |
if (tree.className === "gr") { | |
tree.style.opacity = 0; | |
setTimeout(() => { | |
const val = eval(`${tree.textContent}`); | |
tree.className = "num"; | |
tree.style.width = tree.style.height = `${size(val)}px`; | |
tree.innerHTML = `${val}`; | |
tree.style.opacity = 1; | |
}, 1000); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment