探検
2 part forth
1デフォルトの名無しさん
NGNG 第四世代
395デフォルトの名無しさん
2008/08/04(月) 22:59:11 Forth は実装が簡単だって聞いてたんで、
自分も作ってみようとちょっと調べたんだけど、
仕組みがよく分からなかったし(ワードの定義とか)、
規格に沿った物にしようとすると意外に仕様が大きくて、
挫折しますた><
自分も作ってみようとちょっと調べたんだけど、
仕組みがよく分からなかったし(ワードの定義とか)、
規格に沿った物にしようとすると意外に仕様が大きくて、
挫折しますた><
396390
2008/08/05(火) 23:09:27 >>395
辞書まわりは次の10個のワードがあればOK(たぶんね)
CREATE
COMMA(,)
[
]
IMMEDIATE
TICK(')
COLON(:)
SEMICOLON(;)
FIND
WORD
このあたりのワードの挙動は、
http://www.annexia.org/forth
ここのjonesforthを参考にすればいいと思う。
これをインスパイヤしたCと日本語のドキュメントを書いてるんだが・・・仕事が忙しくてね・・・
これをざーっと読んで、yforthあたりの簡単な処理系のコード眺めて
実際に動作を確かめればANS-Forthの準拠もそう難しくないかと。
たださ、ANS-Forthって処理系の内部の規定しすぎじゃね?
もっと好きなようにやらしてくれよ。一回確保したWORDが二度と解放できないとか、
文字列はヌル終端しない代わりに文字数を記憶するとか、ちょっと気持ち悪い気がする。
辞書まわりは次の10個のワードがあればOK(たぶんね)
CREATE
COMMA(,)
[
]
IMMEDIATE
TICK(')
COLON(:)
SEMICOLON(;)
FIND
WORD
このあたりのワードの挙動は、
http://www.annexia.org/forth
ここのjonesforthを参考にすればいいと思う。
これをインスパイヤしたCと日本語のドキュメントを書いてるんだが・・・仕事が忙しくてね・・・
これをざーっと読んで、yforthあたりの簡単な処理系のコード眺めて
実際に動作を確かめればANS-Forthの準拠もそう難しくないかと。
たださ、ANS-Forthって処理系の内部の規定しすぎじゃね?
もっと好きなようにやらしてくれよ。一回確保したWORDが二度と解放できないとか、
文字列はヌル終端しない代わりに文字数を記憶するとか、ちょっと気持ち悪い気がする。
397デフォルトの名無しさん
2008/08/05(火) 23:23:59 >文字列はヌル終端しない代わりに文字数を記憶する
これは正当だと思う。ヌル終端がどれだけのバグを生み出しているか……
これは正当だと思う。ヌル終端がどれだけのバグを生み出しているか……
398デフォルトの名無しさん
2008/08/06(水) 21:05:50 実装としては文字列をヌル終端にしても可。
但し、文字数は必要、かつ、
ヌル終端を当てにしたコードを書いても一般には動く保証なし。
が規定の内容と思われます。他の規定も同様。
但し、文字数は必要、かつ、
ヌル終端を当てにしたコードを書いても一般には動く保証なし。
が規定の内容と思われます。他の規定も同様。
399デフォルトの名無しさん
2008/08/08(金) 19:23:22 ASCIIZはねーよマジで
400デフォルトの名無しさん
2008/08/09(土) 16:38:27 でも、C言語で作られたプログラムとの連携したいときは、NUL文字終端がいいよね。
C言語で作られたプログラムの数の多さ、便利さから言うと、無視できないなと。
C言語で作られたプログラムの数の多さ、便利さから言うと、無視できないなと。
401デフォルトの名無しさん
2008/08/09(土) 18:30:35 Cは捨てるのがよろしいかと。
C++をbetter Cとして使う方がまだましだと思う。
C++を使えないようなリソースのキツい環境で使うんだったらforthを直書きした方が良いんじゃね?
C++をbetter Cとして使う方がまだましだと思う。
C++を使えないようなリソースのキツい環境で使うんだったらforthを直書きした方が良いんじゃね?
402デフォルトの名無しさん
2008/08/10(日) 00:15:50 >C++をbetter Cとして使う
それ最悪
それ最悪
403デフォルトの名無しさん
2008/08/11(月) 00:15:21 402 と同感だが、better Cとして使うのは FORTH 実装にはない(価値が少ない)だろ。
自己学習として作るならまだしも、
FORTHに期待される動作環境だったらアセンブリレベルの設計が必要だろ。
C++使うならC++的設計をしろって。
自己学習として作るならまだしも、
FORTHに期待される動作環境だったらアセンブリレベルの設計が必要だろ。
C++使うならC++的設計をしろって。
404デフォルトの名無しさん
2008/08/27(水) 00:31:36 forthチック俺言語のプロセスが回った記念カキコ。
forthだと引数管理がけっこう面倒だと思うけど、wordの名前に
引数の数の情報を盛り込んだら楽にならんかね?
俺言語ではこんな感じでドットの数=引数の数にしているんだけど、どう思う?
1 2 ..sum
1 2 3 .:sum
名前の衝突も起こりにくくなって一石二鳥かと思うんだけど。
forthだと引数管理がけっこう面倒だと思うけど、wordの名前に
引数の数の情報を盛り込んだら楽にならんかね?
俺言語ではこんな感じでドットの数=引数の数にしているんだけど、どう思う?
1 2 ..sum
1 2 3 .:sum
名前の衝突も起こりにくくなって一石二鳥かと思うんだけど。
405デフォルトの名無しさん
2008/08/27(水) 09:31:38 ドット打つのがひたすらめんどくさそう
ifだと.:ifになるの?
ifだと.:ifになるの?
406デフォルトの名無しさん
2008/08/27(水) 21:05:33 こういう風にしたらどう?
・引数可変のワードは # で始まることとする
・ワード [ は現在のパラメータスタックポインタの値を
リターンスタックに積む
・ワード ] は現在のパラメータスタックポインタの値と
リターンスタックポインタのトップの値の差から
パラメータ数を計算しパラメータスタックに積む
たとえば
[ 10 20 30 ] #sum
と書くと、#sum実行直前にはパラメータスタックは
10 20 30 3
となっていて、#sumは3つの数の和を求めればいいことがわかる。
・引数可変のワードは # で始まることとする
・ワード [ は現在のパラメータスタックポインタの値を
リターンスタックに積む
・ワード ] は現在のパラメータスタックポインタの値と
リターンスタックポインタのトップの値の差から
パラメータ数を計算しパラメータスタックに積む
たとえば
[ 10 20 30 ] #sum
と書くと、#sum実行直前にはパラメータスタックは
10 20 30 3
となっていて、#sumは3つの数の和を求めればいいことがわかる。
407404
2008/08/27(水) 22:38:18 >405
そこは構文糖使った方がよろしいかと (a ? b ! cの三項演算子とか)
>406
それも考えたけど、そうするとConcatenativeのメリットが死ぬんだよね。
できるだけ前の計算結果に依存しないように考えると、セパレータのようなものを
スタックに積むのは良くないので、ワード単体で引数までを意味するようにしたい、
ということですな。
そこは構文糖使った方がよろしいかと (a ? b ! cの三項演算子とか)
>406
それも考えたけど、そうするとConcatenativeのメリットが死ぬんだよね。
できるだけ前の計算結果に依存しないように考えると、セパレータのようなものを
スタックに積むのは良くないので、ワード単体で引数までを意味するようにしたい、
ということですな。
408デフォルトの名無しさん
2008/08/28(木) 02:39:56 prologみたいにsum/3みたいにするとか。
よく判ってないが。
よく判ってないが。
409デフォルトの名無しさん
2008/09/19(金) 17:01:15 引数管理しなきゃいけないようなコードの構成だと崩壊しそう
410デフォルトの名無しさん
2008/09/25(木) 03:11:26 しばらくforthやってたら他の言語がいじれなくなってて驚いた。
のめり込むのは危険だなw
のめり込むのは危険だなw
411デフォルトの名無しさん
2008/09/25(木) 03:16:06412デフォルトの名無しさん
2008/09/25(木) 21:54:56 concatenativeの論理を詰めて行くと、
スタックの機構はコード設計のための因子から外されるのかも。
スタックの機構はコード設計のための因子から外されるのかも。
413デフォルトの名無しさん
2008/09/25(木) 22:34:55 >411
Wordの中でWordを呼ぼうとすると破綻するよ。
>412
結局はトップを基点とした対称性(みたいなもの)になるからな。
対称性があれば何でもOK
Wordの中でWordを呼ぼうとすると破綻するよ。
>412
結局はトップを基点とした対称性(みたいなもの)になるからな。
対称性があれば何でもOK
414デフォルトの名無しさん
2008/10/01(水) 00:29:26 スタック型プログラミング言語の最少命令セットを探して
Whitespaceに辿りついたのですが、
これよりも言語仕様的に小さいスタック型言語ってあります?
Whitespaceに辿りついたのですが、
これよりも言語仕様的に小さいスタック型言語ってあります?
415デフォルトの名無しさん
2008/10/01(水) 01:55:39 define
call
return
conditional jump
push
pop
これだけで足りるかな?
call
return
conditional jump
push
pop
これだけで足りるかな?
416デフォルトの名無しさん
2008/10/01(水) 07:09:50 callに条件をつければjumpも省けるんじゃないか?
417デフォルトの名無しさん
2008/10/02(木) 03:17:37 それより、ひと目で何やってるか判るforth作ってくれないかな。
>>54-65とか何やってるのかわからん。
記号覚えればいいんだろうけど。
: は定義っぽいということは文脈で判った。許す。
>rとかr>は何かと。
;は文の終り?
LISPでいう 'a は (quote a)です、みたいに特殊記号をあまり使わずに
誰が見ても大体判るように、平易な形にならないかな。
>>54-65とか何やってるのかわからん。
記号覚えればいいんだろうけど。
: は定義っぽいということは文脈で判った。許す。
>rとかr>は何かと。
;は文の終り?
LISPでいう 'a は (quote a)です、みたいに特殊記号をあまり使わずに
誰が見ても大体判るように、平易な形にならないかな。
418デフォルトの名無しさん
2008/10/02(木) 17:56:08419デフォルトの名無しさん
2008/10/03(金) 02:22:08 リターンスタックに何をプッシュ(とポップ)するの?TOSの内容ってこと?
>rとr>って判りにくいと思う。
一瞬で見分けられないというか。
不等号ちがうんかと。
記号使わずに全部記述的にできないかな。
mindとかそんなのかな。
>rとr>って判りにくいと思う。
一瞬で見分けられないというか。
不等号ちがうんかと。
記号使わずに全部記述的にできないかな。
mindとかそんなのかな。
420デフォルトの名無しさん
2008/10/03(金) 03:00:42 わかりやすい文法が欲しいのならforth系はあきらめた方がいいと思うよ
421デフォルトの名無しさん
2008/10/03(金) 06:08:32 : pushTOStoReturnStack postpone >r ; immediate
: popFromReturnStackToTOS postpone r> ; immediate
: popFromReturnStackToTOS postpone r> ; immediate
422デフォルトの名無しさん
2008/10/03(金) 12:26:50 自分も420に賛成する、forthは裸の2スタックマシンのアセンブラと思えばいいんだけど、それがつらいとちょっときついと思う
ただ、それがインタラクティブ環境を作るあたりと小さな核で構築できるのが非常に面白いのでがんばって覚えてみてよ。
逆に言うと簡単にぶっ壊れるとも言う
ただ、それがインタラクティブ環境を作るあたりと小さな核で構築できるのが非常に面白いのでがんばって覚えてみてよ。
逆に言うと簡単にぶっ壊れるとも言う
423デフォルトの名無しさん
2008/10/03(金) 16:59:48 Cとかの他の言語の常識持ち込もうとしてるヤツいないか?
「Forthではこう書く」ってのに納得いかないなら
悪いことは言わんから、使うのやめとけ
「Forthではこう書く」ってのに納得いかないなら
悪いことは言わんから、使うのやめとけ
424デフォルトの名無しさん
2008/10/03(金) 17:54:20 スタックっつうのはあくまで機械にやさしいものであってユーザーフレンドリーなものじゃないしな
425デフォルトの名無しさん
2008/10/03(金) 18:38:23 頻繁にスタックを意識しないといけないのは悪いForthコード
426デフォルトの名無しさん
2008/10/03(金) 20:05:40 正直アセンブラの方が楽だよ
427デフォルトの名無しさん
2008/10/03(金) 20:24:33 慣れると気持ちいいよJoy。forthは知らんけど
428デフォルトの名無しさん
2008/10/03(金) 20:29:08 >426
Forthは仮想スタックマシンのアセンブラだから、
(仮想)マシンの理解度によるだろな。
Forthは仮想スタックマシンのアセンブラだから、
(仮想)マシンの理解度によるだろな。
429デフォルトの名無しさん
2008/10/03(金) 22:29:45 いや、もっと視認しやすい記号セットを使ってくれって話だろ。
ハイライトできるエディタで単語登録するか、トランスレータでもかますのがいいと思う。
ハイライトできるエディタで単語登録するか、トランスレータでもかますのがいいと思う。
430デフォルトの名無しさん
2008/10/03(金) 23:01:49 ところでリターンスタックって別に必要なの?
普通のCPUは1本だよね。
スタックに対して相対アドレッシングがないからってことかな?
普通のCPUは1本だよね。
スタックに対して相対アドレッシングがないからってことかな?
431デフォルトの名無しさん
2008/10/03(金) 23:57:29 >419
>rとr>は確かに見た目がわかりにくい。
よほどのことが無い限り使わない。
localがあれば要らない。
>430
呼出しのときにデータスタックで直接パラメターを渡すためでしょう。
>rとr>は確かに見た目がわかりにくい。
よほどのことが無い限り使わない。
localがあれば要らない。
>430
呼出しのときにデータスタックで直接パラメターを渡すためでしょう。
432デフォルトの名無しさん
2008/10/04(土) 00:00:27 >>430
普通のアーキテクチャだと関数呼び出しのスタックにパラメータも突っ込んじゃうけど
forthはデータのpushと関数呼び出しの戻りアドレスが入るスタックが別なんよ。
っていうか別だから面白いことができるので、一緒だったらループとかで涙が出そうだと思う。
普通のアーキテクチャだと関数呼び出しのスタックにパラメータも突っ込んじゃうけど
forthはデータのpushと関数呼び出しの戻りアドレスが入るスタックが別なんよ。
っていうか別だから面白いことができるので、一緒だったらループとかで涙が出そうだと思う。
433デフォルトの名無しさん
2008/10/04(土) 00:10:21 SP, BPレジスタに相当するものがあれば良いのでは
434デフォルトの名無しさん
2008/10/04(土) 17:45:11 リターンスタックとデータスタックが一緒だと、
リターンアドレスを壊さないようにデータをいじるのがメンドイ。
リターンアドレスが詰まれている位置を避けるようにして
スタックをアクセスしなきゃいけないから。
それはSPとBPがあってもメンドイことに変わりはない。
リターンアドレスを壊さないようにデータをいじるのがメンドイ。
リターンアドレスが詰まれている位置を避けるようにして
スタックをアクセスしなきゃいけないから。
それはSPとBPがあってもメンドイことに変わりはない。
435デフォルトの名無しさん
2008/10/04(土) 19:46:33436デフォルトの名無しさん
2008/10/04(土) 21:37:24 factorだともうひとつスタックあるよ
437デフォルトの名無しさん
2008/10/04(土) 23:25:44 データスタックとリターンスタックがないと
チューリングマシンと等価じゃないらしいぞ
チューリングマシンと等価じゃないらしいぞ
438デフォルトの名無しさん
2008/10/05(日) 00:17:09439デフォルトの名無しさん
2008/10/05(日) 01:12:05 今理解した。
リターンスタックってそのままBP相当じゃん。
ほんとはBPポインタ一個あれば十分だよね?
素直にBPを持たずにわざわざリターンスタックなんて用意してるのは、
スタックマシンと言えなくなるからかね。
なんだかなあ。
リターンスタックってそのままBP相当じゃん。
ほんとはBPポインタ一個あれば十分だよね?
素直にBPを持たずにわざわざリターンスタックなんて用意してるのは、
スタックマシンと言えなくなるからかね。
なんだかなあ。
440デフォルトの名無しさん
2008/10/05(日) 03:10:12 BPあってもメモリがないとな
441デフォルトの名無しさん
2008/10/05(日) 03:49:49 今理解した。
BPってそのままリターンスタック相当じゃん。
ほんとはリターンスタックあれば十分だよね?
素直にリターンスタックを持たずに、わざわざBPなんて用意してるのは、
レジスタマシンと言えなくなるからかね。
なんだかなあ。
BPってそのままリターンスタック相当じゃん。
ほんとはリターンスタックあれば十分だよね?
素直にリターンスタックを持たずに、わざわざBPなんて用意してるのは、
レジスタマシンと言えなくなるからかね。
なんだかなあ。
442デフォルトの名無しさん
2008/10/05(日) 07:20:41 >>437
メモリアクセスできない純粋なスタックマシンなら、スタックが二本ないと
チューリング等価ではないかも知れないが、FORTHはメモリアクセス @ ! が
あるから、たとえスタック一本であってもチューリング等価じゃね?
考えてみればわかるが、メモリアクセスがあるとスタックの本数を自由に増やせる。
FORTHとスタックマシンとConcatenative言語は、それぞれ別の概念で、
単純に等号で結べないから、何について話しているのか意識しないと混乱すると思われ。
メモリアクセスできない純粋なスタックマシンなら、スタックが二本ないと
チューリング等価ではないかも知れないが、FORTHはメモリアクセス @ ! が
あるから、たとえスタック一本であってもチューリング等価じゃね?
考えてみればわかるが、メモリアクセスがあるとスタックの本数を自由に増やせる。
FORTHとスタックマシンとConcatenative言語は、それぞれ別の概念で、
単純に等号で結べないから、何について話しているのか意識しないと混乱すると思われ。
443デフォルトの名無しさん
2008/10/05(日) 09:51:29 ForthのVMとしては、
論理的には最低限二つの区別されたスタックがある。
標準的な実装での利点(v.s.スタックフレーム方式)は、
サブルーチン間でのデータのコピーが減らせること。
スタックフレーム一本でやるのはCとかでも標準的な実装だけど、
VMという同じ抽象度で比べれば、Cにはスタックは無い。
VMが実装できれば機械自体の仕組みはどうでも良い。
論理的には最低限二つの区別されたスタックがある。
標準的な実装での利点(v.s.スタックフレーム方式)は、
サブルーチン間でのデータのコピーが減らせること。
スタックフレーム一本でやるのはCとかでも標準的な実装だけど、
VMという同じ抽象度で比べれば、Cにはスタックは無い。
VMが実装できれば機械自体の仕組みはどうでも良い。
444デフォルトの名無しさん
2008/10/05(日) 13:26:57 込み入った話は分からんけど、
とりあえずBF書けたらチューリング完全じゃなかったっけ?
とりあえずBF書けたらチューリング完全じゃなかったっけ?
445デフォルトの名無しさん
2008/10/05(日) 14:12:31 なんか話が噛み合ってない気がする。
446デフォルトの名無しさん
2008/10/05(日) 15:11:57 なんでそこまでチューリングマシンにこだわるのかわからん。
Forthがチューリングマシンであろうとなかろうと
Forthで実用的なプログラムは書ける。
あともう一人、やたらリターンスタックを排除したがる奴も
何をしたいのかさっぱりわからん。
Forthがチューリングマシンであろうとなかろうと
Forthで実用的なプログラムは書ける。
あともう一人、やたらリターンスタックを排除したがる奴も
何をしたいのかさっぱりわからん。
447デフォルトの名無しさん
2008/10/05(日) 17:47:31 まず当たり前の大前提の確認からだけど、Forthはチューリング完全だから。
仮にForthの仕様からリターンスタックだけを排除したとしても(それはForthとは呼べないだろうが)
チューリング完全だ。理由は>>442
リターンスタックがBPで代用できるとか正直意味わからん。
スタック演算自体理解してない希ガス。
仮にForthの仕様からリターンスタックだけを排除したとしても(それはForthとは呼べないだろうが)
チューリング完全だ。理由は>>442
リターンスタックがBPで代用できるとか正直意味わからん。
スタック演算自体理解してない希ガス。
448デフォルトの名無しさん
2008/10/05(日) 18:27:08 リターンスタックという名前がいかんのだろ。
449デフォルトの名無しさん
2008/10/05(日) 18:35:04 >>437
スタックオートマトンとスタックマシンをごっちゃにしてる気がする。
スタックオートマトンとスタックマシンをごっちゃにしてる気がする。
450デフォルトの名無しさん
2008/10/05(日) 18:39:13 >>448
むしろリターンスタック以外の名前があるなら知りたいものだが。
むしろリターンスタック以外の名前があるなら知りたいものだが。
451デフォルトの名無しさん
2008/10/05(日) 19:02:41 >442
大雑把にはこんな感じかね。
・データスタック: 引数&戻り値
・リターンスタック: 実行する命令列(辞書で展開された単語含む)
リターンスタックというよりもオーダースタックといった方がちょうど良い気がするけどね
大雑把にはこんな感じかね。
・データスタック: 引数&戻り値
・リターンスタック: 実行する命令列(辞書で展開された単語含む)
リターンスタックというよりもオーダースタックといった方がちょうど良い気がするけどね
452デフォルトの名無しさん
2008/10/05(日) 19:25:44 リターンアドレスを積んでいるからリターンスタック
それでいいと思うが、難しく考えすぎじゃね?>>451
それでいいと思うが、難しく考えすぎじゃね?>>451
453デフォルトの名無しさん
2008/10/05(日) 19:28:44 Aスタック←→Bスタック
だったら勘違いが起きなかったと思う。
だったら勘違いが起きなかったと思う。
454デフォルトの名無しさん
2008/10/05(日) 19:34:19 >>453
むしろ勘違いを引き起こしそうなんだが。
リターンスタックが難しいんじゃなくて、
リターンアドレスをスタックに積むという
当たり前の関数呼び出し規約を説明しなければ、
理解されない時代になったということか…
むしろ勘違いを引き起こしそうなんだが。
リターンスタックが難しいんじゃなくて、
リターンアドレスをスタックに積むという
当たり前の関数呼び出し規約を説明しなければ、
理解されない時代になったということか…
455デフォルトの名無しさん
2008/10/05(日) 21:59:43 なんでリターンスタックの名前で混乱とか勘違いがあるの?
ひょっとして、リターンと聞いて戻り値を連想しちゃう人がいる、とか?
だとしたらかなりキビシい状況だな。
ひょっとして、リターンと聞いて戻り値を連想しちゃう人がいる、とか?
だとしたらかなりキビシい状況だな。
456デフォルトの名無しさん
2008/10/06(月) 01:09:11 カールスタックの方が一般的じゃね?
457デフォルトの名無しさん
2008/10/06(月) 01:09:52 あ、カールじゃなくてコールスタック
458デフォルトの名無しさん
2008/10/06(月) 01:24:45 カールはスナックだな
459デフォルトの名無しさん
2008/10/06(月) 07:35:22 カールと言えば薄べったいのが出てることを最近知った。
従来品に比べて口の裏に張り付きにくいのはメリットだが、
少し物足りない気がした。
従来品に比べて口の裏に張り付きにくいのはメリットだが、
少し物足りない気がした。
460デフォルトの名無しさん
2008/10/06(月) 11:21:56 Forth では昔からリターンスタックと呼んできたので、その伝統に則ればいいと
思うんだけどな。Wikipedia だと項目はコールスタックで立てられているが。
思うんだけどな。Wikipedia だと項目はコールスタックで立てられているが。
461デフォルトの名無しさん
2008/10/06(月) 12:10:36 コールスタック->カールスナック->コーンスターチ->張り付かないならカールじゃない
勉強し過ぎでしょう。
勉強し過ぎでしょう。
462461
2008/10/06(月) 12:30:27 補:そもそもForthが一般的じゃない
463デフォルトの名無しさん
2008/10/06(月) 21:49:04 ・リターンスタックが普通のCPUで言うとことの「スタック」。
ワード(Cで言うところの関数、実際にはサブルーチン)
を呼ぶと呼び出し戻るためのアドレスを積む。
# 普通のCPUでCALL命令(68系だとBSR、JSR)を実行すると
# リターンアドレスがスタックに積まれるのは理解しているよね?
・データスタックってのは、言ってみれば「無限に増えるアキュムレータ」って感じ。
・「辞書」が命令コードストレージ、C言語でいえばTEXTセグメント
Forthの本質は上記3点をおさえて置けば理解できるんだが。
BPがリターンスタックと等価なんて言ってる人とか、
>・リターンスタック: 実行する命令列(辞書で展開された単語含む)
>リターンスタックというよりもオーダースタックといった方がちょうど良い気がするけどね
なんて言っている人、本当に理解できてるの?
ワード(Cで言うところの関数、実際にはサブルーチン)
を呼ぶと呼び出し戻るためのアドレスを積む。
# 普通のCPUでCALL命令(68系だとBSR、JSR)を実行すると
# リターンアドレスがスタックに積まれるのは理解しているよね?
・データスタックってのは、言ってみれば「無限に増えるアキュムレータ」って感じ。
・「辞書」が命令コードストレージ、C言語でいえばTEXTセグメント
Forthの本質は上記3点をおさえて置けば理解できるんだが。
BPがリターンスタックと等価なんて言ってる人とか、
>・リターンスタック: 実行する命令列(辞書で展開された単語含む)
>リターンスタックというよりもオーダースタックといった方がちょうど良い気がするけどね
なんて言っている人、本当に理解できてるの?
464デフォルトの名無しさん
2008/10/07(火) 00:25:52 >463
いや、別にWORDがサブルーチンである必要はないんじゃない?WORD毎の環境要らないんだし。
Cとの相性を考えるとサブルーチンにした方が良いと思うけど。
あと、CPUのアーキテクチャには疎いんだけど、最近のCPUでスタック持ってるのってあったっけ?
いや、別にWORDがサブルーチンである必要はないんじゃない?WORD毎の環境要らないんだし。
Cとの相性を考えるとサブルーチンにした方が良いと思うけど。
あと、CPUのアーキテクチャには疎いんだけど、最近のCPUでスタック持ってるのってあったっけ?
465デフォルトの名無しさん
2008/10/07(火) 06:15:51466デフォルトの名無しさん
2008/10/07(火) 06:37:45 >>464
前半は実装と仕様が混乱してそう。
後半は、たぶん、CPUの「レジスタアーキテクチャ」「スタックアーキテクチャ」と
データ構造としてのスタックを混同している。
Wikipediaやblog読んで理解した気にならないで実際に自分で手を動かしてみなよ。
ちょっと恥ずかし過ぎるぞ、あんた。
前半は実装と仕様が混乱してそう。
後半は、たぶん、CPUの「レジスタアーキテクチャ」「スタックアーキテクチャ」と
データ構造としてのスタックを混同している。
Wikipediaやblog読んで理解した気にならないで実際に自分で手を動かしてみなよ。
ちょっと恥ずかし過ぎるぞ、あんた。
467デフォルトの名無しさん
2008/10/07(火) 12:34:16468デフォルトの名無しさん
2008/10/07(火) 13:28:27 post,preのincやdec付きレジスタ間接参照命令があればデータスタックと等価だよね?
リターンスタックってのはサブルーチンコール時に戻りアドレスをpushする為のレジスタの事でしょう?
なら今時のCPUで無い物の方が珍しいと思うんだけど
リターンスタックってのはサブルーチンコール時に戻りアドレスをpushする為のレジスタの事でしょう?
なら今時のCPUで無い物の方が珍しいと思うんだけど
469デフォルトの名無しさん
2008/10/07(火) 20:49:02 x86って俺の生まれる前からあるな。
定年過ぎた方には最近なんでしょうけど。
定年過ぎた方には最近なんでしょうけど。
470デフォルトの名無しさん
2008/10/07(火) 21:09:44 定年過ぎて無く立ってプロセッサ自体30年の歴史しかないじゃないか
471デフォルトの名無しさん
2008/10/07(火) 21:36:31 最近のCPUは古いアーキテクチャのものがほとんどだよね。
細かいところは違うんだろが。
>>468
>戻りアドレスをpushする為のレジスタ
レジストリって意味?
RISCだと、戻りアドレスを保存するレジスタがあること多いよね。
まあ、リターンスタックは、
リターンアドレスを積むため専用(原則)のスタック
ってことがわかれば、いいじゃない。
データスタックと別にある利点もわかってるわけでしょ。
本当は「リターンスタックがあること」じゃなくて、
データスタックが複数のワードを横断して固定されていること、
の方が特徴だよね。
普通の言語の実装だと、
データスタックがサブルーチンごとに別々にリターンスタックの中にあって、
受け渡すデータはコピーする、
という感じなわけだ。比喩的に言えば。
アセンブリレベルでもリターンアドレスのpush/popが自動になってるなら、
気付かない人がいてもしょうがない。
細かいところは違うんだろが。
>>468
>戻りアドレスをpushする為のレジスタ
レジストリって意味?
RISCだと、戻りアドレスを保存するレジスタがあること多いよね。
まあ、リターンスタックは、
リターンアドレスを積むため専用(原則)のスタック
ってことがわかれば、いいじゃない。
データスタックと別にある利点もわかってるわけでしょ。
本当は「リターンスタックがあること」じゃなくて、
データスタックが複数のワードを横断して固定されていること、
の方が特徴だよね。
普通の言語の実装だと、
データスタックがサブルーチンごとに別々にリターンスタックの中にあって、
受け渡すデータはコピーする、
という感じなわけだ。比喩的に言えば。
アセンブリレベルでもリターンアドレスのpush/popが自動になってるなら、
気付かない人がいてもしょうがない。
472464
2008/10/07(火) 23:32:13 >465
いや、スタックポインタ(レジスタ)じゃなくてスタック。>467 の通りですな。>463で『アドレスを積む』とか
書いているからHWスタックのことかと思った。
スタックを内部に持つCPUの話があった記憶があったので勘違いしたわ。すまんね。
forthあんまり詳しくないんで済まんのだけど、『リターンスタックには、ワードを呼ぶと呼び出し戻るため
のアドレスを積む』んだっけ?
正規化の観点からは『まだ実行していないWORD』もリターンスタックに積めた方が便利だと思うけど。
WORDコンパイルの実装で手が抜けなくなるし……
いや、スタックポインタ(レジスタ)じゃなくてスタック。>467 の通りですな。>463で『アドレスを積む』とか
書いているからHWスタックのことかと思った。
スタックを内部に持つCPUの話があった記憶があったので勘違いしたわ。すまんね。
forthあんまり詳しくないんで済まんのだけど、『リターンスタックには、ワードを呼ぶと呼び出し戻るため
のアドレスを積む』んだっけ?
正規化の観点からは『まだ実行していないWORD』もリターンスタックに積めた方が便利だと思うけど。
WORDコンパイルの実装で手が抜けなくなるし……
473デフォルトの名無しさん
2008/10/07(火) 23:56:37474デフォルトの名無しさん
2008/10/08(水) 04:22:01 >>469
いまでも現役バリバリで使われていて
マイクロソフトの最新OS「VISTA」がポーティングされる
x86アーキテクチャが「最近のCPU」では無いとでも?
あるいはCore2DUOとかがX86アーキテクチャじゃないとでも思ってる?
いまでも現役バリバリで使われていて
マイクロソフトの最新OS「VISTA」がポーティングされる
x86アーキテクチャが「最近のCPU」では無いとでも?
あるいはCore2DUOとかがX86アーキテクチャじゃないとでも思ってる?
475デフォルトの名無しさん
2008/10/08(水) 06:31:12 >>472
Forthと関係なく、関数の呼び出し元に戻るためにアドレスをスタックに積む、
という動作は、アセンブリレベルでは普通の関数呼び出し規約。
Forthは言語レベルでリターンスタックを操作できる言語だけど、
普通は意識しなくてもいいから、リターンアドレスが何のために存在しているのか
理解できない人がいても不思議じゃないけど、せめてもう少し自分で勉強して欲しい。
Forthと関係なく、関数の呼び出し元に戻るためにアドレスをスタックに積む、
という動作は、アセンブリレベルでは普通の関数呼び出し規約。
Forthは言語レベルでリターンスタックを操作できる言語だけど、
普通は意識しなくてもいいから、リターンアドレスが何のために存在しているのか
理解できない人がいても不思議じゃないけど、せめてもう少し自分で勉強して欲しい。
476デフォルトの名無しさん
2008/10/08(水) 06:35:19 >forthあんまり詳しくないんで済まんのだけど、
とか、逃げをうたず自分で触ってみろよ。
とか、逃げをうたず自分で触ってみろよ。
477デフォルトの名無しさん
2008/10/08(水) 14:37:36 441だけど盛り上がってるね。
自分なりのまとめ。
リターンスタックはBPとcall/retの役割がある。
call/retを他の命令で書くと
・関数の呼び出し
push $LNEXT
jmp func
$LNEXT:
・関数のret
pop ecx ; $LNEXTのアドレスがecxに入る
jmp [ecx]
・関数のはじめ
push ebp
mov ebp, esp
・関数のおわり
mov esp, ebp
pop ebp
こうなる。
つまりBPはリターンスタックのトップと同じ。
BPを基点にすればデータスタックだけでも同じ事ができる。
「ボクが考えたforth」ではリターンスタックは必要ない。
自分なりのまとめ。
リターンスタックはBPとcall/retの役割がある。
call/retを他の命令で書くと
・関数の呼び出し
push $LNEXT
jmp func
$LNEXT:
・関数のret
pop ecx ; $LNEXTのアドレスがecxに入る
jmp [ecx]
・関数のはじめ
push ebp
mov ebp, esp
・関数のおわり
mov esp, ebp
pop ebp
こうなる。
つまりBPはリターンスタックのトップと同じ。
BPを基点にすればデータスタックだけでも同じ事ができる。
「ボクが考えたforth」ではリターンスタックは必要ない。
478デフォルトの名無しさん
2008/10/08(水) 18:17:31479デフォルトの名無しさん
2008/10/08(水) 18:47:05 で、その「ボクが考えたforth」では、
パラメタはどうやって渡すんだ?
パラメタはどうやって渡すんだ?
480デフォルトの名無しさん
2008/10/08(水) 19:05:03 どう考えても普通にCALL/RETした方が速そうだけど
わざわざ面倒くさくしてどうするの?
あと、ENTER/LEAVEとか使わないの
わざわざ面倒くさくしてどうするの?
あと、ENTER/LEAVEとか使わないの
481デフォルトの名無しさん
2008/10/08(水) 21:00:40 >>477
もはやどこから突っ込んで良いものやら…
二つほど疑問が。
一つ目。
>>479も言ってるけれど、その実装だとパラメタの受け渡しが面倒そうなのだが。
たとえば、その実装方法で、
: foo drop drop 3 4 5 ;
1 2 foo
としたときにスタックがどのように変化していくのか書いてみてくれ。
解決方法を考えられなくもないが、たぶん独立したリターンスタックが
あるほうがシンプルだと思われ。
二つ目。
リターンスタックを操作する命令はどうやって実装するの?
これも独立したリターンスタックがあるほうがシンプルだと思われ。
forthじゃない何かをつくろうとしているのだろうか?
もはやどこから突っ込んで良いものやら…
二つほど疑問が。
一つ目。
>>479も言ってるけれど、その実装だとパラメタの受け渡しが面倒そうなのだが。
たとえば、その実装方法で、
: foo drop drop 3 4 5 ;
1 2 foo
としたときにスタックがどのように変化していくのか書いてみてくれ。
解決方法を考えられなくもないが、たぶん独立したリターンスタックが
あるほうがシンプルだと思われ。
二つ目。
リターンスタックを操作する命令はどうやって実装するの?
これも独立したリターンスタックがあるほうがシンプルだと思われ。
forthじゃない何かをつくろうとしているのだろうか?
482デフォルトの名無しさん
2008/10/08(水) 21:16:43 二つ目用の問題も書いておくよ。
: bar 1 2 3 >r >r 1 + r> r> ;
: bar 1 2 3 >r >r 1 + r> r> ;
483デフォルトの名無しさん
2008/10/08(水) 23:38:28 混乱してるようだから、
まず、ネイティブの場合とスレッディングの場合を分けて考えた方がいい。
ネイティブForthで自然な実装では、
SP=リターンスタックポインタ(RSP)
BP=データスタックポインタ(DSP)
となってる。
UNIX/Cの普通のスタックを知ってれば、機能的な対応は明瞭なはず。
リターンスタックが伸びても、DSPは別フレームに移らないのがForthのポイント。
ちなみに、Forthでも局所変数が使えるヤツがあって、
その局所変数には、リタースタック中にフレームを作って割り当てるのが普通。
これも、標準のスタックがわかってれば意味は明瞭。
スレッディング(直接・間接)方式だと、
呼出しはCallじゃないから、
BPをRSPにしてもかまわんが、
パラメタとリターンアドレスの混合は、
Forthでは無謀。動的にチェックが必要な上に、完璧にはできそうにない。
まず、ネイティブの場合とスレッディングの場合を分けて考えた方がいい。
ネイティブForthで自然な実装では、
SP=リターンスタックポインタ(RSP)
BP=データスタックポインタ(DSP)
となってる。
UNIX/Cの普通のスタックを知ってれば、機能的な対応は明瞭なはず。
リターンスタックが伸びても、DSPは別フレームに移らないのがForthのポイント。
ちなみに、Forthでも局所変数が使えるヤツがあって、
その局所変数には、リタースタック中にフレームを作って割り当てるのが普通。
これも、標準のスタックがわかってれば意味は明瞭。
スレッディング(直接・間接)方式だと、
呼出しはCallじゃないから、
BPをRSPにしてもかまわんが、
パラメタとリターンアドレスの混合は、
Forthでは無謀。動的にチェックが必要な上に、完璧にはできそうにない。
484464
2008/10/09(木) 01:15:39 446です。
forthは興味半分で使ったレベルでしかないですね……
concatenative俺言語の設計の参考にしているぐらいです。
>473
リターンスタックを「次に実行する命令の列」という形に抽象化すると、「現在処理中のWORD」と
「ソースコードを解釈したWORD」「Dictionaryに保持されているWORD列」…つまり呼び出されて
いないWORDを対称(等価/交換可能)に扱うことができるようになるので、バーチャルマシンの
構造を簡単化することができるかと思います。
……forthで許されているのかしらんけど。
forthは興味半分で使ったレベルでしかないですね……
concatenative俺言語の設計の参考にしているぐらいです。
>473
リターンスタックを「次に実行する命令の列」という形に抽象化すると、「現在処理中のWORD」と
「ソースコードを解釈したWORD」「Dictionaryに保持されているWORD列」…つまり呼び出されて
いないWORDを対称(等価/交換可能)に扱うことができるようになるので、バーチャルマシンの
構造を簡単化することができるかと思います。
……forthで許されているのかしらんけど。
485デフォルトの名無しさん
2008/10/09(木) 06:24:10 リターンスタックに積んであるリターンアドレスは、
「これから実行される命令列」へのポインタそのものと見なせるから、
そのアイデアが新しいとは思えないけどな。
Forthぐらいバーチャルマシンの実装が簡単な言語もないし。
ただ、リターンスタックの意味がよくわからないままに、
他の言語のように抽象構文木を再帰的に処理するような
実装にしていると、リターンスタック操作の実装で悩むの
かもしれない。
「これから実行される命令列」へのポインタそのものと見なせるから、
そのアイデアが新しいとは思えないけどな。
Forthぐらいバーチャルマシンの実装が簡単な言語もないし。
ただ、リターンスタックの意味がよくわからないままに、
他の言語のように抽象構文木を再帰的に処理するような
実装にしていると、リターンスタック操作の実装で悩むの
かもしれない。
486464
2008/10/09(木) 08:54:40 >485
>463は呼び出したWORDを積むことを前提にしているし、>451 >472で言ってるのが >463 >473で
思い切り否定されてるので、forthじゃそういう考え方無いのかな、と思った。
もしforthでもそういう使い方しているんだったらおいらの不勉強だね。
>463は呼び出したWORDを積むことを前提にしているし、>451 >472で言ってるのが >463 >473で
思い切り否定されてるので、forthじゃそういう考え方無いのかな、と思った。
もしforthでもそういう使い方しているんだったらおいらの不勉強だね。
487デフォルトの名無しさん
2008/10/09(木) 10:46:32 >>486
485のいってる意味は、
スレッディング方式のforthでは、
辞書は実行されるワードのポインタのリストとみなせるわけで、
リターンアドレスというのは、辞書内への戻りアドレス、
つまり、これから実行されるワードのリストへのポインタといえる
ということと思われる。
ワードのポインタを直接リターンスタックに積み込むような、
インストラクションキャッシュみたいな仕様のリターンスタックの実装は、
ちょっと聞いたことが無い。
というかそれじゃリターンスタックじゃない。
485のいってる意味は、
スレッディング方式のforthでは、
辞書は実行されるワードのポインタのリストとみなせるわけで、
リターンアドレスというのは、辞書内への戻りアドレス、
つまり、これから実行されるワードのリストへのポインタといえる
ということと思われる。
ワードのポインタを直接リターンスタックに積み込むような、
インストラクションキャッシュみたいな仕様のリターンスタックの実装は、
ちょっと聞いたことが無い。
というかそれじゃリターンスタックじゃない。
488デフォルトの名無しさん
2008/10/09(木) 20:52:04 487の言わんとすることを俺なりに解釈してみる…
: foo dup + ;
: bar foo drop ;
bar の処理中に foo を実行するときに、
foo の次の drop のアドレスをリターンスタックに積む。
それで、foo の実行終了時にリターンアドレスから戻り先を取る。
これが、さっき積んだ drop のアドレスということ。
で、「drop のアドレス」っていうのを「ポインタ」と呼んでいる。
: foo dup + ;
: bar foo drop ;
bar の処理中に foo を実行するときに、
foo の次の drop のアドレスをリターンスタックに積む。
それで、foo の実行終了時にリターンアドレスから戻り先を取る。
これが、さっき積んだ drop のアドレスということ。
で、「drop のアドレス」っていうのを「ポインタ」と呼んでいる。
489デフォルトの名無しさん
2008/10/09(木) 21:08:57 fooが呼ばれたときのリターンアドレスは 「dropのアドレス」というより
「dropの直前のアドレス」だ。
微妙なニュアンスに聞こえるかもしれないが。
: bar foo ( ここ ) drop ;
( ここ ) と書いた部分に戻ってくる。
「dropの直前のアドレス」だ。
微妙なニュアンスに聞こえるかもしれないが。
: bar foo ( ここ ) drop ;
( ここ ) と書いた部分に戻ってくる。
490デフォルトの名無しさん
2008/10/09(木) 21:12:38 : foo dup + ;
: bar dup * ;
: baz foo ( ここ ) bar ( そこ ) ;
foo が呼ばれたときリターンスタックには( ここ )が積まれてる。
bar が呼ばれたときリターンスタックには( そこ )が積まれてる。
bar というワード自身がリターンスタックに積まれているのではない。
: bar dup * ;
: baz foo ( ここ ) bar ( そこ ) ;
foo が呼ばれたときリターンスタックには( ここ )が積まれてる。
bar が呼ばれたときリターンスタックには( そこ )が積まれてる。
bar というワード自身がリターンスタックに積まれているのではない。
491デフォルトの名無しさん
2008/10/09(木) 21:16:04 ついでに >>56 のリターンスタックを使ったパズルの説明でも書いておこう。
問題は、
: foo twice ." Hello" ;
で、
HelloHello
を出力する twice を定義しろというパズル。
問題は、
: foo twice ." Hello" ;
で、
HelloHello
を出力する twice を定義しろというパズル。
492デフォルトの名無しさん
2008/10/09(木) 21:22:30 解答は、
: twice r> dup >r >r ;
何が起きているか説明すると、twice が呼ばれたとき、リターンスタックには、
: foo twice ( ここ ) ." Hello" ;
上の( ここ )が積まれている。
twice は最初に r> を実行して、( ここ ) をリターンスタックからデータスタックに移している。
次の dup で ( ここ ) がデータスタックに二つ積まれた状態になる。
最後に、 二つの >r で ( ここ ) が二つリターンスタックに戻される。
: twice r> dup >r >r ;
何が起きているか説明すると、twice が呼ばれたとき、リターンスタックには、
: foo twice ( ここ ) ." Hello" ;
上の( ここ )が積まれている。
twice は最初に r> を実行して、( ここ ) をリターンスタックからデータスタックに移している。
次の dup で ( ここ ) がデータスタックに二つ積まれた状態になる。
最後に、 二つの >r で ( ここ ) が二つリターンスタックに戻される。
493デフォルトの名無しさん
2008/10/09(木) 21:27:12 さて、定義されたワードの終端に到達したので Forthは、
リターンスタックからリターンアドレスを一つ取り出してそこに戻ろうとする。
: foo twice ( ここ ) ." Hello" ;
↑これの ( ここ )に戻ってくるわけだね。
そして、Helloを出力する。
そしてまた定義されたワードの終端に到達するので、Forth は
リターンスタックからリターンアドレスを一つ取り出してそこに戻ろうとするわけだ。
つまり、もう一度 ( ここ ) に戻る。
もう一度、Helloが出力されたら、次にリターンスタックからpopされる
リターンアドレスは foo を呼び出したアドレスなので、ここでようやく、
foo の実行が終了することになる。
リターンスタックからリターンアドレスを一つ取り出してそこに戻ろうとする。
: foo twice ( ここ ) ." Hello" ;
↑これの ( ここ )に戻ってくるわけだね。
そして、Helloを出力する。
そしてまた定義されたワードの終端に到達するので、Forth は
リターンスタックからリターンアドレスを一つ取り出してそこに戻ろうとするわけだ。
つまり、もう一度 ( ここ ) に戻る。
もう一度、Helloが出力されたら、次にリターンスタックからpopされる
リターンアドレスは foo を呼び出したアドレスなので、ここでようやく、
foo の実行が終了することになる。
494デフォルトの名無しさん
2008/10/09(木) 21:29:45 リターンスタックに積まれているリターンアドレスは、
次に実行すべきワード単体ではなくて、
それ以降、実行すべきコード全体の先頭を指し示すアドレスだ、
と、理解できたかしらん?
次に実行すべきワード単体ではなくて、
それ以降、実行すべきコード全体の先頭を指し示すアドレスだ、
と、理解できたかしらん?
495488
2008/10/10(金) 00:34:56 (ここ) は分かってるつもりなんですが、
メモリアドレス的に的確に伝えるには難しいような気が。。。
: baz foo ( ここ ) bar ( そこ ) ;
16bitアドレス環境として、スレデッドコードで考えると、
(ここ)は foo のアドレスと同じか、それとも +1 でしょうか?
# foo のアドレス +2 すると bar のアドレスですよね
なんかアホなこと言っているようですみません。
メモリアドレス的に的確に伝えるには難しいような気が。。。
: baz foo ( ここ ) bar ( そこ ) ;
16bitアドレス環境として、スレデッドコードで考えると、
(ここ)は foo のアドレスと同じか、それとも +1 でしょうか?
# foo のアドレス +2 すると bar のアドレスですよね
なんかアホなこと言っているようですみません。
レスを投稿する
ニュース
- 習政権、高市首相への態度硬化 台湾有事発言で連日非難 中国 ★11 [ぐれ★]
- 日本損失1.7兆円に修正 中国渡航自粛の影響試算 [蚤の市★]
- 国内ホテル、既にキャンセルも 訪日客関連業界、事態見守る ★3 [蚤の市★]
- 「どうしようもない」 ため息つくアジアの玄関口 中国の訪日自粛で−福岡市 [蚤の市★]
- 「アベノミクス」で投資対象と化したマンション ローンの低金利続き「年収の12倍」借りる20代出現 [蚤の市★]
- 橋下徹氏 外務省幹部の訪中受け「口だけ番長」へ痛烈指摘 「喧嘩は日本の完敗…なんとかっこ悪い日本か」 [冬月記者★]
- 【実況】博衣こよりのえちえち朝こよ🧪 ★2
- 【!?】高市早苗「靖国神社電撃参拝プラン」浮上!これもう戦争だろ… [481941988]
- 【実況】博衣こよりのえちえち朝こよ🧪
- カカロット、腰痛い
- 【超悲報】中国への武力行使、世論調査で「賛成」「どちらかといえば賛成」48.8% 「反対」「どちらかといえば反対」の44.2%を上回る [314039747]
- 中国「高市が頭を下げて謝罪しない限り、絶対に許さない」 [329329848]
