4

対話型言語を使用して、レガシー プロジェクトの C コードをテストしたいと考えています。Forth は少し知っていますが、実際のプロジェクトで使用したことはありません。私は今pForthを見ています。

インタラクティブな Forth インタープリターを使用して、C プログラムの一部の関数の動作をテストすることは合理的ですか? この C コードには、多くの構造体、構​​造体へのポインター、ハンドル、および C で見られるその他の一般的な構造体が含まれています。

パラメーターの受け渡しを処理するためのグルー コードと、Forth 側での構造体の割り当てを処理する必要があると思います。この分野の経験のある方に見積もりをお願いしたいです。その価値はありますか?

4

1 に答える 1

9

インタラクティブなテストが必要で、組み込みプラットフォームをターゲットにしている場合、Forth は間違いなく良い候補です。ターゲット プラットフォームで実行される Forth 実装が常に見つかります。必要に応じて、書くことも難しくありません。

当面のニーズに合わせたグルー コードを記述する代わりに、一般的な目的で Forth から C へのインターフェイスを使用します。私は、非常に使いやすいgforth の汎用 C インターフェイスを使用しています。Forth での構造体の処理には、C とのインターフェイスに関して非常に柔軟なMPE スタイルの実装を使用します (ただし、適切な位置合わせに注意してください。gforth %align / %allot / nalign を参照してください)。

ワードを処理する汎用構造体の定義には、約 20 行の Forth コードが必要です。これは、単一の連結リスト処理またはハッシュ テーブルの場合と同じです。

gforth (POSIX のみ) を使用できないため、同様の C インターフェイスを実装する任意の Forth 用の拡張モジュールを作成します。Forth と C インターフェイス モジュールが、テストする C コードと同じ malloc() と free() を使用していることを確認してください。

このようなインターフェースを使用すると、スタブ ワードを定義するだけで Forth ですべてを行うことができます (つまり、Forth ワードを C 関数および構造体にマップします)。

gettimeofdayこれは、 gforth の C インターフェイスを使用してlibc を呼び出すサンプル テスト セッションです。

s" structs.fs" included also structs \ load structure handling code

clear-libs
s" libc" add-lib  \ load libc.so. Not really needed for this particular library

c-library libc    \ stubs for C functions
\c #include <sys/time.h>
c-function gettimeofday gettimeofday a a -- n ( struct timeval *, struct timezone * -- int )
end-c-library

struct timeval          \ stub for struct timeval
    8 field: ->tv_sec   \ sizeof(time_t) == 8 bytes on my 64bits system
    8 field: ->tv_usec
end-struct

timeval buffer: tv

\ now call it (the 0 is for passing NULL for struct timezone *)
tv 0 gettimeofday .  \ Return value on the stack. output : 0
tv ->tv_sec @ .      \ output : 1369841953

は実際には C とtv ->tv_sec同等であるため、構造体メンバーのアドレスが得られるため、 で値をフェッチする必要があることに注意してください。ここでの別の問題: セル サイズが 8 バイトの 64 ビットの Forth を使用しているため、8 バイトの長さの格納/フェッチは簡単ですが、4 バイトのintのフェッチ/格納には特別な処理が必要になります。とにかく、For はこれを簡単にします: 特別な目的とそのための言葉を定義するだけです。(void *)&tv + offsetof(struct timeval, tv_sec)@int@int!

ご覧のように、優れた汎用目的の C インターフェイスを使用すると、C でグルー コードを記述する必要はなく、C 関数と構造体の Forth スタブのみが必要ですが、これは非常に簡単です (そして、そのほとんどは自動的にCヘッダーから生成されます)。

インタラクティブなテストに満足したら、自動化されたテストに進むことができます:

  • 対話型テスト セッションの入力/出力全体をコピーして、testXYZ.log という名前のファイルに貼り付けます。
  • セッション ログから出力を取り除き (入力のみを保持)、これを testXYZ.fs という名前のファイルに書き込みます。
  • テストを実行するには、testXYZ.fs を 4 番目のインタープリターにパイプし、出力をキャプチャして、testXYZ.log と比較します。

対話型セッション ログから出力を削除するのはやや面倒なので、まずテスト スクリプト testXYZ.fs を作成し、それを実行して出力 testXYZ.log を取得することもできますが、私は対話型セッション ログから開始することを好みます。

ほら!

参考までに、上記の例で使用した構造処理コードを次に示します。

\ *****************************************************************************
\ structures handling
\ *****************************************************************************

\ Simple structure definition words. Structure instances are zero initialized.
\
\ usage :
\ struct foo
\     int: ->refCount
\     int: ->value
\ end-struct
\ struct bar
\            int: ->id
\     foo struct: ->foo
\       16 chars: ->name
\ end-struct
\
\ bar buffer: myBar
\ foo buffer: myFoo
\ 42 myBar ->id !
\ myFoo myBar ->foo !
\ myBar ->name count type
\ 1 myBar ->foo @ ->refCount +! \ accessing members of members could use a helper word

: struct ( "name" -- addr 0 ; named structure header )
    create here 0 , 0
  does>
    @ ;

\ <field-size> FIELD <field-name>
\ Given a field size on the stack, compiles a word <field-name> that adds the
\ field size to the number on the stack.

: field: ( u1 u2 "name" -- u1+u2 ; u -- u+u2 )
    over >r \ save current struct size
    : r> ?dup if
    postpone literal postpone +
    then
    postpone ;
    + \ add field size to struct size
; immediate

: end-struct ( addr u -- ; end of structure definition )
    swap ! ;

: naligned ( addr1 u -- addr2 ; aligns addr1 to alignment u )
    1- tuck + swap invert and ;

\ Typed field helpers
: int: cell naligned cell postpone field: ; immediate
: struct: >r cell naligned r> postpone field: ; immediate
: chars: >r cell naligned r> postpone field: ; immediate
\ with C style alignment
4 constant C_INT_ALIGN
8 constant C_PTR_ALIGN
4 constant C_INT_SIZE
: cint: C_INT_ALIGN naligned C_INT_SIZE postpone field: ; immediate
: cstruct: >r C_PTR_ALIGN naligned r> postpone field: ; immediate
: cchars: >r C_INT_ALIGN naligned r> postpone field: ; immediate

: buffer: ( u -- ; creates a zero-ed buffer of size u )
    create here over erase allot ;
于 2013-05-29T16:53:57.390 に答える