Skip to content

Instantly share code, notes, and snippets.

@n4o847
Created December 14, 2019 16:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save n4o847/a0c3d2010ca09362cba076c77b00c4b3 to your computer and use it in GitHub Desktop.
Save n4o847/a0c3d2010ca09362cba076c77b00c4b3 to your computer and use it in GitHub Desktop.
<!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>
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