MIPS 逆アセンブラー(arch/mips/disasm.fs)には、 非常に反復的なスキームに従って逆アセンブルするための多くのワードが含まれています(訳注: very repetetive scheme; repetitiveのスペルミスっぽい):
:noname disasm-operands s" inst-name" type ; entry-num cells table + !
もちろん、 これは共通点をくくり出して以下のような定義を可能にするというアイデアを刺激します:
disasm-operands entry-num table define-inst inst-name
通常、 パラメーター disasm-operands と table は相関しています。 さらに、 著者が逆アセンブラーを作成する前に、 以下のような命令を定義するコードがすでに存在していました:
entry-num inst-format inst-name
このコードは assembler 由来で、 arch/mips/insts.fs にあります。
したがって、 実行時に上記のスキームを実行する inst-format ワードを定義する必要がありました。 著者は、 まず最初に、ランタイム・コード生成を使用することを選択しました:
: inst-format ( entry-num "name" -- ; compiled code: addr w -- ) :noname Postpone disasm-operands name Postpone sliteral Postpone type Postpone ; swap cells table + ! ;
注意: これにより、 上記のスキームの他に 2 つのパラメーターが提供されることに注意してください。
別の方法として、 create
/does>
を使用してこれを記述することもできます:
: inst-format ( entry-num "name" -- ) here name string, ( entry-num c-addr ) \ parse and save "name" noname create , ( entry-num ) latestxt swap cells table + ! does> ( addr w -- ) \ disassemble instruction w at addr @ >r disasm-operands r> count type ;
どういうわけか、 最初の解決策の方が簡単です。 その主な理由は、 string,
やその友達を使用するよりも、
sliteral
を使用した方が、 文字列を定義時から使用時へシフトするのが簡単だからです。
私はこのスキームに従ってたくさんのワードを書き、 すぐにそれらの共通点を取り出すことを考えました。 これは 2 レベルの定義ワード、 つまり通常の定義ワードを定義するワードを使用していることに注意してください。
今回は、 postpone
とそのファミリーが関与する解決策はより困難に思えたので(研究課題として試してみましょう)、
create
/does>
というワードを使用することにしました。 私はすでにそれを行っていたので、 下位レベルにも
create
/does>
を使用しました(研究課題として postpone
などを使用してみましょう)。
その結果、 以下の定義が得られました:
: define-format ( disasm-xt table-xt -- ) \ 逆アセンブルに disasm-xt を使用する命令フォーマットを定義し、 \ 定義された命令を \ 表(table) table-xt に入れます create 2, does> ( u "inst" -- ) \ 命令 inst を逆アセンブルする匿名ワードを定義し、 \ それを u 番目のエントリとして table-xt に入れます 2@ swap here name string, ( u table-xt disasm-xt c-addr ) \ remember string noname create 2, \ define anonymous word execute latestxt swap ! \ enter xt of defined word into table-xt does> ( addr w -- ) \ disassemble instruction w at addr 2@ >r ( addr w disasm-xt R: c-addr ) execute ( R: c-addr ) \ disassemble operands r> count type ; \ print name
注意: ここでのテーブルは(上記とは対照的に) cells +
を単独で実行することに注意してください (そのため、xt
を渡す必要があります)。 このワードは以下のように使用されます:
' disasm-operands ' table define-format inst-format
上に示したように、 定義された命令フォーマットは以下のように使用されます:
entry-num inst-format inst-name
カリー化に関しては、 この種の 2 レベルの定義ワードは 3 段階でパラメーターを提供します。 最初に disasm-operands と
table、 次に entry-num と inst-name 、最後に addr w
つまり、
逆アセンブル対象の命令です。
もちろん、 これは insts.fs で使用されるすべての命令フォーマット名に完全に適合するわけではないため、 パラメーターを正しい形式に条件付けるいくつかのラッパーを定義する必要がありました。
あなたが、 このセクションを理解するのが難しい場合でも、 心配する必要はありません。 まず、 これは複雑であり、
理解するのに時間がかかります(おそらく多少いじくりまわすことも必要です)。 2 番目に、 これは私が Forth の 17 年間で書いた最初の 2
レベルの create
/does>
ワードです。 また、 最初に insts.fs がなかった場合は、 1
レベルの定義ワードのみを使用することを選択した可能性があります(定義ワードを使用するときにパラメーターをいくつか繰り返します)。 したがって、
これを理解する必要はありませんが、 あなたの Forth についての理解が深まるかもしれません。