diff --git a/ipynb/BASIC.ipynb b/ipynb/BASIC.ipynb index 71f7b70..c33033f 100644 --- a/ipynb/BASIC.ipynb +++ b/ipynb/BASIC.ipynb @@ -8,20 +8,18 @@ "\n", "# BASIC Interpreter\n", "\n", - "[Years ago](http://norvig.com/lispy.html), I showed how to write an Interpreter for a dialect of Lisp. Some readers appreciated it, and some asked about an interpreter for a language that isn't just a bunch of parentheses. In 2014 I saw a [celebration](http://time.com/69316/basic/) of the 50th anniversary of the 1964 [Dartmouth BASIC](http://web.archive.org/web/20120716185629/http://www.bitsavers.org/pdf/dartmouth/BASIC_Oct64.pdf) interpreter, and thought that I could show how to implement such an interpreter. I never quite finished in 2014, but in 2017 I rediscovered my unfinished file and completed it. For those of you unfamiliar with BASIC, here is a sample program:" + "[Years ago](http://norvig.com/lispy.html), I showed how to write an Interpreter for a dialect of Lisp. Some readers appreciated it, and some asked about an interpreter for a language that isn't just a bunch of parentheses. In 2014 I saw a [celebration](http://time.com/69316/basic/) of the 50th anniversary of the 1964 [Dartmouth BASIC](http://web.archive.org/web/20120716185629/http://www.bitsavers.org/pdf/dartmouth/BASIC_Oct64.pdf) interpreter, and thought that I could show how to implement such an interpreter. I never quite finished in 2014, but now it is 2017, I rediscovered this unfinished file, and completed it. For those of you unfamiliar with BASIC, here is a sample program:" ] }, { "cell_type": "code", "execution_count": 1, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "program = '''\n", "10 REM POWER TABLE\n", - "11 DATA 8, 4\n", + "11 DATA 8, 4\n", "15 READ N0, P0\n", "20 PRINT \"N\",\n", "25 FOR P = 2 to P0\n", @@ -47,8 +45,9 @@ "source": [ "Of course I don't have to build everything from scratch in assembly language, and I don't have to worry about every byte of storage, like [Kemeny](http://www.dartmouth.edu/basicfifty/basic.html), [Gates](http://www.pagetable.com/?p=774), and [Woz](http://www.retrothing.com/2008/07/restoring-wozs.html) did, so my job is much easier. The interpreter consists of three phases: \n", "* **Tokenization**: breaking a text into a list of tokens, for example: `\"10 READ N\"` becomes `['10', 'READ', 'N']`.\n", - "* **Parsing**: building an executable representation from the tokens, so this statement becomes: `Stmt(num=10, typ='READ', args=['N'])`.\n", - "* **Execution**: follow the flow of the program and do what each statement says; in this case an assignment: `variables['N'] = data.popleft()`.\n", + "* **Parsing**: building a representation from the tokens: `Stmt(num=10, typ='READ', args=['N'])`.\n", + "* **Execution**: follow the flow of the program and do what each statement says; in this case the `READ` statement\n", + "has the effect of an assignment: `variables['N'] = data.popleft()`.\n", "\n", "\n", "\n", @@ -60,9 +59,7 @@ { "cell_type": "code", "execution_count": 2, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "import re \n", @@ -73,7 +70,7 @@ " LET|READ|DATA|PRINT|GOTO|IF|FOR|NEXT|END|STOP | # keywords\n", " DEF|GOSUB|RETURN|DIM|REM|TO|THEN|STEP | # more keywords\n", " [A-Z]\\d? | # variable names (letter optionally followed by a digit)\n", - " \" .*? \" | # labels (strings in double quotes)\n", + " \".*? \" | # labels (strings in double quotes)\n", " <>|>=|<= | # multi-character relational operators\n", " \\S # any non-space single character ''', \n", " re.VERBOSE).findall" @@ -90,9 +87,7 @@ { "cell_type": "code", "execution_count": 3, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -112,9 +107,7 @@ { "cell_type": "code", "execution_count": 4, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -133,9 +126,7 @@ }, { "cell_type": "markdown", - "metadata": { - "collapsed": false - }, + "metadata": {}, "source": [ "That looks good. Note that my tokens are just strings; it will be the parser's job, not the tokenizer's, to recognize that `'2'` is a number and `'X'` is the name of a variable. (In some interpreters, the tokenizer makes distinctions like these.)\n", "\n", @@ -151,9 +142,7 @@ { "cell_type": "code", "execution_count": 5, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -180,15 +169,13 @@ "* `peek()`: returns the next token in `tokens` (without changing `tokens`), or `None` if there are no more tokens.\n", "* `pop()`: removes and returns the next token. \n", "* `pop(`*string*`)`: removes and returns the next token if it is equal to the string; else return `None` and leave `tokens` unchanged.\n", - "* `pop(`*predicate*`)`: removes and returns the next token if *predicate*(*token*) is true; else return `None` and leave `tokens` unchanged." + "* `pop(`*predicate*`)`: remove and return the next token if *predicate*(*token*) is true; else return `None`, leave `tokens` alone." ] }, { "cell_type": "code", "execution_count": 6, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "tokens = [] # Global variable to hold a list of tokens\n", @@ -202,9 +189,10 @@ " return (tokens[0] if tokens else None)\n", "\n", "def pop(constraint=None):\n", - " \"\"\"Remove and return the first token in `tokens`, or return None if first token fails a constraint.\n", - " `constraint` can be None, a literal string (e.g. pop('=')), or a predicate (e.g. pop(is_varname)).\"\"\"\n", - " if constraint is None or (peek() == constraint) or (callable(constraint) and constraint(peek())):\n", + " \"\"\"Remove and return the first token in `tokens`, or return None if token fails constraint.\n", + " constraint can be None, a literal (e.g. pop('=')), or a predicate (e.g. pop(is_varname)).\"\"\"\n", + " top = peek()\n", + " if constraint is None or (top == constraint) or (callable(constraint) and constraint(top)):\n", " return tokens.pop(0)\n", " \n", "def remove_spaces(line): \n", @@ -228,9 +216,7 @@ { "cell_type": "code", "execution_count": 7, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -255,11 +241,12 @@ " ['100', 'IF', 'X1', '+', '123.4', '+', 'E1', '-', '12.3E4', '<>', \n", " '1.2E-34', '*', '-', '12E34', '+', '1', '+', '\"HI\"', 'THEN', '99'])\n", " assert remove_spaces('10 GO TO 99') == '10GOTO99'\n", - " assert remove_spaces('100 PRINT \"HELLO WORLD\", SIN(X) ^ 2') == '100PRINT\"HELLO WORLD\",SIN(X)^2'\n", + " assert (remove_spaces('100 PRINT \"HELLO WORLD\", SIN(X) ^ 2')\n", + " == '100PRINT\"HELLO WORLD\",SIN(X)^2')\n", " assert lines('one line') == ['one line']\n", " assert lines(program) == [\n", " '10 REM POWER TABLE',\n", - " '11 DATA 8, 4',\n", + " '11 DATA 8, 4',\n", " '15 READ N0, P0',\n", " '20 PRINT \"N\",',\n", " '25 FOR P = 2 to P0',\n", @@ -313,6 +300,43 @@ "test_tokenizer()" ] }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['10 REM POWER TABLE',\n", + " '11 DATA 8, 4',\n", + " '15 READ N0, P0',\n", + " '20 PRINT \"N\",',\n", + " '25 FOR P = 2 to P0',\n", + " '30 PRINT \"N ^\" P,',\n", + " '35 NEXT P',\n", + " '40 PRINT \"SUM\"',\n", + " '45 LET S = 0',\n", + " '50 FOR N = 2 TO N0',\n", + " '55 PRINT N,',\n", + " '60 FOR P = 2 TO P0',\n", + " '65 LET S = S + N ^ P',\n", + " '70 PRINT N ^ P,',\n", + " '75 NEXT P',\n", + " '80 PRINT S',\n", + " '85 NEXT N',\n", + " '99 END']" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lines(program)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -347,10 +371,8 @@ }, { "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": false - }, + "execution_count": 9, + "metadata": {}, "outputs": [], "source": [ "def Grammar(): \n", @@ -408,7 +430,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": { "collapsed": true }, @@ -419,11 +441,11 @@ " num = linenumber()\n", " typ = pop(is_stmt_type) or fail('unknown statement type')\n", " args = []\n", - " for c in grammar[typ]: # For each constituent of rule, call if callable or match if literal string\n", - " if callable(c):\n", - " args.append(c())\n", + " for p in grammar[typ]: # For each part of rule, call if callable or match if literal string\n", + " if callable(p):\n", + " args.append(p())\n", " else:\n", - " pop(c) or fail('expected ' + repr(c))\n", + " pop(p) or fail('expected ' + repr(p))\n", " return Stmt(num, typ, args)" ] }, @@ -436,19 +458,17 @@ }, { "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": false - }, + "execution_count": 11, + "metadata": {}, "outputs": [], "source": [ "def linenumber(): return (int(pop()) if peek().isnumeric() else fail('missing line number'))\n", - "def number(): return (-1 if pop('-') else +1) * float(pop()) # Optional minus sign before number\n", + "def number(): return (-1 if pop('-') else +1) * float(pop()) # Optional minus sign\n", "def step(): return (expression() if pop('STEP') else 1) # 1 is the default step\n", "def relational(): return pop(is_relational) or fail('expected a relational operator')\n", "def varname(): return pop(is_varname) or fail('expected a variable name')\n", "def funcname(): return pop(is_funcname) or fail('expected a function name')\n", - "def anycharacters(): tokens.clear() # The tokens in a REM statement don't matter, so just clear them" + "def anycharacters(): tokens.clear() # Ignore tokens in a REM statement" ] }, { @@ -460,18 +480,20 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": { "collapsed": true }, "outputs": [], "source": [ - "def is_stmt_type(x): return isinstance(x, str) and x in grammar # LET, READ, ...\n", - "def is_funcname(x): return isinstance(x, str) and len(x) == 3 and x.isalpha() # SIN, COS, FNA, FNB, ...\n", - "def is_varname(x): return isinstance(x, str) and len(x) in (1, 2) and x[0].isalpha() # A, A1, A2, B, ...\n", - "def is_label(x): return isinstance(x, str) and x.startswith('\"') # \"HELLO WORLD\", ...\n", - "def is_relational(x): return isinstance(x, str) and x in ('<', '=', '>', '<=', '<>', '>=')\n", - "def is_number(x): return isinstance(x, str) and x and x[0] in '.0123456789' # '3', '.14', ..." + "def is_stmt_type(x): return is_str(x) and x in grammar # LET, READ, ...\n", + "def is_funcname(x): return is_str(x) and len(x) == 3 and x.isalpha() # SIN, COS, FNA, FNB, ...\n", + "def is_varname(x): return is_str(x) and len(x) in (1, 2) and x[0].isalpha() # A, A1, A2, B, ...\n", + "def is_label(x): return is_str(x) and x.startswith('\"') # \"HELLO WORLD\", ...\n", + "def is_relational(x): return is_str(x) and x in ('<', '=', '>', '<=', '<>', '>=')\n", + "def is_number(x): return is_str(x) and x and x[0] in '.0123456789' # '3', '.14', ...\n", + "\n", + "def is_str(x): return isinstance(x, str)" ] }, { @@ -483,10 +505,8 @@ }, { "cell_type": "code", - "execution_count": 12, - "metadata": { - "collapsed": false - }, + "execution_count": 13, + "metadata": {}, "outputs": [], "source": [ "def variable(): \n", @@ -509,7 +529,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "metadata": { "collapsed": true }, @@ -536,7 +556,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "metadata": { "collapsed": true }, @@ -556,10 +576,8 @@ }, { "cell_type": "code", - "execution_count": 15, - "metadata": { - "collapsed": true - }, + "execution_count": 16, + "metadata": {}, "outputs": [], "source": [ "def parse_line(line):\n", @@ -572,8 +590,8 @@ " return stmt\n", " except SyntaxError as err:\n", " print(\"Error in line '{}' at '{}': {}\".format(line, ' '.join(tokens), err))\n", - " return Stmt(0, 'REM', []) # Have to return something: a dummy statement\n", - " \n", + " return Stmt(0, 'REM', []) # Return dummy statement\n", + " \n", "def fail(message): raise SyntaxError(message)" ] }, @@ -588,7 +606,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "metadata": { "collapsed": true }, @@ -596,14 +614,14 @@ "source": [ "from collections import namedtuple, defaultdict, deque\n", "\n", - "Stmt = namedtuple('Stmt', 'num, typ, args') # Statement: '20 GOTO 99' => Stmt(20, 'GOTO', 99)\n", - "Subscript = namedtuple('Subscript', 'var, indexes') # Subscripted reference: 'A(I)' => Subscript('A', ['I'])\n", - "Funcall = namedtuple('Funcall', 'f, x') # Function call: 'SQR(X)' => Funcall('SQR', 'X')\n", - "Opcall = namedtuple('Opcall', 'x, op, y') # Infix operation: 'X + 1' => Opcall('X', '+', 1)\n", - "ForState = namedtuple('ForState', 'continu, end, step') # Data used to control a FOR loop variable\n", + "Stmt = namedtuple('Stmt', 'num, typ, args') # '1 GOTO 9' => Stmt(1, 'GOTO', 9)\n", + "Subscript = namedtuple('Subscript', 'var, indexes') # 'A(I)' => Subscript('A', ['I'])\n", + "Funcall = namedtuple('Funcall', 'f, x') # 'SQR(X)' => Funcall('SQR', 'X')\n", + "Opcall = namedtuple('Opcall', 'x, op, y') # 'X + 1' => Opcall('X', '+', 1)\n", + "ForState = namedtuple('ForState', 'continu, end, step') # Data for FOR loop \n", "\n", "class Function(namedtuple('_', 'parm, body')):\n", - " \"User-defined callable function; 'DEF FNC(X) = X ^ 3' => functions['FNC'] = Function('X', Opcall('X', '^', 3))\"\n", + " \"User-defined function; 'DEF FNC(X) = X ^ 3' => Function('X', Opcall('X', '^', 3))\"\n", " def __call__(self, value): \n", " variables[self.parm] = value # Global assignment to the parameter\n", " return evalu(self.body)" @@ -651,7 +669,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 18, "metadata": { "collapsed": true }, @@ -692,10 +710,8 @@ }, { "cell_type": "code", - "execution_count": 18, - "metadata": { - "collapsed": false - }, + "execution_count": 19, + "metadata": {}, "outputs": [], "source": [ "def expression(prec=1): \n", @@ -724,9 +740,11 @@ " else:\n", " return fail('unknown expression')\n", "\n", - "def precedence(op): return (3 if op == '^' else 2 if op in ('*', '/') else 1 if op in ('+', '-') else 0)\n", + "def precedence(op): \n", + " return (3 if op == '^' else 2 if op in ('*', '/') else 1 if op in ('+', '-') else 0)\n", "\n", - "def associativity(op): return (0 if op == '^' else 1)" + "def associativity(op): \n", + " return (0 if op == '^' else 1)" ] }, { @@ -740,10 +758,8 @@ }, { "cell_type": "code", - "execution_count": 19, - "metadata": { - "collapsed": false - }, + "execution_count": 20, + "metadata": {}, "outputs": [ { "data": { @@ -768,7 +784,7 @@ " Stmt(num=99, typ='END', args=[])]" ] }, - "execution_count": 19, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -788,10 +804,8 @@ }, { "cell_type": "code", - "execution_count": 20, - "metadata": { - "collapsed": false - }, + "execution_count": 21, + "metadata": {}, "outputs": [ { "data": { @@ -799,17 +813,17 @@ "'ok'" ] }, - "execution_count": 20, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "def test_parse(text, result, category=expression):\n", - " \"Test that text can be parsed as a category to yield the semantic result, with no tokens left over.\"\n", + "def test_exp(text, repr):\n", + " \"Test that text can be parsed as an expression to yield repr, with no tokens left over.\"\n", " global tokens\n", " tokens = tokenizer(text)\n", - " return category() == result and not tokens\n", + " return (expression() == repr) and not tokens\n", " \n", "def test_parser():\n", " assert is_funcname('SIN') and is_funcname('FNZ') # Function names are three letters\n", @@ -818,16 +832,17 @@ " assert not is_varname('FNZ') and not is_varname('A10') and not is_varname('')\n", " assert is_relational('>') and is_relational('>=') and not is_relational('+')\n", " \n", - " assert test_parse('A + B * X + C', Opcall(Opcall('A', '+', Opcall('B', '*', 'X')), '+', 'C'))\n", - " assert test_parse('A + B + X + C', Opcall(Opcall(Opcall('A', '+', 'B'), '+', 'X'), '+', 'C'))\n", - " assert test_parse('SIN(X)^2', Opcall(Funcall('SIN', 'X'), '^', 2))\n", - " assert test_parse('10 ^ 2 ^ 3', Opcall(10, '^', Opcall(2, '^', 3))) # right associative\n", - " assert test_parse('10 - 2 - 3', Opcall(Opcall(10, '-', 2), '-', 3)) # left associative\n", - " assert test_parse('A(I)+M(I, J)', Opcall(Subscript(var='A', indexes=['I']), '+', \n", - " Subscript(var='M', indexes=['I', 'J'])))\n", - " assert test_parse('X * -1', Opcall('X', '*', Funcall('NEG', 1.0)))\n", - " assert test_parse('X--Y--Z', Opcall(Opcall('X', '-', Funcall('NEG', 'Y')), '-', Funcall('NEG', 'Z')))\n", - " assert test_parse('((((X))))', 'X')\n", + " assert test_exp('A + B * X + C', Opcall(Opcall('A', '+', Opcall('B', '*', 'X')), '+', 'C'))\n", + " assert test_exp('A + B + X + C', Opcall(Opcall(Opcall('A', '+', 'B'), '+', 'X'), '+', 'C'))\n", + " assert test_exp('SIN(X)^2', Opcall(Funcall('SIN', 'X'), '^', 2))\n", + " assert test_exp('10 ^ 2 ^ 3', Opcall(10, '^', Opcall(2, '^', 3))) # right associative\n", + " assert test_exp('10 - 2 - 3', Opcall(Opcall(10, '-', 2), '-', 3)) # left associative\n", + " assert test_exp('A(I)+M(I, J)', Opcall(Subscript(var='A', indexes=['I']), '+', \n", + " Subscript(var='M', indexes=['I', 'J'])))\n", + " assert test_exp('X * -1', Opcall('X', '*', Funcall('NEG', 1.0)))\n", + " assert test_exp('X--Y--Z', Opcall(Opcall('X', '-', Funcall('NEG', 'Y')), \n", + " '-', Funcall('NEG', 'Z')))\n", + " assert test_exp('((((X))))', 'X')\n", " return 'ok'\n", "\n", "test_parser()" @@ -844,7 +859,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 22, "metadata": { "collapsed": true }, @@ -881,10 +896,8 @@ }, { "cell_type": "code", - "execution_count": 22, - "metadata": { - "collapsed": false - }, + "execution_count": 23, + "metadata": {}, "outputs": [], "source": [ "def execute(stmts): \n", @@ -944,10 +957,8 @@ }, { "cell_type": "code", - "execution_count": 23, - "metadata": { - "collapsed": false - }, + "execution_count": 24, + "metadata": {}, "outputs": [], "source": [ "import math\n", @@ -1040,10 +1051,8 @@ }, { "cell_type": "code", - "execution_count": 24, - "metadata": { - "collapsed": false - }, + "execution_count": 25, + "metadata": {}, "outputs": [], "source": [ "def basic_print(items): \n", @@ -1082,10 +1091,8 @@ }, { "cell_type": "code", - "execution_count": 25, - "metadata": { - "collapsed": false - }, + "execution_count": 26, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1093,7 +1100,7 @@ "text": [ "\n", "10 REM POWER TABLE\n", - "11 DATA 8, 4\n", + "11 DATA 8, 4\n", "15 READ N0, P0\n", "20 PRINT \"N\",\n", "25 FOR P = 2 to P0\n", @@ -1120,9 +1127,8 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 27, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [ @@ -1149,7 +1155,7 @@ " Stmt(num=99, typ='END', args=[])]" ] }, - "execution_count": 26, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -1160,10 +1166,8 @@ }, { "cell_type": "code", - "execution_count": 27, - "metadata": { - "collapsed": false - }, + "execution_count": 28, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1197,10 +1201,8 @@ }, { "cell_type": "code", - "execution_count": 28, - "metadata": { - "collapsed": false - }, + "execution_count": 29, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1237,10 +1239,8 @@ }, { "cell_type": "code", - "execution_count": 29, - "metadata": { - "collapsed": false - }, + "execution_count": 30, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1277,10 +1277,8 @@ }, { "cell_type": "code", - "execution_count": 30, - "metadata": { - "collapsed": false - }, + "execution_count": 31, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1306,10 +1304,8 @@ }, { "cell_type": "code", - "execution_count": 31, - "metadata": { - "collapsed": false - }, + "execution_count": 32, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1369,10 +1365,8 @@ }, { "cell_type": "code", - "execution_count": 32, - "metadata": { - "collapsed": false - }, + "execution_count": 33, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1401,10 +1395,8 @@ }, { "cell_type": "code", - "execution_count": 33, - "metadata": { - "collapsed": false - }, + "execution_count": 34, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1455,39 +1447,37 @@ }, { "cell_type": "code", - "execution_count": 34, - "metadata": { - "collapsed": false - }, + "execution_count": 35, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ "defaultdict(float,\n", - " {'J': 5.0,\n", - " ('S', (1.0, 1.0)): 40.0,\n", - " ('S', (2.0, 4.0)): 21.0,\n", - " ('P', (1.0,)): 1.25,\n", - " ('S', (3.0, 2.0)): 47.0,\n", - " ('S', (2.0, 2.0)): 16.0,\n", - " ('S', (3.0, 3.0)): 29.0,\n", + " {('P', (1.0,)): 1.25,\n", " ('S', (3.0, 5.0)): 33.0,\n", - " ('S', (1.0, 5.0)): 42.0,\n", " ('S', (3.0, 4.0)): 16.0,\n", - " 'I': 3.0,\n", + " ('S', (1.0, 5.0)): 42.0,\n", + " ('S', (2.0, 1.0)): 10.0,\n", " ('P', (3.0,)): 2.5,\n", " ('S', (1.0, 4.0)): 29.0,\n", - " ('S', (2.0, 3.0)): 3.0,\n", - " ('S', (1.0, 3.0)): 37.0,\n", - " ('S', (2.0, 1.0)): 10.0,\n", " ('S', (1.0, 2.0)): 20.0,\n", - " ('S', (2.0, 5.0)): 8.0,\n", " ('S', (3.0, 1.0)): 35.0,\n", + " 'I': 3.0,\n", + " ('S', (2.0, 4.0)): 21.0,\n", + " ('P', (2.0,)): 4.3,\n", + " ('S', (2.0, 5.0)): 8.0,\n", + " ('S', (1.0, 1.0)): 40.0,\n", + " ('S', (3.0, 3.0)): 29.0,\n", + " 'J': 5.0,\n", + " ('S', (3.0, 2.0)): 47.0,\n", " 'S': 169.4,\n", - " ('P', (2.0,)): 4.3})" + " ('S', (2.0, 2.0)): 16.0,\n", + " ('S', (2.0, 3.0)): 3.0,\n", + " ('S', (1.0, 3.0)): 37.0})" ] }, - "execution_count": 34, + "execution_count": 35, "metadata": {}, "output_type": "execute_result" } @@ -1498,19 +1488,17 @@ }, { "cell_type": "code", - "execution_count": 35, - "metadata": { - "collapsed": false - }, + "execution_count": 36, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "6 3 2 6 9 0 0 3 3 6 9 2 7 9 1 2 1 4 4 1 2 7 3 7 8 \n", - "5 2 5 4 4 9 7 7 0 5 4 9 7 7 5 5 4 9 3 8 6 2 6 4 5 \n", - "8 7 6 0 3 4 1 4 2 2 8 1 1 9 2 4 0 1 0 2 1 3 4 0 2 \n", - "9 0 2 7 4 1 8 4 3 2 8 3 9 3 9 3 2 4 6 8 9 0 9 5 9 \n" + "7 2 8 4 9 1 9 8 0 8 3 0 3 4 5 6 4 2 1 6 9 9 9 7 5 \n", + "8 4 1 5 9 9 7 5 5 7 2 0 3 2 1 2 1 8 3 9 9 3 0 0 2 \n", + "2 8 9 7 5 8 9 0 2 7 8 6 7 4 9 9 4 2 5 4 0 9 6 5 3 \n", + "3 3 5 1 7 1 6 1 0 7 3 5 8 1 9 0 4 7 1 7 4 5 1 7 6 \n" ] } ], @@ -1527,10 +1515,8 @@ }, { "cell_type": "code", - "execution_count": 36, - "metadata": { - "collapsed": false - }, + "execution_count": 37, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1564,10 +1550,8 @@ }, { "cell_type": "code", - "execution_count": 37, - "metadata": { - "collapsed": false - }, + "execution_count": 38, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1602,10 +1586,8 @@ }, { "cell_type": "code", - "execution_count": 38, - "metadata": { - "collapsed": false - }, + "execution_count": 39, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1632,10 +1614,8 @@ }, { "cell_type": "code", - "execution_count": 39, - "metadata": { - "collapsed": false - }, + "execution_count": 40, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1668,10 +1648,8 @@ }, { "cell_type": "code", - "execution_count": 40, - "metadata": { - "collapsed": false - }, + "execution_count": 41, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1730,22 +1708,18 @@ }, { "cell_type": "markdown", - "metadata": { - "collapsed": false - }, + "metadata": {}, "source": [ "# Final Program\n", "\n", "Now for a final, longer example, Conway's Game of [Life](https://en.wikipedia.org/wiki/Conway's_Game_of_Life),\n", - "which shows that BASIC is capable of handling a non-trivial problem—but I wouldn't want to rely on it for anything much bigger. This should give us some added confidence in the validity of the interpreter, but I would say the interpreter needs more work before I would trust it. I hope you found working through the interpreter informative, and maybe you have ideas for how to improve it, or to develop an interpreter for another language." + "which shows that BASIC is capable of handling a non-trivial problem—but I wouldn't want to rely on it for anything much bigger. This should give us some added confidence in the validity of the interpreter, but I would say the interpreter needs more work before I would trust it. I hope you found working through the interpreter infortative, and maybe you have ideas for how to improve it, or to develop an interpreter for another language." ] }, { "cell_type": "code", - "execution_count": 41, - "metadata": { - "collapsed": false - }, + "execution_count": 42, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1931,6 +1905,15 @@ "999 END \n", "''')" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] } ], "metadata": { @@ -1949,9 +1932,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.1" + "version": "3.5.3" } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 }