function forth(print = console.log) { const s = []; // the stack const popNum = () => Number(s.pop()); const fs = { ' ' : () => {}, '\n' : () => {}, '\t' : () => {}, '/' : () => { const a2 = popNum(); const a1 = popNum(); s.push(a1 / a2); }, '-' : () => { const a2 = popNum(); const a1 = popNum(); s.push(a1 - a2); }, '+' : () => { s.push(popNum() + popNum()) }, '*' : () => { s.push(popNum() * popNum()) }, '.' : () => print(s.pop()), 'peek' : () => print(s[s.length - 1]), ':' : (initialIdx, tokens) => { let localIdx = initialIdx + 1; const fname = tokens[localIdx++]; const fnContent = []; for (;tokens[localIdx] !== ';'; localIdx++) { fnContent.push(tokens[localIdx]); } fs[fname] = () => { exec(fnContent); } return localIdx - initialIdx; // numItemsSkipped }, 's' : () => print(JSON.stringify(s)), 'sum' : () => { let total = 0; while (s.length > 0) { total += popNum(); } s.push(total); }, '(' : (initialIdx, tokens) => { let localIdx = initialIdx + 1; while (tokens[localIdx] !== ')') { localIdx++ } return localIdx - initialIdx; } } function exec(tokens) { for (let tokenIdx = 0; tokenIdx < tokens.length; tokenIdx++) { const token = tokens[tokenIdx]; if (fs[token]) { const numItemsSkipped = fs[token](tokenIdx, tokens); if (Number.isInteger(numItemsSkipped)) { tokenIdx += numItemsSkipped; } } else { s.push(token); } } } return t => exec(t.split(/[ \n\t]+/)); } if (window) { const style = document.createElement('style') style.innerHTML = ` #forthroot * { background-color: #42456f; color: white; font-family: monospace; font-size: 1.2rem; box-sizing: border-box; } #forthouter { cursor: text; border: solid thin black; } #forthline { width: 97%; border: none; } #forthline:focus { outline: none; } #forthresultsbox { height: 90vh; } #forthresults { margin-top: 0px; } #forthlinelabel { padding-top:1px; max-width: 3%; } `; document.head.appendChild(style); forthroot.innerHTML = `