* acl4の開発ログ #08
-(by [[K]], 2026.03.14)

-''acl4開発のもくじ → [[a4_i01]]''

** 2026.03.14(土) #0
-ライブラリに加えるとなると、一応それなりの完成度は欲しくて、だからテスト用に雑に書いた関数はライブラリに含めらません。
-だからいろいろ書いているのに、ライブラリには全然追加できてなくて、なんかそこがもどかしいです。

** 2026.03.14(土) #1
-この開発ログの書き方もよくないよなあと反省中。
-ログはずっと同じページに書き続けて、たくさんになったら過去ログへ移動するスタイルにしたいので、後でそれをやろうと思います。

** 2026.03.15(日) #0
-最新の開発ログのURLが https://essen.osask.jp/?a4_log に固定されるようにページの構成を変えました。

** 2026.03.15(日) #1
-ここ数年で最高のアイデアかもしれないものを思いつきました。

-[1](前提の説明)
-まず私は自作プリプロセッサを作りました。そしてプリプロセッサ処理関数を使えば、アセンブラ・仮想マシン・トランスパイラなどがとても簡単に作れることを示しました。
--[[a4_p0004]] (プリプロセッサを利用して短時間でアセンブラを作りました)
--[[a4_p0005]] (プリプロセッサを利用して短時間で仮想マシンを作りました)
--[[a4_p0006]] (プリプロセッサを利用して短時間でトランスパイラを作りました)

-[2](前提の説明)
-こんなにふうに何でも作れて本当に便利なのですが、でもこれには適用条件があります。プリプロセッサの置換機能が生きてくるのは、Macro(arg0, arg1, ...) みたいな形式で書かれているときだけなのです。
-だから、 a = b + c * d; みたいな構文があっても、プリプロセッサは何もできません。もしこれが何とかできるようになったら、言語の開発なんて革命的に楽ができそうなのに・・・。そんなふうにずっと前から(10年以上前から)なんとなく思っていました。
-そこまでは思っていても、そこから先を思いつくことはありませんでした。

-[3](今回のアイデア)
-それならば、そういう変換だけをするプログラムを作ればいいじゃないですか!
 Mul(tmp0. c, d);
 Add(tmp1, b, tmp0);
 Let(a, tmp1);
-この形式に変換できさえすれば、あとはいくらでもプリプロセッサだけで加工できます。そしてこの形式に変換するだけなら、コンパイラを作るのはずっと楽になるし、これを一度作っておけば後段の置換処理を用意するだけで、実に様々な用途に使えるはずです。

-[4](今回のアイデア)
-この拡張プリプロセッサは、型情報を持たせようと思っていて、だから Mul(int,int)とMul(float,float)は別の定義を与えることができます。これができれば置換処理の記述は楽になると思っています。
-また前方参照も可能にしようと思っています。

** 2026.03.16(月) #0
-新しいプリプロセッサ:
--C言語との互換性は気にしない
--#include は #incl にする
--#if 類はそのまま
--#undef はなくす
--#define は #def にする
--#ldef がある(ローカル宣言)
--#scop 命令があって、#endscop するとその中の #ldef は全部消える
--前方参照OK

** 2026.03.17(火) #0
-私が最初に覚えたアセンブラは MC6809 という CPU のものでした。これには COM という命令があって、ビット反転を意味していました。 x86 でいうところの NOT 命令です。
-昨日この COM 命令が急に気になりました。なぜビット反転なのに NOT ではなく COM なのか? COM は何の省略形なのか?
-苦労しましたが、ようやく分かりました。 complement の略のようです。補数ってことですね。ビット反転は「1の補数表現」に当たるので、これは納得がいきます。

-ついでに補数表現についても調べました。いや「1の補数表現」「2の補数表現」というのがあるのは35年以上前から知っていましたが、「3の補数表現」とか「4の補数表現」とかが何であるのか急に気になったためです。
-結論からいうと、2進数で考えているときは「1の補数表現」と「2の補数表現」しかなくて、3や4はないということが分かりました。他の進法で考えれば、3や4も出てきます。
-(詳細に興味があれば「補数表現」を調べてみてください。)

** 2026.03.17(火) #1
-とりあえず適当にこんなプログラムを作りました。

 // tt0003a.c (memo: p0002b.c を参考にして作った)
 
 #define a_Version 1
 #include <acl4.c>
 
 a_class(a_BufFree) { a_VecChr stk[1]; };
 a_static void a_BufFree_ini(a_BufFree *w) { a_VecChr_ini(w->stk); }
 a_static void a_BufFree_din(a_BufFree *w) { a_VecChr_din(w->stk); }
 
 a_static void a_BufFree_add(a_BufFree *w, void *p, intptr_t sz)
 {
     void **t = a_VecChr_stkAdd(w->stk, 2 * sizeof (void *));
     t[0] = p; t[1] = (void *) sz;
 }
 
 a_static void *a_BufFree_malloc(a_BufFree *w, intptr_t sz)
 {
     void *p = a_malloc(_arg_  sz); a_BufFree_add(w, p, sz); return p;
 }
 
 a_static void a_BufFree_flush(a_BufFree *w)
 {
     while (w->stk->n > 0) {
         w->stk->n -= 2 * sizeof (void *);
         void **t = (void **) (w->stk->p + w->stk->n);
         a_free(_arg_  t[0], (intptr_t) t[1]);
     }
 }
 
 a_class(MiniCompiler) {
     a_Token0 *t0;
     a_BufFree bf[1];
     a_VecChr *vc;
     int tmpNo;
 };
 
 a_static void MiniCompiler_ini(MiniCompiler *w)
 {
     a_BufFree_ini(w->bf); w->tmpNo = 0;
 }
 
 a_static void MiniCompiler_din(MiniCompiler *w)
 {
     a_BufFree_flush(w->bf); a_BufFree_din(w->bf);
 }
 
 a_static char *MiniCompiler_newTmp(MiniCompiler *w)
 {
     char s[256];
     intptr_t n = sprintf(s, "tmp%d", w->tmpNo++);
     char *v = a_BufFree_malloc(w->bf, n + 1);
     memcpy(v, s, n + 1);
     return v;
 }
 
 #define MiniCompiler_compile_Macro0(pri, fmt)   vv = MiniCompiler_compile(w, pri); tv = MiniCompiler_newTmp(w); a_VecChr_printf(w->vc, fmt, tv, v, vv); v = tv; goto op2
 
 a_static char *MiniCompiler_compile(MiniCompiler *w, int pri)
 {
     const char *t = Token1_get(w->t0); intptr_t n = w->t0->len; uint32_t c = w->t0->c;
     char *v, *tv, *vv;
     if (n == 0) return NULL;
     if (c == '(') { v = MiniCompiler_compile(w, 99); Token1_get(w->t0); goto op2; }
     v = a_BufFree_malloc(w->bf, n + 1);
     memcpy(v, t, n); v[n] = '\0';
 op2:
     t = Token1_get(w->t0); c = w->t0->c; n = w->t0->len;
     if (n == 0) return v;
     if (c ==  '*' && pri >=  4) { MiniCompiler_compile_Macro0( 3, "Mul(%s, %s, %s);\n"); }
     if (c ==  '/' && pri >=  4) { MiniCompiler_compile_Macro0( 3, "Div(%s, %s, %s);\n"); }
     if (c ==  '%' && pri >=  4) { MiniCompiler_compile_Macro0( 3, "Mod(%s, %s, %s);\n"); }
     if (c ==  '+' && pri >=  5) { MiniCompiler_compile_Macro0( 4, "Add(%s, %s, %s);\n"); }
     if (c ==  '-' && pri >=  5) { MiniCompiler_compile_Macro0( 4, "Sub(%s, %s, %s);\n"); }
     if (c == '='  && pri >= 15) { a_VecChr_printf(w->vc, "Let(%s, %s);\n", v, MiniCompiler_compile(w, 15)); goto op2; }
     if (c ==  ';' && pri >= 98) { a_VecChr_printf(w->vc, "Semi();\n"); v = MiniCompiler_compile(w, 97); goto op2; }
     w->t0->s = t; return v; // 一度読み込んだ未解釈の演算子をt0に押し戻してからreturn.
 }
 
 int main(int argc, const char **argv)
 {
     VecChr src[1], dst[1]; VecChr_iniArg(src, argc, argv, 1, 3);
     Token0 t0[1]; Token0_ini1(t0);
     t0->s = src->p; t0->s1 = src->p + src->n;
     MiniCompiler mc[1]; MiniCompiler_ini(mc); mc->t0 = t0;
     VecChr_ini(dst); mc->vc = dst;
     char *v = MiniCompiler_compile(mc, 99);
     if (v == NULL) v = "(null)";
     printf("%sans: %s\n", dst->p, v);
     MiniCompiler_din(mc);
     VecChr_din4(src, dst, 0, 0);
     a_malloc_debugList(_arg);
     return 0;
 }

 実行結果:
 >tt0003a "x=y=1+2*3; (a+b)*c"
 Mul(tmp0, 2, 3);
 Add(tmp1, 1, tmp0);
 Let(y, tmp1);
 Let(x, y);
 Semi();
 Add(tmp2, a, b);
 Mul(tmp3, tmp2, c);
 ans: tmp3
-とてもよく動いています。 BufFree は有用だと思ったので、 a4_0014 を作るときに入れたいと思います。

-この構想がうまくいくと、「型によって処理が変わる部分」と「型に関係なく共通でできる部分」がうまく分離できて、言語が(コンパイラもインタプリタも)作りやすくなるのではないかという期待を持っています。
--今日作った MiniCompiler は「型に関係ない共通の部分」の処理を担当しています。

** 2026.03.17(火) #2
-if~gotoとfor文をつけてみました。

 // tt0003b.c
 
 // (tt0003a.cと同じ部分は省略).
 
 a_static void *VecChr_stkTop(a_VecChr *w, intptr_t sz) { return w->p + w->n - sz; }
 
 a_class(MiniCompiler_Sub) {
     int mod;
     int lb; VecChr vc[2];
         // mod=0: for文.
         //   lb+0:continue0, lb+1:continue, lb+2:break.
         //   vc0:繰り返し条件, vc1:cotinue時のインクリメント処理など.
 };
 
 a_class(MiniCompiler) {
     a_Token0 *t0;
     a_BufFree bf[1];
     a_VecChr *vc;
     a_VecChr stk[1];
     int tmpNo, tmpLb, autoClose;
 };
 
 a_static void MiniCompiler_ini(MiniCompiler *w)
 {
     a_BufFree_ini(w->bf); a_VecChr_ini(w->stk); w->tmpNo = 0; w->tmpLb = 0; w->autoClose = 0;
 }
 
 a_static void MiniCompiler_din(MiniCompiler *w)
 {
     a_BufFree_flush(w->bf); a_BufFree_din(w->bf); a_VecChr_din(w->stk);
 }
 
 a_static char *MiniCompiler_newTmp(MiniCompiler *w)
 {
     char s[256];
     intptr_t n = sprintf(s, "tmp%d", w->tmpNo++);
     char *v = a_BufFree_malloc(w->bf, n + 1);
     memcpy(v, s, n + 1);
     return v;
 }
 
 #define MiniCompiler_compile_Macro0(pri, fmt)   vv = MiniCompiler_compile(w, pri); tv = MiniCompiler_newTmp(w); a_VecChr_printf(w->vc, fmt, tv, v, vv); v = tv; goto op2
 
 a_static char *MiniCompiler_compile(MiniCompiler *w, int pri)
 {
     char *v, *tv, *vv;
 op1:
     const char *tt, *t = a_Token1_get(w->t0); intptr_t n = w->t0->len; uint32_t c = w->t0->c;
     if (w->autoClose > 0) { w->t0->s = t; c = '}'; w->autoClose--; }
     if (c == '}') {
         MiniCompiler_Sub *sb = VecChr_stkTop(w->stk, sizeof (MiniCompiler_Sub));
         if (sb->mod == 0) {
             a_VecChr_printf(w->vc, "Lbt(LT%04d);\n%s%sLbt(LT%04d);\n", sb->lb + 1, sb->vc[1].p, sb->vc[0].p, sb->lb + 2);
             a_VecChr_din4(&sb->vc[0], &sb->vc[1], 0, 0); w->stk->n -= sizeof (MiniCompiler_Sub); goto op1;
         }
         w->t0->s = t; return NULL;
     }
     if (n == 0) return NULL;
     if (c ==  ';') { if (pri == 98) { w->t0->s = t; return NULL; } a_VecChr_printf(w->vc, "Semi();\n"); w->autoClose *= -1; goto op1; }
     if (c == '(') { v = MiniCompiler_compile(w, 99); a_Token1_get(w->t0); goto op2; }
     tt = Token1_get(w->t0); if (w->t0->c == ':') { a_VecChr_printf(w->vc, "Lbt(%.*s);\n", n, t); goto op1; } // コードラベル宣言.
     if (n == 2 && memcmp(t, "if", 2) == 0 && w->t0->c == '(') {
         v = MiniCompiler_compile(w, 99); a_Token1_get(w->t0); // ')'.
         tt = a_Token1_get(w->t0);
         if (w->t0->len == 4 && memcmp(tt, "goto", 4) == 0) {
              tt = a_Token1_get(w->t0); a_VecChr_printf(w->vc, "Jne(%s, 0, %.*s);\n", v, w->t0->len, tt); goto op1;
         }
         w->t0->s = t; return NULL;
     }
     if (n == 3 && memcmp(t, "for", 2) == 0 && w->t0->c == '(') {
         MiniCompiler_compile(w, 98); Token1_get(w->t0);
         MiniCompiler_Sub *sb = a_VecChr_stkAdd(w->stk, sizeof (MiniCompiler_Sub));
         sb->mod = 0;
         sb->lb = w->tmpLb; w->tmpLb += 3;
         a_VecChr_ini4(&sb->vc[0], &sb->vc[1], 0, 0);
         a_VecChr_printf(w->vc, "Lbt(LT%04d);\n", sb->lb + 0);
         a_VecChr *vc0 = w->vc; w->vc = &sb->vc[0];
         v = MiniCompiler_compile(w, 98); Token1_get(w->t0);
         if (v == NULL) { a_VecChr_printf(w->vc, "Jmp(LT%04d);\n", sb->lb + 0); }
         else { a_VecChr_printf(w->vc, "Jne(%s, 0, LT%04d);\n", v, sb->lb + 0); }
         w->vc = &sb->vc[1];
         v = MiniCompiler_compile(w, 98); Token1_get(w->t0); // ')'
         w->vc = vc0;
         tt = a_Token1_get(w->t0); if (w->t0->c != '{') { w->t0->s = tt; w->autoClose--; }
         goto op1;
     }
     w->t0->s = tt; // 一度読み込んだ未解釈の演算子をt0に押し戻す.
     v = a_BufFree_malloc(w->bf, n + 1);
     memcpy(v, t, n); v[n] = '\0';
 op2:
     t = Token1_get(w->t0); c = w->t0->c; n = w->t0->len;
     if (n == 0) return v;
     if (c ==  '*' && pri >=  4)             { MiniCompiler_compile_Macro0( 3, "Mul(%s, %s, %s);\n"); }
     if (c ==  '/' && pri >=  4)             { MiniCompiler_compile_Macro0( 3, "Div(%s, %s, %s);\n"); }
     if (c ==  '%' && pri >=  4)             { MiniCompiler_compile_Macro0( 3, "Mod(%s, %s, %s);\n"); }
     if (c ==  '+' && pri >=  5)             { MiniCompiler_compile_Macro0( 4, "Add(%s, %s, %s);\n"); }
     if (c ==  '-' && pri >=  5)             { MiniCompiler_compile_Macro0( 4, "Sub(%s, %s, %s);\n"); }
     if (c == ('<' | '=' << 8) && pri >=  7) { MiniCompiler_compile_Macro0( 6, "Cle(%s, %s, %s);\n"); }
     if (c ==  '<'             && pri >=  7) { MiniCompiler_compile_Macro0( 6, "Clt(%s, %s, %s);\n"); }
     if (c == ('>' | '=' << 8) && pri >=  7) { MiniCompiler_compile_Macro0( 6, "Cge(%s, %s, %s);\n"); }
     if (c ==  '>'             && pri >=  7) { MiniCompiler_compile_Macro0( 6, "Cgt(%s, %s, %s);\n"); }
     if (c == ('=' | '=' << 8) && pri >=  8) { MiniCompiler_compile_Macro0( 7, "Ceq(%s, %s, %s);\n"); }
     if (c == ('!' | '=' << 8) && pri >=  8) { MiniCompiler_compile_Macro0( 7, "Cne(%s, %s, %s);\n"); }
     if (c == '='  && pri >= 15) { a_VecChr_printf(w->vc, "Let(%s, %s);\n", v, MiniCompiler_compile(w, 15)); goto op2; }
     if (c ==  ';' && pri >= 98) { if (pri == 98) { w->t0->s = t; return v; } a_VecChr_printf(w->vc, "Semi();\n"); w->autoClose *= -1; goto op1; }
     w->t0->s = t; return v; // 一度読み込んだ未解釈の演算子をt0に押し戻してからreturn.
 }

 // 実行結果.
 >tt0003b "s=0; for (i=0;i<10;i=i+1) s=s+i;"
 Let(s, 0);
 Semi();
 Let(i, 0);
 Lbt(LT0000);
 Add(tmp2, s, i);
 Let(s, tmp2);
 Semi();
 Lbt(LT0001);
 Add(tmp1, i, 1);
 Let(i, tmp1);
 Clt(tmp0, i, 10);
 Jne(tmp0, 0, LT0000);
 Lbt(LT0002);
 ans: (null)
 
 >tt0003b "s=0; for (i=0;i<10;i=i+1) for (j=0;j<10;j=j+1) s=s+i*j;"
 Let(s, 0);
 Semi();
 Let(i, 0);
 Lbt(LT0000);
 Let(j, 0);
 Lbt(LT0003);
 Mul(tmp4, i, j);
 Add(tmp5, s, tmp4);
 Let(s, tmp5);
 Semi();
 Lbt(LT0004);
 Add(tmp3, j, 1);
 Let(j, tmp3);
 Clt(tmp2, j, 10);
 Jne(tmp2, 0, LT0003);
 Lbt(LT0005);
 Lbt(LT0001);
 Add(tmp1, i, 1);
 Let(i, tmp1);
 Clt(tmp0, i, 10);
 Jne(tmp0, 0, LT0000);
 Lbt(LT0002);
 ans: (null)
-どちらも、とてもよく動いています。





* こめんと欄
#comment

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