もしかしたらES-BASICの根幹部分だけを残して、ほかを全部削ったバージョンを作ってみたら、何か得るものがあるのではないかと思ってやってみました。
#include "kll0.h"
KSrc *src; // ソースコードを記憶しておくところ.
KLexer *lx; // 汎用レキサー.
KSizPtr *varSp; // 変数の値を記憶しておくところ(可変長領域).
unsigned char *code; // 機械語を一時的に置くところ.
int qc;
void sub_print(int i) { printf("%d\n", i); }
void sub_exit() { exit(0); }
void sub_list()
{
for (int i = 0, i1 = src->ln.sp.sizPtr(); i < i1; i++) {
KSrcLine *pl = (KSrcLine *) src->ln.sp.getPtr(i);
printf("%4d %.*s\n", pl->ln, pl->src.s, pl->src.p);
}
}
int compile(int l, const char *s, int ln)
{
static KPhraseCmp *phr = NEW1(kautoreleasePool, KPhraseCmp)(32, 100, lx->sid); // フレーズ比較支援クラス.
while (l > 0 && s[l - 1] == '\n')
l--;
lx->sp->s = 0;
int i0 = *lx->sid->n;
lx->add(l, (const char *) s);
KLexer_Elmt *le = (KLexer_Elmt *) lx->add(1, ";")->p, *lp;
int i1 = *lx->sid->n, *var = (int *) varSp->reserve(i1 * sizeof (int))->p, pc = 0;
for (int i = i0; i < i1; i++)
var[i] = lx->getConstInt(i); // intではないときは0を返す.
for (int pc1 = lx->getElmtLen(); pc < pc1; pc++) {
phr->setPr(le, 0, pc, pc1);
lp = &le[pc];
if (phr->cmpPr( 1, "@ ;")) continue;
if (phr->cmpPr( 2, "@ @* = @* ;")) { qc += kputBin(&code[qc], "8b_85_%i32 89_85_%i32", lp[2].i * 4, lp[0].i * 4);
} else if (phr->cmpPr( 3, "@ @* = @* + @* ;")) { qc += kputBin(&code[qc], "8b_85_%i32 03_85_%i32 89_85_%i32", lp[2].i * 4, lp[4].i * 4, lp[0].i * 4);
} else if (phr->cmpPr( 4, "@ @* = @* - @* ;")) { qc += kputBin(&code[qc], "8b_85_%i32 2b_85_%i32 89_85_%i32", lp[2].i * 4, lp[4].i * 4, lp[0].i * 4);
} else if (phr->cmpPr( 5, "@ PRINT @* ;")) { qc += kputBin(&code[qc], "8b_85_%i32 89_04_24 e8_%r32", lp[1].i * 4, sub_print);
} else if (phr->cmpPr( 6, "@ EXIT ;")) { qc += kputBin(&code[qc], "e8_%r32", sub_exit);
} else if (phr->cmpPr( 7, "@ LIST ;")) { qc += kputBin(&code[qc], "e8_%r32", sub_list);
} else
goto err;
while (le[pc].i != 0)
pc++;
}
return 0;
err:
if (l >= 30)
l = 30;
printf("syntax error [%d] : %.*s\n\n", ln, l, le[pc].p0);
return 1;
}
int main()
{
code = (unsigned char *) kmallocRWX(1024 * 1024);
lx = NEW1(kautoreleasePool, KLexer)(NEW1(kautoreleasePool, KStringId)(1, "; = + - PRINT EXIT LIST")); // 予約語を登録しておく.
varSp = NEW1(kautoreleasePool, KSizPtr)(kmemPool);
char *cmdlin = (char *) kautoreleasePool->alloc(65536), *p;
src = NEW1(kautoreleasePool, KSrc);
for (;;) {
ok:
printf("Ok\n");
skip:
fgets(cmdlin, 65536, stdin);
for (p = cmdlin; *p == ' ' || *p == '\t'; p++);
if (*p == '\n') goto skip;
kupperCaseM(strlen(p), (unsigned char *) p, lx->chrTyp); // 変数名や予約語を大文字化する(BASICっぽくするための演出).
if ('0' <= *p && *p <= '9') {
src->editLine(strchr(p, '\n') - p, p); // 数字で始まる入力だった場合は、editLineに渡せば、あとは適当にやってくれるのでライブラリに丸投げ.
goto skip;
}
qc = 0;
qc += kputBin(&code[qc], "60 83_ec_7c 0xbd_%i32"); // PUSHAD. SUB ESP,124. MOV EBP,0. この命令でスタックを調整させる.
if (strncmp(p, "RUN", 3) == 0 && p[3] <= ' ') {
for (int i = 0, i1 = src->ln.sp.sizPtr(); i < i1; i++) {
KSrcLine *pl = (KSrcLine *) src->ln.sp.getPtr(i);
if (compile(pl->src.s, pl->src.p, pl->ln) != 0) goto ok;
}
} else {
if (compile(strlen(p), p, -1) != 0) goto ok;
}
qc += kputBin(&code[qc], "83_c4_7c 61 c3"); // ADD ESP,124. 最初に調整したスタックを元に戻す. POPAD. RET.
kputBin(&code[5], "%i32", varSp->p);
((void (*)()) code)(); // codeを関数呼び出し.
printf("\n");
}
}