Misaインタプリタ
こないだ会社でMisaというプログラミング言語を教えてもらいました。といってもBrainfuckの派生言語です。
ちょっと仕事に疲れていたので、息抜きにPythonでインタプリタを書いてみました。といっても、あまりに単純なので構文解析と言えるような処理はありません。
書いてて感じたことですが、Brainfuckは言語が単純なだけに、基礎的な原理を理解させる教材として結構よいかも知れません。
- -vオプションをつけて動かすと、おおよその実行状況が分かります。
- ファイルの文字コードは、みんなutf8のつもりで動いてます。
#!/usr/bin/python # -*- coding: utf-8 -*- import sys, getopt, codecs EOF = 'eof' def cmd(ch): CMD = [ ['>', '→', '〜', 'ー'], ['<', '←', '★', '☆'], ['+', 'あ', 'ぁ', 'お', 'ぉ'], ['-', 'っ', 'ッ'], ['.', '!'], [',', '?'], ['[', '「', '『'], [']', '」', '』'],] for clist in CMD: for c in clist: if c == ch: return clist[0] return ' ' class Misa: def __init__(self, lines, verbose): self.p = 0 self.mem = 3000*[0] self.stack = [] self.lines = lines self.lno = 0 self.cno = 0 self.cmd = '' self.char = '' self.verbose = verbose def log(self, s): if self.verbose: print s, def loglog(self): self.log('char%3d:%2s --> %s : [%d]=%d\n' % (self.cno+1, self.char, self.cmd, self.p, self.mem[self.p])) def currentline(self): if self.lno >= len(self.lines): return '' return self.lines[self.lno] def is_control_cmd(self): return self.cmd == '[' or self.cmd == ']' def getc(self): if self.cno == 0: self.log("line%3d: %s\n" % (self.lno+1, self.currentline())) if self.lno >= len(self.lines): return EOF if self.cno >= len(self.currentline()): return EOF return self.lines[self.lno][self.cno] def forward(self): self.cno = self.cno + 1 if self.cno >= len(self.currentline()): self.lno = self.lno + 1 self.cno = 0 def run(self): while True: self.char = self.getc() if self.char == EOF: break self.apply(cmd(self.char)) def apply(self, ch): self.cmd = ch if self.is_control_cmd(): self.loglog() if ch == '>': self.p = self.p + 1 elif ch == '<': self.p = self.p - 1 elif ch == '+': self.mem[self.p] = self.mem[self.p] + 1 elif ch == '-': self.mem[self.p] = self.mem[self.p] - 1 elif ch == '.': self.outp() elif ch == ',': self.mem[self.p] = ord(sys.stdin.read(1)) elif ch == '[': self.beginloop() elif ch == ']': (self.lno, self.cno) = self.stack[len(self.stack)-1] if not self.is_control_cmd(): self.loglog() self.forward() def jump2loopend(self): jump = 1 c = '' while jump != 0 and c != EOF: c = cmd(self.getc()) if c == '[': jump = jump + 1 elif c == ']': jump = jump - 1 self.forward() del self.stack[len(self.stack)-1] def outp(self): self.log('output :') sys.stdout.write('%c' % self.mem[self.p]) self.log('\n') def beginloop(self): if self.mem[self.p] != 0: self.stack.append((self.lno, self.cno-1)) else: self.forward() self.jump2loopend() if __name__ == "__main__": try: optlist, args = getopt.getopt(sys.argv[1:], 'v') if len(args) == 1: Misa(codecs.open(args[0], 'r', 'utf8').readlines(), len(optlist) > 0).run(); else: print "Usage: misa.py [-v] filename" except Exception, e: print e