Skip to content

Instantly share code, notes, and snippets.

@mg6
Last active August 29, 2015 14:17
Show Gist options
  • Save mg6/34a9f822554b49782cd8 to your computer and use it in GitHub Desktop.
Save mg6/34a9f822554b49782cd8 to your computer and use it in GitHub Desktop.
W-machine interpreter written in Python
#!/usr/bin/env python3
#
# wu.py - W-machine interpreter written in Python
# Copyright (C) 2015 Maciej Gamrat <maciej@gamrat.it>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from collections import deque
# instructions
STP = 'STP' # stop
POB = 'POB' # get variable
LAD = 'LAD' # set variable
DOD = 'DOD' # add
ODE = 'ODE' # subtract
SOB = 'SOB' # unconditional jump
SOM = 'SOM' # conditional jump (if: Acc < 0 <=> Z == 1)
WPR = 'WPR' # input
WYP = 'WYP' # output
RST = 'RST' # constant
RPA = 'RPA' # variable
# custom instructions
DUMP = 'DUMP'
class StopExecution(Exception):
pass
class Wu:
def __init__(self, code, debug=False):
self.ak = 0
self.ins = 0
self.labels = {}
self.variables = {}
self.program = []
self.debug = debug
self.lexer(code)
def lexer(self, code):
code = deque(code.strip().upper().split())
at = 0
while len(code) > 0:
tok = code.popleft()
if tok in (POB, LAD, WPR, WYP, DOD, ODE, SOB, SOM):
self.program.append((tok, code.popleft()))
at += 1
elif tok in (STP, DUMP):
self.program.append((tok,))
at += 1
elif tok.endswith(':'):
next_tok = code.popleft()
if next_tok not in (RST, RPA):
code.appendleft(next_tok) # unshift
self.labels[tok[:-1]] = at
elif next_tok == RPA:
self.variables[tok[:-1]] = None
elif next_tok == RST:
num = code.popleft().lower()
if num[-1] == 'b':
num = int(num[:-1], 2)
elif num[-1] == 'd':
num = int(num[:-1], 10)
elif num[-1] == 'h':
num = int(num[:-1], 16)
else:
num = int(num, 10)
self.variables[tok[:-1]] = num
def execute(self, ins):
cmd = ins[0]
arg = ins[1] if len(ins) > 1 else None
self.ins += 1
self.at += 1
# standard
if cmd == POB:
self.ak = self.variables[arg]
elif cmd == LAD:
self.variables[arg] = self.ak
elif cmd == WPR:
self.variables[arg] = int(input('%s := ' % arg))
elif cmd == WYP:
print('%s = %s' % (arg, self.variables[arg]))
elif cmd == DOD:
self.ak += self.variables[arg]
elif cmd == ODE:
self.ak -= self.variables[arg]
elif cmd == SOB:
self.at = self.labels[arg]
elif cmd == SOM:
if self.ak < 0: self.at = self.labels[arg]
elif cmd == STP:
raise StopExecution
# custom
elif cmd == DUMP:
print(self)
def run(self):
self.at = 0
if len(self.program) == 0:
print('Error: Empty instruction list supplied.')
return
while True:
try:
instr = self.program[self.at]
readable = ' '.join(instr) if type(instr) == tuple else instr
if self.debug: print('@%d %s' % (self.at, readable))
self.execute(instr)
except StopExecution:
if self.debug: print('Info: Execution finished.')
break
except IndexError:
print('Error: Program counter out of range (STP missing).')
break
except KeyError as e:
print('Error: Reading from undefinied variable %s.' % e)
break
finally:
if self.debug: print(self)
def __str__(self):
return '<Wu #{} ak={} vars={}>'.format(self.ins, self.ak, self.variables)
if __name__ == '__main__':
import sys
if len(sys.argv) < 2:
print("W-machine interpreter written in Python")
print("Usage: %s file.wu [-d]" % sys.argv[0])
print(" file.wu input file with W-machine instructions")
print(" -d if present, show debug info")
exit(0)
with open(sys.argv[1], 'r') as f:
code = f.read()
dbg = '-d' in sys.argv or '--debug' in sys.argv
Wu(code, debug=dbg).run()
POB ZERO
LAD N
WPR A
WPR B
LOOP:
POB A
ODE B
SOM END
LAD A
POB N
DOD ONE
LAD N
SOB LOOP
END:
WYP N
STP
A: RPA
B: RPA
ONE: RST 1d
ZERO: RST 0d
N: RPA
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment