6: 2009-12-26 (土) 16:40:36 HOSINO[6] [7] | 7: 2009-12-27 (日) 07:36:44 HOSINO[6] [8] | ||
---|---|---|---|
Line 331: | Line 331: | ||
**BrainCrashでプログラミング [#i3b6f609] | **BrainCrashでプログラミング [#i3b6f609] | ||
+ | BrainCrashはBrainf*ckを拡張した言語です。~ | ||
+ | 新たにビット演算を行う命令が加えられました。~ | ||
+ | また、0バイトでHello, world!プログラムが書ける言語としても有名です。~ | ||
+ | ip02.g01でBrainCrashで書かれたプログラムを実行するには、~ | ||
+ | プロンプト>efg01 ip02 file:ファイル名 type:2 | ||
+ | と入力します。~ | ||
+ | 以下に、BrainCrashの追加機能を示します。~ | ||
+ | 追加命令~ | ||
+ | | レジスタが指しているメモリのアドレスにある値と、その次のアドレスにある値をOR計算し、 | ||
+ | レジスタが指しているアドレスの次のアドレスに値を入れます。 | ||
+ | また、レジスタの値は一つ進められます。 | ||
+ | & レジスタが指しているメモリのアドレスにある値と、その次のアドレスにある値をAND計算し、 | ||
+ | レジスタが指しているアドレスの次のアドレスに値を入れます。 | ||
+ | また、レジスタの値は一つ進められます。 | ||
+ | ~ レジスタが指しているメモリのアドレスにある値をビット反転(NOT計算)させます。 | ||
+ | レジスタの値は変化しません。 | ||
+ | ^ レジスタが指しているメモリのアドレスにある値と、その次のアドレスにある値をXOR計算し、 | ||
+ | レジスタが指しているアドレスの次のアドレスに値を入れます。 | ||
+ | また、レジスタの値は一つ進められます。 | ||
+ | 開始、終了時の挙動~ | ||
+ | 処理開始時、メモリにはHello, world!に相当する72,101,108,108,111,44,32,119,111,114,108,100,33が0番地よりこの順で積まれます。 | ||
+ | 終了時、現在レジスタが指し示すアドレスの値が0になるまでレジスタを1づつ進めて出力します。 | ||
+ | よって、BrainCrashでHello, worldを書くと、以下のようになります。~ | ||
+ | Let us write Hello world ! | ||
+ | 何かしら英文が書かれていますが、全部コメントなので無視されます。~ | ||
+ | これを実行すると、まずメモリにHello, world!に当たる文字コードが0番地から順に積まれ、レジスタは0番地を示しています。~ | ||
+ | そして、プログラムが何も書かれていないので、このまま終了処理に移行し、Hから順に文字が出力されつつレジスタの値が増加していきます。~ | ||
+ | !に当たる33を出力し、レジスタの値が1増加すると、レジスタが指し示すアドレスの値が0になるので、そこで処理が終了します。~ | ||
+ | BrainCrashのインタプリタでBrainf*ckのプログラムを動かす際には、~ | ||
+ | [>] | ||
+ | Brainf*ckのプログラム | ||
+ | [>] | ||
+ | とします。~ | ||
+ | ただし、ip.g01ではtypeの値を0にすればBrainf*ckのプログラムとして実行できるので、通常は使う事のないテクニックです。~ | ||
+ | *efg01上で動くプログラムの作り方講座(3) [#b5f36808] | ||
+ | 前回までは、難解プログラミング言語と呼ばれる言語でプログラミングを行っていました。~ | ||
+ | やはりそれらの言語では実用性が高いとは言えません。~ | ||
+ | 今回扱うeasy Forthは立派な実用言語であるForthを少し変更を加えた実用言語です。~ | ||
+ | これでip.g01でのプログラミングもかなり楽になるはずです。~ | ||
+ | ちなみに、easy Forthの「easy」は処理系にとって処理しやすいという意味で、初心者向け、という意味ではありません。~ | ||
+ | Forth自体が十分簡単な言語ですので、お間違えの無いように。~ | ||
+ | |||
+ | **easy Forthでプログラミング [#qb5d8096] | ||
+ | ip02.g01でeasy Forthのプログラムを実行するには~ | ||
+ | プロンプト>efg01 ip02 file:ファイル名 type:20 | ||
+ | と入力します。~ | ||
+ | ***基本はHello, world!! [#pb448222] | ||
+ | 今回もHello, world!と表示するプログラムから解説していきます。~ | ||
+ | : main | ||
+ | "!" "d" "l" "r" "o" "w" " " "," "o" "l" "l" "e" "H" | ||
+ | PUT PUT PUT PUT PUT PUT PUT PUT PUT PUT PUT PUT PUT | ||
+ | ; | ||
+ | 以上を実行すると、Hello, world!と表示されます。~ | ||
+ | easy Forthでは、プログラムはワードと呼ばれる物の集まりで出来ています。~ | ||
+ | このプログラムでは「:」「main」「"!"」「PUT」「;」などがワードです。~ | ||
+ | ワードとワードの間は一つ以上のスペースか改行で区切られている必要が有ります。~ | ||
+ | 最初の「:」というワードは新たに自分でワードを定義することを宣言するワードです。~ | ||
+ | このように、easy Forthでは、最初から定義されているワード以外に自分でワードを定義することが出来ます。~ | ||
+ | 「:」の次にワードが新たに定義するワードの名前となり、「;」までがワードの内容となります。~ | ||
+ | ここでは、mainというワードを定義していますが、インタプリタは実行を開始すると、このmainという名前のワードを探し、そこから処理を始めます。~ | ||
+ | そのため、easy Forthでは、必ずmainというワードを定義することが必要になります。~ | ||
+ | さて、ワードの中身ですが、二行目に"!"、"d"、"l"…というワードが有ります。~ | ||
+ | easy Forthでは、スタックと呼ばれる靴下のような物を使って色々な処理をするのですが、この"と"で文字が囲まれたワードはその文字のデータをスタックの中に放り込みます。~ | ||
+ | つまり、二行目が終わった段階で靴下の中身は以下のようになります。~ | ||
+ | (左側が靴下の口です。)~ | ||
+ | ------------------------------+ | ||
+ | H e l l o , w o r l d ! | | ||
+ | ------------------------------+ | ||
+ | Hello, world!を逆の順番でスタックに入れていったので、スタックの奥に!がきます。~ | ||
+ | 三行目のPUTというワードは、スタックから一つデータを取り出して、文字として出力するワードです。~ | ||
+ | 勿論靴下は物を入れたり出したりする穴は一つしかないので、最後に入れたHから、順番に出力されていきます。~ | ||
+ | このようにして、mainはHello, world!を出力するワードとして定義され、それがインタプリタによって実行されて、Hello, world!が表示されたわけです。~ | ||
+ | しかし、いちいちこんな書き方をしていたのでは、めんどくさいです。~ | ||
+ | 以下に、ちょっとめんどくさくなくなったHello, world!を示します。~ | ||
+ | : main "!dlrow ,olleH" PUT PUT PUT PUT PUT PUT PUT PUT PUT PUT PUT PUT PUT ; | ||
+ | PUTの連続がカッコ悪いのは変わりませんが、だいぶんまともに見えます。~ | ||
+ | easy Forthでは、もし"と"の間の文字が二つ以上なら、一つ一つに分解して一つずつスタックに入れてくれます。~ | ||
+ | そのため、最初の"!dlrow ,olleH"は"!" "d" "l" "r" "o" "w" " " "," "o" "l" "l" "e" "H"と解釈されるわけです。~ | ||
+ | つぎに、PUTの連続を何とかしたいと思います。~ | ||
+ | : main 0 "!dlrow ,olleH" print ; | ||
+ | : print BGN DUP WHL PUT RPT DRP ; | ||
+ | mainの次に、0というワードが有ります。~ | ||
+ | これは、スタックに0を積むワードです。~ | ||
+ | また、"!dlrow ,olleH"の次にprintというワードが有ります。~ | ||
+ | これは、最初から定義されているワードではなく、二行目で定義しているワードです。~ | ||
+ | ここで、処理が二行目に移ります。~ | ||
+ | 二行目では、C言語で言うところのwhile文が使われています。~ | ||
+ | easy Forthでの繰り返し処理は、以下のように書きます。~ | ||
+ | BGN ワード列(1) WHL ワード列(2) RPT | ||
+ | まず、ワード列(1)が実行されて、WHLに到達した時点でスタックから一つデータが取り出されます。~ | ||
+ | そのデータが0ならRPTの次まで処理をジャンプします。~ | ||
+ | そのデータが0以外ならばワード列(2)を実行し、BGNに戻り、以上の処理を繰り返し行います。~ | ||
+ | 今回ワード列(1)のところにあるのはDUPだけです。~ | ||
+ | このDUPはスタックから一つデータを取り出し、それを二回スタックに入れます。~ | ||
+ | つまり、スタックの一番上のデータを複製します。~ | ||
+ | 最後のDRPは、スタックから一つデータを取り出し、それを捨てるワードです。~ | ||
+ | では、print全体の処理を見てみます。~ | ||
+ | まず最初にワード列(1)のDUPで、スタックの一番上にあるHが複製されます。~ | ||
+ | 次にWHLで複製されたHが取り出されます。~ | ||
+ | Hの文字コードは72なので、0以外である為、ワード列(2)のPUTが実行されます。~ | ||
+ | PUTは、スタックからHを取り出し、表示します。~ | ||
+ | もう一度BGNの次のDUPが行われてeが複製され、0以外なので、表示されます。~ | ||
+ | これを繰り返して、!まで無事表示されます。~ | ||
+ | !を表示してBGNに戻ると、DUPで今度は0が複製されます。~ | ||
+ | そして、WHLで0が取り出され、0なのでPUTを行わずにRPTの次へ処理が移ります。~ | ||
+ | スタックの中に残った0をDRPで掃除します。~ | ||
+ | 次は、ワードの定義が終了した事を示す;が有るので、printワードを呼び出したmainワードに処理が戻る、という流れです。~ | ||
+ | これでだいぶんカッコ良くなりましたが、Hello, world!が逆向きなのが気に食わないので、これを何とかします。~ | ||
+ | : main 0 "Hello, world!" print ; | ||
+ | : print invert BGN DUP WHL PUT RPT DRP ; | ||
+ | : invert | ||
+ | VAR pointer VAR256 words | ||
+ | 0 pointer ! | ||
+ | 256 BGN DUP WHL | ||
+ | 1 - DUP words + 0 SWP ! | ||
+ | RPT DRP | ||
+ | BGN DUP WHL | ||
+ | words pointer @ + ! | ||
+ | pointer @ 1 + pointer ! | ||
+ | RPT | ||
+ | 0 words pointer @ + ! | ||
+ | 0 pointer ! | ||
+ | BGN words pointer @ + @ WHL | ||
+ | words pointer @ + @ | ||
+ | pointer @ 1 + pointer ! | ||
+ | RPT | ||
+ | ; | ||
+ | とりあえず、Hello, world!は正しい向きになりました。~ | ||
+ | 色々と新しいワードが出ていますが、これを今説明するのは難しいので、後回しにさせてください。~ | ||
+ | とりあえずこれで、printとinvertをきちんと定義すれば、0 "文字列" print とするだけで文字列が表示できるようになりました。~ | ||
+ | |||
+ | ***計算をする! [#j2b87d24] | ||
+ | いきなりですが、easy Forthを使って計算をさせて見たいと思います。~ | ||
+ | : main | ||
+ | 0 "11 + 3 =" print 11 3 + . "\n" PUT | ||
+ | 0 "11 - 3 =" print 11 3 - . "\n" PUT | ||
+ | 0 "11 * 3 =" print 11 3 * . "\n" PUT | ||
+ | 0 "11 / 3 =" print 11 3 / . "\n" PUT | ||
+ | 0 "11 % 3 =" print 11 3 % . "\n" PUT | ||
+ | ; | ||
+ | : print invert BGN DUP WHL PUT RPT DRP ; | ||
+ | : invert VAR pointer VAR256 words 0 pointer ! 256 BGN DUP WHL 0 DUP 1 - words ! RPT DRP | ||
+ | BGN DUP WHL words pointer @ + ! pointer @ 1 + pointer ! RPT 0 words pointer @ + ! | ||
+ | 0 pointer ! BGN words pointer @ + @ WHL words pointer @ + @ pointer @ 1 + pointer ! RPT ; | ||
+ | ''工事中!''~ | ||
+ | ~ | ||
+ | ~ | ||
+ | ~ | ||
+ | ~ | ||
+ | ~ | ||
+ | ~ |
(This host) = http://osask.net