* acl4のページ0009
-(by [[K]], 2026.02.04)

** (1)
 #if (a_Version >= 1)
     #define Preprocessor_Define         a_Preprocessor_Define
     #define Preprocessor_Define_din     a_Preprocessor_Define_din
     #define Preprocessor_newKey         a_Preprocessor_newKey
     #define Preprocessor_marking0       a_Preprocessor_marking0
     #define Preprocessor_marking1       a_Preprocessor_marking1
     #define Preprocessor_define2        a_Preprocessor_define2
     #define Preprocessor_define3        a_Preprocessor_define3
     #define Preprocessor_define4        a_Preprocessor_define4
 #endif
 
 a_class(a_Preprocessor_Define) { a_SetElm elm[1]; char *q; intptr_t n; };
 
 a_static void a_Preprocessor_Define_din(a_Preprocessor_Define *w)
 {
     if (w->q != NULL) a_free(_arg_  w->q, w->n);
     a_free(_arg_  (char *) w->elm->k, w->elm->n);
 }
 
 a_static char *a_Preprocessor_newKey(int an, const char *nam, intptr_t len)
 {
     char *k = a_malloc(_arg_  len + 1);
     k[0] = an; memcpy(&k[1], nam, len);
     return k;
 }
 
 a_static void a_Preprocessor_marking0(a_VecChr *tmp, a_Token0 *t0, a_VecChr *args, int c)
 // #defineの引数を [01 01] とか [01 02] などに置換する.
 {
     int i, n = (int) (args->n / (2 * sizeof (char *)));
     a_Set0 set[1]; a_Set0_ini(set); a_SetElm elm[256];
     char mark[2]; mark[0] = c;
     char **ap = (char **) args->p, *t;
     if (n + c > 256) a_errExit("Preprocessor_define1: too many args (c=%d, n=%d)", c, n);
     for (i = 0; i < n; i++) {
         elm[i].k = ap[i * 2];
         elm[i].n = ap[i * 2 + 1] - ap[i * 2];
         a_Set0_add(set, &elm[i]);
     }
     t0->s = tmp->p; t0->s1 = tmp->p + tmp->n; tmp->n = 0;
     for (;;) {
         t = a_Token1_get(t0);
         if (t0->len == 0) break;
         tmp->n = t + t0->len - tmp->p;
     }
     t0->s = tmp->p; t0->s1 = tmp->p + tmp->n;
     for (;;) {
         t = a_Token1_get(t0);
         if (t0->len == 0) break;
         if (t0->len >= 2 && t[0] == '/' && t[1] == '/') {
             tmp->n = t - tmp->p; // コメントが後続しているならそこから打ち切る。
             break;
         }
     }
     while (tmp->n > 0 && ((unsigned char *) tmp->p)[tmp->n - 1] <= ' ') tmp->n--;
     t0->s = tmp->p; t0->s1 = tmp->p + tmp->n;
     for (;;) {
         t = a_Token1_get(t0);
         if (t0->len == 0) break;
         a_SetElm *e = a_Set0_findKn(set, t, t0->len);
         if (e != NULL) {
             mark[1] = (char) (c + (e - elm));
             intptr_t pos0 = t - tmp->p;
             a_VecChr_replace(tmp, pos0, t0->len, mark, 2); // 変数名を [01 xx] に置換.
             t0->s = tmp->p + pos0 + t0->len;
             t0->s1 = tmp->p + tmp->n;
         }
     }
     a_Set0_din(set);
 }
 
 a_static void a_Preprocessor_marking1(a_VecChr *tmp, a_VecChr *args, int c, int an, a_VecChr *tmp1)
 {
     if (an < 0xff) { // Token1_getをあえて使わずに、strstrで見つけて置換していく.
         char **ap = (char **) args->p;
         int i;
         for (i = 0; i < an; i++) {
             tmp1->n = 0;
             a_VecChr_puts(tmp1, ap[i * 2], ap[i * 2 + 1]);
             char *p = strstr(tmp->p, tmp1->p), mark[2];
             mark[0] = c;
             mark[1] = c + i;
             while (p != NULL) {
                 intptr_t pos = p - tmp->p;
                 a_VecChr_replace(tmp, pos, tmp1->n, mark, 2);
                 p = strstr(tmp->p + pos + 2, tmp1->p);
             }
         }
     }
 }
 
 a_static int a_Preprocessor_define4(a_Set0 *set, const char *s, intptr_t sn, int an);
 
 a_static int a_Preprocessor_define2(a_Set0 *set, a_Token0 *t0, a_VecChr *lin, int c, a_VecChr *path, intptr_t linNo, uint32_t stpTkn)
 {
     a_VecChr args[1], tmp[1]; a_VecChr_ini4(args, tmp, 0, 0);
     char *p = lin->p; t0->s1 = p + lin->n;
     int rp = 0, i;
     for (i = 0; i < 64; i++) { // 無限適用の可能性があるので64回を上限とする.
         char lrp = 0;
         for (t0->s = p;;) {
             char *t = a_Token1_get(t0);
             if (t0->len == 0 || t0->c == stpTkn) break;
             if (t0->len == 2 && t[0] == '#' && t[1] == '#') { // ## があったら前後の空白類とともに削除する.
                 intptr_t pos0 = t - p, pos1 = pos0 + 2;
                 while (pos0 > 0 && p[pos0 - 1] <= ' ') pos0--;
                 while (pos1 < lin->n && p[pos1] <= ' ') pos1++;
                 a_VecChr_replace(lin, pos0, pos1 - pos0, NULL, 0); lrp = 1; // 長さ0文字の文字列と置換することで削除を実現.
                 t0->s = p; // 長さが短くなるだけなのでpは変化しない.
                 t0->s1 = p + lin->n;
                 continue;
             }
         }
 cont0:
         t0->c = 0; intptr_t pos0 = 0; 
         for (t0->s = p;;) {
             intptr_t c0 = t0->c, pos00 = pos0;
 cont1:
             char *t = a_Token1_get(t0);
             if (t0->len == 0 || t0->c == stpTkn) break;
             pos0 = t - p;
             if (t0->c == '.' && t[1] == '(') {
                 a_VecChr_replace(lin, pos0, 2, "(_arg, ", 7); lrp = 1; // 置換する.
                 a_VecChr_din4(args, tmp, 0, 0); return 1;
             }
             if (c0 == '(' && t0->c == ',') { *t = ' '; goto cont1; } // ここで処理すると改行を超えられないという問題はある.
             if (c0 == '{' && t0->c == ',') { *t = ' '; goto cont1; } // それが深刻な問題になったら、プリプロセッサ後に対処するしかない.
             if (c0 == ',' && t0->c == ',') { *t = ' '; goto cont1; }
             if (c0 == ',' && t0->c == ')') { p[pos00] = ' '; goto cont0; }
             if (c0 == ',' && t0->c == '}') { p[pos00] = ' '; goto cont0; }
             if (t0->cTyp != 3) continue;
             if (t0->len == 8 && memcmp(t, "__FILE__", 8) == 0) {
                 char *rp = a_malloc(_arg_  path->n + 3);
                 sprintf(rp, "\"%.*s\"", (int) path->n, path->p);
                 a_VecChr_replace(lin, pos0, t0->len, rp, path->n + 2); lrp = 1; // 置換する.
                 a_free(_arg_  rp, path->n + 3);
                 a_VecChr_din4(args, tmp, 0, 0); return 1;
             }
             if (t0->len == 8 && memcmp(t, "__LINE__", 8) == 0) {
                 char rp[64];
                 sprintf(rp, "%d", (int) linNo);
                 a_VecChr_replace(lin, pos0, t0->len, rp, strlen(rp)); lrp = 1; // 置換する.
                 a_VecChr_din4(args, tmp, 0, 0); return 1;
             }
             if (t0->len == 7 && memcmp(t, "defined", 7) == 0) {
                 char result;
                 if (&t[7] < t0->s1 && t[7] == '(') {
                     t0->s = &t[8]; a_parseArgs(t0, args);
                     if (t0->c == ')' && 0 < args->n && args->n <= 4 * (intptr_t) sizeof (char *)) {
                         int an = -2; char **ap = (char **) args->p;
                         if (args->n == 4 * sizeof (char *)) an = strtol(ap[2], NULL, 0);
                         result = '0' + a_Preprocessor_define4(set, ap[0], ap[1] - ap[0], an);
                     }
                 } else {
                     t = a_Token1_get(t0);
                     result = '0' + a_Preprocessor_define4(set, t, t0->len, -2);
                 }
                 a_VecChr_replace(lin, pos0, t0->s - t, &result, 1); lrp = 1;
                 p = lin->p;
                 t0->s = p + pos0 + 1;
                 t0->s1 = p + lin->n;
                 goto cont0;
             }
             intptr_t kn = t0->len + 1;
             unsigned char *k = (unsigned char *) a_Preprocessor_newKey(0xff, t, t0->len);
             a_Preprocessor_Define *d = a_Set0_findKn(set, k, kn); // 引数なしマクロで一致するものはあるか?.
             if (d != NULL) {
                 a_VecChr_replace(lin, pos0, t0->len, d->q, d->n); lrp = 1; // 置換する.
 nxt:
             //  p = lin->p;
             //  t0->s = p + pos0;
             //  t0->s1 = p + lin->n;
                 a_free(_arg_  k, kn);
                 // continue;
                 a_VecChr_din4(args, tmp, 0, 0); return 1;
             }
             if (t[t0->len] == '(') {
                 const char *t0s = t0->s++;
                 t = a_parseArgs(t0, args);
                 k[0] = (unsigned char) (args->n / (2 * sizeof (char *)));
                 d = a_Set0_findKn(set, k, kn); // 引数付きマクロで一致するものはあるか?.
                 if (d != NULL) {
                     a_VecChr_resize(_arg_  tmp, d->n);
                     memcpy(tmp->p, d->q, d->n);
                     for (;;) {
                         p = memchr(tmp->p, c, tmp->n);
                         if (p == NULL) break;
                         int i = ((unsigned char *) p)[1] - c;
                         char **ap = (char **) args->p;
                         a_VecChr_replace(tmp, p - tmp->p, 2, ap[i * 2], ap[i * 2 + 1] - ap[i * 2]); // 引数を代入.
                     }
                     a_VecChr_replace(lin, pos0, t + 1 - (lin->p + pos0), tmp->p, tmp->n); lrp = 1; // 置換する.
                     goto nxt;
                 }
                 t0->s = t0s;
             }
             a_free(_arg_  k, kn);
         }
         if (lrp == 0) break;
         rp = 1;
     }
     a_VecChr_din4(args, tmp, 0, 0);
     return rp;
 }
 
 a_static void a_Preprocessor_define3(a_Set0 *set)
 {
     intptr_t i, n = set->tbl->n / sizeof (a_Preprocessor_Define *);
     a_Preprocessor_Define **tbl = (a_Preprocessor_Define **) set->tbl->p;
     for (i = 0; i < n; i++) {
         a_free(_arg_  (char *) tbl[i]->elm->k, tbl[i]->elm->n);
         a_free(_arg_  tbl[i]->q, tbl[i]->n);
         a_free(_arg_  tbl[i], sizeof (a_Preprocessor_Define));
     }
     a_Set0_din(set);
 }
 
 a_static int a_Preprocessor_define4(a_Set0 *set, const char *s, intptr_t sn, int an)
 {
     char *k = a_Preprocessor_newKey(0, s, sn);
     int i;
     if (an == -2) {
         for (an = -1; an <= 64; an++) {
             k[0] = an & 0xff;
             if (a_Set0_findKn(set, k, sn + 1) != NULL) break;
         }
         i = (an <= 64);
         goto fin;
     }
     k[0] = an & 0xff;
     i = (a_Set0_findKn(set, k, sn + 1) != NULL);
 fin:
     a_free(_arg_  k, sn + 1);
     return i;
 }

** (2)
-[[p0002b.c>a4_p0002]] がとても面白いです。
-これにプリプロセッサが使えれば関数マクロとかも定義できて、もっと面白くなりそうだと思いました。
-そしてマクロだけでよければ p0001a.c で既に開発済みなのです。
-これはもういけるところまで行くしかないと思いました(笑)。

-なんだか今後も似たようなことがあるかもなーと思ったので、まずdefine0~3の関数をacl4のライブラリに組み入れてしまうことにしました。
-やっていることはそれだけです。

-class_(Preprocessor_Define) → [[a4_p0001]] の class_(Def) に相当するものです。
-Preprocessor_Define_din → Preprocessor_Defineに対する解放関数です。
-Preprocessor_newKey → マクロ引数の数anとマクロ名(nam, len)から、Set0に対するキーバイト列を生成します。
-Preprocessor_marking0 → [[a4_p0001]] の define1 に相当するものです。
-Preprocessor_marking1 → #.def などはこちらのアルゴリズムで引数マーク変換をします。
-Preprocessor_define2 → [[a4_p0001]] の define2 に相当するものです。少し拡張しています。
-Preprocessor_define3 → [[a4_p0001]] の define3 に相当するものです。
-Preprocessor_define4 → 指定されたマクロが定義済みかどうかを返します。
-Preprocessor_define0 → バージョンアップの際に [[a4_0012]] に引っ越しました。

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

 #define a_Version 1
 #include <acl4.c>
 
 int main(int argc, const char **argv)
 {
     VecChr src[1], linBuf[1], tmp[1]; VecChr_ini4(linBuf, tmp, 0, 0);
     VecChr_iniArg(src, argc, argv, 1, 2); Token0 t0[1]; Token0_ini1(t0);
     Set0 set[1]; Set0_ini(set);
     char *s = src->p, *s1 = src->p + src->n, *t;
     for (;;) {
         s = VecChr_gets(linBuf, s, s1); // 1行をlinBufに格納.
         if (linBuf->n == 0) break;
         for (;;) { // 末尾が "\\\n"であれば、後続行を接続.
             char *p1 = linBuf->p + linBuf->n;
             if (!(linBuf->n >= 2 && p1[-2] == '\\' && p1[-1] == '\n')) break;
             s = VecChr_gets(tmp, s, s1);
             VecChr_replace(linBuf, linBuf->n - 2, 2, tmp->p, tmp->n);
         }
         t0->s = linBuf->p; t0->s1 = linBuf->p + linBuf->n;
         t = Token1_get(t0);
         if (t0->c == '#') {
             t = Token1_get(t0);
             if (t0->len == 6 && memcmp(t, "define", 6) == 0) {
                 Preprocessor_define0(set, t0, linBuf, 1); continue;
             }
             continue;
         } else {
             while (Preprocessor_define2(set, t0, linBuf, 1, NULL, 0, 0) != 0);
             printf("%.*s", (int) linBuf->n, linBuf->p);
         }
     }
     Preprocessor_define3(set);
     VecChr_din4(src, linBuf, tmp, 0);
     a_malloc_debugList(_arg);
     return 0;
 }

 >t0009a p0001a0.txt
 
 x = ((9)-(5))*((9)-(5));
 y = ((5)*(5))-((3)*(3));
 t0009a.c(34): malloc_debugList()
-まずは動作確認のために [[p0001a.c>a4_p0001]] 相当のものを作りました。ちゃんと動いているようです。
-主要なコードをライブラリに逃がしたので、プログラムは 183行→36行 になっています。

** (99) 更新履歴
-2026.02.04(水) 初版
-2026.02.06(金) Preprocessor_define2にdefined(...)機能を追加。a_Preprocessor_define4を追加
-2026.02.06(金) Preprocessor_define2にdefined(...)機能を追加。Preprocessor_define4を追加
-2026.02.11(水) Preprocessor_newKey などを追加し、 Preprocessor_define0 を引っ越し

-2026.02.15(日) Preprocessor_marking0 のバグを修正

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