* acl4のページ0004
-(by [[K]], 2026.01.28)

** (1)
 #if (a_Version >= 1)
     #define VecChr_vprintf              a_VecChr_vprintf
     #define VecChr_printf               a_VecChr_printf
     #define VecChr_putc                 a_VecChr_putc
     #define VecChr_readFileAll          a_VecChr_readFileAll
     #define VecChr_readFileAll_errChk   a_VecChr_readFileAll_errChk
     #define VecChr_eraseCr              a_VecChr_eraseCr
     #define VecChr_writeFileAll         a_VecChr_writeFileAll
     #define VecChr_writeFileAll_errChk  a_VecChr_writeFileAll_errChk
     #define VecChr_stkAdd               a_VecChr_stkAdd
     #define VecChr_stkRmv               a_VecChr_stkRmv
 #endif
 
 a_static intptr_t a_VecChr_vprintf(a_VecChr *w, const char *f, va_list a)
 {
     intptr_t d = w->n1 - w->n;
     intptr_t i = vsnprintf(w->p + w->n, d, f, a);
     if (i <= 0) goto fin;
     if (i + 1 > d) {
         a_VecChr_reserveDiff(w, i + 1);
         d = w->n1 - w->n;
         i = vsnprintf(w->p + w->n, d, f, a);
         if (i <= 0) goto fin;
     }
     w->n += i;
 fin:
     return i;
 }
 
 a_static intptr_t a_VecChr_printf(a_VecChr *w, const char *f, ...)
 {
     va_list ap;
     va_start(ap, f);
     intptr_t i = a_VecChr_vprintf(w, f, ap);
     va_end(ap);
     return i;
 }
 
 a_static int a_VecChr_putc(a_VecChr *w, int c)
 {
     a_VecChr_reserveDiff(w, 2);
     w->p[w->n++] = c;
     w->p[w->n] = '\0';
     return c;
 }
 
 a_static intptr_t a_VecChr_readFileAll(a_VecChr *w, const char *path)
 {
     FILE *fp = fopen(path, "rb");
     if (fp == NULL) return -1;
     intptr_t bufSz = 1024 * 1024, n0 = w->n;
     for (;;) {
         a_VecChr_reserveDiff(w, bufSz);
         intptr_t i = (intptr_t) fread(w->p + w->n, 1, bufSz, fp);
         if (i <= 0) break;
         w->n += i;
     }
     fclose(fp);
     a_VecChr_reserve0(w);
     a_VecChr_shrink(_arg_  w, 1);
     return w->n - n0;
 }
 
 a_static intptr_t a_VecChr_readFileAll_errChk(a_VecChr *w, const char *path)
 {
     if (path == NULL) a_errExit("fopen error: path=NULL");
     intptr_t i = a_VecChr_readFileAll(w, path);
     if (i < 0) a_errExit("fopen error: %s", path);
     return i;
 }
 
 a_static intptr_t a_VecChr_eraseCr(a_VecChr *w)
 {
     char *p, *q, *p1;
     p = q = w->p;
     p1 = p + w->n;
     while (p < p1) {
         if (*p++ != '\r')
             *q++ = p[-1];
     }
     w->n -= p1 - q;
     a_VecChr_reserve0(w);
     return p1 - q;
 }
 
 a_static intptr_t a_VecChr_writeFileAll(a_VecChr *w, const char *path, const char *mod)
 {
     FILE *fp = fopen(path, mod);
     if (fp == NULL) return -1;
     intptr_t i = 0, j;
     for (;;) {
         j = fwrite(w->p + i, 1, w->n - i, fp);
         if (j <= 0) break;
         i += j;
     }
     fclose(fp);
     return i;
 }
 
 a_static intptr_t a_VecChr_writeFileAll_errChk(a_VecChr *w, const char *path, const char *mod)
 {
     if (path == NULL) a_errExit("fopen error: path=NULL");
     intptr_t i = a_VecChr_writeFileAll(w, path, mod);
     if (i < 0)
         a_errExit("fopen error: %s", path);
     if (i < w->n)
         a_errExit("fwrite error: %s", path);
     return i;
 }
 
 a_static void *a_VecChr_stkAdd(a_VecChr *w, intptr_t sz)
 {
     a_VecChr_resizeDiff(_arg_  w, + sz);
     return w->p + w->n - sz;
 }
 
 a_static void *a_VecChr_stkRmv(a_VecChr *w, intptr_t sz)
 {
     return w->p + (w->n -= sz);
 }

** (2) VecChr_printf など
-雰囲気としては sprintf の拡張版みたいなものです。
-違うのは、出力結果が準備した配列に収まるかどうかを気にする必要がないことと、コンソールやファイルのように、どんどん追記できるというところです。

-私がコンパイラを作るとき、fprintfなどでアセンブラをファイルに出力したりはしません。VecChrを使って、メモリ上に出力します。
-こうしておけば、ファイルに出力することもしないこともできます。ファイルに出力せず、オンメモリで自作のアセンブラに渡すこともあります。こうすれば中間ファイルを生成せずに処理を進めることもできるのです。

-そうやってファイルを出力しないプログラミングをやっていると、入力もファイルではなくメモリでやりたくなるので、結局、メモリから入力してメモリへ出力するような作り方になります。
-すると、ファイルを全部読んでメモリに入れる関数や、メモリからファイルへ書き出す関数が欲しくなって、readFileAllやwriteFileを作っています。

-eraseCrは、メモリ上の'\r'の文字コードをすべて消去する関数です。
-本来はfopenするときに"rt"でオープンすればいいだけなので、こんな関数は必要ないはずです。実際、Windows上ではこれでうまくいきます。
-しかしLinux上ではうまくいきません。Linuxではテキストモード・バイナリモードという区別がなく、"t"をつけても何もしません。・・・Linuxではテキストファイルに'\r'を含めずに出力するので、この仕様で問題ないのですが、しかしWindowsで作ったテキストファイルをLinux上で読ませると'\r'を含んだまま読み込んでしまいます。こうして'\r'の存在を想定していないプログラムを書いてしまうと、誤動作してしまうのです。
-これに悩まされたので、私はWindowsでもLinuxでも"rb"で読み込んで、自前の関数で'\r'を消去するようにしています。これならどんな組み合わせでも誤動作はありません。

** (3) サンプルプログラム: t0004a.c
-acl4ライブラリは以下のようにして利用します。
-[1]まずa4_0001~a4_0004のプログラムをつなげて"acl4.c"として保存します。
-[2]次にacl4を使ったプログラムを書きます。
-[3]コンパイル時に、"acl4.c"のあるパスをインクルードパスの一つとして指定します。

 #define a_Version 1
 #include <acl4.c>
 
 int main()
 {
     VecChr vc[1]; VecChr_ini(vc);
     VecChr_printf(vc, "hello, world\n");
     int i;
     for (i = 0; i < 10; i++)
         VecChr_printf(vc, "%d ", i);
     VecChr_putc(vc, '\n');
     printf("%s", vc->p); // メモリ内で作った文字列を一気に出力.
     printf("vc.n=(%d/%d)\n", (int) vc->n, (int) vc->n1);
     VecChr_din(vc);
     a_malloc_debugList(_arg); // 開放忘れがないことを確認するために、これを書くくせがある.
     return 0;
 }

 >t0004a
 hello, world
 0 1 2 3 4 5 6 7 8 9
 vc.n=(34/64)
 t0004a.c(15): malloc_debugList()

** (4) VecChr_stkAdd, stkRmv
-VecChrでスタックを作れば、サイズの管理を気にしなくてよくなるのではないかと思いついて、作ってみたものです。

** (5) サンプルプログラム: t0004b.c
-acl4ライブラリは以下のようにして利用します。
-[1]まずa4_0001~a4_0004のプログラムをつなげて"acl4.c"として保存します。
-[2]次にacl4を使ったプログラムを書きます。
-[3]コンパイル時に、"acl4.c"のあるパスをインクルードパスの一つとして指定します。

 #define a_Version 1
 #include "acl4.c"
 
 class_(Elm) { int i; const char *s; };
 
 int main()
 {
     VecChr stk[1]; VecChr_ini(stk); Elm *sp;
 
     sp = VecChr_stkAdd(stk, sizeof (Elm)); sp->i = 123; sp->s = "abc";
     sp = VecChr_stkAdd(stk, sizeof (Elm)); sp->i = 456; sp->s = "def";
     sp = VecChr_stkAdd(stk, sizeof (Elm)); sp->i = 789; sp->s = "ghi";
 
     sp = VecChr_stkRmv(stk, sizeof (Elm));
     printf("poped data = [%d, %s]\n", sp->i, sp->s);
     sp = VecChr_stkRmv(stk, sizeof (Elm));
     printf("poped data = [%d, %s]\n", sp->i, sp->s);
     sp = VecChr_stkRmv(stk, sizeof (Elm));
     printf("poped data = [%d, %s]\n", sp->i, sp->s);
 
     VecChr_din(stk);
     a_malloc_debugList(_arg);
     return 0;
 }

 >t0004b
 stack-top = [789, ghi]
 stack-top = [456, def]
 stack-top = [123, abc]
 t0004b.c(20): malloc_debugList()
 poped data = [789, ghi]
 poped data = [456, def]
 poped data = [123, abc]
 t0004b.c(22): malloc_debugList()


** (99) 更新履歴
-2026.01.28(水) 初版。
-2026.01.30(金) 関数名変更: stkPush → stkAdd, stkPull → stkRmv
-2026.02.09(月) a_VecChr_stkRmv の仕様を変更

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS