Add files via upload

This commit is contained in:
Peter Norvig 2018-01-12 21:30:50 -08:00 committed by GitHub
parent c11f19c640
commit 2714d19d9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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&mdash;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&mdash;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
}