* acl4のページ0018
-(by [[K]], 2026.04.23)

** (1) 概要
-a4_0018 は、 acl4v1 にとっての3番目のライブラリプログラムになります。
-提供される主な機能は、以下の通りです。
--(1-1)ファイルなどの文字列からトークンを切り出す Token0/Token1 クラス
--(1-2)VecChrを使ってスタック構造を作って読み書きする VecChr_stkAdd/Rmv/Top 関数
--(1-3)かっこでくくられた構造を切り分ける parseArgs
--(1-4)Cの文字列リテラルで使われるエスケープシーケンスをデコードする VecChr_convEsc
-以下、それぞれについてもう少し詳しく説明します。

~

-(1-1)ファイルなどの文字列からトークンを切り出す Token0/Token1 クラス
--プログラミング言語を作るなら、トークン繰り出し関数があればきっと便利だろうと思って用意しています。
-(1-2)VecChrを使ってスタック構造を作って読み書きする VecChr_stkAdd/Rmv/Top 関数
--Add が push で、Rmv が pop(pull) です。 x86 などのスタックとは異なり、スタックにデータを積んでいくとスタックポインタの値は増えていきます。 Rmv すればスタックポインタは減っていくことになります。スタックポインタの値は VecChr_N() で得られます。しかしこれを直接使うことはなくて、基本的に Add/Rmv/Top だけ使っていれば問題なく制御できます。そしてそういう扱いをしている限りにおいては、スタックの伸びる向きが違うことを意識する必要はありません。
-(1-3)かっこでくくられた構造を切り分ける parseArgs
--「(a,b+c,d-3)」みたいな文字列を、「a」「b+c」「d-3」に切り分けます。
-(1-4)の文字列リテラルで使われるエスケープシーケンスをデコードする VecChr_convEsc
--\nとか\tなどをしかるべき文字コードに置換していきます。



** (2) デモ




** (3) ライブラリプログラム
 #if (a_Version >= 1)
     #define Token0              a_Token0
     #define Token0Table         a_Token0Table
     #define Token0Table_ini     a_Token0Table_ini
     #define Token0_get          a_Token0_get
     #define Token1_get          a_Token1_get
     #define Token0_ini1         a_Token0_ini1
 #endif
 
 a_class(a_Token0Table) {
     uint32_t *op[4];
     unsigned char chrTyp[256];
         // 0: 空白類.
         // 1: 1文字記号.
         // 2: 一般記号文字.
         // 3: アルファベット/数字.
 };
 
 a_class(a_Token0) {
     a_Token0Table *tbl;
     const char *s, *s1;
     unsigned char cTyp;
     uint32_t c;
     intptr_t len;
 };
 
 a_static int a_Token0Table_iniSub(uint32_t *op, const char *s)
 {
     int i = 0;
     for (;;) {
         while (*s == ' ') s++;
         if (*s == '\0') break;
         if (s[1] <= ' ') { op[i++] = s[0];                                       s++;    continue; }
         if (s[2] <= ' ') { op[i++] = s[0] | s[1] << 8;                           s += 2; continue; }
         if (s[3] <= ' ') { op[i++] = s[0] | s[1] << 8 | s[2] << 16;              s += 3; continue; }
         if (s[4] <= ' ') { op[i++] = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; s += 4; continue; }
         break;
     }
     op[i] = 0;
     return i;
 }
 
 a_static void a_Token0Table_ini(a_Token0Table *w)
 {
     static uint32_t op4[64], op3[64], op2[64], op1[64];
     a_Token0Table_iniSub(op4, "");
     a_Token0Table_iniSub(op3, ">>= <<= ...");
     a_Token0Table_iniSub(op2, "== != <= >= << >> ++ -- += -= *= /= %= ^= |= && || -> :: // /* ## .. !! %% ~~");
     a_Token0Table_iniSub(op1, "= < > + - * / % ^ & | ! ~ . : #");
     int c;
     for (c = 0; c < 256; c++) {
         unsigned char ct = 0;
         if (c != 0) {
             if (strchr(" \t\r\n", c) != NULL) ct = 0;
             if (strchr("(){},;[]\"\'", c) != NULL) ct = 1;
             if (strchr("!#%&-=^~:+*<>./?", c) != NULL) ct = 2;
             if (strchr("!#%&-=^~:+*<>./?|", c) != NULL) ct = 2;
             if ('0' <= c && c <= '9') ct = 3;
             if ('A' <= c && c <= 'Z') ct = 3;
             if ('a' <= c && c <= 'z') ct = 3;
             if (strchr("_$@`", c) != NULL) ct = 3;
         }
         w->chrTyp[c] = ct;
     }
     w->op[0] = op4;
     w->op[1] = op3;
     w->op[2] = op2;
     w->op[3] = op1;
 }
 
 a_static char *a_Token0_get(a_Token0 *w)
 {
     const char *s = w->s, *s1 = w->s1;
     unsigned char ct = 0, *chrTyp = w->tbl->chrTyp;
     intptr_t len = 0, i; w->c = 0;
     for (;;) {
         if (s >= s1) goto fin;
         ct = chrTyp[*(const unsigned char *) s];
         if (ct == 0) { s++; continue; }
         break;
     }
     if (ct == 1) {
         len = 1;
         w->c = *s;
         goto fin;
     }
     if (ct == 2) {
         unsigned char ch0 = *s, ch1 = 0, ch2 = 0, ch3 = 0;
         if (s + 3 < s1) {
             ch1 = s[1]; ch2 = s[2]; ch3 = s[3];
         } else {
             if (s + 1 < s1) ch1 = s[1];
             if (s + 2 < s1) ch2 = s[2];
         }
         uint32_t op = ch0 | ch1 << 8 | ch2 << 16 | ch3 << 24, *opTbl;
         opTbl = w->tbl->op[0]; len = 4; w->c = op;
         for (i = 0; opTbl[i] != 0; i++) {
             if (opTbl[i] == op) goto fin;
         }
         opTbl = w->tbl->op[1]; len = 3; w->c = op &= 0x00ffffff;
         for (i = 0; opTbl[i] != 0; i++) {
             if (opTbl[i] == op) goto fin;
         }
         opTbl = w->tbl->op[2]; len = 2; w->c = op &= 0x0000ffff;
         for (i = 0; opTbl[i] != 0; i++) {
             if (opTbl[i] == op) goto fin;
         }
         opTbl = w->tbl->op[3]; len = 1; w->c = op &= 0x000000ff;
         for (i = 0; opTbl[i] != 0; i++) {
             if (opTbl[i] == op) goto fin;
         }
         ct = 255; len = 0; w->c = 0;
     }
     if (ct == 3) {
         w->c = *s;
         for (len = 1;;) {
             if (s + len >= s1) goto fin;
             if (chrTyp[((unsigned char *) s)[len]] == ct) { len++; continue; }
             break;
         }
     }
 fin:
     w->cTyp = ct;
     w->len = len;
     w->s = s + len;
     return (char *) s;
 }
 
 a_static char *a_Token1_get(a_Token0 *w)
 {
     for (;;) {
         const char *s = a_Token0_get(w), *s1 = w->s1, *t;
         uint32_t c = w->c;
         if (s >= s1) return (char *) s;
         if (c == ('/' | '/' << 8)) {
             t = memchr(s, '\n', s1 - s);
             if (t != NULL) { w->s = t; continue; }
             w->s = s1; w->len = 0; return (char *) s1;
         }
         if (c == 0x22 || c == 0x27) {
             // 改行もしくはエスケープされていないcがでるまで.
             t = s + 1;
             for (;;) {
                 if (t >= s1) break;
                 if (*t == (char) c) { t++; break; }
                 if (*t == '\n') break;
                 if (*t != '\\') { t++; continue; }
                 t++;
                 if (t >= s1) break;
                 if (*t == '\n') break;
                 t++;
             }
             w->len = t - s;
             w->s = t;
             return (char *) s;
         }
         if ('0' <= c && c <= '9') {
             t = s + w->len;
             for (;;) {
                 if (t >= s1) break;
                 c = *t;
                 if (c == '.') { t++; continue; }
                 if ('0' <= c && c <= '9') { t++; continue; }
                 if ('A' <= c && c <= 'Z') { t++; continue; }
                 if ('a' <= c && c <= 'z') { t++; continue; }
                 if (c == '_') { t++; continue; }
                 if ((c == '+' || c == '-') && t[-1] == 'e') { t++; continue; }
                 break;
             }
             w->len = t - s;
             w->s = t;
             return (char *) s;
         }
         return (char *) s;
     }
 }
 
 a_static void a_Token0_ini1(a_Token0 *w)
 {
     static a_Token0Table t0t[1];
     a_Token0Table_ini(t0t);
     w->tbl = t0t;
 }
 
 a_static void a_memcpy( void *t, const void *s, intptr_t n) { if (t != s && n > 0) memcpy( t, s, n); }
 a_static void a_memmove(void *t, const void *s, intptr_t n) { if (t != s && n > 0) memmove(t, s, n); }
 
 #if (a_Version >= 1)
     #define VecChr_stkAdd       a_VecChr_stkAdd
     #define VecChr_stkRmv       a_VecChr_stkRmv
     #define VecChr_stkTop       a_VecChr_stkTop
     #define parseArgs_Arg       a_parseArgs_Arg
     #define parseArgs           a_parseArgs
     #define VecChr_convEsc      a_VecChr_convEsc
     #define ptrAdd              a_ptrAdd
     #define ptrSub              a_ptrSub
 #endif
 
 a_static void *a_VecChr_stkAdd(a_VecChr *w, intptr_t sz) { a_VecChr_resizeDiff(w, sz); return w->p + a_VecChr_N(w) - sz; }
 a_static void *a_VecChr_stkRmv(a_VecChr *w, intptr_t sz) { return w->p + (a_VecChr_N(w) -= sz); }
 a_static void *a_VecChr_stkTop(a_VecChr *w, intptr_t sz) { return w->p + a_VecChr_N(w) - sz; }
 
 a_class(a_parseArgs_Arg) { const char *s; intptr_t n; };
 
 a_static char *a_parseArgs(a_Token0 *t0, a_VecChr *v)
 {
     intptr_t nest = 0, len;
     char flg = 0;
     a_VecChr_N(v) = 0;
     const char *s = NULL, *t;
     a_parseArgs_Arg *paa;
     for (;;) {
         len = t0->len; t = s;
         s = a_Token1_get(t0);
         if (t0->len == 0) {
             if (flg != 0) {
                 paa = a_VecChr_stkTop(v, sizeof (a_parseArgs_Arg));
                 paa->n = t + len - paa->s;
             }
             break;
         }
         if (*s == ',') {
             if (nest == 0 && flg != 0) {
                 paa = a_VecChr_stkTop(v, sizeof (a_parseArgs_Arg));
                 paa->n = t + len - paa->s; flg = 0;
             }
             continue;
         }
         if (*s == ')' || *s == '}' || *s == ']') nest--;
         if (nest < 0) {
             if (flg != 0) {
                 paa = a_VecChr_stkTop(v, sizeof (a_parseArgs_Arg));
                 paa->n = t + len - paa->s;
             }
             break;
         }
         if (flg == 0 && nest == 0) {
             paa = a_VecChr_stkAdd(v, sizeof (a_parseArgs_Arg));
             paa->s = s; flg = 1;
         }
         if (*s == '(' || *s == '{' || *s == '[') nest++;
     }
     return (char *) s;
 }
 
 a_static void a_VecChr_convEsc(a_VecChr *w)
 {
     a_VecChr_reserveDiff(w, 4);
     memset(w->p + ((intptr_t *) w->p)[-1], 0, 4);
     char *p, *q, *p1;
     p = q = w->p;
     p1 = p + ((intptr_t *) w->p)[-1];
     while (p < p1) {
         if (*p == '\\') {
             if (p[1] == 'a') { *q++ = '\a'; p += 2; continue; }
             if (p[1] == 'b') { *q++ = '\b'; p += 2; continue; }
             if (p[1] == 'f') { *q++ = '\f'; p += 2; continue; }
             if (p[1] == 'n') { *q++ = '\n'; p += 2; continue; }
             if (p[1] == 'r') { *q++ = '\r'; p += 2; continue; }
             if (p[1] == 't') { *q++ = '\t'; p += 2; continue; }
             if (p[1] == 'v') { *q++ = '\v'; p += 2; continue; }
             if (p[1] == 'x') {
                 *q++ = (char) strtol(p + 1, &p, 16);
                 if (strchr(",.;:", *p) != NULL) p++;
                 continue;
             }
             if ('0' <= p[1] && p[1] <= '7') {
                 *q++ = (char) strtol(p + 1, &p, 8);
                 if (strchr(",.;:", *p) != NULL) p++;
                 continue;
             }
             p++;
             *q++ = *p++;
         } else
             *q++ = *p++;
     }
     ((intptr_t *) w->p)[-1] -= p1 - q;
     a_VecChr_reserve0(w);
 }
 
 a_static void *a_ptrAdd(void *p, intptr_t i)
 {
     if (p != NULL) p = ((char *) p) + i;
     return p;
 }
 
 a_static void *a_ptrSub(void *p, intptr_t i)
 {
     if (p != NULL) p = ((char *) p) - i;
     return p;
 }


** (99) 更新履歴
-2026.04.23(木) 初版
-2026.05.06(水) a_Token0Table_ini()のバグを修正

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