Calculator

Run Settings
LanguageJavaScript
Language Version
Run Command
let fs = require("fs"); function start() { //let program = fs.readFileSync("/dev/stdin", "utf-8"); let program = "- 40 + 2 * ( 3 - 20 )"; let tokens = lex(program); //console.log(tokens); let ast = parse(tokens); //console.log(JSON.stringify(ast, null, 2)); let output = run(ast); console.log(output); } function lex(program) { let result = []; let splitProgram = program .split(" "); for (let text of splitProgram) { let number = parseFloat(text); let token = {}; if (!isNaN(number)) { token = { type: "number", value: number, }; } else if (text == "+") { token = { type: "+", }; } else if (text == "-") { token = { type: "-", }; } else if (text == "*") { token = { type: "*", }; } else if (text == "/") { token = { type: "/", }; } else if (text == "(") { token = { type: "(", }; } else if (text == ")") { token = { type: ")", }; } else { console.log(`Lex: token "${text}" is not recognized`); throw ""; } result.push(token); } result.push({ type: "EOF", }); return result; } function parse(tokens) { let i = 0; let stream = { pop: () => { let result = tokens[i]; i += 1; return result; }, peek: () => { let result = tokens[i]; return result; }, consume: () => { i += 1; }, }; let result = parseExpr(stream, 9999); return result; } function parseExpr(stream, prevPrecedence) { let t = stream.pop(); let left; if (t.type == "number") { left = { type: t.type, value: t.value, }; } else if (t.type == "-") { let expr = parseExpr(stream, 30); left = { type: "u-", expr: expr, }; } else if (t.type == "(") { let expr = parseExpr(stream, 90); let closingToken = stream.pop(); if(closingToken.type != ")") { console.log(`Parse: Expected ")", found: ${closingToken.type}`); } left = { type: "()", expr: expr, }; } else { console.log(`Parse: Expected operand, found: ${t.type}`); throw ""; } while(true) { let operator = stream.peek(); if (isClosing(operator)) { return left; } let precedence = getPrecedence(operator); if (precedence >= prevPrecedence) { return left; } stream.consume(); let right = parseExpr(stream, precedence); left = { type: operator.type, left: left, right: right, }; } } function isClosing(operator) { switch(operator.type) { case ")": return true; case "EOF": return true; } return false; } function getPrecedence(operator) { switch(operator.type) { case "+": return 60; case "-": return 60; case "*": return 40; case "/": return 40; } console.log(`Parse: No precedence for operator "${operator.type}"`); throw ""; } function run(ast) { let result = calculate(ast); return result; } function calculate(ast) { if (ast.type == "number") { return ast.value; } else if (ast.type == "+") { let left = calculate(ast.left); let right = calculate(ast.right); let result = left + right; return result; } else if (ast.type == "-") { let left = calculate(ast.left); let right = calculate(ast.right); let result = left - right; return result; } else if (ast.type == "*") { let left = calculate(ast.left); let right = calculate(ast.right); let result = left * right; return result; } else if (ast.type == "/") { let left = calculate(ast.left); let right = calculate(ast.right); let result = left / right; return result; } else if (ast.type == "()") { let result = calculate(ast.expr); return result; } else if (ast.type == "u-") { let expr = calculate(ast.expr); let result = -expr; return result; } else { console.log(`Run: Unxepected type: ${ast.type}`); throw ""; } } start();
Editor Settings
Theme
Key bindings
Full width
Lines