X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=07-interpreter%2Fmachine-code.ipynb;h=48da543feccf20468c7c036c640544966007074b;hb=84f849f83970f3a6295d09da5c1bef1fe9cec4cb;hp=cb8e18600d40cbfd97a6eb768e2ebb982478a3d4;hpb=009976af40a98c5cb0151fca6525c75f12222373;p=ou-summer-of-code-2017.git diff --git a/07-interpreter/machine-code.ipynb b/07-interpreter/machine-code.ipynb index cb8e186..48da543 100644 --- a/07-interpreter/machine-code.ipynb +++ b/07-interpreter/machine-code.ipynb @@ -1,9 +1,43 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 111, + "cell_type": "markdown", "metadata": {}, + "source": [ + "# Machine interpreter\n", + "\n", + "## Instructions\n", + "\n", + "Three registers, `a`, `b`, and `c`. \n", + "Program counter, `pc`.\n", + "Unlimited memory in numbered addresses, completely separate from program storage.\n", + "\n", + "Each register and memory location can hold 8-byte integers (Java `long`s).\n", + "\n", + "Machine carries out the instruction at location `pc`. After it's executed, `pc` increments by 1.\n", + "\n", + "`jmp` and `jpz` override this normal change in `pc`.\n", + "\n", + "| Instruction | Description |\n", + "|:------------|:------------|\n", + "| `inc r` | increment contents of register `r` |\n", + "| `dec r` | decrement contents of register `r` |\n", + "| `set r i` | set contents of register `r` to literal value `i` |\n", + "| `cpy r s` | set contents of register `r` into register `s` | \n", + "| `sto r m` | store contents of register `r` into memory location `m` |\n", + "| `ld r m` | load contents of memory location `m` into register `r` |\n", + "| `jmp i` | jump to instruction `i` places forward |\n", + "| `jpz r i` | jump to instruction `i` places forward if
register `r` contains zero, otherwise continue to next instruction |\n", + "\n", + "For `jmp` and `jpz`, `i` is relative to the current instruction. `i` can be negative to jump to earlier places in the program. `i`=1 is a no-op, `i`=0 causes an infinite loop." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "def new_machine():\n", @@ -16,7 +50,7 @@ }, { "cell_type": "code", - "execution_count": 193, + "execution_count": 2, "metadata": { "collapsed": true }, @@ -30,7 +64,7 @@ }, { "cell_type": "code", - "execution_count": 112, + "execution_count": 3, "metadata": { "collapsed": true }, @@ -43,7 +77,7 @@ }, { "cell_type": "code", - "execution_count": 113, + "execution_count": 4, "metadata": { "collapsed": true }, @@ -56,7 +90,7 @@ }, { "cell_type": "code", - "execution_count": 114, + "execution_count": 5, "metadata": { "collapsed": true }, @@ -68,7 +102,7 @@ }, { "cell_type": "code", - "execution_count": 115, + "execution_count": 6, "metadata": { "collapsed": true }, @@ -83,7 +117,7 @@ }, { "cell_type": "code", - "execution_count": 116, + "execution_count": 7, "metadata": { "collapsed": true }, @@ -96,7 +130,7 @@ }, { "cell_type": "code", - "execution_count": 117, + "execution_count": 8, "metadata": { "collapsed": true }, @@ -109,7 +143,7 @@ }, { "cell_type": "code", - "execution_count": 129, + "execution_count": 9, "metadata": { "collapsed": true }, @@ -122,7 +156,7 @@ }, { "cell_type": "code", - "execution_count": 130, + "execution_count": 10, "metadata": { "collapsed": true }, @@ -138,8 +172,10 @@ }, { "cell_type": "code", - "execution_count": 131, - "metadata": {}, + "execution_count": 11, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "instruction_table = {'inc': inc, 'dec': dec, 'jmp': jmp,\n", @@ -150,7 +186,7 @@ }, { "cell_type": "code", - "execution_count": 121, + "execution_count": 12, "metadata": { "collapsed": true }, @@ -168,7 +204,7 @@ }, { "cell_type": "code", - "execution_count": 122, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -177,7 +213,7 @@ "{'a': 2, 'b': 1, 'c': 0, 'instructions': [], 'pc': 3}" ] }, - "execution_count": 122, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -193,7 +229,7 @@ }, { "cell_type": "code", - "execution_count": 123, + "execution_count": 14, "metadata": { "collapsed": true }, @@ -205,19 +241,110 @@ }, { "cell_type": "code", - "execution_count": 124, + "execution_count": 42, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def program_from_listing(listing, machine):\n", - " program_from_instructions([i for i in listing.split('\\n') if i], machine)" + " labelled_instructions = [i.strip() for i in listing.split('\\n') \n", + " if i.strip() \n", + " if not i.strip().startswith('#')]\n", + " instructions = replace_labels(labelled_instructions)\n", + " program_from_instructions(instructions, machine)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def replace_labels(listing):\n", + " locations = {}\n", + " for n, i in enumerate(listing):\n", + " if ':' in i:\n", + " locations[i.split(':')[0]] = n\n", + "\n", + " unlabelled_listing = []\n", + " for n, i in enumerate(listing):\n", + " instr = i.split()\n", + " if ':' in i:\n", + " instr = i.split(':')[1].split()\n", + " else:\n", + " instr = i.split()\n", + " terms = []\n", + " for term in instr:\n", + " if term in locations:\n", + " terms += [str(locations[term] - n)]\n", + " else:\n", + " terms += [term]\n", + " transformed_instr = ' '.join(terms)\n", + " unlabelled_listing += [transformed_instr]\n", + " \n", + " return unlabelled_listing " + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['inc', 'a']" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "'fred: inc a'.split(':')[1].split()" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "set a 10\n", + "dec a\n", + "inc b\n", + "sto b 1\n", + "jpz a 2\n", + "jmp -4\n" + ] + } + ], + "source": [ + "program = \"\"\"\n", + " set a 10\n", + " # comment line\n", + " \n", + "loop: dec a\n", + " inc b\n", + " sto b 1\n", + " jpz a 2\n", + " jmp loop\n", + "\"\"\"\n", + "labelled_instructions = [i.strip() for i in program.split('\\n') if i.strip() if not i.strip().startswith('#')]\n", + "instructions = replace_labels(labelled_instructions)\n", + "print('\\n'.join(instructions))" ] }, { "cell_type": "code", - "execution_count": 156, + "execution_count": 19, "metadata": { "collapsed": true }, @@ -235,7 +362,7 @@ }, { "cell_type": "code", - "execution_count": 146, + "execution_count": 20, "metadata": { "collapsed": true }, @@ -250,7 +377,7 @@ }, { "cell_type": "code", - "execution_count": 127, + "execution_count": 21, "metadata": {}, "outputs": [ { @@ -266,7 +393,7 @@ " 'pc': 4}" ] }, - "execution_count": 127, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -283,26 +410,26 @@ }, { "cell_type": "code", - "execution_count": 143, + "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'c': 20,\n", - " 'instructions': [(, ['a', 10]),\n", + "{'instructions': [(, ['a', 10]),\n", " (, ['a']),\n", " (, ['b']),\n", " (, ['b', 1]),\n", " (, ['a', 2]),\n", " (, [-4])],\n", " 1: 10,\n", - " 'b': 10,\n", + " 'c': 20,\n", + " 'a': 0,\n", " 'pc': 6,\n", - " 'a': 0}" + " 'b': 10}" ] }, - "execution_count": 143, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -324,7 +451,45 @@ }, { "cell_type": "code", - "execution_count": 159, + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'instructions': [(, ['a', 10]),\n", + " (, ['a']),\n", + " (, ['b']),\n", + " (, ['b', 1]),\n", + " (, ['a', 2]),\n", + " (, [-4])],\n", + " 1: 10,\n", + " 'c': 20,\n", + " 'a': 0,\n", + " 'pc': 6,\n", + " 'b': 10}" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "program = \"\"\"\n", + " set a 10\n", + "loop: dec a\n", + " inc b\n", + " sto b 1\n", + " jpz a 2\n", + " jmp loop\n", + "\"\"\"\n", + "execute(program, initial_state={'c': 20})" + ] + }, + { + "cell_type": "code", + "execution_count": 24, "metadata": {}, "outputs": [ { @@ -345,7 +510,7 @@ " 'pc': 10}" ] }, - "execution_count": 159, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -370,38 +535,372 @@ }, { "cell_type": "code", - "execution_count": 196, + "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'10: 10, a: 0, b: 0, c: 5, pc: 11'" + "{'a': 0,\n", + " 'b': 1,\n", + " 'c': 5,\n", + " 'instructions': [(, ['c', 'a']),\n", + " (, ['b', 0]),\n", + " (, ['a']),\n", + " (, ['b', 3]),\n", + " (, ['b']),\n", + " (, [2]),\n", + " (, ['b']),\n", + " (, ['a', 2]),\n", + " (, [-6])],\n", + " 'pc': 9}" ] }, - "execution_count": 196, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "# b holds parity of number in c: (c % 2)\n", "program = \"\"\"\n", - "sto a 10\n", - "set c 0\n", - "set b 0\n", - "dec a\n", - "jpz b 4\n", - "dec b\n", - "inc c\n", - "jmp 2\n", - "inc b\n", - "jpz a 2\n", - "jmp -7\n", + " cpy c a\n", + " set b 0\n", + "loop: dec a\n", + " jpz b odd\n", + " dec b\n", + " jmp end\n", + "odd: inc b\n", + "end: jpz a 2\n", + " jmp loop\n", + "\"\"\"\n", + "# m = new_machine()\n", + "# program_from_listing(program, m)\n", + "# run(m)\n", + "execute(program, initial_state={'c': 5})" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'1: 8, a: 0, b: 1, c: 8, pc: 11'" + ] + }, + "execution_count": 85, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# c holds floor(a/2)\n", + "program = \"\"\"\n", + " set c 0\n", + " set b 0\n", + "loop: dec a\n", + " jpz b odd\n", + " dec b\n", + " inc c\n", + " jmp end\n", + "odd: inc b\n", + "end: jpz a 2\n", + " jmp loop\n", + " sto c 1\n", + "\"\"\"\n", + "# m = new_machine()\n", + "# program_from_listing(program, m)\n", + "# run(m)\n", + "show_machine(execute(program, initial_state={'a': 17}))" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'a: 4, b: 0, c: 12, pc: 9'" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# c holds a * 3\n", + "program = \"\"\"\n", + " set c 0\n", + " cpy a b\n", + " # start of main loop\n", + "loop: jpz b end\n", + " dec b\n", + " inc c\n", + " inc c\n", + " inc c\n", + " jmp loop\n", + " \n", + " # end of program \n", + " \n", + "end: jmp 1\n", + "\"\"\"\n", + "# m = new_machine()\n", + "# program_from_listing(program, m)\n", + "# run(m)\n", + "show_machine(execute(program, initial_state={'a': 4}))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# c holds a!\n", + "program = \"\"\"\n", + "??????????????\n", + " set c 0\n", + " cpy a b\n", + " # start of main loop\n", + "loop: jpz b end\n", + " dec b\n", + " inc c\n", + " inc c\n", + " inc c\n", + " jmp loop\n", + " \n", + " # end of program \n", + " \n", + "end: jmp 1\n", + "\"\"\"\n", + "# m = new_machine()\n", + "# program_from_listing(program, m)\n", + "# run(m)\n", + "show_machine(execute(program, initial_state={'a': 4}))" + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'1: 52, a: 0, b: 0, c: 0, pc: 46'" + ] + }, + "execution_count": 82, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Collatz. a initially holds value, but location 1 is used to store the current value as we're going along.\n", + "# Location 2 holds number of steps taken\n", + "# Location 3 holds max value reached\n", + "program = \"\"\"\n", + " sto a 1\n", + " \n", + " set b 0\n", + " \n", + " # if a is one, finish, \n", + "main: dec a\n", + " jpz a end\n", + " inc a\n", + " \n", + " # find parity of a\n", + " cpy a c\n", + " set b 0\n", + "prty: dec c\n", + " jpz b odd\n", + " dec b\n", + " jmp prte\n", + "odd: inc b\n", + "prte: jpz c 2\n", + " jmp prty\n", + " \n", + " # b == 0 means a even; b == 1 means a odd\n", + " jpz b isev\n", + "\n", + " # c holds a * 3 + 1\n", + " cpy a b\n", + "mul: jpz b emul\n", + " dec b\n", + " inc c\n", + " inc c\n", + " inc c\n", + " jmp mul\n", + "emul: inc c\n", + " cpy c a\n", + " jmp fin\n", + " \n", + " \n", + "isev: set c 0\n", + " set b 0\n", + "hlvl: dec a\n", + " jpz b oddh\n", + " dec b\n", + " inc c\n", + " jmp endh\n", + "oddh: inc b\n", + "endh: jpz a 2\n", + " jmp hlvl\n", + " cpy c a\n", + "\n", + "fin: cpy a b\n", + " ld c 1\n", + "maxc: jpz c this\n", + " jpz b othr\n", + " dec b\n", + " dec c\n", + " jmp maxc\n", + "this: sto a 1\n", + "othr: jmp main\n", + " \n", + " # end of program \n", + " \n", + "end: set c 0\n", "\"\"\"\n", "# m = new_machine()\n", "# program_from_listing(program, m)\n", "# run(m)\n", - "show_machine(execute(program, initial_state={'a': 10}))" + "show_machine(execute(program, initial_state={'a': 7}))" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "40" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "13*3+1" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def max_collatz(start):\n", + " mc = start\n", + " i = start\n", + " while i != 1:\n", + " if i % 2 == 0:\n", + " i = i // 2\n", + " else:\n", + " i = 3 * i + 1\n", + " if i > mc:\n", + " mc = i\n", + " return mc" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "52" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "max_collatz(7)" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(250504, 937)" + ] + }, + "execution_count": 80, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "max([(max_collatz(i), i) for i in range(1, 1000)])" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ans = []\n", + "for i in range(1, 100):\n", + " m = execute(program, initial_state={'a': i})\n", + " c = max_collatz(i)\n", + " if m[1] != c:\n", + " ans += [(i, m[1], c)]\n", + "ans" + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'1: 250504, a: 0, b: 0, c: 0, pc: 46'" + ] + }, + "execution_count": 83, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_machine(execute(program, initial_state={'a': 937}))" ] }, {