Skip to content

Instantly share code, notes, and snippets.

@tokoroten
Created May 1, 2012 16:10
Show Gist options
  • Save tokoroten/2569226 to your computer and use it in GitHub Desktop.
Save tokoroten/2569226 to your computer and use it in GitHub Desktop.
forth interpriter implimented by python.
# -*- 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()
@tokoroten
Copy link
Author

codepad result is here.
http://codepad.org/EqMhkKte

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment