From: Neil Smith Date: Wed, 30 Aug 2017 16:26:00 +0000 (+0100) Subject: Added solution notes for day 7 X-Git-Url: https://git.njae.me.uk/?a=commitdiff_plain;h=164ea7d668222c45a6a62a3416ba59b0485bbed1;p=ou-summer-of-code-2017.git Added solution notes for day 7 --- diff --git a/07-interpreter/interpreter-solution.ipynb b/07-interpreter/interpreter-solution.ipynb index 78200d9..9c042e5 100644 --- a/07-interpreter/interpreter-solution.ipynb +++ b/07-interpreter/interpreter-solution.ipynb @@ -67,6 +67,23 @@ "Starting with register `a` holding 937, and all other registers and memory locations holding zero, what does register `a` contain when the program finishes?" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Worked example solution: parts 1 and 2\n", + "This follows a very similar idea to [Day 5](../05-display-board/display-board-solution.ipynb): we're building a virtual machine and applying a set of instructions to it.\n", + "\n", + "The virtual machine is, if anything, simpler than the laser display board from day 5. There are just four registers, the special `pc` register, and the list of instructions. \n", + "\n", + "Again, as with the laser display board, each operation is defined as Python function, which takes as arguments the instruction's arguments and the machine being operated on. The operations update the machine in-place.\n", + "\n", + "One decision is over what counts as an 'instruction'. I've taken the view that what's stored in the machine should be as close to what's exectuted as possible. Therefore, each instruction is a pair (2-tuple) of the function that performs that instruction. The first element is the Python function that performs the operation; the second is a list of arguments, either register names or literal number values. See the `run()` procedure for how it's used.\n", + "\n", + "## Parsing instructions\n", + "Another change from the laser display board is how the instructions are parsed. In the same way as before, I use a dispatch table (called `instruction_table`) to relate the instruction names to the Python procedures that perform them. But I also have a the `numeric_args_table` which specifies which arguments to which instructions should be processed as numbers. The `parse` procedure reads both of those and converts the instruction text into the correct Python representation." + ] + }, { "cell_type": "code", "execution_count": 3, @@ -220,6 +237,32 @@ " machine['instructions'] = [parse(instr) for instr in prog]" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that I've added an extra step in the program parsing stage, which is dealing with labels. When you're writing programs like this, it's very easy to lose track of where each instruction is and how large the jumps should be. To get around that, I take a leaf from standard assembly programming of allowing user-defined labels for positions. That allows me to write the example multiplication program like this:\n", + "\n", + "```\n", + " set c 0\n", + " cpy a d\n", + "loop: jpz b end \n", + " dec b\n", + " cpy d a\n", + "smul: jpz a emul\n", + " inc c\n", + " dec a\n", + " jmp smul\n", + "emul: jmp loop \n", + " \n", + "end: set d 0\n", + "```\n", + "\n", + "where the words at the start of the line are the labels and all the jumps move to particular labels. This is a bit more readable, and also means I can add and remove instructions without having to change all the jump instructions as well.\n", + "\n", + "The `replace_labels` function makes two passes through the program listing. The first pass finds all the labels and stores their absolute positions. The second pass replaces each label in an instruction with the relative position from the instruction number to the label's position." + ] + }, { "cell_type": "code", "execution_count": 14, @@ -281,6 +324,23 @@ " return unlabelled_listing " ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note the 'splat operator' trick, which unpacks a list of items into positional parameters of the function. It has the effect of converting\n", + "```\n", + "cpy(['a', 'd'], machine)\n", + "```\n", + "into\n", + "```\n", + "cpy('a', 'd', machine)\n", + "```\n", + "which is the form I want. \n", + "\n", + "Another way of doing this could be to have the individual instruction-implementing procedures take a list of parameters, but I think this is clearer to understand." + ] + }, { "cell_type": "code", "execution_count": 17, @@ -382,7 +442,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.2+" + "version": "3.5.3" } }, "nbformat": 4,