プレゼンテーションZenに触発されてつくろうと思ったが途中で飽きた。あとは画像に埋め込むのと画像から抽出する部分を書けばいいんだけどね。まぁ気が向いたらまたやる。
import sys
import re
from re import Scanner
import Image
LOGLEVEL = 2
def log(level, *msg):
if level <= LOGLEVEL:
print "\t".join(map(str, msg))
class VM(object):
""" Virtual Machine """
def __init__(self,insns):
self.insns = insns
self.stack = []
self.heap = {}
self.labels = self.find_labels(insns)
def run(self):
return_to = []
pc = 0
while pc < len(self.insns):
if len(self.insns[pc]) == 1:
insn = self.insns[pc][0]
else:
insn,arg = self.insns[pc]
if insn == "push":
self.push(arg)
elif insn == "dup":
self.push(self.stack[-1])
elif insn == "copy":
self.push(self.stack[(arg+1)])
elif insn == "swap":
x = self.pop()
y = self.pop()
self.push(x)
self.push(y)
elif insn == "discard":
self.pop()
elif insn == "slide":
x = self.pop()
for i in range(arg):
self.pop()
self.push(x)
elif insn == "add":
self.push(self.pop() + self.pop())
elif insn == "sub":
y = self.pop()
x = self.pop()
self.push(x - y)
elif insn == "mul":
self.push(self.pop() * self.pop())
elif insn == "div":
y = self.pop()
x = self.pop()
self.push(x / y)
elif insn == "mod":
y = self.pop();
x = self.pop()
self.push(x % y)
elif insn == "heap_write":
value = self.pop()
addr = self.pop()
self.heap[addr] = value
elif insn == "heap_read":
addr = self.pop()
value = self.heap[addr]
self.push(value)
elif insn == "jump":
pc = self.jump_to(arg)
elif insn == "jump_zero":
if self.pop() == 0:
pc = self.jump_to(arg)
elif insn == "jump_negative":
if self.pop() < 0:
pc = self.jump_to(arg)
elif insn == "call":
return_to.append(pc)
pc = self.jump_to(arg)
elif insn == "return":
if len(return_to) < 1: IndexError('return_to has no item')
pc = return_to.pop()
elif insn == "exit":
return
elif insn == "char_out":
sys.stdout.write(chr(self.pop()))
elif insn == "num_out":
print self.pop()
elif insn == "char_in":
addr = self.pop()
self.heap[addr] = ord(sys.stdin.read(1))
elif insn == "num_in":
addr = self.pop()
self.heap[addr] = int(sys.stdin.read())
pc += 1
print "プログラムの最後がexitではない"
def push(self, item):
if type(item).__name__ != 'int': raise TypeError('Not a Integer')
self.stack.append(item)
log(2, "stack op: ",self.stack)
def pop(self):
if len(self.stack) < 1: raise IndexError('stack has no item')
return self.stack.pop()
def jump_to(self, name):
pc = self.labels[name]
return pc
def find_labels(self, insns):
labels = {}
for i,tp in enumerate(insns):
if tp[0] == 'label':
labels[tp[1]] = i
return labels
### Scanner
rnum = "([01]+)2"
rlabel = rnum
scanner = Scanner([
(r"00%s" % rnum, lambda s,token: ("push", to_num(re.sub(r'^00','',token)))),
(r"020", lambda s,token: ("dup",)),
(r"010%s" % rnum, lambda s,token: ("copy", to_num(re.sub(r'^010','',token)))),
(r"021", lambda s,token: ("swap",)),
(r"022", lambda s,token: ("discard",)),
(r"012%s" % rnum, lambda s,token: ("slide", to_num(re.sub(r'^012','',token)))),
(r"1000", lambda s,token: ("add",)),
(r"1001", lambda s,token: ("sub",)),
(r"1002", lambda s,token: ("mul",)),
(r"1010", lambda s,token: ("div",)),
(r"1011", lambda s,token: ("mod",)),
(r"110", lambda s,token: ("heap_write",)),
(r"111", lambda s,token: ("heap_read",)),
(r"200%s" % rlabel, lambda s,token: ("label", to_label(re.sub(r'^200','',token)))),
(r"201%s" % rlabel, lambda s,token: ("call", to_label(re.sub(r'^201','',token)))),
(r"202%s" % rlabel, lambda s,token: ("jump", to_label(re.sub(r'^202','',token)))),
(r"210%s" % rlabel, lambda s,token: ("jump_zero", to_label(re.sub(r'^210','',token)))),
(r"211%s" % rlabel, lambda s,token: ("jump_negative", to_label(re.sub(r'^211','',token)))),
(r"212", lambda s,token: ("return",)),
(r"222", lambda s,token: ("exit",)),
(r"1200", lambda s,token: ("char_out",)),
(r"1201", lambda s,token: ("num_out",)),
(r"1210", lambda s,token: ("char_in",)),
(r"1211", lambda s,token: ("num_in",))
])
def to_num(str):
n = int(str[1:-1],2)
if str[0] == '0': return n
elif str[0] == '1': return -n
else: raise TypeError('Not a Integer')
def to_label(str): return str[:-1]
### Parser
def parse_image(file):
"pixelのrgpの合計のmod3をつなげた文字列を返す"
modstr = ""
im = Image.open(file)
height,width = im.size
for h in range(height):
for w in range(width):
r,g,b = im.getpixel((h,w))
modstr += str((r+g+b)%3)
return modstr
def extract_code(str):
"""10個以上の210の並びと10個以上の210の並びに挟まれた領域がコード領域"""
return re.search(r'(210){10,}([012]+?)(210){10,}').group(2)
if __name__ == '__main__':
# print "Hello World\n================="
# t = [('push',10),('push',100),('push',108),('push',114),('push',111),('push',87),('push',32),
# ('push',111),('push',108),('push',108),('push',101),('push',72),('char_out',),('char_out',),
# ('char_out',),('char_out',),('char_out',),('char_out',),('char_out',),('char_out',),
# ('char_out',),('char_out',),('char_out',),('char_out',),('exit',),]
# vm = VM(t)
# vm.run()
print "token check\n================"
tokens, remainder = scanner.scan("0001000012000110010020001101100200011100102000110111120001010111200010000020001101111200011011002000110110020001100101200010010002120012001200120012001200120012001200120012001200222")
print tokens
print "token -> vm\n================"
vm2 = VM(tokens)