From a5a18b917dbacda0524ab7800f16a582880d81fa Mon Sep 17 00:00:00 2001 From: Grzegorz Kucmierz Date: Sat, 16 May 2020 19:15:56 +0200 Subject: [PATCH] Assembler interpreter (part II) --- assembler-interpreter-part-ii/index.js | 62 ++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 assembler-interpreter-part-ii/index.js diff --git a/assembler-interpreter-part-ii/index.js b/assembler-interpreter-part-ii/index.js new file mode 100644 index 0000000..de5af35 --- /dev/null +++ b/assembler-interpreter-part-ii/index.js @@ -0,0 +1,62 @@ +// https://www.codewars.com/kata/58e61f3d8ff24f774400002c/javascript + +function assemblerInterpreter(program) { + const lines = (program + .split(/\n/) + .map(line => line.replace(/;.*$/, '').trim()) + .filter(line => line !== '')); + const parsed = []; + const labels = new Map(); + let diff = 0; + for (i = 0; i < lines.length; ++i) { + const tokens = lines[i].split(/[,\s]+/); + const m = tokens[0].match(/(\w+)\:/); + if (m) { + labels.set(m[1], i-diff); + ++diff; + } else if (tokens[0] === 'msg') { + parsed[i-diff] = lines[i].match(/('[^']*')|[a-z0-9_]+/g); + } else { + parsed[i-diff] = tokens; + } + } + let ip = 0; + let cmp; + const res = []; + const stack = []; + const regs = new Map(); + const constOrVal = n => ((+n) + '') === n ? +n : regs.get(n); + const jmpIf = (lbl, cond) => ip = cond ? labels.get(lbl) - 1 : ip; + const instr = { + mov: (a, b) => regs.set(a, constOrVal(b)), + inc: a => regs.set(a, regs.get(a) + 1), + dec: a => regs.set(a, regs.get(a) - 1), + add: (a, b) => regs.set(a, regs.get(a) + constOrVal(b)), + sub: (a, b) => regs.set(a, regs.get(a) - constOrVal(b)), + mul: (a, b) => regs.set(a, regs.get(a) * constOrVal(b)), + div: (a, b) => regs.set(a, regs.get(a) / constOrVal(b) | 0), + jmp: lbl => jmpIf(lbl, true), + cmp: (a, b) => cmp = Math.sign(constOrVal(a) - constOrVal(b)), + jne: lbl => jmpIf(lbl, cmp !== 0), + je: lbl => jmpIf(lbl, cmp === 0), + jge: lbl => jmpIf(lbl, cmp >= 0), + jg: lbl => jmpIf(lbl, cmp > 0), + jle: lbl => jmpIf(lbl, cmp <= 0), + jl: lbl => jmpIf(lbl, cmp < 0), + call: lbl => (stack.push(ip), jmpIf(lbl, true)), + ret: () => ip = stack.pop(), + msg: (...args) => res.push(args.map(arg => { + const m = arg.match(/^'(.*)'$/); + if (m) return m[1]; + return constOrVal(arg); + }).join``) + }; + let cntdwn = 1e6; + while (ip < parsed.length && --cntdwn > 0) { + const [cmd, ...args] = parsed[ip]; + if (cmd === 'end') return res.join``; + instr[cmd](...args); + ++ip; + } + return -1; +}