acl4のページ0009
(1)
#if (a_Version >= 1)
#define Preprocessor_Define a_Preprocessor_Define
#define Preprocessor_define0 a_Preprocessor_define0
#define Preprocessor_define1 a_Preprocessor_define1
#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_define1(a_VecChr *tmp, a_Token0 *t0, a_VecChr *args, int c);
a_static void a_Preprocessor_define0(a_Set0 *set, a_Token0 *t0, a_VecChr *linBuf, int c)
// #defineの登録処理.
{
a_VecChr args[1], tmp[1]; a_VecChr_ini4(args, tmp, 0, 0);
char *k = a_Token1_get(t0);
intptr_t kn = t0->len, argsN = 0xff;
if (k[kn] == '(') {
t0->s++; a_parseArgs(t0, args);
if (t0->len == 0) goto fin;
argsN = args->n / (2 * sizeof (char *));
}
char *t = a_Token1_get(t0);
a_VecChr_resize(_arg_ tmp, linBuf->p + linBuf->n - t);
memcpy(tmp->p, t, tmp->n);
a_Preprocessor_define1(tmp, t0, args, c);
a_Preprocessor_Define *d = a_malloc(_arg_ sizeof (a_Preprocessor_Define));
d->elm->k = a_malloc(_arg_ kn + 1);
d->elm->n = kn + 1;
((unsigned char *) d->elm->k)[0] = argsN;
memcpy((char *) d->elm->k + 1, k, kn);
d->q = a_malloc(_arg_ tmp->n);
d->n = tmp->n;
memcpy(d->q, tmp->p, tmp->n);
a_Set0_add(set, d->elm);
fin:
a_VecChr_din4(args, tmp, 0, 0);
}
a_static void a_Preprocessor_define1(a_VecChr *tmp, a_Token0 *t0, a_VecChr *args, int c)
// #defineの引数を [01 01] とか [01 02] などに置換する.
{
int i, n = 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;
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] = 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 int a_Preprocessor_define4(a_Set0 *set, const char *s, intptr_t sn, int an);
a_static void a_Preprocessor_define2(a_Set0 *set, a_Token0 *t0, a_VecChr *linBuf, int c)
// 一般行に対して#defineの登録内容を適用する.
{
a_VecChr args[1], tmp[1]; a_VecChr_ini4(args, tmp, 0, 0);
char *p = linBuf->p;
for (t0->s = p;;) {
char *t = a_Token1_get(t0);
if (t0->len == 0) 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 < linBuf->n && p[pos1] <= ' ') pos1++;
a_VecChr_replace(linBuf, pos0, pos1 - pos0, NULL, 0); // 長さ0文字の文字列と置換することで削除を実現.
t0->s = p;
t0->s1 = p + linBuf->n;
continue;
}
if (t0->cTyp != 3) continue;
intptr_t pos0 = t - p;
if (t0->len == 7 && memcmp(t, "defined", 7) == 0 && &t[7] < t0->s1 && t[7] == '(') {
t0->s = &t[8]; a_parseArgs(t0, args);
if (t0->c == ')' && 0 < args->n && args->n <= 4 * sizeof (char *)) {
int an = -2; char **ap = (char **) args->p;
if (args->n == 4 * sizeof (char *)) an = strtol(ap[2], NULL, 0);
char result = '0' + a_Preprocessor_define4(set, ap[0], ap[1] - ap[0], an);
a_VecChr_replace(linBuf, pos0, t0->s - t, &result, 1);
p = linBuf->p;
t0->s = p + pos0 + 1;
t0->s1 = p + linBuf->n;
}
continue;
}
intptr_t kn = t0->len + 1;
unsigned char *k = a_malloc(_arg_ kn);
memcpy(k + 1, t, kn); k[0] = 0xff;
a_Preprocessor_Define *d = a_Set0_findKn(set, k, kn); // 引数なしマクロで一致するものはあるか?.
if (d != NULL) {
a_VecChr_replace(linBuf, pos0, t0->len, d->q, d->n); // 置換する.
nxt:
p = linBuf->p;
t0->s = p + pos0;
t0->s1 = p + linBuf->n;
a_free(_arg_ k, kn);
continue;
}
if (t[t0->len] == '(') {
const char *t0s = t0->s++;
t = a_parseArgs(t0, args);
k[0] = 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(linBuf, pos0, t + 1 - (linBuf->p + pos0), tmp->p, tmp->n); // 置換する.
goto nxt;
}
t0->s = t0s;
}
a_free(_arg_ k, kn);
}
a_VecChr_din4(args, tmp, 0, 0);
}
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_malloc(_arg_ sn + 1);
memcpy(k + 1, 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 がとても面白いです。
- これにプリプロセッサが使えれば関数マクロとかも定義できて、もっと面白くなりそうだと思いました。
- そしてマクロだけでよければ p0001a.c で既に開発済みなのです。
- これはもういけるところまで行くしかないと思いました(笑)。
- なんだか今後も似たようなことがあるかもなーと思ったので、まずdefine0~3の関数をacl4のライブラリに組み入れてしまうことにしました。
- やっていることはそれだけです。
- 各関数の詳しい説明は、 a4_p0001 を見てください。
(3) サンプルプログラム: t0009a.c
- acl4ライブラリは以下のようにして利用します。
- [1]まずa4_0001~a4_0009のプログラムをつなげて"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 {
Preprocessor_define2(set, t0, linBuf, 1);
printf("%.*s", 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 相当のものを作りました。ちゃんと動いているようです。
- 主要なコードをライブラリに逃がしたので、プログラムは 183行→36行 になっています。
(99) 更新履歴
- 2026.02.04(水) 初版
- 2026.02.06(金) Preprocessor_define2にdefined(...)機能を追加。a_Preprocessor_define4を追加