2 part forth (907レス)
2 part forth http://mevius.5ch.net/test/read.cgi/tech/1073673931/
上
下
前
次
1-
新
通常表示
512バイト分割
レス栞
465: デフォルトの名無しさん [sage] 2008/10/07(火) 06:15:51 x86アーキテクチャには思いっきりスタックポインタがありますが? >>464のいう「最近のCPU」が非ノイマンアーキテクチャとかを指すなら スタックがないCPUもあるかも知れないけど。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/465
466: デフォルトの名無しさん [sage] 2008/10/07(火) 06:37:45 >>464 前半は実装と仕様が混乱してそう。 後半は、たぶん、CPUの「レジスタアーキテクチャ」「スタックアーキテクチャ」と データ構造としてのスタックを混同している。 Wikipediaやblog読んで理解した気にならないで実際に自分で手を動かしてみなよ。 ちょっと恥ずかし過ぎるぞ、あんた。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/466
467: デフォルトの名無しさん [sage] 2008/10/07(火) 12:34:16 >>464 の言ってる「スタック」はハードウェアスタックのことと思われる。 >>463 の 「データスタックってのは、言ってみれば「無限に増えるアキュムレータ」って感じ。」 ってのは、確かにハードウェアスタックを思わせる記述だが。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/467
468: デフォルトの名無しさん [sage] 2008/10/07(火) 13:28:27 post,preのincやdec付きレジスタ間接参照命令があればデータスタックと等価だよね? リターンスタックってのはサブルーチンコール時に戻りアドレスをpushする為のレジスタの事でしょう? なら今時のCPUで無い物の方が珍しいと思うんだけど http://mevius.5ch.net/test/read.cgi/tech/1073673931/468
469: デフォルトの名無しさん [sage] 2008/10/07(火) 20:49:02 x86って俺の生まれる前からあるな。 定年過ぎた方には最近なんでしょうけど。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/469
470: デフォルトの名無しさん [sage] 2008/10/07(火) 21:09:44 定年過ぎて無く立ってプロセッサ自体30年の歴史しかないじゃないか http://mevius.5ch.net/test/read.cgi/tech/1073673931/470
471: デフォルトの名無しさん [sage] 2008/10/07(火) 21:36:31 最近のCPUは古いアーキテクチャのものがほとんどだよね。 細かいところは違うんだろが。 >>468 >戻りアドレスをpushする為のレジスタ レジストリって意味? RISCだと、戻りアドレスを保存するレジスタがあること多いよね。 まあ、リターンスタックは、 リターンアドレスを積むため専用(原則)のスタック ってことがわかれば、いいじゃない。 データスタックと別にある利点もわかってるわけでしょ。 本当は「リターンスタックがあること」じゃなくて、 データスタックが複数のワードを横断して固定されていること、 の方が特徴だよね。 普通の言語の実装だと、 データスタックがサブルーチンごとに別々にリターンスタックの中にあって、 受け渡すデータはコピーする、 という感じなわけだ。比喩的に言えば。 アセンブリレベルでもリターンアドレスのpush/popが自動になってるなら、 気付かない人がいてもしょうがない。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/471
472: 464 [sage] 2008/10/07(火) 23:32:13 >465 いや、スタックポインタ(レジスタ)じゃなくてスタック。>467 の通りですな。>463で『アドレスを積む』とか 書いているからHWスタックのことかと思った。 スタックを内部に持つCPUの話があった記憶があったので勘違いしたわ。すまんね。 forthあんまり詳しくないんで済まんのだけど、『リターンスタックには、ワードを呼ぶと呼び出し戻るため のアドレスを積む』んだっけ? 正規化の観点からは『まだ実行していないWORD』もリターンスタックに積めた方が便利だと思うけど。 WORDコンパイルの実装で手が抜けなくなるし…… http://mevius.5ch.net/test/read.cgi/tech/1073673931/472
473: デフォルトの名無しさん [sage] 2008/10/07(火) 23:56:37 >>472 意味が理解できん。 「まだ実行してないWord」を積む、って具体的に何を積むの? まだ実行してないワードのアドレスなら辞書に入ってると思う(関節スレッディングの場合) http://mevius.5ch.net/test/read.cgi/tech/1073673931/473
474: デフォルトの名無しさん [sage] 2008/10/08(水) 04:22:01 >>469 いまでも現役バリバリで使われていて マイクロソフトの最新OS「VISTA」がポーティングされる x86アーキテクチャが「最近のCPU」では無いとでも? あるいはCore2DUOとかがX86アーキテクチャじゃないとでも思ってる? http://mevius.5ch.net/test/read.cgi/tech/1073673931/474
475: デフォルトの名無しさん [sage] 2008/10/08(水) 06:31:12 >>472 Forthと関係なく、関数の呼び出し元に戻るためにアドレスをスタックに積む、 という動作は、アセンブリレベルでは普通の関数呼び出し規約。 Forthは言語レベルでリターンスタックを操作できる言語だけど、 普通は意識しなくてもいいから、リターンアドレスが何のために存在しているのか 理解できない人がいても不思議じゃないけど、せめてもう少し自分で勉強して欲しい。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/475
476: デフォルトの名無しさん [sage] 2008/10/08(水) 06:35:19 >forthあんまり詳しくないんで済まんのだけど、 とか、逃げをうたず自分で触ってみろよ。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/476
477: デフォルトの名無しさん [sage] 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」ではリターンスタックは必要ない。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/477
478: デフォルトの名無しさん [sage] 2008/10/08(水) 18:17:31 >>441=477 それを実際に作って発表したら いままで君をバカにしていた連中にギャフンと言わせられるよ。 ガンバ。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/478
479: デフォルトの名無しさん [sage] 2008/10/08(水) 18:47:05 で、その「ボクが考えたforth」では、 パラメタはどうやって渡すんだ? http://mevius.5ch.net/test/read.cgi/tech/1073673931/479
480: デフォルトの名無しさん [sage] 2008/10/08(水) 19:05:03 どう考えても普通にCALL/RETした方が速そうだけど わざわざ面倒くさくしてどうするの? あと、ENTER/LEAVEとか使わないの http://mevius.5ch.net/test/read.cgi/tech/1073673931/480
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/1073673931/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/498
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
511: デフォルトの名無しさん [sage] 2008/10/11(土) 02:02:28 誤爆スマソ http://mevius.5ch.net/test/read.cgi/tech/1073673931/511
512: 464 [sage] 2008/10/11(土) 02:18:22 >509 いや、基本はWORD呼び出し時に展開(そのWORDに定義されたWORD列をスタックに押し込む)。 WORDコンパイル時に全部インラインに展開するわけじゃないです。 #高速化を目的として、WORDコンパイル時にある程度はインライン化することになると思うけど。 WORDに定義されたWORD列を、実行時にその場で積んでその場で処理する必要があるから、 FIFOの仕組みが必要になります。 まあ、小まめにWORDの積み降ろしをやらなきゃいけないから、確かに重そうだけどね。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/512
513: デフォルトの名無しさん [sage] 2008/10/11(土) 05:37:05 464のやり方は、ありえなくはないけどForth的じゃないね。 どっちかっていうとJava VMのJITコンパイラみたいな。 Forthはシンプルな実装で軽い、ってイメージ。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/513
514: デフォルトの名無しさん [sage] 2008/10/11(土) 06:54:12 >>464のやり方だと実行の度にリターンスタックに命令列のコピーが発生するわけだな。 対して普通のForthはリターンアドレス一つのコピーで済む。 Forthでは関数の戻り場所を実行時に入れ替えたりできる( >>59, >>62 ) わけだけど、 >>464のやり方だと命令列自体の入れ替えになるから相当面倒。 Forthの自由度をわざわざ減らしている気がするんだけどな。 でも作るというならがんがれ。 様々な進化があってこそ発展もある。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/514
515: 464 [sage] 2008/10/11(土) 13:07:00 >513 いや、実装はこっちの方がシンプルだよ。辞書の解釈を全部WORDに押し付けることができるから。 ただ、スタック操作が増えるから重くなる方向だけどね。 >514 リターンアドレス前提だと難しいよね。作業用スタックがもう一本ありゃいいんだけど。 俺言語のVMだと自前スタックで実装しているので大した話じゃないです。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/515
516: 464 [sage] 2008/10/11(土) 13:22:12 >514 ちょっと補足。 複数のWORDを押し込もうとすると確かに面倒だね。 俺言語でも 1. 無名WORDを作る 2. 1.のWORDに実行するWORDを押し込む 3. 1.のWORDをリターンスタックに押し込む といったパック化が必要になります。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/516
517: デフォルトの名無しさん [sage] 2008/10/11(土) 13:26:05 464のVMだが、 ハードウェアレベルではもう一般化してる インストラクションのプリフェッチとおなじだよね。 マシン語のデコーダレベルでのVMという感じか。 実装する場合の最難題は条件付きジャンプだと思う。 IFとか不定ループをどう載せるかが鍵だな。 これを考えると、VMが仕組みとして単純になるかどうかは微妙だと思う。 まあ、ベタでやればできそうな気はするが、 ハードウエアの仕組みをソフトウェアで二重にしてるだけのような気がしないでもない。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/517
518: 464 [sage] 2008/10/11(土) 13:38:04 >514 思い出した……>59を実現するにはreverse自体のパック化も必須なんだっけ。 そういや>59みたいな操作をどうしようか悩んだな。 ただ、こういったWORDを跨ぐ暗黙的なリターンスタック制御てけっこう危険じゃない? 個人的にはWORDはデータスタックの状態にのみ依存すべきだと思うけど、WORDを越えた 範囲までリターンスタックを操作できるようにすると、WORD同士の依存関係が出てしまって 連鎖性(concatenative)が崩れるような気がする。 forthの条件分岐でも、セパレーターを使った明示的な制御をしているわけだし。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/518
519: 464 [sage] 2008/10/11(土) 13:49:31 連投スマソ >517 そうか、CPUだともう一般的なのか……。さすがに天才的な変態が集まる業界だな。 やっぱりCPUのアーキテクチャ勉強しないといけないなあ。 IFは構文解析で逃げました。 block := block ? WORD1 ! WORD2 という三項演算子を用意して、条件分岐用WORDに解釈するようにしました。 不定ループの構文を用意するかどうかは検討中です。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/519
520: 517 [sage] 2008/10/11(土) 13:59:32 もうすこし考えてみたんだが、 ワードがどこかで他のワードを呼び出し、そのワードがどこかで他のワードを呼出し... という場合には、 ワードシーケンスに展開する段階で、 展開すべき個所をたどるためのリターンスタックが必要な気がする。 だから、464のVMは、 普通のForthでの実行と同じ動作でワード系列をコピーして、 それから順番にInterpretして実行するという感じになって、 単なる二度手間ではないかな。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/520
521: 464 [sage] 2008/10/11(土) 15:30:32 >520 どのみちリターンスタック(実行する命令列を保存する専用スタック)が必要なのはその通り。 WORDの動作:普通のForthでの実行と同じ動作でワード系列をコピー VMの動作: 順番にInterpretして実行する というところがポイントですな。VMは辞書のこととか考える必要がないのでシンプルになります。 その代わり「辞書からWORD列を拾ってリターンスタックに展開する」というWORDが必要になるけど。 確かにコピーする手間はムダな気もするんだけどね…… 辞書のWORD列を直接トレースするのと比べてどんぐらい余計な手間がかかってるんだろう? ポインタ操作数回&アクセス数回レベルだと思うけど。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/521
522: 514 [sage] 2008/10/11(土) 18:35:01 >>518 普通はリターンスタックとか継続とか触れない言語の方が多いから、 Forthではなく俺言語を作るつもりなら、言語デザイナであるお前様自身の 判断で実現可能にしてもいいし、そうでなくしてもいいと思うよ。 ただForthは言語レベルでリターンスタックを操れる結果、協調的マルチタスクやら コルーチンやら言語実装のレベルで普通対処するものも、ライブラリレベルで実現できる柔軟さがある。 リターンスタックは他の言語にはないForthの特徴の一つだからね。 俺言語でなんとか実現する方法を悩んでみるのも楽しいんじゃない? http://mevius.5ch.net/test/read.cgi/tech/1073673931/522
523: 514 [sage] 2008/10/11(土) 18:47:48 あとForthのVMって相当シンプルだよ。 アセンブリ言語で書かれた昔のForthとかコアの部分はアセンブリ言語で数行レベルだった気がする。 どのへんが複雑だと思ったのかは興味がある… http://mevius.5ch.net/test/read.cgi/tech/1073673931/523
524: 517 [sage] 2008/10/11(土) 21:01:10 >>521 いや、そうではなくて、 「WORDの動作」の中の、「普通のForthと同じ動作で」ってところに、 リターンアドレスを保存するスタックという意味でのリターンスタックが、もう必要なのではないかということ。 あと、言葉の問題として、 大きい意味でのワードを展開する動作のところからもうInterpreter(=VM)の動作というのが普通だと思う。 つまり、VMの動作の前半をWORDの動作と呼んで違う名前にしたから、 残ったVMの動作が簡単に見えるというだけなんじゃないかな。 辞書中のワードから始めると、ForthのVMよりも(多分プリミティブ)WORDの系列を作る部分が余分で、 より複雑になってると思う。 でも、自分の言語を作るのをやめろといってるんじゃないよ。 むしろ応援してる。 ちょっと話題はそれるけど、Forthというか、スタック指向言語は、 コンパイラライターフレンドリーなんだよね。 だから、Forthコード書くよりForth(風オレ言語)VMを書く人が多かったりするわけだが、 ホントはForthでアプリケーションを書くときも「オレ言語」を作るつもりで書くと良いと思ってる。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/524
525: デフォルトの名無しさん [sage] 2008/10/11(土) 21:33:08 Forthの用語って独特な言い回しがあるからな。 知らない人は結構混乱する。 スレデッドコードのForthの場合、ソースコードを解釈してスレデッドコードを 生成することをコンパイルといい、スレデッドコードを生成する部分を外部インタープリタ、 スレデッドコードを解釈実行する部分を内部インタープリタと呼ぶ。 (これで良かったよな?同志?) このスレでVMと言った時に内部インタープリタだけなのか、外部インタープリタも含むのか? どっちだろうか? http://mevius.5ch.net/test/read.cgi/tech/1073673931/525
526: デフォルトの名無しさん [sage] 2008/10/12(日) 00:45:26 >>525 テキストを読み込んで、 1) ワードを辞書内で特定 2) だめならリテラルに変換 3) ダメならエラーで終了。 という部分が外部インタープリタ 1)または2)で成功したときに モードに応じてコンパイル(Forth的意味)するか実行する のが内部インタープリタ だと思ってました。 Forthはテキストインプットも弄れるという面白さもあるよね。 Forth VMというと、外部も含むのかな。 上のリターンスタック云々の話は、 内部インタープリタのことだと思うけど。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/526
527: デフォルトの名無しさん [sage] 2008/10/12(日) 07:57:23 内部インタプリタて(スレッドコードで実装してる場合は)nextルーチンのことじゃなかったっけ。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/527
528: デフォルトの名無しさん [sage] 2008/10/12(日) 08:49:02 そうNEXTルーチン。アセンブリ言語で数行、という奴。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/528
529: 464 [sage] 2008/10/12(日) 15:10:26 >522 その辺は「自由と責任」というやつですな。「銃で足をブッとばす自由」でもあるけど。 >どのへんが複雑だと思ったのかは興味がある… 自分でも何でだったっけな、と過去の記憶を探り出してみたけど、 ・実行中のWORDの次のWORDを辞書の中から探せるようにする仕組みが必要 ×実行中のWORDの中身を変更するのが大変(VMのスタックに積んでいるWORD含む) ×番兵などの終了処理が必須 --> VM側のスタックに積むことにすればpop&top参照で正規化できるし、元の値を コピーするからWORD変更にも影響されない。 ・VM側に「WORDを実行する」という手順が必要になる --> VM側のスタックに積むことにすればpushで正規化できる ぐらいかもしれない。 コンパイル時にWORDの中身が確定するforthだとあんまり問題にならなそうだね。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/529
530: 464 [sage] 2008/10/12(日) 15:20:28 >524 「スタックに複数のデータを押し込む操作は機械語レベルだとアトミックにならない」ということ?? C++で実装しているから意識していなかったけど、そうかもしれないですね。 少なくともプリミティブで実装する必要あるね。 >ForthのVMよりも(多分プリミティブ)WORDの系列を作る部分が余分で、 これは狙ってやっていることだから仕様がないですね。 まあ、俺言語ではVM自体もWORD扱いにしているのですが…… http://mevius.5ch.net/test/read.cgi/tech/1073673931/530
531: デフォルトの名無しさん [sage] 2008/10/12(日) 15:50:56 >>529 んー、やっぱり、思い込みでForthを理解したつもりになるんじゃなくて、 本格的に触ってみたほうが良いと思うんだけどな。 >実行中のWORDの次のWORDを辞書の中から探せるようにする仕組みが必要 通常、Forthは実行時には、スレデッドコードにコンパイルされた命令列を、 上にも出ているnextルーチンで辿るだけなので、仕組みというほどの仕組みはないよ。 >実行中のWORDの中身を変更するのが大変(VMのスタックに積んでいるWORD含む) 間接スレッディングのForthだと定義済みのワードの変更は、一カ所ポインタを書き換える だけで済むはず。 >番兵などの終了処理が必須 番兵というかワードの最後にnextルーチンへのジャンプかnextルーチン自身を書き込むだけ。 >VM側に「WORDを実行する」という手順が必要になる スレデッドコードのForthの命令列は、ワードへのポインタが並んでいるだけで、 「WORDを実行する」という意味のインストラクションは必要ないよ。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/531
532: 464 [sage] 2008/10/12(日) 23:25:00 本格的に触るのは……あの構文は色々と嫌だ。 [条件] IF [肯定時] ELSE [否定時] THEN とか。 せめて条件算子的だったらなぁ。[条件] ? [肯定時] : [否定時] ; >531 細かいことを言うと、nextルーチンが辞書内のスレッデッドコード構造の詳細を知らなきゃ ならないので、VMと辞書の関連が密になりそうな気がします。スレッデッドコードをスタックに pushしてVM内に取り込んじゃえば辞書内の構造を気にする必要無いし。 まあ、最適化のために作り込んでも良い気がするけどね。そこは将来の課題ということで。 >一カ所ポインタを書き換えるだけで済むはず。 WORD自体を置換する場合はそうですね。WORDの挿入や削除はたぶん難しいかと。 そんな特殊なことは禁止にして、新規にWORD定義させた方が良いかも知れないけど。 あるいは無名WORDとかスキップWORDを用意するとか。 >「WORDを実行する」という意味のインストラクションは必要ないよ。 あれ?VMに保存されている「現在実行中のWORD」って、間接ポインタじゃないの? (nextの動作を考えると、間接ポインタじゃないと色々と面倒臭そうな) 実行前に間接参照からWORDを探す操作が一段余計に必要になるかと思ってた。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/532
533: デフォルトの名無しさん [sage] 2008/10/12(日) 23:34:45 >VMと辞書の関連が密 というか、それがFORTHの肝のような気がする。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/533
534: デフォルトの名無しさん [sage] 2008/10/13(月) 00:16:22 スレデッドコード自体、ワードへのポインタを並べたものでしかないから、 ジャンプとかコールとかそういう類のインストラクションをデコードする必要がない、 という意味ね。 あとForthの実装にはダイレクトスレデッドなものもあるよ。 nextルーチンからみると命令列を順に辿ってるだけであって、 「辞書からワードを毎回探している」ってわけじゃないしね。 それより、スタックに命令列を毎回pushするオーバーヘッドのほうがよほど大きいと思うし、 nextルーチンに比べてシンプルとも思えないんだな。 ま、いろいろ悩んで勉強して、これだ!と思える言語デザインに邁進してください、と。 このスレが本当に久しぶりに活性化したのは間違いないしね。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/534
535: デフォルトの名無しさん [sage] 2008/10/13(月) 00:21:58 >>533 間接スレデッドの場合、Forthコンソールの側から見ると、 逆コンパイルしやすかったり、便利な面はたしかにあるけれど、 VMつうかnextルーチンから見ると、単にポインタを辿っているだけなので、 構造として、VM実装と辞書構造が密、というわけでもないと思う。 実際VM実装テクニックとしてのスレデッドコードは、今や、Forth以外でも 当たり前の技術になってるし。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/535
536: デフォルトの名無しさん [sage] 2008/10/27(月) 00:52:54 jonesforth読んだ。 ソース付きなので理解しやすい。 OS Xで動かそうとしたが挫折した。 OSXのGASではマクロが対応してないみたいだ。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/536
537: デフォルトの名無しさん [sage] 2008/11/23(日) 01:13:24 急にスレが進んだと思ったら、止まるのも急だよなこのスレ やっぱ誰も使ってないってこったな http://mevius.5ch.net/test/read.cgi/tech/1073673931/537
538: デフォルトの名無しさん [sage] 2008/11/26(水) 17:30:54 ttp://www.intellasys.net/index.php?option=com_frontpage&Itemid=64 なんか並列forthマシンっぽいw http://mevius.5ch.net/test/read.cgi/tech/1073673931/538
539: デフォルトの名無しさん [sage] 2008/12/27(土) 14:00:32 factor使ってる奴いる? http://mevius.5ch.net/test/read.cgi/tech/1073673931/539
540: デフォルトの名無しさん [sage] 2008/12/27(土) 21:13:14 とりあえず入れてみたけど特に使ってないなw http://mevius.5ch.net/test/read.cgi/tech/1073673931/540
541: 539 [sage] 2008/12/28(日) 01:26:48 factorおもしろいぜ。デプロイするとスタンドアロンで動く物もできるし。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/541
542: デフォルトの名無しさん [sage] 2008/12/29(月) 13:31:00 やっぱだめだこの言語。 人間工学から著しく反してる。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/542
543: デフォルトの名無しさん [sage] 2008/12/29(月) 19:52:22 サルが人間工学語ってやがる。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/543
544: デフォルトの名無しさん [sage] 2008/12/29(月) 21:45:56 自分の思考をスタック処理に最適化させればいいんだよw http://mevius.5ch.net/test/read.cgi/tech/1073673931/544
545: デフォルトの名無しさん [sage] 2008/12/29(月) 22:06:52 forthに慣れるのはそんなに大変なことじゃないと思うけどなあ。 まあ、問題をごく単純な部分に細分して考えることができないと、 スタック処理が爆発しがちになるとはいえますね。 でも、問題の細分ができない人は、どの言語でプログラミングしても たかが知れてる。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/545
546: デフォルトの名無しさん [sage] 2009/01/01(木) 11:45:56 Lispのマクロ的なことができるってほんと? http://mevius.5ch.net/test/read.cgi/tech/1073673931/546
547: デフォルトの名無しさん [sage] 2009/01/01(木) 11:56:23 イミディエイトなワードのことかな。 結果としては似たようなことができると言えなくもないけど、 Lispのマクロみたいな2度evalするみたいな高水準のものじゃありません。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/547
548: デフォルトの名無しさん [sage] 2009/01/07(水) 22:44:24 つまり・・・どういうことだってばよ? http://mevius.5ch.net/test/read.cgi/tech/1073673931/548
549: デフォルトの名無しさん [sage] 2009/01/07(水) 23:39:44 factorならlispのマクロと同じようなことができるよ http://mevius.5ch.net/test/read.cgi/tech/1073673931/549
550: デフォルトの名無しさん [sage] 2009/01/08(木) 00:11:19 同じ機能を達成できるとしても言語が違えばそこに至るロジックは異なる。 具体的に何がしたいのか特定しないと。 factorはおもしろい言語だが、関数型言語のフリし過ぎなのがイヤラシくもある。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/550
551: デフォルトの名無しさん [sage] 2009/01/09(金) 12:30:14 何かサンプルが欲しいな。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/551
552: デフォルトの名無しさん [sage] 2009/01/09(金) 22:47:55 http://ancient.s6.xrea.com/factor/cookbook.html http://mevius.5ch.net/test/read.cgi/tech/1073673931/552
553: デフォルトの名無しさん [] 2009/02/26(木) 00:17:58 組み込み用FORTH検討中・・・ http://mevius.5ch.net/test/read.cgi/tech/1073673931/553
554: デフォルトの名無しさん [sage] 2009/03/07(土) 05:11:31 part 1 の URL ってないの? http://mevius.5ch.net/test/read.cgi/tech/1073673931/554
555: デフォルトの名無しさん [sage] 2009/03/07(土) 10:00:54 http://piza.2ch.net/tech/kako/987/987562311.html http://mevius.5ch.net/test/read.cgi/tech/1073673931/555
556: デフォルトの名無しさん [sage] 2009/03/07(土) 10:13:20 : Mops ( オブジェクト指向FORTH -- ) ; http://pc.2ch.net/tech/kako/1000/10001/1000118518.html http://mevius.5ch.net/test/read.cgi/tech/1073673931/556
557: デフォルトの名無しさん [sage] 2009/03/07(土) 13:25:33 thanks http://mevius.5ch.net/test/read.cgi/tech/1073673931/557
558: デフォルトの名無しさん [sage] 2009/03/07(土) 18:54:17 このスレも長いね http://mevius.5ch.net/test/read.cgi/tech/1073673931/558
559: デフォルトの名無しさん [sage] 2009/03/07(土) 21:43:31 factorとかJoyとか触ってる奴いないのかよ http://mevius.5ch.net/test/read.cgi/tech/1073673931/559
560: デフォルトの名無しさん [sage] 2009/03/07(土) 23:32:50 普通の関数型言語に比べてどういうメリットがあるのか分からない。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/560
561: デフォルトの名無しさん [sage] 2009/03/08(日) 10:51:09 forthは関数型ちゃうし http://mevius.5ch.net/test/read.cgi/tech/1073673931/561
562: デフォルトの名無しさん [sage] 2009/03/08(日) 12:22:51 >>560はなんでこのスレにいるんだ? http://mevius.5ch.net/test/read.cgi/tech/1073673931/562
563: デフォルトの名無しさん [sage] 2009/03/08(日) 19:52:03 いや、factorがって事なんだが。 http://mevius.5ch.net/test/read.cgi/tech/1073673931/563
564: デフォルトの名無しさん [sage] 2009/03/08(日) 20:01:58 なんで関数型言語と比較するんだ? Factor = forth + 無名関数とオブジェクト指向だよ http://mevius.5ch.net/test/read.cgi/tech/1073673931/564
メモ帳
(0/65535文字)
上
下
前
次
1-
新
書
関
写
板
覧
索
設
栞
歴
あと 343 レスあります
スレ情報
赤レス抽出
画像レス抽出
歴の未読スレ
AAサムネイル
Google検索
Wikipedia
ぬこの手
ぬこTOP
0.024s