2 part forth (907レス)
2 part forth http://mevius.5ch.net/test/read.cgi/tech/1073673931/
上
下
前
次
1-
新
通常表示
512バイト分割
レス栞
481: デフォルトの名無しさん [sage] 2008/10/08(水) 21:00:40 >>477 もはやどこから突っ込んで良いものやら… 二つほど疑問が。 一つ目。 >>479も言ってるけれど、その実装だとパラメタの受け渡しが面倒そうなのだが。 たとえば、その実装方法で、 : foo drop drop 3 4 5 ; 1 2 foo としたときにスタックがどのように変化していくのか書いてみてくれ。 解決方法を考えられなくもないが、たぶん独立したリターンスタックが あるほうがシンプルだと思われ。 二つ目。 リターンスタックを操作する命令はどうやって実装するの? これも
独立したリターンスタックがあるほうがシンプルだと思われ。 forthじゃない何かをつくろうとしているのだろうか? http://mevius.5ch.net/test/read.cgi/tech/1073673931/481
482: デフォルトの名無しさん [sage] 2008/10/08(水) 21:16:43 二つ目用の問題も書いておくよ。 : bar 1 2 3 >r >r 1 + r> r> ; http://mevius.5ch.net/test/read.cgi/tech/1073673931/482
483: デフォルトの名無しさん [sage] 2008/10/08(水) 23:38:28 混乱してるようだから、 まず、ネイティブの場合とスレッディングの場合を分けて考えた方がいい。 ネイティブForthで自然な実装では、 SP=リターンスタックポインタ(RSP) BP=データスタックポインタ(DSP) となってる。 UNIX/Cの普通のスタックを知ってれば、機能的な対応は明瞭なはず。 リターンスタックが伸びても、DSPは別フレームに移らないのがForthのポイント。 ちなみに、Forthでも局所変数が使えるヤツがあって、 その局所変数には、リタースタック中にフレームを作って割り当て
るのが普通。 これも、標準のスタックがわかってれば意味は明瞭。 スレッディング(直接・間接)方式だと、 呼出しはCallじゃないから、 BPをRSPにしてもかまわんが、 パラメタとリターンアドレスの混合は、 Forthでは無謀。動的にチェックが必要な上に、完璧にはできそうにない。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/483
484: 464 [sage] 2008/10/09(木) 01:15:39 446です。 forthは興味半分で使ったレベルでしかないですね…… concatenative俺言語の設計の参考にしているぐらいです。 >473 リターンスタックを「次に実行する命令の列」という形に抽象化すると、「現在処理中のWORD」と 「ソースコードを解釈したWORD」「Dictionaryに保持されているWORD列」…つまり呼び出されて いないWORDを対称(等価/交換可能)に扱うことができるようになるので、バーチャルマシンの 構造を簡単化することができるかと思います。 ……forthで
許されているのかしらんけど。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/484
485: デフォルトの名無しさん [sage] 2008/10/09(木) 06:24:10 リターンスタックに積んであるリターンアドレスは、 「これから実行される命令列」へのポインタそのものと見なせるから、 そのアイデアが新しいとは思えないけどな。 Forthぐらいバーチャルマシンの実装が簡単な言語もないし。 ただ、リターンスタックの意味がよくわからないままに、 他の言語のように抽象構文木を再帰的に処理するような 実装にしていると、リターンスタック操作の実装で悩むの かもしれない。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/485
486: 464 [sage] 2008/10/09(木) 08:54:40 >485 >463は呼び出したWORDを積むことを前提にしているし、>451 >472で言ってるのが >463 >473で 思い切り否定されてるので、forthじゃそういう考え方無いのかな、と思った。 もしforthでもそういう使い方しているんだったらおいらの不勉強だね。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/486
487: デフォルトの名無しさん [sage] 2008/10/09(木) 10:46:32 >>486 485のいってる意味は、 スレッディング方式のforthでは、 辞書は実行されるワードのポインタのリストとみなせるわけで、 リターンアドレスというのは、辞書内への戻りアドレス、 つまり、これから実行されるワードのリストへのポインタといえる ということと思われる。 ワードのポインタを直接リターンスタックに積み込むような、 インストラクションキャッシュみたいな仕様のリターンスタックの実装は、 ちょっと聞いたことが無い。 というかそれじゃリターンスタックじゃ
ない。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/487
488: デフォルトの名無しさん [sage] 2008/10/09(木) 20:52:04 487の言わんとすることを俺なりに解釈してみる… : foo dup + ; : bar foo drop ; bar の処理中に foo を実行するときに、 foo の次の drop のアドレスをリターンスタックに積む。 それで、foo の実行終了時にリターンアドレスから戻り先を取る。 これが、さっき積んだ drop のアドレスということ。 で、「drop のアドレス」っていうのを「ポインタ」と呼んでいる。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/488
489: デフォルトの名無しさん [sage] 2008/10/09(木) 21:08:57 fooが呼ばれたときのリターンアドレスは 「dropのアドレス」というより 「dropの直前のアドレス」だ。 微妙なニュアンスに聞こえるかもしれないが。 : bar foo ( ここ ) drop ; ( ここ ) と書いた部分に戻ってくる。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/489
490: デフォルトの名無しさん [sage] 2008/10/09(木) 21:12:38 : foo dup + ; : bar dup * ; : baz foo ( ここ ) bar ( そこ ) ; foo が呼ばれたときリターンスタックには( ここ )が積まれてる。 bar が呼ばれたときリターンスタックには( そこ )が積まれてる。 bar というワード自身がリターンスタックに積まれているのではない。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/490
491: デフォルトの名無しさん [sage] 2008/10/09(木) 21:16:04 ついでに >>56 のリターンスタックを使ったパズルの説明でも書いておこう。 問題は、 : foo twice ." Hello" ; で、 HelloHello を出力する twice を定義しろというパズル。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/491
492: デフォルトの名無しさん [sage] 2008/10/09(木) 21:22:30 解答は、 : twice r> dup >r >r ; 何が起きているか説明すると、twice が呼ばれたとき、リターンスタックには、 : foo twice ( ここ ) ." Hello" ; 上の( ここ )が積まれている。 twice は最初に r> を実行して、( ここ ) をリターンスタックからデータスタックに移している。 次の dup で ( ここ ) がデータスタックに二つ積まれた状態になる。 最後に、 二つの >r で ( ここ ) が二つリターンスタックに戻される。 http://mevius.5ch.net/test/read.cgi/tech/1073
673931/492
493: デフォルトの名無しさん [sage] 2008/10/09(木) 21:27:12 さて、定義されたワードの終端に到達したので Forthは、 リターンスタックからリターンアドレスを一つ取り出してそこに戻ろうとする。 : foo twice ( ここ ) ." Hello" ; ↑これの ( ここ )に戻ってくるわけだね。 そして、Helloを出力する。 そしてまた定義されたワードの終端に到達するので、Forth は リターンスタックからリターンアドレスを一つ取り出してそこに戻ろうとするわけだ。 つまり、もう一度 ( ここ ) に戻る。 もう一度、Helloが出力されたら、次にリターンスタック
からpopされる リターンアドレスは foo を呼び出したアドレスなので、ここでようやく、 foo の実行が終了することになる。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/493
494: デフォルトの名無しさん [sage] 2008/10/09(木) 21:29:45 リターンスタックに積まれているリターンアドレスは、 次に実行すべきワード単体ではなくて、 それ以降、実行すべきコード全体の先頭を指し示すアドレスだ、 と、理解できたかしらん? http://mevius.5ch.net/test/read.cgi/tech/1073673931/494
495: 488 [sage] 2008/10/10(金) 00:34:56 (ここ) は分かってるつもりなんですが、 メモリアドレス的に的確に伝えるには難しいような気が。。。 : baz foo ( ここ ) bar ( そこ ) ; 16bitアドレス環境として、スレデッドコードで考えると、 (ここ)は foo のアドレスと同じか、それとも +1 でしょうか? # foo のアドレス +2 すると bar のアドレスですよね なんかアホなこと言っているようですみません。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/495
496: デフォルトの名無しさん [sage] 2008/10/10(金) 00:55:01 >>495 「barのアドレス」と書くとbazの定義の中のbarの呼び出しのあるアドレスなのか、 それともbar自身の定義のアドレスなのか混乱するから、 ( ここ ) と表現したわけで、その違いがわかってるなら問題ないですよん。 あとポインタってわかるよね? http://mevius.5ch.net/test/read.cgi/tech/1073673931/496
497: デフォルトの名無しさん [sage] 2008/10/10(金) 01:03:18 >>495 その言い方で言えば、(ここ)はbarのアドレスですね。 正確には、bazの定義の中のbarのアドレス。 >>490 での例を少し補って、 : foo dup + ; : bar ( あっち ) dup * ; : baz foo ( ここ ) bar ( そこ ) ; と書けば、「barというワード自身」というのは( あっち )のことになる。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/497
498: 496 [sage] 2008/10/10(金) 01:20:54 >>497 補足ありがとう。 >>486の書き込みの問題点を考えてみると、Forthのリターンスタックは、 明らかに「WORDを積」んではいない。 WORDを積むという表現で想起されるのは、>>497の( あっち ) を積むという ことだとForth使いは受け取るだろうから。 そして ( ここ ) や ( そこ ) は明らかに>>484の「次に実行する命令の列」を 指し示しているわけなので、何が新しいのかよくわからない、という感想に なるのだと思う。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/4
98
499: 464 [sage] 2008/10/10(金) 01:36:27 >498 新しいかどうかなんて知らんよ。単にWORDの扱いを正規化できてVMが簡素になるっつうだけの話。 >497で言及している(ここ)(そこ)みたいな間接ポインタをVMで扱う必要も無くなるし。 まあ、その皺寄せをWORDに押し込んでるだけなんだけどね。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/499
500: 496 [sage] 2008/10/10(金) 01:42:51 >>499 なんていうか… 「(ここ)(そこ)みたいな間接ポインタ」というそれそのものが、 アセンブリ言語の時代からある「リターンアドレス」という概念なんですよ…。 Forthはそれをリターンスタックに分離して保存・復帰しているだけのこと。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/500
501: デフォルトの名無しさん [sage] 2008/10/10(金) 06:35:09 >>491 >そして、Helloを出力する。 . "Hello" がなんでHelloを出力することになるの? "Hello" . じゃないのはなんで? 文字列リテラルは特別扱い? http://mevius.5ch.net/test/read.cgi/tech/1073673931/501
502: デフォルトの名無しさん [sage] 2008/10/10(金) 08:32:35 >500 今は実際のリターンアドレスの話をしとらんよ。 リターンスタックを「次に実行する命令の列」という形に抽象化するっつうとるだろうに。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/502
503: デフォルトの名無しさん [sage] 2008/10/10(金) 08:46:05 >>501 ." とか、 前付きの " は、Forthではただの引用符じゃなくて、一つのワード。 だから、Helloとの間に空白が要る。 但し、終わりの " はセパレーターだから、空白なしで良い。 前にも出てたけど、 Forthでは文字列リテラルはポインタと長さの二つの数値で表す。 「.」は、トップアイテムを一つpopして値をプリントするワードだから、 " Hello" . だと5がプリントされるだけ。文字列ポインタがスタックに残る。 「."」 が 「次の " までの文字列をプリントする」というワ
ード。 文字列をスタックに積んだときは " Hello" type とやる。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/503
504: デフォルトの名無しさん [sage] 2008/10/10(金) 08:52:55 >>502 だから、「次に実行する命令列」は辞書の中に既にあるんであって、 それはスタックである必要はなくて、いってみればアレイ。 辞書の中で実行は動的に行ったり戻ったりするから、 やっぱりリターンアドレスの保存は必要。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/504
505: デフォルトの名無しさん [sage] 2008/10/10(金) 09:06:11 >>503 >「."」 が 「次の " までの文字列をプリントする」というワード。 なんじゃそら ワロタ http://mevius.5ch.net/test/read.cgi/tech/1073673931/505
506: デフォルトの名無しさん [sage] 2008/10/10(金) 17:24:55 factorだと文字列リテラルはあるよ http://mevius.5ch.net/test/read.cgi/tech/1073673931/506
507: 488 [sage] 2008/10/10(金) 22:08:31 >>496,497 サンクス スレデッドコードと書いておいて誤解がなかったようだ。 497 のレスだと、俺の中では「次のワード」という認識になる。 (あっち)という表現を使えば確かに誤解はなくなる。 なんだか、リターンスタックのデータ内容と、 (サブルーチン)リターンアドレスを混同した希ガス http://mevius.5ch.net/test/read.cgi/tech/1073673931/507
508: 464 [sage] 2008/10/11(土) 00:37:41 >504 「必要がないから積まない」じゃなくて、「VMの原理を簡単にするために積む」んだって。 VMが辞書の中を行ったり来たりしないようにするのが目的。 もちろん、VMの仕事をWORDに移管しただけの話だし、スタックが大きくなるデメリットもあるけどな。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/508
509: 504 [sage] 2008/10/11(土) 01:03:24 >>508 つまり、ワードを全部インラインにするということ? それなら確かに理論的には可能だし、リターンスタック自体要らない。 普通は、大きくなるのはスタックじゃなくて辞書だな。 まあ、辞書からインラインで展開したものを リターンスタックにコピーしてもいいけど、 ランタイムにやるなら相当動作が遅くなると思う。 それに、 なぜそのためにスタックというデータ構造を使うのかがわからない。 後ろから先に積んでいくことになるわけだが。 その発想はインストラクションキャッシュだと思う。
だから、むしろキューがいいと思う。 ソフトウェア的にやると相当遅いとは思うけど、 論理的には可能だと思うよ。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/509
510: デフォルトの名無しさん [sage] 2008/10/11(土) 02:00:15 サンクス >693 5 ソースコード 6 boost::spirit というので激しく不安になるな。 というか、スクリプトの入門というのなら、BASICタイプ言語の作成とかCタイプ言語の作成 とか分散しないで、どっちか一つに集中すべきじゃない? 入門だったら、むしろ構文はシンプルなforthライクにして、エンジンの中身に拘るべきだと思うけど…… http://mevius.5ch.net/test/read.cgi/tech/1073673931/510
メモ帳
(0/65535文字)
上
下
前
次
1-
新
書
関
写
板
覧
索
設
栞
歴
あと 397 レスあります
スレ情報
赤レス抽出
画像レス抽出
歴の未読スレ
Google検索
Wikipedia
ぬこの手
ぬこTOP
0.014s