Node:Top, Next:, Previous:(dir), Up:(dir)


Node:Overview of sogen, Next:, Previous:Top, Up:Top

sogenとは

sogenはユーザーが定義した構造体の操作コードを生成するコード・ ジェネレータです。構造体を格納する可変長コンテナを用意し、追加・削除・ 変更・ソート・検索等の操作をユーザーに提供するものです。ユーザーは 構造体の定義だけすればよく、後はsogenに任せればよいのです。

C++ではSTLが使えて不便な思いはしませんが、Cだけの環境では同じような コードを何度も書いて、且つバグと戦わなければならないことを考えると このようなコード・ジェネレータが必要と思われました。しかも、 ポータブルな。


Node:Usage, Next:, Previous:Overview of sogen, Up:Top

使用法

ユーザーはaddress.hを作成します。 ソース生成の都合上、ターゲットとなる構造体はtypedefでそれ用の型を定義しておいてください。 struct _ADDRESSのままだとsogenは使用できません。ご注意ください。

        typedef struct _ZIP {
            int  i_key;
            char zip[7];
        } ZIP;

        typedef struct _PERSON {
            int  i_key;
            char name[16];
        } PERSON;

        typedef struct _ADDRESS {
            int    i_key;
            char   name[256];
            char   *p_symbol;
            ZIP    zip_code;
            PERSON *person;
        } ADDRESS;


sogenは以下のようにして使用します。sogenはコードを生成する 際にaddress.hは読みません。単純にコマンドライン引数から得た情報から 単調にソースを作るだけなのです。

$ sogen -i address.h -n ADDRESS -k i_key

これにより、2つのファイルaddress_mgr.caddress_mgr.hが 生成されます。ユーザーはaddress_mgr.hをインクルードすれば、 構造体操作関数が使えます。

      #include <stdio.h>
      #include "address_mgr.h"
      ...

      int
      main(int argc, char **argv)
      {
          size_t i;
          ADDRESS  adr;
          adr.i_key = 0;
          strcpy( adr.name, "masu" );
          ...
          address_push_back( &adr );    /* コンテナに追加 */
          ...
          address_push_back( &adr );    /* コンテナに追加 */
          ...
          address_push_back( &adr );    /* コンテナに追加 */
          ...
          address_sort();      /* sort */

          /* 全要素の name を表示 */
          for ( i = 0; i < address_size(); i++ ) {
              printf( "name: %s\n", address_at( i )->name );
          }
          ...
          address_clear();     /* メモリ解放 */
          return 0;
       }


Node:Functions, Next:, Previous:Usage, Up:Top

操作関数

sogenにより生成された操作関数を以下に示します。 NAMEは構造体の名前1です。nameNAMEを全て小文字にした文字列です。


int name_push_back( const NAME *p )
コンテナの後方から要素を追加します。追加される要素は内部で新たに メモリ確保した実体です。内容はmemcopyのイメージでコピーします。 内部でメモリ確保に失敗した場合は0以外を返します。正常な場合は 0を返します。
void name_pop_back( void )
コンテナの後方から要素を一つ削除します。
void name_touch_pop_back( void ( *fn )( NAME * ) )
コンテナの後方から要素を一つ削除します。削除に先立って関数fnを実行 します。fnは通常、要素のクリーンアップ関数として使われます。
void name_clear( void )
コンテナの全ての要素を削除します。コンテナは空になります。
void address_touch_clear( void ( *fn )( NAME * ) );
コンテナの全ての要素を削除します。各要素の削除に先立って関数fnを 実行します。fnは通常、要素のクリーンアップ関数として使われます。
size_t address_size( void )
コンテナの要素数を返します。
const NAME * address_at( size_t i )
コンテナのi番目の要素へのポインタを返します。 内部ではコンテナを配列として実装しているのでこのような表現が出てきます。 要素数を超えてアクセスをしようとしたときはNULLを返します(fence post)。
int name_find( NAME **pp )
name_findfirst( NULL, NAME ** )と同じです。 コンテナの最初の要素へのポインタを獲得します。要素があれば0以外を、 要素がなければ0を返します。要素を総ナメしたしときの最初に呼ぶ 関数です。
int name_findfirst( int ( *fn_flt )( NAME * ), NAME **pp )
関数fn_fltで真を返す要素を検索します。最初に条件を満足した要素への ポインタを獲得します。条件を満足する要素があれば0以外を、条件を 満足する要素がひとつもないときは0を返します。

次に条件を満足する要素を探したいときは、関数name_findnextを呼びます。 前回の条件を満たした位置は静的に保持しています。

int name_findnext( int ( *fn_flt )( NAME * ), NAME **pp )
関数name_findfirst、またはname_findnext自身を呼んだ後 に呼びます。前回のヒットした位置より 後方を、条件関数fn_fltを満たす要素を検索します。 条件を満足した要素へのポインタを獲得します。 条件を満足する要素があれば0以外を、条件を 満足する要素がひとつもないときは0を返します。 条件を満たした位置は静的に保持しています。
NAME * name_bsearch( NAME *p )
pで指定した要素と一致する要素がコンテナに存在するかサーチします(binary search)。 一致する要素がある場合にはその要素へのポインタを返します。なければNULLを 返します。 sogen実行時に主キー(primary key)を指定(-k,-K)した 場合にのみ使用できます。 比較関数を別途用意する場合は、以下のname_bsearch_by関数を使用します。
NAME * name_bsearch_by( NAME *p, int ( *fn_cmp )( const void * ,const void * ) )
比較関数fn_cmpを指定して、pで指定した要素と一致する要素がコンテナに存在するかサーチします(binary search)。 一致する要素がある場合にはその要素へのポインタを返します。なければNULLを 返します。

比較関数の引数の型がconst void *なのは、標準関数bsearchに渡す 比較関数の型に依存しているからです。

void name_sort( void )
コンテナ内をソートします(quick sort)。 sogen実行時に主キー(primary key)を指定(-k,-K)した 場合にのみ使用できます。主キーが値、文字列の場合とも昇順です。比較関数を 別途用意する場合は、以下のname_sort_by関数を使用します。
void name_sort_by( int ( *fn_cmp )( const void * ,const void * ) )
比較関数fn_cmpを指定して、コンテナ内をソートします(quick sort)。 比較関数の引数の型がconst void *なのは、標準関数qsortに渡す 比較関数の型に依存しているからです。
void name_transform( void ( *fn )( NAME * ) )
コンテナ内の全要素に対して、関数fnを実行します。 要素に対する変更・更新を一括して行う場合に使用します。
void name_transform_if( int ( *fn_flt )( NAME * ), void ( *fn )( NAME * ) )
フィルタ関数fn_fltを実行して真を返す要素にのみ、関数fnを実行します。 選別された要素に対する変更・更新を一括して行う場合に使用します。


Node:Options, Next:, Previous:Functions, Up:Top

起動オプション

sogenの起動オプションです。

-i <include_file>
構造体を定義したヘッダファイルを指定します。必須です。
-n <NAME>
構造体の名前を指定します。大小文字を区別します。必須です。
-k <primary_key_val>
構造体の主キーを指定します。この場合、主キーの型は値です。 -Kオプションと同時に使用できません。
-K <primary_key_string>
構造体の主キーを指定します。この場合、主キーの型は文字列となります。 -kオプションと同時に使用できません。
-s <body_suffix>
sogenが生成するファイル名のサフィックスを指定します。 デフォルトでは_mgrとなっています。例えば-n FOO -s _aaaと指定した 場合、生成させるファイルは、foo_aaa.cfoo_aaa.hになります。
-h
簡単な使用方法を表示します。
-V
sogenのバージョン情報を表示します。


Node:Note, Next:, Previous:Options, Up:Top

その他


Node:Container Implimentation, Next:, Up:Note

コンテナの実装

コンテナは可変長配列として実装しています。 初期サイズは128です。このサイズをオーバーするときは新たに、その2倍の 容量を確保しなおします。つまり、128を超えるときは256です。256を超えるときは 512です。少々メモリが無駄になりますが、オーダー的には収まっていて手軽な 実装方法です。


Node:Another Generator, Previous:Container Implimentation, Up:Note

別のコード・ジェネレータ

sogenのソースコードの一部は、opgenにより生成されています。 opgenはコマンドライン・パーサーを生成するコード・ジェネレータです。


Node:Bug, Previous:Note, Up:Top

バグ

sogenは実体をユーザーから隠蔽した可変長コンテンナを提供しますが、 生憎その数は唯一です。ですから、コンテンナの配列、構造体メンバ中にコンテンナ を配する等、よく出会いそうな問題には対処できません。 そこでこれらの問題に対処すべくsogenを拡張する予定です。

バグリポートは massun.masumoto@nifty.ne.jpへお願いいたします。 また、現在のところ公開は作者のWebサイト http://member.nifty.ne.jp/~masumoto/ で行います。

Table of Contents


Footnotes

  1. typedefで定義した名前です。