Pythonで作る奇妙なプログラミング言語 その1(HQ9+)
二ヶ月ほど放置しておりました。
その間何もやってなかったわけではないです。主にGoogle App Engineまわりで色々やってました。
とかここに書くネタはあるんですが、ええと、そのうち書きます。
そんなことより、ちょいとRubyを勉強しなきゃいけない事情がありまして、1年ほど前に買った
Rubyで作る奇妙なプログラミング言語 ~Esoteric Language~
- 作者: 原悠
- 出版社/メーカー: 毎日コミュニケーションズ
- 発売日: 2008/12/20
- メディア: 単行本(ソフトカバー)
- 購入: 8人 クリック: 148回
- この商品を含むブログ (69件) を見る
この本は、Hello, world!を表示するのにわざわざ
+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-. ------------.<++++++++.--------.+++.------.--------.>+.
と書かなければいけない、お馴染みBrainf*ckに代表されるような
「奇妙な言語(Esoteric Language)」の処理系を実装しながら、プログラミング言語がどのようにできているのか、その秘密に迫っていく。最後まで読み終えれば、きっと自分でも新しいプログラミング言語を作れるようになっているだろう。
というものです。
買った直後に半分ぐらい読みましたが、かなり面白いですね。コードのレベル自体はそんなに高くないので、入門書を読んだばかりの初心者でもついていけると思いますし、初心者から中級者への橋渡しに丁度いいんじゃないかと思います。
再びこれを読んで勉強しているところですが、折角なのでここに出てるプログラムをPythonに移植して、RubyとPythonの特徴を比べてみようじゃないか、ということでやってみたいと思います。
その第1弾が今回のHQ9+です。
HQ9+ - Wikipedia
HQ9+はクリフ・ビッフルによって作られたジョーク向け難解プログラミング言語である。実用言語ではない。
...
というたった4つの命令からなる実用性ゼロの言語ですが、これからもっとイカれた言語を実装していくための準備体操としてはまずまずでしょう。
hq9.py
import sys class HQ9Plus(): def __init__(self, src): self._src = src self._count = 0 def run(self): for c in self._src: if c == 'H': self._hello() if c == 'Q': self._print_source() if c == '9': self._print_99bottles_of_beer() if c == '+': self._increment() def _hello(self): print 'Hello, world!' def _print_source(self): print self._src def _print_99bottles_of_beer(self): for i in range(99, -1, -1): if i == 0: before = 'no more bottles' after = '99 bottles' elif i == 1: before = '1 bottle' after = 'no more bottle' elif i == 2: before = '2 bottles' after = '1 bottle' else: before = '%d bottles' % i after = '%d bottles' % (i-1) if i == 0: action = 'Go to the store and buy some more' else: action = 'Take one down and pass it around' print '%s of beer on the wall, %s of beer.' % (before.capitalize(), before) print '%s, %s of beer on the wall' % (action, after) if not i == 0: print '' def _increment(self): self._count += 1 try: src = open(sys.argv[1]).read() except IOError: src = sys.argv[1] except IndexError: src = raw_input() hq9plus = HQ9Plus(src) hq9plus.run()
できました。早速動かしてみましょう。入力はファイルから、コマンドライン引数から、標準入力からの3つに対応していますが、ここではファイルを読み込ませます。ソースコードは
h.hq9
H
とってもシンプル!!
C:\hogehoge>python hq9.py h.hq9
Hello, world!
動きました。「ハロワ表示させただけじぇえねか馬鹿にしてんのか!」との声が聞こえてきそうですが仕様なので諦めてください。
Rubyとの比較で気付いた点をいくつか
- やっぱりメソッド定義の時にいちいちself入力するの面倒臭い。一方Rubyは引数取らない場合はメソッド名に続く()を省略できる(呼び出し時も同様)けど、それはそれで変数呼び出しと勘違いしそう。
- インスタンス変数やクラスメソッドを呼び出す時にself.foo()とselfつけるのも面倒臭い。Rubyはインスタンス変数は先頭に@をつけるし、クラスメソッドは明示しなくてもいい。ただこれは一長一短ありそう。
- RubyのARGFに相当するものはPythonにないのかな?同じ事を実装するのに例外処理とかしないといけないからやや面倒
- ループについて、Rubyはfor, whileに加えてeach, times, upto, downtoと沢山ある。全てfor(たまにwhile)で処理するPythonの方がシンプルで好きかな
さて、このHQ9+はもちろん言語として使い物になりません。四則演算すらできませんし。次回は他のメジャーな言語と同等の機能を備える、チューリング完全な言語を実装します。
そう、冒頭にも挙げた、あのBrainf*ckです。