* acl4のプログラムのページ0003
-(by [[K]], 2026.02.04)

** (1) 「式の評価」プログラムの発展版
-[[a4_0009]]までの関数があれば、そこそこ面白いことができるはずだと思ったので、適当に書いてみました。
-今回は [[a4_p0002]] で作った 「式の評価」プログラム に#define機能を足して、マクロ定義ができるようにしました。

** (2) p0003a の実行例
-最初にプログラムの中身を見せるために、 [[t0008a>a4_0008]] を使っています。
 >t0008a file:p0003a0.txt
 #define Pi      3.14159265358979323
 #define Abs(x)  sqrt((x)*(x))
 print Abs(-1.23);
 print sin(Pi/2);
 print cos(Pi);
 
 >p0003a file:p0003a0.txt
 1.230000
 1.000000
 -1.000000
-こんな感じで、ばっちり動いています!
-p0003a.exeは15.5KBです。まあこれだけいろいろできるなら、15.5KBでも悪くはないかなー。

** (3) p0003a.c [119行]

 #define a_Version 1
 #include <acl4.c>
 
 void preprocessor_p0003a(VecChr *src, VecChr *dst, Token0 *t0)
 {
     VecChr linBuf[1], tmp[1]; VecChr_ini4(linBuf, tmp, 0, 0);
     Set0 set[1]; Set0_ini(set); dst->n = 0;
     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 {
             Preprocessor_define2(set, t0, linBuf, 1);
             while (Preprocessor_define2(set, t0, linBuf, 1, NULL, 0, 0) != 0);
             VecChr_puts(dst, linBuf->p, linBuf->p + linBuf->n);
         }
     }
     Preprocessor_define3(set);
     VecChr_din4(linBuf, tmp, 0, 0);
 }
 
 class_(Var) { SetElm elm[1]; double d; };
 Set0 setVar[1];
 
 double *getVarPtr(const char *s, intptr_t n)
 {
     Var *v = Set0_findKn(setVar, s, n);
     if (v == NULL) {
         v = malloc_(_arg_  sizeof (Var));
         v->elm->k = s;
         v->elm->n = n;
         v->d = 0.0;
         Set0_add(setVar, v->elm);
     }
     return &(v->d);
 }
 
 int np = 0;
 
 double eval(Token0 *t0, int pri)
 {
     const char *t = Token1_get(t0); double d = 0.0, *pd = NULL; intptr_t n = t0->len; uint32_t c = t0->c;
     if (n == 0) return d;
     if (c == '(') { d = eval(t0, 99); Token1_get(t0); goto op2; }
     if (c == '+' && pri >= 2) { d = +       eval(t0, 2); goto op2; }
     if (c == '-' && pri >= 2) { d = -       eval(t0, 2); goto op2; }
     if (c == '!' && pri >= 2) { d = ! (int) eval(t0, 2); goto op2; }
     if (c == '~' && pri >= 2) { d = ~ (int) eval(t0, 2); goto op2; }
     if (pri >= 2 && n == 3 && memcmp(t, "sin",   3) == 0) { d = sin( eval(t0, 2)); goto op2; }
     if (pri >= 2 && n == 3 && memcmp(t, "cos",   3) == 0) { d = cos( eval(t0, 2)); goto op2; }
     if (pri >= 2 && n == 3 && memcmp(t, "tan",   3) == 0) { d = tan( eval(t0, 2)); goto op2; }
     if (pri >= 2 && n == 3 && memcmp(t, "exp",   3) == 0) { d = exp( eval(t0, 2)); goto op2; }
     if (pri >= 2 && n == 3 && memcmp(t, "log",   3) == 0) { d = log( eval(t0, 2)); goto op2; }
     if (pri >= 2 && n == 4 && memcmp(t, "sqrt",  4) == 0) { d = sqrt(eval(t0, 2)); goto op2; }
     if (pri >= 2 && n == 5 && memcmp(t, "print", 5) == 0) { d = eval(t0, 97); printf("%f\n", d); np++; goto op2; }
     if ('0' <= *t && *t <= '9')
         d = strtod(t, NULL);
     else {
         pd = getVarPtr(t, n);
         d = *pd;
     }
 op2:
     t = Token1_get(t0); c = t0->c; n = t0->len;
     if (n == 0) return d;
     if (c ==  '*'             && pri >=  4) { d =       d *        eval(t0,  3); goto op2; }
     if (c ==  '/'             && pri >=  4) { d =       d /        eval(t0,  3); goto op2; }
     if (c ==  '%'             && pri >=  4) { d = (int) d % (int)  eval(t0,  3); goto op2; }
     if (c ==  '+'             && pri >=  5) { d =       d +        eval(t0,  4); goto op2; }
     if (c ==  '-'             && pri >=  5) { d =       d -        eval(t0,  4); goto op2; }
     if (c == ('<' | '<' << 8) && pri >=  6) { d = (int) d << (int) eval(t0,  5); goto op2; }
     if (c == ('>' | '>' << 8) && pri >=  6) { d = (int) d >> (int) eval(t0,  5); goto op2; }
     if (c == ('<' | '=' << 8) && pri >=  7) { d =       d <=       eval(t0,  6); goto op2; }
     if (c ==  '<'             && pri >=  7) { d =       d <        eval(t0,  6); goto op2; }
     if (c == ('>' | '=' << 8) && pri >=  7) { d =       d >=       eval(t0,  6); goto op2; }
     if (c ==  '>'             && pri >=  7) { d =       d >        eval(t0,  6); goto op2; }
     if (c == ('=' | '=' << 8) && pri >=  8) { d =       d ==       eval(t0,  7); goto op2; }
     if (c == ('!' | '=' << 8) && pri >=  8) { d =       d !=       eval(t0,  7); goto op2; }
     if (c ==  '&'             && pri >=  9) { d = (int) d &  (int) eval(t0,  8); goto op2; }
     if (c ==  '^'             && pri >= 10) { d = (int) d ^  (int) eval(t0,  9); goto op2; }
     if (c ==  '|'             && pri >= 11) { d = (int) d |  (int) eval(t0, 10); goto op2; }
     if (c == ('&' | '&' << 8) && pri >= 12) { d = (int) d && (int) eval(t0, 11); goto op2; }
     if (c == ('|' | '|' << 8) && pri >= 13) { d = (int) d || (int) eval(t0, 12); goto op2; }
     if (c == '='              && pri >= 15) { d = eval(t0, 15); if (pd != NULL) { *pd = d; } goto op2; }
     if (c ==  ';'             && pri >= 98) { d =                  eval(t0, 97); goto op2; }
     t0->s = t; return d; // 一度読み込んだ未解釈の演算子をt0に押し戻してからreturn.
 }
 
 int main(int argc, const char **argv)
 {
     VecChr src0[1], src1[1]; VecChr_ini(src1);
     VecChr_iniArg(src0, argc, argv, 1, 3);
     Token0 t0[1]; Token0_ini1(t0);
     preprocessor_p0003a(src0, src1, t0);
     Set0_ini(setVar);
     t0->s = src1->p; t0->s1 = src1->p + src1->n;
     double d = eval(t0, 99);
     if (np == 0)
         printf("%f\n", d);
     VecChr_din4(src0, src1, 0, 0);
     intptr_t i, n = setVar->tbl->n / sizeof (Var *);
     for (i = 0; i < n; i++)
         free_(_arg_  ((Var **) setVar->tbl->p)[i], sizeof (Var));
     Set0_din(setVar);
     a_malloc_debugList(_arg);
     return 0;
 }

** (4) 説明
-p0002b.c との差分は preprocessor_p0003a くらいしかありません。
-これは t0009a.c の main 関数を少々手直ししただけのものです。


** (99) 更新履歴
-2026.02.04(水) 初版

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