試される大地から

furaiboが送る技術ブログ。プログラミングのTipsなど書いていきます。

brainfuck系言語インタープリタ(もどき)生成スクリプト


最近はプログラミング言語コンパイラインタープリタを作りたいと考えていて、そのためにコンパイラガベージコレクションなどについてこれから本格的に勉強しようかと考えています。



とは言え、コンパイラ技術というのは難しいもので素人がすぐに作れるシロモノではないので、手始めにプログラミング言語brainfuckインタープリタを作ってみました(仮想機械も介さないので、本来はインタープリタと呼ぶべきではないかもしれませんが)。そして、どうせならとbrainfuck系列のプログラミング言語インタープリタ生成スクリプトもつくってみました。


ダウンロードは、Githubから。
https://github.com/furaibo/tinytools/tree/master/bfgenerator




使い方は、以下のzipファイルを解凍後、以下の画像のようにします。


f:id:incodethx3932:20140113233443p:plain

f:id:incodethx3932:20140113233448p:plain

f:id:incodethx3932:20140113233450p:plain

f:id:incodethx3932:20140113233459p:plain

f:id:incodethx3932:20140113233501p:plain

f:id:incodethx3932:20140114010341p:plain



brainfuckについて


brainfuckについての詳細は以下のページから御覧ください。

プログラミング言語/Brainfuck - プログラミングスレまとめ in VIP

Brainfuck - Wikipedia




brainfuckは、ちょっと前に話題になったプログラミング言語である「nyaruko」や、「neko mimi Fu**」といった言語の元となっています。

「Nyaruko」。それは(」・ω・)」うー!(/・ω・)/にゃー!でプログラムが書ける言語 : Kotaku JAPAN

新言語 neko mimi Fu**♥ - reroの日記




言語インタープリタ生成スクリプトで作成したソースコードを以下に示したいと思います。インタープリタPythonによって書かれています。





プログラミング言語「nyaruko」のインタープリタ

#!/usr/bin/python
#-*- coding:utf-8 -*-
# プログラミング言語「nyaruko」のインタープリタ
	
# パッケージのインポート
import os
import sys
	
# 変数
file_buffer = ""		# ファイルの読み込み結果
file_array  = []		# 文字列を一文字ずつ分割したリスト
indent_char = "    "		# インデントの文字
depth       = 0			# pythonのインデントの深さ
source      = ""		# pythonスクリプト変換後のソースコード
	
# コマンドライン引数の確認
argvs = sys.argv  		# コマンドライン引数を格納したリストの取得
argc = len(argvs) 		# 引数の個数
if argc == 1:
	sys.exit("コマンドライン引数としてbrainf*ckのソースファイル名を指定してください。")
elif argc > 2:
	sys.exit("引数が多すぎます。")

# 入力ファイル名を得る
input_file = argvs[1]
	
# ファイルの読み込み
if os.path.exists(input_file):
	for line in open(input_file, 'r'):
		file_buffer += line
else:
	sys.exit("指定したファイルは存在しません。")

# ファイルから得た文字列を一度brainfuckのソースに変換
file_buffer = file_buffer.replace("(」・ω・)」うー!(/・ω・)/にゃー!", "+")
file_buffer = file_buffer.replace("(」・ω・)」うー!!!(/・ω・)/にゃー!!!", "-")
file_buffer = file_buffer.replace("Let's\(・ω・)/にゃー", ".")
file_buffer = file_buffer.replace("cosmic!", ",")
file_buffer = file_buffer.replace("(」・ω・)」うー(/・ω・)/にゃー", ">")
file_buffer = file_buffer.replace("(」・ω・)」うー!!(/・ω・)/にゃー!!", "<")
file_buffer = file_buffer.replace("CHAOS☆CHAOS!", "[")
file_buffer = file_buffer.replace("I WANNA CHAOS!", "]")

# 文字列をリストに変換
file_array = list(file_buffer)	# 一文字ずつリストに格納される
file_array.remove('\n')		# 改行文字の要素をリストから取り除く
	
# ファイル文字列をpythonソースコードに変換
source += "#-*- coding:utf-8 -*-\n\n"
source += "import sys\n\n"
source += "buf = \"\"\n"
source += "x   = []\n"
source += "xc  = 0\n\n"
source += "for i in range(32768):\n"
source += (indent_char + "x.append(0)\n\n")
	
for i in file_array:
	# インデントの挿入
	if depth > 0:
		for j in range(depth):
			source += indent_char

	# 出現した文字によって分岐
	if i == '+':
		source += "x[xc] += 1\n"
	elif i == '-':
		source += "x[xc] -= 1\n"
	elif i == '.':
		source += "sys.stdout.write(chr(x[xc]))\n"
	elif i == ',':
		source += "x[xc] = getchar()\n"
	elif i == '>':
		source += "xc += 1\n"
	elif i == '<':
		source += "xc -= 1\n"
	elif i == '[':
		source += "while x[xc] != 0:\n"
		depth += 1
	elif i == ']':
		source += "\n"
		depth -= 1
	
	
# 変換したpythonソースコードを一時ファイルに書き込む
f = open('tmp.py', "w")
f.write(source)
f.close()

# 一時ファイルの実行
os.system('python tmp.py')

# 一時ファイルを削除する
os.remove('tmp.py')


ちなみに、brainfuckインタープリタソースコードは以下の通り

#!/usr/bin/python
#-*- coding:utf-8 -*-
# プログラミング言語「brainfuck」のインタープリタ

# パッケージのインポート
import os
import sys


# 変数
file_buffer = ""		# ファイルの読み込み結果
file_array  = []		# 文字列を一文字ずつ分割したリスト
indent_char = "    "		# インデントの文字
depth       = 0			# pythonのインデントの深さ
source      = ""		# pythonスクリプト変換後のソースコード

# コマンドライン引数の確認
argvs = sys.argv  		# コマンドライン引数を格納したリストの取得
argc = len(argvs) 		# 引数の個数
if argc == 1:
	sys.exit("コマンドライン引数としてbrainf*ckのソースファイル名を指定してください。")
elif argc > 2:
	sys.exit("引数が多すぎます。")

# 入力ファイル名を得る
input_file = argvs[1]

# ファイルの読み込み
if os.path.exists(input_file):
	for line in open('test.bf', 'r'):
		file_buffer += line
else:
	sys.exit("指定したファイルは存在しません。")

# 文字列をリストに変換
file_array = list(file_buffer)	# 一文字ずつリストに格納される
file_array.remove('\n')		# 改行文字の要素をリストから取り除く

# ファイル文字列をpythonソースコードに変換
source += "#-*- coding:utf-8 -*-\n\n"
source += "import sys\n\n"
source += "buf = \"\"\n"
source += "x   = []\n"
source += "xc  = 0\n\n"
source += "for i in range(32768):\n"
source += (indent_char + "x.append(0)\n\n")

for i in file_array:
	# インデントの挿入
	if depth > 0:
		for j in range(depth):
			source += indent_char

	# 出現した文字によって分岐
	if i == '+':
		source += "x[xc] += 1\n"
	elif i == '-':
		source += "x[xc] -= 1\n"
	elif i == '.':
		source += "sys.stdout.write(chr(x[xc]))\n"
	elif i == ',':
		source += "x[xc] = getchar()\n"
	elif i == '>':
		source += "xc += 1\n"
	elif i == '<':
		source += "xc -= 1\n"
	elif i == '[':
		source += "while x[xc] != 0:\n"
		depth += 1
	elif i == ']':
		source += "\n"
		depth -= 1


# 変換したpythonソースコードを一時ファイルに書き込む
f = open('tmp.py', "w")
f.write(source)
f.close()

# 一時ファイルの実行
os.system('python tmp.py')

# 一時ファイルを削除する
os.remove('tmp.py')




これらのソースコードは以下のアーカイブページに有る、brainfuckプログラムをC言語へと変換するプログラムBF2c.cを元に書かれています。

Index of /brainfuck




この先暇があれば、なんちゃってインタープリタではなく本当の仮想機械を利用したインタープリタC言語で実装したいと思います。





その他、プログラミング時に参考にしたページは以下の通り。

Python: コマンドライン引数の取得 – sys.argv変数

putchar(8)