Created
May 1, 2012 16:10
-
-
Save tokoroten/2569226 to your computer and use it in GitHub Desktop.
forth interpriter implimented by python.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
import re | |
class forth(): | |
Stack = [] | |
FunctionList = {} | |
VariableList = {} | |
ParsedCode = [] | |
def __init__(self, text): | |
pc = self.perse(text) | |
#空文字列を取り除く | |
for x in pc: | |
if x != '': | |
self.ParsedCode.append(x) | |
pass | |
def __del__(self): | |
pass | |
def perse(self, text): | |
ret = "" | |
for x in text.split("\n"): | |
t = x.split("#") | |
ret += t[0] + " " | |
return re.split("\s+", ret) | |
def execute(self): | |
cl = self.ParsedCode | |
pc = [0] | |
nc = [0] | |
self._execute(cl, pc, nc) | |
def _execute(self, cl, pc , nc): | |
while(pc[0] < len(cl)): | |
if (self.operator(cl, pc, nc)): | |
pass #operatorが評価されたので、スタックに積まない | |
else: | |
try: | |
#数値化できれば数値化する | |
i = int(cl[pc[0]]) | |
self.Stack.append(i) | |
except: | |
#数値化できないので、文字列として積む | |
self.Stack.append(cl[pc[0]]) | |
pc[0] += 1 | |
def operator(self, cl, pc, nc): | |
#stack の回転関数 上からn個をm回回転させる n>mが前提 | |
def rot_p(n,m): | |
front = self.Stack[:len(self.Stack) - n] | |
back = self.Stack[-n:] | |
self.Stack = front + back[-m:] + back[:n - m] | |
ope = cl[pc[0]] | |
#四則演算系 | |
if ope == "+": | |
self.Stack.append(self.Stack.pop() + self.Stack.pop()) | |
elif ope == "-": | |
rot_p(2,1) | |
self.Stack.append(self.Stack.pop() - self.Stack.pop()) | |
elif ope == "*": | |
self.Stack.append(self.Stack.pop() * self.Stack.pop()) | |
elif ope == "/": | |
rot_p(2,1) | |
self.Stack.append(self.Stack.pop() / self.Stack.pop()) | |
#比較演算系 | |
elif ope == "<": | |
rot_p(2,1) | |
self.Stack.append(int(self.Stack.pop() < self.Stack.pop())) | |
elif ope == "<=": | |
rot_p(2,1) | |
self.Stack.append(int(self.Stack.pop() <= self.Stack.pop())) | |
elif ope == ">": | |
rot_p(2,1) | |
self.Stack.append(int(self.Stack.pop() > self.Stack.pop())) | |
elif ope == ">=": | |
rot_p(2,1) | |
self.Stack.append(int(self.Stack.pop() >= self.Stack.pop())) | |
elif ope == "==" or ope == "=": | |
rot_p(2,1) | |
self.Stack.append(int(self.Stack.pop() == self.Stack.pop())) | |
elif ope == "<>" or ope == "!=": | |
rot_p(2,1) | |
self.Stack.append(int(self.Stack.pop() != self.Stack.pop())) | |
#ビット演算系 | |
elif ope == "|": | |
self.Stack.append(int(self.Stack.pop() | self.Stack.pop())) | |
elif ope == "&": | |
self.Stack.append(int(self.Stack.pop() & self.Stack.pop())) | |
elif ope == "^": | |
self.Stack.append(int(self.Stack.pop() ^ self.Stack.pop())) | |
elif ope == "~": | |
self.Stack.append(int(~self.Stack.pop())) | |
#論理演算系 めんどくさいのでドモルガンの定理を利用 | |
elif ope == "or": | |
self.Stack.append(int(not self.Stack.pop() and not self.Stack.pop())) | |
elif ope == "and": | |
self.Stack.append(int(not self.Stack.pop() or not self.Stack.pop())) | |
elif ope == "not": | |
self.Stack.append(int(not self.Stack.pop)) | |
#スタック操作系 | |
elif ope == "dup": | |
s = self.Stack.pop() | |
self.Stack.append(s) | |
self.Stack.append(s) | |
elif ope == "load": | |
n = self.Stack.pop() | |
self.Stack.append(self.Stack[-n]) | |
elif ope == "drop": | |
self.Stack.pop() | |
elif ope == "swap": | |
rot_p(2,1) | |
elif ope == "rot": | |
rot_p(3,1) | |
elif ope == "over": | |
self.Stack.append(self.Stack[-2]) | |
elif ope == "dump": | |
print self.Stack | |
#表示系 | |
elif ope == ".": | |
print self.Stack.pop() | |
elif ope =="if": | |
if self.Stack.pop(): | |
nc[0] += 1 | |
pass | |
else: | |
#elseか、endifまで読み飛ばす | |
n = 0 | |
while(True): | |
pc[0] += 1 | |
o = cl[pc[0]] | |
if o == "if": | |
n += 1 | |
elif o == "else": | |
if n == 0: | |
nc[0] += 1 | |
break | |
elif o == "endif": | |
if n == 0: | |
break | |
else: | |
n -= 1 | |
elif ope == "else": | |
#endif まで読み飛ばす | |
n = 0 | |
while(True): | |
pc[0] += 1 | |
o = cl[pc[0]] | |
if o == "if": | |
n += 1 | |
elif o == "endif": | |
if n == 0: | |
break | |
else: | |
n -= 1 | |
elif ope == "endif": | |
pass | |
#手続きの宣言 | |
elif ope == ":" : #これdefか何かに変える? | |
pc[0] += 1 | |
name = cl[pc[0]] | |
self.FunctionList[name] = [] | |
while(True): | |
pc[0] += 1 | |
c = cl[pc[0]] | |
if c == ";": | |
break | |
else: | |
self.FunctionList[name].append(c) | |
elif self.FunctionList.has_key(ope): | |
self._execute(self.FunctionList[ope],[0],[0]) | |
#変数の代入と参照 | |
elif ope == "!": | |
name = self.Stack.pop() | |
self.VariableList[name] = self.Stack.pop() | |
elif ope == "@": | |
name = self.Stack.pop() | |
self.Stack.append(self.VariableList[name]) | |
#while文 | |
elif ope == "while": | |
if self.Stack.pop(): | |
pass | |
else: | |
#対応するrepeat まで読み飛ばす | |
n = 0 | |
while(True): | |
pc[0] += 1 | |
o = cl[pc[0]] | |
if o == "while": | |
n += 1 | |
elif o == "repeat": | |
if n == 0: | |
break | |
else: | |
n -= 1 | |
elif ope == "repeat": | |
#whileの一個前まで戻る | |
n = 0 | |
while(True): | |
pc[0] -= 1 | |
o = cl[pc[0]] | |
if o == "while": | |
if n == 0: | |
#一個前に戻す | |
pc[0] -= 1 | |
break | |
else: | |
n -= 1 | |
elif o == "repeat": | |
n += 1 | |
else: | |
return False | |
return True | |
f = forth( | |
''' | |
1 20 - . # 1-20をして表示する | |
1 10 < . # 1<10をして表示する | |
1 if # スタックの一番上を評価する | |
here is TRUE . . . # trueならここが実行される | |
0 if | |
NOTCOMING . # こない | |
endif | |
else | |
here is FALSE . . . # falseならばここが実行される | |
endif | |
100 n ! # nに100を代入する | |
n @ . # nを参照して表示する | |
: hoge n @ 1 - n ! ; # void hoge(){n = n - 1} を定義する | |
hoge hoge hoge # hogeを三回実行する | |
n @ . # nを表示してみる(97が表示される) | |
# 0~9までカウントする | |
0 n ! # nに0を代入する | |
1 # スタックの一番上が真ならwhileを実行 | |
while | |
n @ . # nの値を表示する | |
n @ 1 + n ! # n=n+1 | |
n @ 10 < # n < 10 をpushする | |
repeat # whileに戻る | |
: square dup * ; # 二乗する関数を定義する | |
10 square . | |
: fac # 再帰で階乗を書いてみる。スタックを二個引数に取る | |
dump # 突入時にメモリダンプしてみる | |
dup | |
if | |
over over * | |
over 1 - | |
fac | |
rot drop drop # ローカル変数を開放する(?) | |
dump | |
else | |
drop | |
endif | |
; | |
1 10 fac . # 1*10!の意味 | |
''') | |
f.execute() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
codepad result is here.
http://codepad.org/EqMhkKte