川合のプログラミング言語自作のためのテキスト#0006

(11) TJ-03

int var[256];	// 変数.
unsigned char txt[10000];	// ソースコード.
int pc = 0;	// プログラム・カウンター.
unsigned char *code;	// 機械語出力先.
int qc = 0; // 出力用のプログラム・カウンター.

void put32(int i)
{
    code[qc++] =  i        & 0xff;
    code[qc++] = (i >>  8) & 0xff;
    code[qc++] = (i >> 16) & 0xff;
    code[qc++] = (i >> 24) & 0xff;
}

#define EAX     0
#define ECX     1

void getNumber(int reg)  // 定数は2桁以上でもOK. レジスタに値をセットするための命令群を出力する.
{
    unsigned char c = txt[pc], *p, *q;
    if ('0' <= c && c <= '9') { // 数字.
        p = &txt[pc];
        code[qc++] = 0xb8 + reg;	// MOV reg,const.
        put32(strtol(p, (char **) &q, 0));
        pc += q - p;
        return;
    }
    pc++; // 1文字の変数.
    code[qc++] = 0x8b;	// MOV reg,[const].
    code[qc++] = reg * 8 + 0x05;
    put32((int) &var[c]);
}

void sub_print(int i)
{
    printf("%d\n", i);
}

void sub_time()
{
    printf("time=%.3f[sec]\n", clock() / (double) CLOCKS_PER_SEC);
}

int main(int argc, const char **argv)
{
    int i, j, k, pc0, wqc = 0, wqc2 = 0;
    void (*func)();	// funcは関数へのポインタ型の変数.
    loadText(argc, argv, txt, 10000);

    // Windowsに対して、実行権限のあるメモリを特別に要求.
    code = VirtualAlloc(0, 1024 * 1024, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

    code[qc++] = 0x83;	// SUB ESP,124.
    code[qc++] = 0xec;	//  この命令でスタックを調整させる.
    code[qc++] = 0x7c;
    for (;;) {
        pc0 = pc;
        if (txt[pc] == 0)	// ファイル終端.
            break;		
        if (txt[pc] == '\n' || txt[pc] == ' ' || txt[pc] == '\t' || txt[pc] == ';') { // 空行など.
            pc++;
        } else if (txt[pc + 1] == '=') { // 2文字目が"=".
            i = txt[pc];	// 1文字の変数名.
            pc += 2;
            getNumber(EAX);
            if (txt[pc] == ';') {
            } else if (txt[pc] == '+') {	// 加算.
                pc++;
                getNumber(ECX);
                code[qc++] = 0x01;	// ADD EAX,ECX.
                code[qc++] = 0xc8;
            } else if (txt[pc] == '-') {	// 減算.
                pc++;
                getNumber(ECX);
                code[qc++] = 0x29;	// SUB EAX,ECX.
                code[qc++] = 0xc8;
            } else
                goto err;
            code[qc++] = 0xa3;	// MOV [const],EAX.
            put32((int) &var[i]);
        } else if (txt[pc] == 'p' && txt[pc + 1] == 'r' && txt[pc + 5] == ' ') { // 最初の2文字しか調べてない(手抜き).
            pc += 6;
            getNumber(EAX);
            code[qc++] = 0x89;	// MOV [ESP],EAX.
            code[qc++] = 0x04;
            code[qc++] = 0x24;
            k = (unsigned char *) sub_print - &code[qc + 5];
            code[qc++] = 0xe8;	// CALL sub_print.
            put32(k);
        } else if (txt[pc] == 'w' && txt[pc + 1] == 'h' && txt[pc + 5] == ' ' && txt[pc + 7] == '<') { // 最初の2文字しか調べてない(手抜き).
            wqc = qc;
            pc += 6;
            getNumber(EAX);	// 1文字の変数名.
            pc++;
            getNumber(ECX);
            if (txt[pc] != '{')
                goto err;
            pc++;
            code[qc++] = 0x39;	// CMP EAX,ECX.
            code[qc++] = 0xc8;
            code[qc++] = 0x0f;	// JGE ????
            code[qc++] = 0x8d;
            wqc2 = qc;
            put32(0);	// ここは後で更新する.
        } else if (txt[pc] == '}') {
            pc++;
            code[qc++] = 0xe9;
            put32(wqc - (qc + 4));
            k = qc - (wqc2 + 4);
            code[wqc2 + 0] =  k        & 0xff;
            code[wqc2 + 1] = (k >>  8) & 0xff;
            code[wqc2 + 2] = (k >> 16) & 0xff;
            code[wqc2 + 3] = (k >> 24) & 0xff;
        } else if (txt[pc] == 't' && txt[pc + 1] == 'i') { // 最初の2文字しか調べてない(手抜き).
            pc += 4;
            k = (unsigned char *) sub_time - &code[qc + 5];
            code[qc++] = 0xe8;	// CALL sub_time.
            put32(k);
        } else
            goto err;
    }
    code[qc++] = 0x83;	// ADD ESP,124.
    code[qc++] = 0xc4;	//  最初に調整したスタックを元に戻す.
    code[qc++] = 0x7c;
    code[qc++] = 0xc3;	// RET.
//  for (i = 0; i < qc; i++) { printf("%02x ", code[i]); } exit(0); //  デバッグ用.
    func = (void *) code;
    func();
    exit(0);
err:
    printf("syntax error : %.10s\n", &txt[pc0]);
    exit(1);
}

次回に続く

こめんと欄


コメントお名前NameLink

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS