#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdint.h> // intptr_tを使うため.

typedef unsigned char *String;	// こう書くと String は unsigned char * の代用になる.

int loadText(String path, String t, int siz) // TL-1のとは違う(改造).
{
    FILE *fp;
    unsigned char s[1000];
    int i = 0, j;
    if (path[0] == 34) { i = 1; } // ダブルフォールトがあればはずす.
    for (j = 0; ; j++) {
        if (path[i + j] == 0 || path[j + i] == 34)
            break; // ファイル名の末尾に来たらそこで終わり.
        s[j] = path[i + j];
    }
    s[j] = 0;
    fp = fopen(s, "rt"); // テキストモードでファイルを開く.
    if (fp == 0) {  // ファイルを開けなかった.
        printf("fopen error : %s\n", path);
        return 1; // 失敗.
    }
    i = fread(t, 1, siz - 1, fp);
    fclose(fp);
    t[i] = 0; // 終端マークを書いておく.
    return 0; // 成功.
}

///////////////////////////////////////////////////////////////////////////////

#define MAX_TC  1000 // トークンコードの最大値.
String ts[MAX_TC + 1]; // トークンの内容(文字列)を記憶.
int tl[MAX_TC + 1]; // トークンの長さ.
unsigned char tcBuf[(MAX_TC + 1) * 10]; // トークン1つ当たり平均10バイトを想定.
int tcs = 0, tcb = 0;

intptr_t var[MAX_TC + 1];	// 変数. (!)

int getTc(String s, int len) // トークン番号を得るための関数.
{
    int i;
    for (i = 0; i < tcs; i++) { // 登録済みの中から探す.
        if (len == tl[i] && strncmp(s, ts[i], len) == 0)
            break;
    }
    if (i == tcs) {
        if (tcs >= MAX_TC) {
            printf("too many tokens\n");
            exit(1);
        }
        strncpy(&tcBuf[tcb], s, len); // 見つからなかったので新規登録.
        tcBuf[tcb + len] = 0; // 終端文字コード.
        ts[i] = &tcBuf[tcb];
        tl[i] = len;
        tcb += len + 1;
        tcs++;
        var[i] = strtol(ts[i], 0, 0);	// 定数だった場合に初期値を設定(定数ではないときは0になる).
        if (ts[i][0] == 34) { // 先頭がダブルクォーテーション
            char *p = malloc(len - 1);
            var[i] = (intptr_t) p;
            memcpy(p, ts[i] + 1, len - 2); // 手抜き実装(エスケープシーケンスを処理していない).
            p[len - 2] = 0;
        }
    }
    return i;
}

///////////////////////////////////////////////////////////////////////////////

int isAlphabetOrNumber(unsigned char c)		// 変数名に使用できる文字かどうか.
{
    if ('0' <= c && c <= '9') return 1;
    if ('a' <= c && c <= 'z') return 1;
    if ('A' <= c && c <= 'Z') return 1;
    if (c == '_') return 1;
    return 0;
}

int lexer(String s, int tc[])		// プログラムをトークンコード列に変換する.
{
    int i = 0, j = 0, len; // i:今s[]のどこを読んでいるか、j:これまでに変換したトークン列の長さ.
    for (;;) {
        if (s[i] == ' ' || s[i] == '\t' || s[i] == '\n' || s[i] == '\r') {	// スペース、タブ、改行.
            i++;
            continue;
        }
        if (s[i] == 0)	// ファイル終端.
            return j;
        len = 0;
        if (strchr("(){}[];,", s[i]) != 0) {	// 1文字記号.
            len = 1;
        } else if (isAlphabetOrNumber(s[i])) {  // 1文字目が英数字.
            while (isAlphabetOrNumber(s[i + len]))
                len++;
        } else if (strchr("=+-*/!%&~|<>?:.#", s[i]) != 0) {  // 1文字目が普通の記号.
            while (strchr("=+-*/!%&~|<>?:.#", s[i + len]) != 0 && s[i + len] != 0)
                len++;
        } else if (s[i] == 34 || s[i] == 39) {	// "文字列" or '文字'.
            len = 1;
            while (s[i + len] != s[i] && s[i + len] >= ' ')
                len++;
            if (s[i + len] == s[i])
                len++;
        } else {
            printf("syntax error : %.10s\n", &s[i]);
            exit(1);
        }
        tc[j] = getTc(&s[i], len);
        i += len;
        j++;
    }
}

int tc[10000];	// トークンコード.

enum { TcSemi = 0, TcDot, TcWiCard, Tc0, Tc1, Tc2, Tc3, Tc4, Tc5, Tc6, Tc7, Tc8, TcBrOpn, TcBrCls, TcSqBrOpn, TcSqBrCls, TcCrBrOpn, TcCrBrCls,
    TcEEq, TcNEq, TcLt, TcGe, TcLe, TcGt, TcPlus, TcMinus, TcAster, TcSlash, TcPerce, TcAnd, TcShr, TcPlPlus, TcEqu,
    TcComma, TcExpr, TcExpr0, TcTmp0, TcTmp1, TcTmp2, TcTmp3, TcTmp4, TcTmp5, TcTmp6, TcTmp7, TcTmp8, TcTmp9 };

char tcInit[] = "; . !!* 0 1 2 3 4 5 6 7 8 ( ) [ ] { } == != < >= <= > + - * / % & >> ++ = , !!** !!*** _t0 _t1 _t2 _t3 _t4 _t5 _t6 _t7 _t8 _t9";

///////////////////////////////////////////////////////////////////////////////

int phrCmp_tc[32 * 100], ppc1, wpc[9], wpc1[9]; // ppc1:一致したフレーズの次のトークンをさす, wpc[]:ワイルドカードのトークンの場所をさす.

int phrCmp(int pid, String phr, int pc) // HL-5のとは違う(改造).
{
    int i0 = pid * 32, i, i1, j, k, t;
    if (phrCmp_tc[i0 + 31] == 0) {
        i1 = lexer(phr, &phrCmp_tc[i0]);
        phrCmp_tc[i0 + 31] = i1;
    }
    i1 = phrCmp_tc[i0 + 31];
    for (i = 0; i < i1; i++) {
        t = phrCmp_tc[i0 + i];
        if (t == TcWiCard || t == TcExpr || t == TcExpr0) {
            i++;
            j = phrCmp_tc[i0 + i] - Tc0; // 後続の番号を取得.
            wpc[j] = pc;
            if (t == TcWiCard) {
                pc++;
   	         continue;
            }
            k = 0; // カッコの深さ.
            for (;;) {
                if (tc[pc] == TcSemi) break;
                if (tc[pc] == TcComma && k == 0) break;
                if (tc[pc] == TcBrOpn || tc[pc] == TcSqBrOpn) k++; // 手抜きで ( と [ を区別せずに数えている.
                if (tc[pc] == TcBrCls || tc[pc] == TcSqBrCls) k--;
                if (k < 0) break;
                pc++;
            }
            wpc1[j] = pc; // 式の終了位置を記憶.
            if (t == TcExpr && wpc[j] == pc) return 0; // "!!**"では、長さ0は不一致とする.
            if (k > 0) return 0; // カッコの深さがおかしい時も不一致とする.
            continue;
        }
        if (t != tc[pc]) return 0; // マッチせず.
        pc++;
    }
    ppc1 = pc;
    return 1; // マッチした.
}

///////////////////////////////////////////////////////////////////////////////

typedef intptr_t *IntP; // こう書くと IntP は intptr_t * の代わりに使えるようになる. (!)

enum { OpCpy = 0, OpCeq, OpCne, OpClt, OpCge, OpCle, OpCgt, OpAdd, OpSub, OpMul, OpDiv, OpMod, OpAnd, OpShr, 
    OpAdd1, OpNeg, OpGoto, OpJeq, OpJne, OpJlt, OpJge, OpJle, OpJgt, OpLop, OpPrint, OpTime, OpEnd,
    OpPrints, OpAryNew, OpAryInit, OpArySet, OpAryGet };

IntP ic[10000], *icq; // ic[]:内部コード、icq:ic[]への書き込み用ポインタ.

void putIc(int op, IntP p1, IntP p2, IntP p3, IntP p4)  // ic[]へ簡単に書き込むための便利関数.
{
    icq[0] = (IntP) op;
    icq[1] = p1;
    icq[2] = p2;
    icq[3] = p3;
    icq[4] = p4;
    icq += 5;
}

///////////////////////////////////////////////////////////////////////////////

char tmp_flag[10]; // 一時変数の利用状況を管理.

int tmpAlloc() // 未使用の一時変数を確保.
{
    int i;
    for (i = 0; i < 10; i++) {
        if (tmp_flag[i] == 0) break;
    }
    if (i >= 10) {
        printf("tmpAlloc: error\n");
        return -1;
    }
    tmp_flag[i] = 1;
    return i + TcTmp0;
}

void tmpFree(int i) // 一時変数を未使用に戻す. ただし、指定されたトークンコードが一時変数でないときは何もしない.
{
    if (TcTmp0 <= i && i <= TcTmp9) {
        tmp_flag[i - TcTmp0] = 0;
    }
}

///////////////////////////////////////////////////////////////////////////////

int epc, epc1;	// exprのためのpcとpc1.

int exprSub(int priority);	// exprSub1()が参照するので、プロトタイプ宣言.
int expr(int j);

int exprSub1(int i, int priority, int op)	// 二項演算子の処理の標準形.
{
    int j, k;
    epc++;
    j = exprSub(priority);
    k = tmpAlloc();
    putIc(op, &var[k], &var[i], &var[j], 0);
    tmpFree(i);
    tmpFree(j);
    if (i < 0 || j < 0) return -1;
    return k;
}

int exprSub(int priority)
{
    int i = -1, e0 = 0, e1 = 0;
    ppc1 = 0;
    if (phrCmp(99, "( !!**0 )", epc)) {	// かっこ.
        i = expr(0);
    } else if (tc[epc] == TcPlPlus) {	// 前置インクリメント.
        epc++;
        i = exprSub(2);
        putIc(OpAdd1, &var[i], 0, 0, 0);
    } else if (tc[epc] == TcMinus) {	// 単項マイナス.
        epc++;
        e0 = exprSub(2);
        i = tmpAlloc();
        putIc(OpNeg, &var[i], &var[e0], 0, 0);
    } else {		// 変数もしくは定数.
        i = tc[epc];
        epc++;
    }
    if (ppc1 > 0)
        epc = ppc1;
    for (;;) {
        tmpFree(e0);
        tmpFree(e1);
        if (i < 0 || e0 < 0 || e1 < 0) return -1;	// ここまででエラーがあれば、処理を打ち切り.
        if (epc >= epc1) break;
        e0 = e1 = 0;
        if (tc[epc] == TcPlPlus) {		// 後置インクリメント.
            epc++;
            e0 = i;
            i = tmpAlloc();
            putIc(OpCpy,  &var[i], &var[e0], 0, 0);
            putIc(OpAdd1, &var[e0], 0, 0, 0);
        } else if (phrCmp(70, "[!!**0]=", epc) && priority >= 15) {
            e1 = i;
            e0 = expr(0);
            epc = ppc1;
            i = exprSub(15);
            putIc(OpArySet, &var[e1], &var[e0], &var[i], 0);
        } else if (phrCmp(71, "[!!**0]", epc)) {
            e1 = i; 
            i = tmpAlloc();
            e0 = expr(0);
            putIc(OpAryGet, &var[e1], &var[e0], &var[i], 0);
            epc = ppc1;
        } else if (TcAster <= tc[epc] && tc[epc] <= TcPerce && priority >= 4) {	// * / %
            i = exprSub1(i, 3, tc[epc] - TcAster + OpMul); // 左結合なので4より1小さくする.
        } else if (TcPlus  <= tc[epc] && tc[epc] <= TcMinus && priority >= 5) {
            i = exprSub1(i, 4, tc[epc] - TcPlus  + OpAdd); // 左結合なので5より1小さくする.
        } else if (tc[epc] == TcShr && priority >= 6) {
            i = exprSub1(i, 5, OpShr); // 左結合なので6より1小さくする.
        } else if (TcLt    <= tc[epc] && tc[epc] <= TcGt    && priority >= 7) {
            i = exprSub1(i, 6, tc[epc] - TcLt    + OpClt); // 左結合なので7より1小さくする.
        } else if (TcEEq   <= tc[epc] && tc[epc] <= TcNEq   && priority >= 8) {
            i = exprSub1(i, 7, tc[epc] - TcEEq   + OpCeq); // 左結合なので8より1小さくする.
        } else if (tc[epc] == TcAnd && priority >= 9) {
            i = exprSub1(i, 8, OpAnd); // 左結合なので9より1小さくする.
        } else if (tc[epc] == TcEqu && priority >= 15) {
            epc++;
            e0 = exprSub(15);	// 右結合なので15のまま.
            putIc(OpCpy, &var[i], &var[e0], 0, 0);
        } else
            break;
    }
    return i;
}

int expr(int j)
{
    int i, k, old_epc = epc, old_epc1 = epc1, s[19]; // epc, epc1を保存する.
    if (wpc[j] == wpc1[j]) return 0;
    for (k = 0; k < 9; k++) { // wpc[], wpc1[]を保存する.
        s[k]     = wpc [k];
        s[k + 9] = wpc1[k];
    }
    s[18] = ppc1; // ppc1を保存する.
    epc  = wpc [j]; // epc, epc1を準備してexprSub()を呼び出す.
    epc1 = wpc1[j];
    i = exprSub(99);
    if (epc < epc1) return -1; // 式を最後まで解釈できなかったらエラー.
    epc  = old_epc; // 保存しておいた変数をすべて復元する.
    epc1 = old_epc1;
    for (k = 0; k < 9; k++) {
        wpc [k] = s[k];
        wpc1[k] = s[k + 9];
    }
    ppc1 = s[18];
    return i;
}

///////////////////////////////////////////////////////////////////////////////

enum { IfTrue = 0, IfFalse = 1 };

void ifgoto(int i, int not, int label)
{
    int j = wpc[i];
    if (j + 3 == wpc1[i] && TcEEq <= tc[j + 1] && tc[j + 1] <= TcGt) { // 条件式の長さが3トークンで、真ん中が比較演算子だったら.
        putIc(((tc[j + 1] - TcEEq) ^ not) + OpJeq, &var[label], &var[tc[j]], &var[tc[j + 2]], 0);
    } else {
        i = expr(i);
        putIc(OpJne - not, &var[label], &var[i], &var[Tc0], 0);
        tmpFree(i);
    }
}
int tmpLabelNo;

int tmpLabelAlloc()
{
    char s[10];
    sprintf(s, "_l%d", tmpLabelNo);
    tmpLabelNo++;
    return getTc(s, strlen(s));
}

#define BInfSiz		10

int binf[BInfSiz * 100], bd, lbd; // binf:block-info, bd:block-depth, lbd:loop-block-depth

enum { BlkIf = 1, BlkFor };
enum { IfLabel0 = 1, IfLabel1 };
enum { ForLopBgn = 1, ForCont, ForBrk, ForLbd0, ForWpc01, ForWpc11, ForWpc02, ForWpc12 };

///////////////////////////////////////////////////////////////////////////////

int compile(String s)
{
    int pc, pc1, i, j;
    IntP *icq1, *icp;
    pc1 = lexer(s, tc);
    tc[pc1++] = TcSemi;	// 末尾に「;」を付け忘れることが多いので、付けてあげる.
    tc[pc1] = tc[pc1 + 1] = tc[pc1 + 2] = tc[pc1 + 3] = TcDot;	// エラー表示用のために末尾にピリオドを登録しておく.
    icq = ic;
    for (i = 0; i < 10; i++) { // 一時変数をすべて未使用にする.
        tmp_flag[i] = 0;
    }
    tmpLabelNo = 0;
    bd = lbd = 0;
    for (pc = 0; pc < pc1; ) { // コンパイル開始.
        int e0 = 0, e2 = 0;
        if (phrCmp( 1, "!!*0 = !!*1;", pc)) { // 単純代入.
            putIc(OpCpy,  &var[tc[wpc[0]]], &var[tc[wpc[1]]], 0, 0);
        } else if (phrCmp(10, "!!*0 = !!*1 + 1; if (!!*2 < !!*3) goto !!*4;", pc) && tc[wpc[0]] == tc[wpc[1]] && tc[wpc[0]] == tc[wpc[2]]) {
            putIc(OpLop, &var[tc[wpc[4]]], &var[tc[wpc[0]]], &var[tc[wpc[3]]], 0);
        } else if (phrCmp( 9, "!!*0 = !!*1 + 1;", pc) && tc[wpc[0]] == tc[wpc[1]]) {  // 高速化のために+1専用の命令を用意(せこくてすみません).
            putIc(OpAdd1, &var[tc[wpc[0]]], 0, 0, 0);
        } else if (phrCmp( 2, "!!*0 = !!*1 !!*2 !!*3;", pc) && TcEEq <= tc[wpc[2]] && tc[wpc[2]] <= TcShr) {  // 加算, 減算など.
            putIc(tc[wpc[2]] - TcEEq + OpCeq,  &var[tc[wpc[0]]], &var[tc[wpc[1]]], &var[tc[wpc[3]]], 0);
        } else if (phrCmp( 4, "print !!**0;", pc)) { // print.
            e0 = expr(0);
            putIc(OpPrint, &var[e0], 0, 0, 0);
        } else if (phrCmp( 0, "!!*0:", pc)) {	// ラベル定義命令.
            var[tc[wpc[0]]] = icq - ic;	// ラベルに対応するicqを記録しておく.
        } else if (phrCmp( 5, "goto !!*0;", pc)) { // goto.
            putIc(OpGoto, &var[tc[wpc[0]]], &var[tc[wpc[0]]], 0, 0); // OpGotoの仕様変更.
        } else if (phrCmp( 6, "if (!!**0) goto !!*1;", pc)) {
            ifgoto(0, IfTrue, tc[wpc[1]]);
        } else if (phrCmp( 7, "time;", pc)) {
            putIc(OpTime, 0, 0, 0, 0);
        } else if (phrCmp(11, "if ( !!**0 ) {", pc)) {	// 	ブロックif.
            bd += BInfSiz;
            binf[bd] = BlkIf;
            binf[bd + IfLabel0] = tmpLabelAlloc(); // 条件不成立のときの飛び先.
            binf[bd + IfLabel1] = 0;
            ifgoto(0, 1, binf[bd + IfLabel0]); // 条件を満たさなければ、binf[bd + IfLabel0]へgotoする.
        } else if (phrCmp(12, "} else {", pc) && binf[bd] == BlkIf) {
            binf[bd + IfLabel1] = tmpLabelAlloc(); // else節の終端.
            putIc(OpGoto, &var[binf[bd + IfLabel1]], &var[binf[bd + IfLabel1]], 0, 0);
            var[binf[bd + IfLabel0]] = icq - ic;	// ラベルに対応するicqを記録しておく.
        } else if (phrCmp( 13, "}", pc) && binf[bd] == BlkIf) {
            if (binf[bd + IfLabel1] == 0) {
                var[binf[bd + IfLabel0]] = icq - ic;	// ラベルに対応するicqを記録しておく.
            } else {
                var[binf[bd + IfLabel1]] = icq - ic;	// ラベルに対応するicqを記録しておく.
            }
            bd -= BInfSiz;
        } else if (phrCmp(14, "for (!!***0; !!***1; !!***2) {", pc)) {	// for文
            bd += BInfSiz;
            binf[bd] = BlkFor; // ブロックのタイプ.
            binf[bd + ForLopBgn] = tmpLabelAlloc(); // ループの頭に戻る用.
            binf[bd + ForCont  ] = tmpLabelAlloc(); // continue用.
            binf[bd + ForBrk   ] = tmpLabelAlloc(); // break用.
            binf[bd + ForLbd0  ] = lbd; // 古い値を保存.
            binf[bd + ForWpc01 ] = wpc [1];
            binf[bd + ForWpc11 ] = wpc1[1];
            binf[bd + ForWpc02 ] = wpc [2];
            binf[bd + ForWpc12 ] = wpc1[2];
            lbd = bd;
            e0 = expr(0);
            if (wpc[1] < wpc1[1]) {	// !!***1に何らかの式が書いてあった.
                ifgoto(1, IfFalse, binf[bd + ForBrk]); // 最初から条件不成立ならbreakへ.
            }
            var[binf[bd + ForLopBgn]] = icq - ic;	// ラベルに対応するicqを記録しておく.
        } else if (phrCmp(15, "}", pc) && binf[bd] == BlkFor) {
            var[binf[bd + ForCont]] = icq - ic;	// ラベルに対応するicqを記録しておく.
            i = binf[bd + ForWpc01];
            j = binf[bd + ForWpc02];
            if (i + 3 == binf[bd + ForWpc11] && j + 2 == binf[bd + ForWpc12] && tc[i] == tc[j] && tc[i + 1] == TcLt && tc[j + 1] == TcPlPlus) {
                // !!***1が「i < ?」かつ、!!***2が「i++」だったら(変数名はiじゃなくてもいいけど、共通である必要がある).
                putIc(OpLop, &var[binf[bd + ForLopBgn]], &var[tc[i]], &var[tc[i + 2]], 0);
            } else {
                wpc [1] = binf[bd + ForWpc01];
                wpc1[1] = binf[bd + ForWpc11];
                wpc [2] = binf[bd + ForWpc02];
                wpc1[2] = binf[bd + ForWpc12];
                e2 = expr(2);
                if (wpc[1] < wpc1[1]) {	// !!***1に何らかの式が書いてあった.
                    ifgoto(1, IfTrue, binf[bd + ForLopBgn]);
                } else {
                    putIc(OpGoto, &var[binf[bd + ForLopBgn]], &var[binf[bd + ForLopBgn]], 0, 0);
                }
            }
            var[binf[bd + ForBrk]] = icq - ic;	// ラベルに対応するicqを記録しておく.
            lbd = binf[bd + ForLbd0]; // 以前の値を復元.
            bd -= BInfSiz;
        } else if (phrCmp(16, "continue;", pc) && lbd > 0) {
            putIc(OpGoto, &var[binf[lbd + ForCont]], &var[binf[lbd + ForCont]], 0, 0);
        } else if (phrCmp(17, "break;", pc) && lbd > 0) {
            putIc(OpGoto, &var[binf[lbd + ForBrk ]], &var[binf[lbd + ForBrk ]], 0, 0);
        } else if (phrCmp(18, "if ( !!**0 ) continue;", pc) && lbd > 0) {
            ifgoto(0, IfTrue, binf[lbd + ForCont]);
        } else if (phrCmp(19, "if ( !!**0 ) break;", pc) && lbd > 0) {
            ifgoto(0, IfTrue, binf[lbd + ForBrk ]);
        } else if (phrCmp(20, "prints !!**0;", pc)) { // prints.
            e0 = expr(0);
            putIc(OpPrints, &var[e0], 0, 0, 0);
        } else if (phrCmp(21, "int !!*0[!!**2];", pc)) {
            e2 = expr(2);
            putIc(OpAryNew, &var[tc[wpc[0]]], &var[e2], 0, 0);
        } else if (phrCmp(22, "int !!*0[!!**2] = {", pc)) {
            e2 = expr(2);
            putIc(OpAryNew, &var[tc[wpc[0]]], &var[e2], 0, 0);
            j = 0;
            for (i = ppc1; i < pc1; i++) {	// コンマ以外のトークンを数える.
                if (tc[i] == TcCrBrCls) break;
                    if (tc[i] != TcComma) {
                        j++;
                    }
                }
                if (i >= pc1) goto err;
                intptr_t *ip = malloc(j * sizeof (intptr_t));
                j = 0;
                for (i = ppc1; tc[i] != TcCrBrCls; i++) {
                    if (tc[i] == TcCrBrCls) break;
                    if (tc[i] != TcComma) {
                    ip[j] = var[tc[i]];
                    j++;
                }
            }
            putIc(OpAryInit, &var[tc[wpc[0]]], (IntP) ip, (IntP) j, 0);
            ppc1 = i + 2; // } と ; の分.
        } else if (phrCmp( 8, "!!***0;", pc)) {	// これはかなりマッチしやすいので最後にする.
            e0 = expr(0);
        } else
            goto err;
        tmpFree(e0);
        tmpFree(e2);
        if (e0 < 0 || e2 < 0) goto err;
        pc = ppc1;
    }
    if (bd > 0) {
        printf("block nesting error (bd=%d, lbd=%d, pc=%d, pc1=%d\n", bd, lbd, pc, pc1);
        return -1;
    }
    putIc(OpEnd, 0, 0, 0, 0);
    icq1 = icq;
    for (icq = ic; icq < icq1; icq += 5) {  // goto先の設定.
        i = (int) icq[0];
        if (OpGoto <= i && i <= OpLop) {
            icp = *icq[1] + ic;
            while ((int) icp[0] == OpGoto) {  // 飛び先がOpGotoだったら、さらにその先を読む(最適化).
                icp = *icp[2] + ic;
            }
            icq[1] = (IntP) icp;
        }
    }
    return icq1 - ic;
err:
    printf("syntax error : %s %s %s %s\n", ts[tc[pc]], ts[tc[pc + 1]], ts[tc[pc + 2]], ts[tc[pc + 3]]);
    return -1;
}

void exec()
{
    clock_t t0 = clock();
    IntP *icp = ic;
    intptr_t i, *a;
    for (;;) {
        switch ((int) icp[0]) {
        case OpNeg:     *icp[1] = - *icp[2];          icp += 5; continue;
        case OpAdd1:    (*icp[1])++;                  icp += 5; continue;
        case OpMul:     *icp[1] = *icp[2] *  *icp[3]; icp += 5; continue;
        case OpDiv:     *icp[1] = *icp[2] /  *icp[3]; icp += 5; continue;
        case OpMod:     *icp[1] = *icp[2] %  *icp[3]; icp += 5; continue;
        case OpAdd:     *icp[1] = *icp[2] +  *icp[3]; icp += 5; continue;
        case OpSub:     *icp[1] = *icp[2] -  *icp[3]; icp += 5; continue;
        case OpShr:     *icp[1] = *icp[2] >> *icp[3]; icp += 5; continue;
        case OpClt:     *icp[1] = *icp[2] <  *icp[3]; icp += 5; continue;
        case OpCge:     *icp[1] = *icp[2] >= *icp[3]; icp += 5; continue;
        case OpCle:     *icp[1] = *icp[2] <= *icp[3]; icp += 5; continue;
        case OpCgt:     *icp[1] = *icp[2] >  *icp[3]; icp += 5; continue;
        case OpCeq:     *icp[1] = *icp[2] == *icp[3]; icp += 5; continue;
        case OpCne:     *icp[1] = *icp[2] != *icp[3]; icp += 5; continue;
        case OpAnd:     *icp[1] = *icp[2] &  *icp[3]; icp += 5; continue;
        case OpCpy:     *icp[1] = *icp[2];            icp += 5; continue;
        case OpPrint:
            printf("%d\n", *icp[1]);
            icp += 5;
            continue;
        case OpGoto:                           icp = (IntP *) icp[1]; continue;
        case OpJge:  if (*icp[2] >= *icp[3]) { icp = (IntP *) icp[1]; continue; } icp += 5; continue;
        case OpJle:  if (*icp[2] <= *icp[3]) { icp = (IntP *) icp[1]; continue; } icp += 5; continue;
        case OpJgt:  if (*icp[2] >  *icp[3]) { icp = (IntP *) icp[1]; continue; } icp += 5; continue;
        case OpJeq:  if (*icp[2] == *icp[3]) { icp = (IntP *) icp[1]; continue; } icp += 5; continue;
        case OpJne:  if (*icp[2] != *icp[3]) { icp = (IntP *) icp[1]; continue; } icp += 5; continue;
        case OpJlt:  if (*icp[2] <  *icp[3]) { icp = (IntP *) icp[1]; continue; } icp += 5; continue;
        case OpTime:
            printf("time: %.3f[sec]\n", (clock() - t0) / (double) CLOCKS_PER_SEC);
            icp += 5;
            continue;
        case OpEnd:
            return;
        case OpLop:
            i = *icp[2];
            i++;
            *icp[2] = i;
            if (i < *icp[3]) {
                icp = (IntP *) icp[1];
                continue;
            }
            icp += 5;
            continue;
        case OpPrints:
            printf("%s\n", (char *) *icp[1]);
            icp += 5;
            continue;
        case OpAryNew:
            *icp[1] = (intptr_t) malloc(*icp[2] * sizeof (intptr_t));
            memset((char *) *icp[1], 0, *icp[2] * sizeof (intptr_t));
            icp += 5;
            continue;
        case OpAryInit:
            memcpy((char *) *icp[1], (char *) icp[2], ((int) icp[3]) * sizeof (intptr_t));
            icp += 5;
            continue;
        case OpArySet:
            a = (intptr_t *) *icp[1];
            i = *icp[2];
            a[i] = *icp[3];
            icp += 5;
            continue;
        case OpAryGet:
            a = (intptr_t *) *icp[1];
            i = *icp[2];
            *icp[3] = a[i];
            icp += 5;
            continue;
       }
   }
}

int run(String s)
{
    if (compile(s) < 0)
        return 1;
    exec();
    return 0;
}

///////////////////////////////////////////////////////////////////////////////

int main(int argc, const char **argv)
{
    unsigned char txt[10000];
    int i;
    lexer(tcInit, tc);
    if (argc >= 2) {
        if (loadText((String) argv[1], txt, 10000) == 0) {
            run(txt);
        }
        exit(0);
    }
    for (;;) { // Read-Eval-Print Loop.
        printf("\n>");
        fgets(txt, 10000, stdin);
        i = strlen(txt);
        if (txt[i - 1] == '\n') { // 末尾に改行コードが付いていればそれを消す.
            txt[i - 1] = 0;
        }
        if (strncmp(txt, "run ", 4) == 0) {
            if (loadText(&txt[4], txt, 10000) == 0) {
                run(txt);
            }
        } else if (strcmp(txt, "exit") == 0) {
            exit(0);
        } else {
            run(txt);
        }
    }
}