約 2,538,276 件
https://w.atwiki.jp/asclepiadaceae/pages/28.html
Haworth, Adrian Hardy (1768-1833) 命名者略記 Haw. 専門分野 種子植物学 国: イギリス
https://w.atwiki.jp/imops-forth/pages/21.html
序 データスタックが変数の役割を果たすとはいえ、forthでも変数は定義できる。 けれども、構文上は、値はすべて一旦スタックにおかれ、スタックを通じて処理されるような形になる。 変数の種類としては、ワードとして定義するパブリックな変数と、1ワード定義内でだけ有効な局所変数がある。 Mopsにはこれらに加えて Local Section (ローカルセクション)という機構があり、近接する特定範囲の複数のワード定義に渡ってのみ存続する変数を定義することができる。 このページでは長くなり過ぎないようForthコアに属するものだけを説明し、オプションである局所変数とMops特有のローカルセクションはそれぞれ別ページに回すこととする。 パブリック変数(VARIABLE, VALUE) VARIABLE VARIABLE V1 と宣言することで、V1という名前の変数が定義される。これは普通のワードと同じ有効範囲をもつ。つまり、宣言がロードされた直後から、同じ名前のワードが重複定義されるまで、この変数は同一性を保ち、その名で呼び出される。普通に大域変数(グローバル)といっても良いのだが、序章でも説明したように、プログラムの全域で有効という意味での普通の大域変数とは微妙に異なる。というか、むしろ、変数もまたまさにワードであるということなのだが。 VARIABLEの宣言(定義)は、実行状態でなされなければならず、コンパイル状態(コロン定義内)では所期の効果は得られない。 このタイプの変数がforthでは最も古典的なものである。 VARIABLEは、変数として利用され、そのように理解されてはいるものの、実体としては変数というよりアレイ(配列)である。長さが1セル長(forth標準規格:1セルはCPUの標準メモリー幅—普通、8ビットコンピュータなら1バイト、16ビットなら2バイト、32ビットなら4バイト、64ビットなら8バイト)で固定されている配列、と考えても大過ない。第一、プログラム上名前が値とは同一視されない。名前と同一視されるのは、その配列オブジェクトのポインタである。そして、値を取り出したり、値を格納したりするために、それぞれ固有のワードを呼び出さなければならない。 値の受け渡しは、もちろん、スタックを経由して行う。 VARIABLEの値は、定義の時点で0に初期化されることになっている。全ビット0である。 VARIABLEから値を取るワードは @ 、アットマークである。単なる特殊文字のように見えるかも知れないが、forthには特殊文字というものは無く、1文字の名前を持つワードは数多くある。これもその一つである。フェッチ (fetch) と読む。 例えば、上の変数V1の値を取るときは、 V1 @ とするわけである。まず変数名、そして動作、である。変数名をコードに書いたとき、つまり、VARIABLEを呼び出したときにも、実は固有の動作がある。それは、その変数のために割り当てられたデータ領域(メモリ)のアドレス値をデータスタック上に置く、ということである。だから、V1と書いた時点で、V1に割り当てられたデータ領域のメモリーアドレス値がデータスタックに押し込まれているのである。そこに、@を作用させると、@の動作は、スタック上のメモリーアドレス値を消費し、それが指している場所から1セル分の値を取ってスタックに押し込む、ということになっている。結果として、上のコードの結果、V1に格納されていた値だけがスタックに残されるのである。 したがって、VARIABLE V1と@のスタック効果を書くと: V1 ( -- addr ) @ ( addr -- x ) xが格納されていた値である。なお、V1に格納された値は、スタック上にコピーされるのであって、取り出されるとV1の中身がなくなってしまうのではない。念のため。 VARIABLE に値を格納するワードは ! 、びっくり(エクスクラメーション)マークである。ストア(store)と読む。値はもちろんスタック経由で取る。 例えば、- 7 を V1に格納(代入)するには、 -7 V1 ! と書く。日本語的には「-7 を V1 に代入」とそのまま読める。 ! のスタック効果は、 ! ( x addr -- ) である。x はスタック上にある値なら何でも良い(タイプは制限ない)し、addr は、1セル分のメモリースペースのアドレスであれば何でも良く、いつもどれかのVARIABLE名を書かなければならないわけではない。この辺の抽象性から、いかにもforth風の展開が可能になっていくのである。 VALUE VALUEもVARIABLEと同じように実行状態で宣言することで定義されるパブリック変数である。 データ領域の大きさも同じように1セルである。 ただし、宣言時から既に、VARIABLEとは挙動が異なる。というのは、VALUEの場合、宣言時にスタック上にある値を用いてデータ域が初期化されるのである。初期値とする値は、ロード中にプログラムが部分的に実行された結果の値でもよい。ともかく宣言時にスタックに値が一つ必要であり、それなしに宣言すると、スタックアンダーフローエラーが出てロードも中断されてしまう。 例えば、初期値-1のVALUE、VL1を定義するには、 -1 VALUE VL1 と書く。 VALUEでは、その名前と格納された値とが同一視できる。つまり、一般のプログラミング言語の変数のように見える。動作としては、名前を書くと、格納されている値のコピーを一つスタック上に置く。値取り出し用ワードは不要である。 スタック効果を書けば: VL1 ( -- x ) また、新しい値に替えるときは、プレフィクス (prefix) を使う。つまり、前置するワードである。こういうものはforthには珍しい。これがかなり後になって追加された機能であることを物語っている。標準のプレフィクスはTOである。値はスタックから取る。 例えば、VL1に37を代入したいときには、 37 TO VL1 と書く。 TOの同義語として、 - が定義されている場合も多い。マイナスに不等号をつなげた、まあ、要するに矢印である。このときは、 37 - VL1 と書ける。Mopsではむしろこちらが本体であって、直観的にも分かり易いので個人的にはこちらを愛用している。 Gazinta(ガジンタ?)という呼び名がある。初めは謎だったが、"goes into"のスランギッシュな言い方であろうと推測される。 TOないし- のスタック効果は、次のように表記する。 TO ( x “ spaces name” -- ) 引用マークに囲まれている入力項は、これはデータスタックから取るのではなく入力テキストから取るのだ、ということを意味する。何を取るかというとVALUEの名前である。つまり、プレフィクスTOにとっては次にあるVALUE名VL1は必要な入力項目なのである。実際、TOや- の後に何も書かないとエラーが出る。後方に書くのに入力としてコメントの左辺に寄せるのは、今ひとつ直観的ではないが、そういう表記法が規則であるようだ。 spaces というのは、はじめの空白文字はいくつあっても飛ばして、空白文字ではない文字列をVALUEの名前として解釈するという意味である。 実は、TOは使用法が拡張されていて、それが受け付けるのはVALUEだけではない。そのため、forth規格書では数値xが複数のこともあり得るような書き方になっている。TOが受け付けないワード名の場合は、エラーがでて中止になる。 ただし、上のTOのスタック効果は、解釈実行時のものである。他のワードの定義(後述)内において利用された場合は、効果が異なる。それを書いてみると、 TO コンパイル時 ( " spaces name" -- ) 実行時 ( x -- ) となる。つまり、ワード定義内でも、TOや- の直後にはValue変数の名前が必要であり、その定義内には「実行時にスタックの値を取って、その変数に格納する」という内容のコードがコンパイルされるのである。TOないし- だけをコンパイルしようとするとエラーになる。 配列(Array) 配列としてのVARIABLE 1バイト配列 VARIABLEは1バイト配列として利用することができる。全体長は1セル分である。ここでは現状一番多いであろう32ビットシステムで考える(2019年現在CPUは64ビットが圧倒的に多くなったが、Forthシステムは32ビットに止まっているものがまだ多いように思われる。)。この場合、1セルは4バイトであるから、1バイトなら4項目配列になる。 メモリーアドレスの個所で、1バイト数を出し入れするワードは、Cを付け足したフェッチ/ストアがある。つまり、c@、c!である。 c@ ( c-addr -- uc ) c! ( c c-addr -- ) 使用法は、 7 8 9 10 V1 3 + c! V1 2 + c! V1 1 + c! V1 c! V1 3 + c@ \ 10 V1 2 + c@ \ 9 V1 1 + c@ \ 8 V1 c@ \ 7 "x +"という形で普通に数値を加算することで配列の項目が進められるわけである。 頭に付け足されるcはcharacterの頭文字である。1文字1バイトとは限らない現在では、やや場違いな命名に見えなくもない。 1バイト数値をスタックにコピーするとき、より一般には1セルより小さいバイト数の数値をコピーするときには、正負の符号をどうするかという問題が出てくる。上のc@は全てを正の値として取り出す(0~255の値になる)。コメントのucのuはunsigned(符号なし)の意味である。正負を反映したい場合は、c@Xを用いる(-127~126の値になる)。最後のXはextend(拡張)を意味し、符号のビットを拡張するということである。 c@X ( c-addr -- c ) 2バイト配列 VARIABLEは、2バイト、2項目配列としても利用できる。その場合の操作ワードは、Wを付け足した、w@, w!, w@Xである。 頭のwは、wordの頭文字だったようだが、ダブルバイトと考えても良いと思う。 もっとも、これらはforth標準のワードではない。いくつかの環境では定義されており、Mopsでも利用できる。 w@ ( w-addr -- uw ) w! ( w w-addr -- ) w@X ( w-addr -- w ) Forthでは、配列も、原則として、項目番号ではなくてアドレスのバイト数値で位置を特定するので、2バイト配列を1項目進めるには、2を足さなければならない。例えば: -1 3 V1 w! V1 2 + w! V1 w@ \ 3 V1 2 + w@X \ -1 V1 2 + w@ \ 65535 (数値の理由が分らない人はコンピュータ内の数値表現法の基礎を勉強しましょう。) CREATE(クリエイト) ForthにはCREATEというワードがある。これを用いた宣言により、VARIABLEと同じように、利用可能なデータ域のメモリーアドレスと結びつく変数ワードを作りだすことができる。ただし、メモリー内に領域を確保しない。そこで、宣言の後に、必要分の領域を確保するためのワードを実行することで、任意の長さのメモリー領域、基本的にはバイト配列、を作りだすことができる。 ALLOT データ領域を確保する最も基本的なワードはALLOTで、確保すべきバイト長に当たる数値をスタックから入力として取る。 以上のような仕組みで、512バイト幅の配列theArrayを作るとすると、 CREATE theArray 512 ALLOT とすればよい。定義された配列theArrayはパブリックワードとなる。 値の出し入れは、項目を何バイトにするか、負の数を必要とするか、に応じて、上で説明したフェッチ/ストア用ワードを使えば良い。 項目位置の計算は、いつもベタのアドレスのバイト数値で計算する。 ALLOTはデータ領域は確保するが、内容の初期化はしない。新規定義の場合はメモリー領域は0で初期化されているのが普通だが、メモリーは前に何かで使ったゴミが残っていて不規則な値になっている場合もあり得る。 RESERVE 内容を消去、つまり、0に初期化して確保するワードとして、MopsにはRESERVEがある。RESERVEという語はデータ域を確保するという意味で通用してはいるようだが、forth規格にはこのワードは見当たらない。RESERVEが定義されている場合は、 CREATE theArray2 256 RESERVE とすれば、theArray2は、256バイト幅の配列として定義され、確実に0で初期化される。 CELLS さらに、1セル単位の配列を作るときは、CELLSというワードが便利である。これは、スタック上の値をセル幅倍する。 例えば、64セルある配列theArray3を定義するには、 CREATE theArray3 64 CELLS ALLOT とすればよい。見た目は理解し易いと思う。 2! , 2@ セルが2つ分のアレイ、あるいはダブルセル変数については、直接に値の出し入れができるワードがある。2@と2!である。これは、アイテム2つを一度にフェッチ/ストアする。 2@ ( addr -- x1 x2 ) 2! ( x1 x2 addr -- ) 格納の順番は、スタックの上の方がデータ域の前のセル、下の方が後のセルに入る。取り出しは、値をスタックから格納したときの順序を保つ。 これらは、ダブルセル数値(例えば、32ビット環境なら64ビット数まで)の取り扱いに適するもののように思われるが、なぜかforth標準では、COREワードとして規定されており、オプショナルではない(forth 94からそうであり、forth200xでも維持されている)。文字列などにも使えるからであろうか。 基本はこんなところと思われる。次は、格納された値を変化させるワードについて、ページを変えて説明しようと思う。 Forthの変数(続)、定数 Forth言語概説Forth開発環境の初歩的使用法
https://w.atwiki.jp/stellaris/pages/44.html
Haworthia maughanii [万象] htmlプラグインエラー このプラグインを使うにはこのページの編集権限を「管理者のみ」に設定してください。
https://w.atwiki.jp/imops-forth/pages/16.html
Forthコード “いかにもfothらしい”コード面に対する嫌悪感を説明してみたい。ただし、“いかにもforthらしい”には引用符をつけておきたい。確かにそれを許しているのはforth自体の特性であるとしても、自由度が高いことは何もかもが正当化されているということではないからだ。プログラマーに責任がかかってくるのである。 “いかにもforthらしい”コードの第一の問題は、何をしようとしているのか解りにくいことだ。ただし、それはスタック状態の変化が追えないからではない。非アルファベット記号が多用されているからでも、人為的な改行記号(C系の ; のような)がないからでもない。そういった初歩的なところで引っ掛かるのは読む側に問題があることも多い(例えば、スタックをどう手なずけるかとか、アレイをどう操作するかという話に集中する自称Forth愛好家は偽物(万年初心者)であり、相手にする必要はないと思われる。)。しかしそれら些末なこととは異なる理由で、なお何をしようとしているのか解りにくいコードがある。Forthコードでも解り易いものは極めてわかり易いのであるから、解りにくいコードを書く側に何か原因があるはずである。 Forthデザイン 現時点では、その原因はプログラムデザイン面でのある種の混同にあるのではないかと思っている。もっとも大きなところは、言語実装の側面と言語利用の側面との混同である。 Forthでは、実際、言語実装面と言語利用面との間に明確な境界が無く、それこそがforth言語の特性であると見ることができる。しかし、連続的であるということは、ごちゃ混ぜに混同して良いということは意味しない。forthの基本諸ワードを均質で一様な要素の集合として取り扱うことは論理的な紛糾を招くだろう。言語実装局面とアプリケーション局面のコンテクストの違いがコードの書き方に加える圧力を考える必要がある。forthはlow levelかつhigh levelな言語である、といわれる。これは正しい。問題はそれがごく標語的に流れてしまうように思われる点である。抽象度のレイヤーなら、どのような言語でも考えられる。しかし、その場合、低レベルであれ高レベルであれ、一つの階層の中では他の階層からシンボリックにひいてくる機能性を別とすれば、どの階層でも同じような均質なアプリケーションプログラミングを行うのが普通である。Forthの場合、単純に縦方向に積み上げていくのではない。そうすることもできるが、それとは異なるやり方ができるのがforthなのである。言語実装のレイヤを横に方向に広げることで、その上の階層における問題の解き方、あるいは問題の設定を変えるという方法があるのである。 しかし、私見だが、言語実装をサポートするワードは、アプリケーションレイヤーでのワードのように自由な使用法はできない。それは機械やコンパイラとアプリケーションプログラムをつなぐ領域であり、一定の堅固さが必要となるからである。また、そこでは、それによって拡大される言語領域によって何がもたらされるかという思考が必要となる。そこでは、確かに、抽象的な言語機能が考察されるわけではなく、プログラムが解く問題を指向して言語拡張が構想されるのではあるが、それは問題を解くアルゴリズムを考えることとは異なるものである。 デザイン思考の硬直化 しかし、アプリケーション問題が一定の型によってのみ捉えられるようになると、こういった言語実装部分の操作可能性は一般に無視され、全体を総動員して(つまり均質一様な集合として扱って)問題を解くことに集中するという思考が一般化してくる。すると、極めてアクロバティックな解法が「elegant」とか「cool」といった評価を受けることにもなる。規制によって成立している標準的なプログラミング言語では、それももっともな話ではある。しかし、forthはそのようなことをする必要がほとんどない言語であるように思われる。言語実装自体さえ拡張できる言語だからである。 まず、言語実装局面と使用局面とを混同したコーダーは、それらの局面がゴチャゴチャに混じりあったアクロバティックなコードを書く。これが、解りにくいコードの第一類型である。結果として、そのようなコードは環境依存的になりやすい。言語実装局面は、機械とそれに対応したコンパイラと言語使用局面とを縦断する領域だからである。言語実装を経て初めて機械の差異が吸収されるのであり、アクロバティックなコードはその点をないがしろにするからである。 通常のアプリケーションプログラミングとは異なる特殊な状況でのデザインのための思考がほとんど欠けている。少し慣れればforthでの言語拡張は容易である。そのために、いわば安易な言語実装拡張に走るのである。 最も残念な意見は、上のようなコードが“悪い”理由は環境依存的なことだ、という見方である。問題を完全に取り違えている上に、ポータビリティー神話への信仰が見え隠れする。その上、「標準に遵うシステムなら動作するはずである」という判断が、無闇なコードアクロバットに完全な免責を与えてしまう結果にもなる。 私見では、コンピュータの動作に対してプログラミングするのが真っ当なプログラマーであって、 コンパイラーやインタープリタなど特定の開発環境に対してプログラミングしようとするのはヘボプログラマーである。 言語拡張的にコンパイラーを変形するときでも、開発環境の不都合な動作をねじ伏せることに執心するのではなく、 変形を通してコンピュータの動作(低レベルで考える必要はなく、当の言語のマシン観にしたがえばよい)をプログラムすることにつなげること、 を第一に意識するのが筋であろう。 他方、難解なコードに直面して表面的な現象面だけを観察し、“悪者”を具体的に特定して、その使用を一般的に禁止したり、その使用を侮蔑するという態度を取るのがもっとも安易な“標準化”方法である。残念ながらコンピュータプログラミング世界ではこの安易な方法が最も標準的なのだ。権威筋による禁止と抑圧は、forthについてみれば言語実装局面にかかわるワード群に向けられがちである。しかし、十分な背景への考察なく現象面の表面的な概観に基づく限り、そういった抑圧はforth言語使用に歪んだ圧力をかけることにしかならない。とりわけ、言語実装の拡張が可能であることこそがforthの強みであるからには、言語実装を可能とする諸ワードを全て禁止するというわけにはいかない。特定のものを優遇し、他のものを抑圧することになる。すると、そこで優遇されたワードに過重な負担をかけるコードが推奨されることになる。結局、利用が奨励されるワードをアクロバティックに利用して、利用禁止されたワードの穴を補おうとするわけである。これが解りにくいコードの第二類型である。 言語実装局面と言語使用局面とが平板に言語利用局面として無差別に捉えられている限り、問題が解決されることは期待できない。禁止すべき例は増えていく一方となるだろう。 そういった、無理を強いているように(私には)見える、意図が解りにくいコードは、実際には、そこまでしなくとも可能なことを不自然なやり方で実現しているのではないだろうか。特定の問題とその解法から離れた「一般理論」ないし「教説」から引き出された一般的な禁則や推奨によって、初めから問題を見る目を歪めてしまっているところに、その解りにくさは発しているように思われてならない。禁則を守りつつ禁止された手段無しで同等の結果を得るという、人為的に作り出された難関をクリアーしてみせる、こけおどしの「cool」なのではなかろうか、と思うのである。
https://w.atwiki.jp/imops-forth/pages/22.html
格納値の操作 変数を値の代理というよりも格納庫としてみて、そこに格納されている値に直接に演算を施すワードが定義されている。+! と -! である。 +! ( n addr -- ) \ nをaddrで指された1セル数値に加算する -! ( n addr -- ) \ nをaddrで指された1セル数値から減算する これらは、スタック上の値nを、addrで指定された1セルメモリー領域にある値に対して、それぞれ、足し算、引き算するのである。例えば、 VARIABLE VR1 5 VR1 ! 8 VR1 +! 2 VR1 -! VR1 @ \ 11 とすれば、VR1に格納されている値は11である。 VALUEに関しては、forth標準には同様の機能をもつワードは無いようであるが、多くの環境では +TO と -TO が定義されている。もっともMopsではこれらは定義されておらず、 ++ と -- として定義されている。 5 VALUE VL1 8 ++ VL1 2 -- VL1 VL1 \ 11 とすれば、上と同値である。 スタック効果を表記すれば、 ++ or +TO ( n “ spaces name” -- ) \ nを“name”で表されるVALUEに加算する -- or -TO ( n “ spaces name” -- ) \ nを“name”で表されるVALUEから減算する である。 もちろん、負の数を加算すれば引き算と同じであり、負の数を減算すれば、その絶対値を足すのと同じである。 変数のメモリーアドレスが出てくるが、そのせいかforthは低級言語だという人もいる(実際は、アドレスはコード面には見えないが)。確かに低級なこともできる。 しかし、forthの方針は機械の動作を記述により明瞭に規定することである。だから低レベルでも隠さないのである。隠さないが故にきちんと記述できるのである。 また、インタープリタやコンパイラを局所的に操作して、抽象的なワード名を付ければ、見た目には極めて高級なことも容易にできるのがforthの特徴である。 抽象度に、階層による分断がないことが、forthの柔軟性のひとつの源泉であり、高級を指向して低レベルへのアクセスを禁止するのは、 せっかくの力を放棄することである。 数値配列の項目値の操作 配列を作った場合でも、1セル配列なら+!, -!によって格納値の増減操作ができる。 CREATE A1 30 CELLS ALLOT ... 5 A1 2 CELLS + +! \ 2番項目(0ベースなので3つ目)に5を加算 7 A1 7 CELLS + -! \ 7番項目について7を減算 など。 項目幅が、1バイト、2バイトである場合には、forth標準ではないが、Mopsでは、それぞれ、c+! , c-!、および、w+! , w-!が利用できる。 c+! ( c c-addr -- ) \ c-addrで指される1バイト数値にcを加算 c-! ( c c-addr -- ) \ c-addrで指される1バイト数値からcを減算 w+! ( w w-addr -- ) \ w-addrで指される2バイト数値にcを加算 w-! ( w w-addr -- ) \ w-addrで指される2バイト数値からcを減算 バイト幅が小さい場合、特に1バイト数の場合には、計算の結果、数値が可能表現範囲をはみ出さないように注意しなければならない。 1バイトは、符号ありでは-128~127の範囲、符号なしでは0~255の範囲。 2バイトは、符号ありでは-32768~32767の範囲、符号なしでは0~65535の範囲。 64ビットMopsでの変数システム 64ビットシステムでは、1セルは8バイトある。Forth標準に文字通りにしたがえば、VARIABLE, VALUE ともに8バイト変数になるはずである。 しかし、Mopsでは当初から32ビットシステムで両変数が4バイトとして扱われてきた歴史は長い。そこで、VARIABLE, VALUEについては4バイト変数に留め、1セル8バイトへの移行に合わせて、あたらしいワード群を導入した。 @XとUVALUE 変数の大きさが4バイトだがスタックセルは8バイトあるわけであるから、VARIABLEやVALUEについても、符号展開をどうするかという問題がでてくる。 VARIABLE VARIABLEに関しては、1バイトフェッチの場合と平行に、@は符号展開なしのフェッチとし、符号展開するワードとして@Xが導入された。4バイト数の取り出しにおいて正負の符号を保持したいときは、@Xを用いなければならない。 4バイトをq-で表せば、次のようなスタック効果となる: @X ( q-addr -- x ) \ q-addrで指された4バイト値を正負のある値としてスタックにコピーする @ ( q-addr -- u ) \ q-addrで指された4バイト値を正か0の値としてスタックにコピーする VARIABLE VR2 -1 VR2 ! VR2 @X \ -- -1 VR2 @ \ -- 4294967295 合わせて、加算、減算ワードも、意味を少し変える。 +! ( n q-addr -- ) \ q-addrで指された4バイト値にnを加算する -! ( n q-addr -- ) \ q-addrで指された4バイト値からnを減算する VALUE UVALUE 他方、VALUEについては、-1(forthではTRUEを意味する)などのフラグを格納することが多かったため、それ自体は符号を保持するものとし、符号なしの4バイト変数としてUVALUEが導入された。Unsigned(符号なし)VALUEである。構文は、VALUEとおなじである。 0 UVALUE UVL1 -1 - UVL1 UVL1 \ -- 4294967295 ZVARIABLE, ZVALUE 1セル8バイトデータ領域を持つ変数として、新たに、ZVARIABLEとZVALUEが設けられた。冒頭にZをつけるのである。 ZVARIABLEに関しては、ストア/フェッチも増減操作も、頭にzを付ける。 ZVARIABLE ZV1 -173 ZV1 z! 65 ZV1 z+! ZV1 z@ \ -- -108 ZVALUEについては、元来のVALUEと全く同じように利用できる。 冒頭に付けるのが、なぜZなのかについては、Mopsの著者であるMichael Horeによれば、IBMの64ビットシステムがZシリーズと呼ばれ、 そこから借りたものである。 では、なぜIBMはZシリーズという呼称にしたのか。これについては、私の憶測ではあるが、Zはラテン文字ではなく、ギリシャ文字のゼータ(大文字Z、小文字ζ) なのではないか、と思われる。というのは、Zないしζは、ギリシャ文字アルファベットでは、6番目なのである。 64は2の6乗だが、英語では"6乗"を、"6番目のパワー"という言い方をするのである(パワー Power は冪という意味)。 定数(CONSTANT) 便宜上、ここで定数を定義する方法を説明しておく。定数定義は、決まった数値を名前で呼び出せるようにすることで、コードの意味の理解しやすくするためのものである。そのように定義された定数もまた、ひとつのワードとして扱われる。 宣言の構文はVALUEと相似であり、CONSTANTというワードを用いる。 64 CONSTANT 1CellBits 上のように宣言すれば、値が64の定数1CellBitsが定義される。1CellBitsというワード名は、数値64と同視される。 CONSTANT ( x “ spaces name” -- ) 定数値はスタックから取られるのであるから、どこかで格納した変数でも、何か計算をした結果の値でもかまわない。ただし、定数であるから、スタック値はコンパイル時に確定していなければならないのは当然である。 別のページで説明するビット判定において、フラグビットの意味を分りやすくするために用いられることも多い。 なお、iMopsではCONSTANTは、4バイト符号付き数として定義されている。拡張としてZCONSTANTが定義されている。PowerMops64ではCONSTANTは64bitである。 次 数値演算 Forth言語概説Forth環境の初歩的使用法 Forthの変数
https://w.atwiki.jp/shn_wiki/pages/24.html
あらし対策として、閲覧専用ページをつくってみました。 最新情報ではないですが、凍結してあるので荒らされません。 2005.08.26 のバックアップです。 はじめに ここはシャドウハーツの新作シャドウハーツ フロム・ザ・ニューワールドの攻略Wikiです ここの情報は2chの住人によって更新されています 情報の転載は自己責任でお願いします メニュー FAQ(閲覧専用)(良くある質問とその答え) サブイベント(キャラクター)(閲覧専用)探偵事務所(ジョニー) UMA狩り(ナタン) 任務(フランク) フランク武器取得リスト 五重の塔(マオ) 週刊アーツ(ヒルダ) 彫像(シャナイア) ティラワ(シャナイアのフュージョン) ルーツアイテム(リカルド) 最強武器・防具・専用アクセ サブイベント(その他)(閲覧専用)歩数計 ピットファイト エリア追加 リングの欠片 漢寿司 モモンガ 特殊アイテム(閲覧専用)リングアイテム その他のレアアイテムと技 お役立ちアイテム 福引(閲覧専用)? スナップ(閲覧専用) ステラ(閲覧専用) ライブラリ(閲覧専用)キャラクター モンスターの属性、ドロップアイテム、にゃんコイン、カロリー ショップリスト(閲覧専用) 小ネタ(閲覧専用)金色ブリキンの倒し方 戦闘ボイス一覧 パロディ元ネタ クリア後(閲覧専用) エンディング分岐(閲覧専用) ネタバレ(閲覧専用)アン尋問セリフ ジョニーの探偵詳細 テンプレ 公式サイト:http //www.shadowhearts.net/ ファンクラブサイト:http //club.shadowhearts.net/ 攻略Wiki(避難用):http //www4.atwiki.jp/shn_wiki/ シャドウハーツ / SHADOW HEARTS 58Hits http //game9.2ch.net/test/read.cgi/gamerpg/1124381737/ シャドウハーツ フロム ザ ニューワールド 攻略スレ 4Hits http //game10.2ch.net/test/read.cgi/goverrpg/1124250978/ シャドウハーツ1+2攻略 Part 4 http //game10.2ch.net/test/read.cgi/goverrpg/1124501895/ シャドウハーツの新作フロム・ザ・ニューワールドの攻略スレです。 攻略スレの性質上、ネタバレの可能性があるのでそれを理解した上で利用してください。 前作1・2の攻略は別スレがありますのでそちらを利用してください。 質問の前にwikiを見ましょう。 sage進行・荒らし・夏厨はカレーにスルー
https://w.atwiki.jp/kisouen/pages/4.html
A リスト A2 リスト A3
https://w.atwiki.jp/imops-forth/pages/17.html
Forthプログラミングは難しい? 当サイトでは標準forthの欠点ばかり書いてきた気もするが、これはforth言語の優れた面の表れでもあるのだ。 弁解ではなく、本当に。 Forthでのプログラミングは、言語の提供している機能を利用する側面と、必要な機能を提供する言語要素を構築する側面がある。他のページにも書いたように、forthでのプログラミングは、初心者を一歩出た段階で言語実装へと立ち入ることになる。forthでいう拡張性はボキャブラリーが増えていくというだけに止まらず、プログラミングの仕方自体を変更するものとなっているのである。 コードや機能それ自体より、アイデアを いわば一種のアプリケーションとして提供されている他言語のハイレベルな機能に相当する手段が、既にforthで提供されているのではないかと、ときおり話題になることがある。しかし、それは微妙にズレた見方のようにも思われる。forth言語は、直接にそのような機能を提供しているというよりも、そのような機能を実装するための方法というか原型を提供しているのである。大抵、上のような話題の結論は、forthには似たような機能はあるが、それほどハイレベルではない、というところに行き着く。しかし、実際には、そのようなハイレベルな機能をforthで実装することは可能であると思われる。他言語で提供されていてforthで実現できないハイレベル機能は存在しない。たまに、「forthでは○○ができない」とか、「forthの○○には××が欠けている」という言い方をする人がいる。しかし、それは、実際には、forthにできないというのではなく、それを実現する具体的な方法を、当の本人が理解できていないというだけのことなのである。その機能がどのような手順で実現できるかが分れば、それをforthで実装するのは驚くほど簡単であることが多い。 簡単 — あくまでも「相対的に」だが — というのならハイレベルな機能を初めから言語の機能として組み込んでしまえばよかったのに、とも確かにいえる。これをしなかったのは、もちろん初めはサイズが大きくなることを避けたのであろう。しかし、問題はそれだけではないのである。 ある傾向のハイレベルな機能がforth環境に定着し、それを当て込んだプログラミングが一般化するなら、その環境でのプログラミングのやり方自体が、「forth的」ではない方向にずれ込んでいく可能性が大きくなる。それを好い現象と考えるかどうかは判断の分かれる所であろう。少なくとも伝統的には、forthプログラミングの視点からすれば、そのような変移は一般には好ましくないことと見られてきたように思われる。というのは、そういったハイレベル機能を用いることでアルゴリズムないし処理手順の上で非常に有利になるアプリケーション問題もある反面、別のやり方の方がもっと簡潔な解が得られるという場面も多くあるはずである、と考えられるからである。けれども、ひとつ一般的な方向性を獲得してしまうと、何でもそれでやってしまおうとするようになるものである。対して、可能性はできるだけ捨てずにとっておく、というのがforthの流儀である(といっても、現在ではこの発想は風前の灯火であるのだが。)。 Forthのやり方とは、現実に具体的に直面しているアプリケーション問題ごとに、最も簡潔に処理できるような抽象化を考えて、それに対応するハイレベル機能を自分で構成するための必要充分な手段を与えよう、というのである。初めから観念的な概念ゲームにあまり関心はないが、現実的処理方法のアイディアには関心がある。やり方をそのまま真似するのではなく、アイディアを自分のやり方で試そうとするのである。一般に、言語設計者には、そのような問題の抽象の方向性を言語が提供する特性枠として与えておこうとする傾向があるように見える。けれども、それはつまり、その方向しか許さないということでもある。Forthでは、抽象的なままの問題を言語構造で解いてしまい、方向を言語仕様として決めてしまうことを、むしろ嫌う傾向がある。そのように制限しなくてもプログラマーは答えをだせると考えるのがforthである。(これが間違いであったかのようでもあるが。) 具体的な処理を書くだけならアセンブラで十分ではないかともいえる。確かにそうなのだが、アセンブラはあまりに具体的な機械に密着し過ぎているため処理が煩雑になり、汎用性もない。機械の個性を捨象できる程度にハイレベルな言語であって、しかし機械の具体的動作を制御する力はアセンブリ言語に匹敵できるようなもの、その辺りがforthの目指した所なのであろう。Forthに対して、抽象度を容易に上げていけるアセンブラのようなものという評価があるが、それほど外れていないと思われる。 他方、forthは自分の必要とするものを準備してくれていない、という類の非難は比較的良く見られる。この裏返しが、ある種のforth方言ではこんなにリッチな高級装置が云々、という評価であろう。要するにそういう発想は、普通のプログラミング言語ではもっともなのだが、forthに関しては頓珍漢な発想と見られてしまうのである。必要ならば自分で実装すればよいのである。そのためには、その機能をどうやって実現するのかを考える必要がある。しかし、アイディアがハッキリと分ってしまえば、実装できないことはないだろう。いくら美味い料理を食べ歩いても、それだけでは料理の腕は上がらない。他からアイディアを得て、どうすれば実現できるのか試してみることが重要ではなかろうか。もっとも、確かにforthは、単純なソートやリスト作成のアルゴリズムも考えられない人に対しては親切な言語とはいえないかもしれない。それは今日では敬遠される十分な根拠になるのであろう。 広い範囲で部分的変更ができるという特性 普通のコンパイル型の高級言語ならコンパイラーや静的リンカーがやるようなことも、forthでは、forth言語自体を使って自分で書くことができる。例えば、Mops(メタなんたらではなく、forth系言語名)では局所変数はレジスタ変数を優先的に用いるが、レジスタを保存-回復したり、値を初期化したりするコードも、forthで書いてあるのである。そのようなコードはプロローグ-エピローグコードとかいわれるが、局所変数定義用のワードを定義するときに、その中身として後から自分で付け足すことができるのである。また、MopsにはSYSCALLとか、 ENTRYとか、 CALLBACKといった、特殊な関数を定義するためのワードセットがある。これらも、使用される状況に応じて必要なプロローグとエピローグを、内容として定義されるコードに追加するのである。そうすることで、普通のコンパイラ言語ならコンパイルコマンドにオプションフラグとかを付けると追加されるようなデータやコードを、自分で内容を決めて任意に追加することができるのである。もちろん、forth言語を用いてアプリケーションと同じ水準で。 コンパイラーやリンカーがやるはずのことをなぜ自分がやるのか、という考えを持つのは、ここでの問題の意味を理解していない。確かに、決まったパターン通りにやるだけなら、自分でしなくても良い方が楽である。いや、汎用的なものならforthでも自動的にやってくれる(とはいえ、開発環境を作るときは、ここもforthで書くのだが。)。しかし、都合でちょっと特殊な変更を追加したいような場合はどうだろうか。そのようなときには、通常ならコンパイラーやリンカーを自分で書き直してビルドし直さないといけないのである。対してforthでは、追加ワードを定義するだけで、同じことが可能なのである。しかも、他の部分には全く影響なく! メタオブジェクトプロトコル(MOP)を提唱していた文献では、そういう、ちょっと追加したいような部分は、プログラマー限りで追加できるような仕組みを予め付けておくべきだ、と言語実装者に勧めているようだった。しかしforthでは1970年代からそれはアプリケーションプログラミンングの普通の一部として可能だったのである。 実は、コンストラクタが何をするのかは普通はプログラマーが自分で決められないものらしいということが初めはわからず、 MOPの提唱が一体何がいいたいのか理解するまで少し時間を要した。 とはいえ、逆にforthではこれが無原則で広範に許され過ぎているともいえる。その点では、MOPという考え方が、論理的な階層として整理してくれたのは重要だと思われる。というのは、観察によれば、forthプログラマーでも本能的に上手く処理できていた人は存在していたようだが、一般にはそこに特殊な問題があることが気づかれていなかったことが酷いコードを産出する原因のひとつになっていたように思われるからである。そのような状況であったので、一般には「プログラマーにもっと強いパワーを与えよう」という話として受け取られたと思われるMOPは、forthから見れば、プログラマーが持っている強力なパワーを合理的に律するための観点を教えてくれるという、制限的なものとして有用なのである。確かにforthの場合でも新機構を追加しようとするときは、どのようなオプションをプログラマーに与えるかという観点から参考になる部分もないではないが、脇道を接続するのが難しいほど入組んだ実装方法に固執したもので限り、欲しい仕組みは自分で足してね、といえるのがforthなのである。 個人的には、オブジェクトシステムを実装する際にも、後で何か追加機能を接続するときにもややこしくならないよう、できるだけ単純にするよう こころがけた。まあ、それは大抵、いちばん簡単な方法なのだが。 局所的変容の原則 上に、コンパイル動作の変更が「他の部分には全く影響なく」可能であることを強調した。このような特性、個人的には「局所性」などと呼んだりしているが、この特性がforthの著しい特徴であるように思われる。これは、別の言い方をすれば、本質からしてモジュラーであるということだ。 モジュラーの意味としては、第一に、各モジュールが機能ないし意味単位としてまとまったものとして捉えられるということが前提となる。その上で、一つには、モジュールの外(ないし他のモジュール)の処理手順の(機能的意味は変わらない)変更のせいでモジュール内部を変更する必要が生じることは無い、ということ、もう一つには、モジュールの内部的手順の(機能的意味は変わらない)変更のせいでモジュールの外(ないし他のモジュール)の変更が必要になることも無い、ということが、モジュラリティーが高いということだといえると思われる。裏からいえば、モジュールの機能的意味を変えずにその内部手順を変更できるという特性が、モジュラリティーであろう。また、こういった機能分割の前提として、モジュールの「機能的意味」の最小単位が十分に小さい、ということが必要である。あるモジュールは、更に小さいモジュールの集まりとして構成されていると考えられる。この階層を、モジュラリティーを崩さずに、非常に小さい機能単位まで降りていくことができる場合、システムとしてのモジュラリティーが高い、ということができる。この意味でみても、forthはシステムとしてのモジュラリティーが極めて高いのである。 「Forthでは、プログラマーがコンパイラーやインタープリターの動作まで変更できる」と言われることがある。 これがコンパイラーやインタープリターに当たるコード部分を直接書き換えるという意味であれば、それは極めて危険である。というのは、インタープリターは全てのコード、ワードを読み込む部分であり、その手順を書き換えれば、今まさに変更しようとしている部分とは関係のないワードの処理にも影響が出る可能性は大きいからである。そのようなことは、普通はしない。というより、できない環境の方が多いだろう。 ではどういうことか。 これは、むしろ、 プログラマーが普通に定義するワードで、ソースコード解析をして適当なコードをコンパイルしたり、その準備操作をしたりすることができる、 ということなのである。いわば小コンパイラーワードが定義できるわけである。そういったワードによって、コンパイラー自体を書き換えることなく、マシンインストラクションを必要に応じて追加できる構文を創出することができるのである。これは、上で触れた CALLBACK などのワードで実際に行っていることである。 そのような"コンパイラの動作の変更"なら、他のワードに影響が出る可能性など考える必要はもちろんない。当のワードに限っての動作だからである。不要ならばそのワードを使わなければよいだけである。他は平素のままである。だから、「コンパイラーの動作まで変更できるので互換性が損なわれる危険が高いだろう」という推論は、因果関係の認識としては誤りである。 互換性問題は、同じ動作に違う名前を付けたり、同じワードの動作が変更されたりすることが可能だから生ずるに過ぎない。 とはいえ、確かに、ifやループ構造のみならず、左括弧 ( やコンマの意味まで自分で定義して書き換えることができる言語はforth以外ほとんどないだろうが。 これに対して、例えば、ワード名やその周辺に何か符牒を付け、それらを標識としてインタープリターが構文解析するという形のグローバルな変更を導入してしまうと、他への影響を消すことはできない。このようなグローバルな変更を志向するのは、発想としてモジュラーと正反対であり、特に、forthの志向には反するもののように思われる。 しかし、「普通の」プログラミング言語のアプローチ方法は、コンパイラ方式であれ、インタープリタ方式であれ、ほとんどが、そのようなグローバルな発想一辺倒である。というのも、インタープリターないしコンパイラーが理解できる構文だけが意味があるのであり、すべてはそこで予め決まってしまっていなければならないからである。 個人的には、言語仕様の規格変更としてであっても、モジュラリティーに反する変更を要する規格には抵抗を覚える。 もっともMopsのメソッドセレクターはこの方法用いているが、iMopsでは他のワードへの影響を減らすため辞書探索順位を変更した。 標準forthでは、$や#を数値リテラルの先頭に(空白なく)付けることで進数指定できるようにしている。これはしかしワードにしてもできる ことであるのに、わざわざインタープリターの内部機構を変えなければならない方法を採用したという点で、あまり好きではない。 ともあれ、モジュラー性が高いということは基本であるように思われる。柔軟性とか、動的変更とか、ダイナミックな運用(パラレルも含む)などが商業宣伝的に誇張されることが多いように思われるが、それは、そういう動作手順を考えればよいというだけ(簡単ではないが)であって、そのような発想の様々な手順による処理を困難なく導入できるためには、各部分の独立性が高いことは重要なのである。モジュラー性を高めるという志向でコード設計することが、結局、様々な「新しい」機能の共通の基盤となっているのではないかと思う。
https://w.atwiki.jp/sakawork/pages/35.html
ファイル閲覧head実行オプション tail実行オプション 実行例 more実行オプション コマンド less cat実行オプション wc実行オプション 実行例 od実行オプション 実行例 ファイル閲覧 head/tail/more/less/cat/wc/odなどについて head ファイルを上から10行表示 実行オプション オプション 動作 -n ファイルを上からn行表示 tail ファイルを下から10行指定表示 実行オプション オプション 動作 -n ファイルを下からn行表示 -f 終了せずに待機し、ファイルの更新時に画面表示ログファイルの監視によく使用する 実行例 $ tail -f xxxx.log | sed s/^/xxxx.log / tail -f yyyy.log |sed s/^/yyyy.log/ xxxx.log YYYY/MM/DD lvl "XXXX" ←xxxx.logの内容 yyyy.log YYYY/MM/DD lvl "YYYY" ←yyyy.logの内容 xxxx.log YYYY/MM/DD lvl "XXXX" ←xxxx.logの追記された内容 more ファイルを画面に表示するコマンド 1画面分づつ表示できるが、前画面には戻れない 実行オプション オプション 動作 -n 一度にn行づつ表示する +/xxxx xxxxが最初に現れる場所から表示 コマンド コマンド 動作 SPACE 次のページを表示 Enter 1行進む q, Q 終了 /xxxx xxxxを検索 less moreと似たビューワ、前画面に戻ることができる viと操作方法が似ている cat ファイルの内容を表示 実行オプション オプション 動作 -n 行番号表示 -v 制御文字の表示 -t タブの表示(^I) wc ワードカウンタ 実行オプション オプション 動作 -c サイズ表示 -l 行数表示 -w 単語数表示 実行例 xxxxを含むファイル数を表示 (ls -1でファイルを1行に表示→xxxxを含むものを抽出→その行数を数える) $ ls -1 | grep xxxx | wc -l od 8進数表示(ダンプ)バイナリファイルのダンプに使用する 実行オプション オプション 動作 -b 内容をビット表示 -c 内容を文字で表示 -d 内容を10進数で表示 -f 内容を浮動小数点数で表示 -o 内容を8進数で表示(デフォルト) -x 内容を16進数で表示 -j [n] nバイト目からダンプ開始b(512),k(1024),m(k^2)などをつけることができる 例 -j 1k = -j 1024 -t 出力形式の指定、複数指定可 -t オプション 動作 a 文字表示(制御文字はCR,LFなどと表示、スペースはSP) c 文字表示(制御文字は\r \nなどと表示、スペースは 空白) d 符号あり8進数表示 f 浮動小数点 o 8進数表示 u 符号なし10進数 x 16進数表示 実行例 ファイルの内容を16進と文字で表示(制御文字は\r,\nなどの形式) $ od -tx1c FILE トップページ
https://w.atwiki.jp/imops-forth/pages/18.html
プログラミング言語Forth 序章 Forthによるプログラミングは、ワードと呼ばれるサブルーチン(意味的に一定のまとまりのある処理の小部分、関数ともいう)を定義することで行われる。ワードの定義は、コロン記号で始め、次にワード名、そしてそのワードが行うべき処理内容の記述と続き、最後にセミコロンを置く。これが最も基本的なForthワード定義方法であり、コロン定義( -definition)などとも呼ばれる。例えば、 square-sum ( a b -- a^2+b^2 ) dup * swap dup * + ; このコードはsquare-sum という名前のワードを定義している。丸括弧の中はコメントで、実行には関わらない。 コード内の各ワードは、半角空白、タブ、改行、のどれかで区切られた文字列で表示される。 や ; もforthでいうワードなのであり、他のワードとの区切りに空白が必要である。 では、dup とか swap とは何だろう? dup と swap は、スタック上の数値を操作するワードで、Forthのコアで定義されている。 では、スタックとは何か、どこにあるのか? Forthは数値データの入出力にスタックというデータ構造を用いる。名前付きの変数は特別な場合しか使わない(といっても、かなりの頻度で利用するが)。スタックはグローバルに存在していて、いつもそこにあると考えて良い。コード内に数値(リテラル)を記述すれば、その値がスタックに積み込まれる。 dup と swap の内容は、スタックの説明の後に説明しよう。 データスタック 入出力を格納するスタックは、別の用途のスタックと区別する場合は、データスタックと呼ぶ。Forthにはスタックが最低2つ準備されている。もう一つはリターンスタックと呼ぶが、これもプログラマが利用できる。リターンスタックについては後で述べる。 スタックはLIFOリストなどともいわれる。LIFOはLast In First Outの略で、数値を取り出すとき、最後に追加した数値が最初に出てくるということである。つまり逆順に取り出される。コードに 5 4 3 と書けば、スタックの一番奥に5、一番表面に3が置かれる。使うときは、3 4 5の順で使われるわけである。 よくあるイメージとしては、リストを上下方向に延ばして"値を積む"などという言い方をする。例えば、本を平積みにして、取るときは最後にのせた一番上から順に取る、というわけだ。しかし、ソースコードは大抵横書きで書くだろうから、横方向で考えた方がわかりやすいかも知れない。つまり、値は、順に左から右に置かれていくのであって、使うときは右端から使っていく、ということである。 以下では、スタックは横向きに考えて説明する。 スタックに値を「積む」のであるから、下から上に伸びると考えるのが良いという人もいる。 他方、実行コンソールに書き込むことを考えると、上から下に伸びると考えれば便利、という人もいる。 しかし、スタックの値の追跡が必要になるようなコードを書くときは、大抵、ファイルにコードを書いているときである。 ファイルにコードを書く際には、経験上、左から右に値を「置いて」行き、右端から喰っていく、と考えるのが、 自分には一番直観的な感じがする。 なお、老婆心だが、「逆順に取り出される」という言い方には注意を要する。いつも1個1個順番を考えるというわけではない。 例えば、"a b -"というコードがあったとき、「まずbを取り出し、次にaを取り出してbから引く」と考えてはならない。二項演算は、まず「上二つの数値」を取るのである。引き算[割り算]の演算は、前にある数値から[を]、後にある数値を[で]、引く[割る]と定義されている。したがって、"a b - " や " a b / "は、それぞれ、"a-b" "a/b"の演算を実施する。逆ではない。 定義内容 square-sumの内容は、要するに2乗和なのだが、ワードの定義を逐一解説してみる。 どのワードも、スタックの値は右から喰っていく。 dup は、一番右端の値を複製して2個にするのである。Duplicate(二重化)の略らしい。 swap は、2つの値の順序を入れ替える。スワップである。 * は掛け算、+ は足し算だが、2項演算は、スタックから2個の値を、まず取り除く。それから、その2箇の値について計算した値をスタックの右端に置くのである。 スタックが 7 8 のところに + を実行すれば、スタックは 15 と変わる。つまり、計算に使われた値は原則なくなるのである。 だから、dup は、1個値を使ってもまだ残しておきたいときなどにも利用される。 実行コードに関わらないスタックの奥の方は影響されない。使われない限り、ずっとそのまま保存されている。 中身を説明しよう。ワードの実行は逐次実行である。単純に書いた順に実行されていくと思って良い。原則、ではあるが。 スタックの初期状態を 3 4 として、スタックの変化を追っていくと、 3 4 dup 3 4 4 * 3 16 swap 16 3 dup 16 3 3 * 16 9 + 25 となる。この演算操作部分を1個にまとめたのがsquare-sumの定義なわけである。数値はスタックという無名変数を通じて抽象化され、実際の計算では自動的に管理されるため、ワード定義内での演算記述の中では見えなくなってしまうが、スタックの現在の状態を意識し判別しやすい処理手順を考えることが、良いforthコードを書く鍵ともなる。 ちなみに、forthでは伝統的に、英大文字と小文字を区別しない。dup もDUP も同じだし、dUpでも同じことである。わかりにくくならないように書けばよい。 スタックコメント square-sumの定義には、ちょっと妙なコメントを付けたが、これはスタックコメントと呼ばれる。フルネームではスタック効果コメントともいう。そこで定義されているワードが、スタック上の値をいくつ使い、スタックに値をいくつ残すか、また、どのような種類(型)の値か、をコメントで明記しておくのである。基本は、 ( 入力1 入力2 入力3 -- 出力1 出力2 ) のように、"--" で区切って書く。入力・出力それぞれに、右の値がスタックの上方(浅い方)である。 "(" はforthのワードである。つまり、コメントを書くときは、左括弧は他の文字列と半角空白で区切られていなければならない。右括弧はそういう条件はないが、区切って書く方がバランスが良いように思う。丸括弧によるコメントは一行コメントで、改行を含むことができない。また入れ子にすることもできない。そのため、コメント中に文字")"を含むことができない(コンパイラはそこでコメント終わりとして処理してしまう)。 Forthにおいては、型によって値が特別に細かく区別されることはない。整数か小数(浮動小数点数)かの違いしかない。整数であれば、数値でもアドレス(メモリーの場所を指す。多くはポインタとして用いられる)でも、同じようにスタックに格納される。これはコンピュータ機械自体の処理と一致している。しかし、プログラムのレベルでは値自体にはもちろん種類はあるのであるから、プログラマーは混同してはいけない。だから、コメントは値の型がわかるようなシンボルを使うと良い。上の例のコメントは、そういう点では、あまり好ましくない。 数値データを、変数名と同一視して名前によって保持・操作するのではなく、“揮発性の”値として用いるforthでは、スタックの状態の変化を見失う危険がある。スタックコメントで一番重要なのは、入出力の値の個数を明記することであるといえるだろう。 コメントであるから書かなくてもプログラム内容に影響はないが、デバッグや保守が困難となるだろう。 小括 コロン定義 上では、ワードsquare-sumが定義された。コロン がワード定義の開始を告げる。その次の文字列(一文字でもよく、文字種の制限もない)は、ここで定義されるワードの名前を宣言する。そして、そのワードが実行されたときに行われるべきオペレーション系列、最後に、セミコロン ; でワード定義は終了する。このワード定義方法をコロン定義と呼ぶ。その一連の過程もまたコロン定義という。この方法で定義されたワードはコロン定義ワードなどという。このプロセスによって、新しいワードsquare-sumが、forthの辞書に登録されることになるのである。それ以後は、このワードは、その名前を書くことで「呼び出す」ことができるようになる。「呼び出さ」れた場合の動作は、コンパイル環境 — つまり、 と ; の間のコロン定義内 — では、呼び出しをコンパイルすることであり、実行環境では、実際に呼び出されて、その定義されたオペレーションがスタックに対して実行されることになる。 ワードの有効範囲 Forthのワードは、すべて、原則として、パブリックである。定義後はソースコードのどこからでも呼び出せる。けれども、他のある種の言語のようにヘッダファイルで定義関数を冒頭にまとめるという慣行はないので、あるワードが利用できるかどうかはソースコードのロードの順序に依存する。厳密な意味では大域 (Global)ではない。そのようなわけで「パブリック」という言い方をしてみた(公式の呼称ではない)。あるワードのコロン定義がロードされ、辞書にコンパイルされた後は、そのワードはどこからでも利用できるということである。 このように、ロードの時間的順序を除けばforthのワード定義は全く自由であるため、五月雨型の定義順序でするコーディングも可能である。 後で見たときに分かりやすいように整理して書くことは、プログラマーの責任である。 局所的にのみ有効なワードを定義するための特別な機構をオプションで持つことはできる。しかし、そのような特別なものを別としても、forthのワード定義は、ちょっとかわった特性を持っている。というのは、同じ名前のワードを再定義できるのである。そのときの挙動は、上書き定義というよりも切り替えである。つまり、同名ワードの再定義は、これまでの部分には全く影響を与えず、それ以後にロードされる部分では、新しい定義だけが有効になるのである。Forthではプログラムの意味の確定に関しても、時間次元が導入されているのである。 この特性は、forthワードに、いく分かの局所性、ないし、プライベート性を与える。モジュラーなコーディングを指向して、一つのまとまりの中で他のまとまりから呼び出されるワードを限定的に特定する、というようにすれば、モジュール内部的ワードはその場で定義されるであろうから、特に他との名前のダブりを気にする必要はないわけである。 この特性は、他方で、ソースコードを読む際の混乱を引き起しうる。また、形式論理主義(つまり時間次元の排除)の観点からすれば、 同一の名前には同一の意味が与えられていなければならない、と考えることになり、forthのやり方はこれと矛盾する。 しかし、工夫して用いれば便利な機能は、大抵、杜撰な使い方もできるものであり、そのときには有害なものになる。 また、特有の考え方さえおさえておけば、教条主義的になることに、あまり意味はないと思われる。 全てがワードの実行 Forthはセマンティカル言語とでもいうべき特性を持つ。Forthのプログラムにおいて重要なのは、行や文など長い構成体の持つ構文ではなく、各ワードの意味(オペレーショナル セマンティクス)である。各ワードの意味が語順に従って継続的に実現されていくことでプログラムは稼働する。 他の多くのプログラミング言語では、特殊記号を組み合わせて構成された陳述や文が読み取られ、それが分解分析され解釈された上でどのような処理が命じられているのかが判定される。その意味を確定するには決まった構文に従っていることが重要であり、その点からいえば構文(シンタクス)的言語である。自然言語(人が話し、読み書きする言葉)理論が、文法の形式的法則性に着目してそこから意味を割り出すというやり方で知識を蓄積していたこともあって、プログラミング言語理論はそれを利用して開発設計されたものが多い。結果として、言語理論というと構文の形式法則を操作するものしかあり得ないという誤信を招いたかのようである。Forthのような意味を中心にする言語を理論的に「武装」するには、まだ便利な方法がないようである。しかし、プログラミングが普及し、言語理論にあまりこだわらない発想で設計された新しい(といっても1980年代以降だが)言語は、forthにとは言わないまでも、Mopsと似たような構文を持つものも散見される。 Mopsは、Forthも元はそうであったのだが、実践において有用な機能を混同や混乱無く指定・記述できることを最優先した設計になっている。それは、いわば、データスタックを利用するプログラミングのためのUtilitiesの集合体である。言語はプログラマーに自由を与え、プログラマーが自らの能力と責任でそれを律していくという方針は正しいものと思われる。奇妙に教師然とした言語(とその威を借るプログラマー)が多く目につくけれども。 * 近年のforthには、標準化に向けた統制を強めようとしているようである。 しかし、Forthにとっては普通のプログラミング言語のようになろうとすることが自殺行為なのである。 ごく一部だが、標準化の議論を観察すると、forth言語規格の形で、forth開発環境のソフトウエアとしての仕様を規格化したいようである。 コマンドラインからのコマンド入力であって、プログラミング「言語」ではないかのようである。 この発想は、構造をもった言語の規格を考える上では、良くないように思われるのだが。 以下、forth言語について概説する。内部的な実装の話にも触れたい。当面は、基本的な既定義ワードの意味や語用法については、こちらを参照されたい。リンク先には、ややMops方言に傾くものの、基礎的なことを含めて大抵のことは書いたつもりである。ここに書くこととのダブりもあろうかと思われる。 次 Forth開発環境の初歩的使用法