サイトトップへ
OSASK.NET
  サイトトップへ       新掲示板(閉鎖済)   Wiki(凍結済)   旧掲示板(廃止済)   ニュース(廃止済)  
6: 2009-12-26 (土) 16:40:36 HOSINO ソース 現: 2024-01-08 (月) 12:58:43 lina ソース
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 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 ;
 +これを実行すると、11+3、11-3、11*3、11/3、11%3の結果がそれぞれ表示されます。~
 +(*は掛け算、/は小数点以下切り捨ての割り算、%は割り算の余り)~
 +まず、0 "11 + 3 = " printのところは前回までの内容なのでいいと思います。~
 +invertの中身は今回も説明しません。もう少し待って下さい。~
 +2~6行目の最後の"\n" PUTはちょっと変に思われた方もいるかもしれません。~
 +\nというのは改行を表す特別な文字で、この二文字で一文字として扱われます。~
 +そのため、PUT一回で出力することが出来、これが出力されると改行されます。~
 +さて、最後に残ったprintと"\n"の間の説明です。~
 +代表して、2行目で説明します。~
 +まず、11というワードが実行され、スタックに11が積まれます。~
 +次に、3というワードが実行され、スタックに3が積まれます。~
 +そして、+というワードでは、スタックから二つデータを取り出し、その二つを足して答えをスタックに積みます。~
 +これで、11+3の答えである14がスタックに積まれるわけです。~
 +最後に、.というワードは、スタックから一つデータを取り出し、それを数値として出力します。~
 +ここでは、14が出力されます。~
 +3~6行もほぼ同じです。割る方、割られる方、引く方、引かれる方に注意してください。~
 +スタックの一番上のデータで(を)、二番目のデータを(から)割る(引く)します。~
 +***if文を使う! [#ac5b9d2b]
 +easy Forthでは、勿論if文も使う事が出来ます。~
 +以下にサンプルを示します。~
 + : main
 +   100 RND DUP . 0 " + " print 100 RND DUP . 0 " = " print + , "\n" PUT
 +   = IF 0 "That's true !" print ELS 0 "That's false !" print THN
 + ;
 + : 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 ;
 +これを実行すると、足し算の問題が出題されます。~
 +これに、正しい答えを入力してEnterを押すとThat's true !と、間違った答えを入力してEnterを押すとThat's false !と表示されます。~
 +では、プログラムを見ていきます。~
 +2行目にRNDというワードが二回出ています。~
 +このワードは、スタックから一つデータを取り出し、0~取り出したデータ-1までの数で、ランダムに一つ選んでスタックに積みます。~
 +今回はどちらも100が直前に積まれているので、0~99の間で、ランダムに数が積まれます。~
 +(ちなみに、このランダムな数の事を乱数と言います。)~
 +それらの数はそれぞれDUPで複製され、片方は.でそれぞれ出力されています。~
 +" = "が出力された後、二つの乱数は足されています。~
 +そして、,というワードがきます。~
 +このワードは、このプログラムを実行している人に数字を入力してもらうワードです。~
 +Enterで入力を終了します。~
 +数字以外はもちろん入力できず、入力された物は数字として処理されます。~
 +今回はこのワードで、それまでに表示した足し算の式の答えを入力してもらいます。~
 +2行目が終わった時点で、スタックの中には、一番上に入力してもらった数値が、二番目に足し算の答えが入っています。~
 +3行目では、いきなり=というワードが実行されます。~
 +このワードはスタックから値を二つ取り出し、その二つの値が等しければ1を、等しくなければ0をスタックに積みます。~
 +ここでは、足し算の答えと入力された答えが同じなら1が、違えば0がスタックに積まれます。~
 +そしてついにIFです。~
 +easy Forthでは、IFというワードは以下のように使います。~
 + IF ワード列(1) ELS ワード列(2) THN
 +IFというワードが実行されるとスタックからデータが一つ取り出され、その値が0以外ならワード列(1)を、0ならワード列(2)を実行します。~
 +もし、値が0の時何もしないのであれば、~
 + IF ワード列(1) THN
 +とすることもできます。~
 +今回は、答えが正解ならワード列(1)が、不正解ならワード列(2)が実行されます。~
 +最後に、=と似たような意味を持つワード群を書いておきます。~
 + =  スタックの1番目のデータが2番目のデータと等しければ1を、そうでなければ0をスタックに積みます
 + <  スタックの1番目のデータが2番目のデータより小さければ1を、そうでなければ0をスタックに積みます
 + >  スタックの1番目のデータが2番目のデータより大きければ1を、そうでなければ0をスタックに積みます
 + <=  スタックの1番目のデータが2番目のデータより小さいか等しければ1を、そうでなければ0をスタックに積みます
 + >=  スタックの1番目のデータが2番目のデータより大きいか等しければ1を、そうでなければ0をスタックに積みます
 + <>  スタックの1番目のデータが2番目のデータと等しくなければ1を、そうでなければ0をスタックに積みます
 +***変数を使う! [#u26830eb]
 +~
 +~
 +~
 +~
 +''工事中!''~

トップ   差分 バックアップ 複製 名前変更 リロード印刷に適した表示   ページ新規作成 全ページ一覧 単語検索 最新ページの一覧   ヘルプ
新着

目次
メンバー一覧


最新の20件
2016-10-01 2016-09-08
  • @MenuBar.
2016-09-07 2016-09-04 2016-08-15 2015-09-23 2014-07-30 2014-07-04 2014-02-04 2013-10-26 2013-06-21 2013-06-17 2013-06-15 2013-04-02 2013-02-09 2013-02-04 2012-12-25 2012-12-01 2012-05-28 2012-03-31

トピック一覧
一般用コメント最新
新掲示板lina
2016/9/5 20:58
SandBoxゲスト
2016/9/4 12:01
RecentDeletedlina
2015/6/2 19:29
Old-OSASK-MLlina
2014/6/29 9:14
hideyosi/メールhideyosi
2014/1/6 20:17
hideyosi/募集中lina
2013/11/8 19:56

このサイトは川合秀実から委託を受けて、OSASKコミュニティによって管理・運営されています。