a21_txt02_6
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
* 「10日くらいでできる!プログラミング言語自作入門」の続...
-(by [[K]], 2021.04.29)
** (1) HL-16
-HL-15aで「print 1+2*3」をJITコンパイルするとこうなります。
>print 1+2*3
b8 02 00 00 00 6b c0 03 89 05 a0 0a 42 00 b8 01 00 00 00...
(len=34)
-この機械語を整理するとこうなります。
b8_02_00_00_00_00; // EAX=2;
6b_c0_03; // EAX=EAX*3;
89_05_a0_0a_42_00; // _t0=EAX;
b8_01_00_00_00_00; // EAX=1;
03_05_a0_0a_42_00; // EAX=EAX+_t0;
89_44_24_00; // [ESP+0]=EAX;
e8_8f_27_c6_ff; // CALL sub_print;
-つまり、一生懸命に式を計算しているのです。当たり前ですけ...
-でも、こんな定数式は別に実行時に計算しなくたっていいはず...
b8_07_00_00_00; // EAX=7;
89_44_24_00; // [ESP+0]=EAX;
e8_8f_27_c6_ff; // CALL sub_print;
-みたいにJITコンパイルできたらかっこいいと思いませんか?...
-ということで、それを実現するのがHL-16の目標です。
----
-[1]isConst()関数に2行追加
int isConst(int i)
{
if ('0' <= ts[i][0] && ts[i][0] <= '9') return 1;
+ if (ts[i][0] == '-' && '0' <= ts[i][1] && ts[i][1] <...
+ if (ts[i][0] == 34) return 1;
return 0;
}
-[2]getConstM()関数の後に以下の記述を追加
int calcConst1(int op, int a)
{
int v = 0, va = var[a];
char s[100];
if (isConst(a) == 0) return 0;
switch (op) {
case TcMinus: v = - va; break;
}
sprintf(s, "%d", v);
return getTc(s, strlen(s));
}
int calcConst2(int op, int a, int b)
{
int v = 0, va = var[a], vb = var[b];
char s[100];
if (isConst(a) == 0 || isConst(b) == 0) return 0;
switch (op) {
case TcEEq: v = va == vb; break;
case TcNEq: v = va != vb; break;
case TcLt: v = va < vb; break;
case TcGe: v = va >= vb; break;
case TcLe: v = va <= vb; break;
case TcGt: v = va > vb; break;
case TcPlus: v = va + vb; break;
case TcMinus: v = va - vb; break;
case TcAster: v = va * vb; break;
case TcSlash: v = va / vb; break;
case TcPerce: v = va % vb; break;
case TcAnd: v = va & vb; break;
case TcShr: v = va >> vb; break;
}
sprintf(s, "%d", v);
return getTc(s, strlen(s));
}
-[3]exprSub1()関数に3行追加
int exprSub1(int i, int priority, int op) // 二項演算子...
{
int j, k;
epc++;
j = exprSub(priority);
+ k = calcConst2(op, i, j);
+ if (k == 0) {
k = tmpAlloc();
putIcX86(opBin[op - TcEEq], &var[k], &var[i], &v...
+ }
tmpFree(i);
tmpFree(j);
if (i < 0 || j < 0) return -1;
return k;
}
-[4]exprSub()関数に3行追加
} else if (tc[epc] == TcMinus) { // 単項マイナス.
epc++;
e0 = exprSub(2);
+ i = calcConst1(TcMinus, e0);
+ if (i == 0) {
i = tmpAlloc();
putIcX86("8b_%1m0; f7_d8; 89_%0m0;", &var[i]...
+ }
-[5]compile()関数に9行追加
} else if (phrCmp( 2, "!!*0 = !!*1 !!*2 !!*3;", ...
+ i = calcConst2(tc[wpc[2]], tc[wpc[1]], tc[wp...
+ if (i == 0) {
putIcX86(opBin[tc[wpc[2]] - TcEEq], &var...
+ } else {
+ if (regVar(&var[tc[wpc[0]]]) < 0) {
+ putIcX86("%1L11; 89_&8:%0m0;", &var[...
+ } else {
+ putIcX86("%0L00; 8b_&8:%1m0;", &var[...
+ }
+ }
----
-以上すべての改造を終えると、プログラムは1065行になります。
-それでは効果を確認してみます。
>print 1+2*3
b8 07 00 00 00 89 44 24 00 e8 f4 28 2f fe
(len=14)
-こんなふうにちゃんと定数式が計算されて7がいきなり渡され...
-以下の例のように、部分的に定数式がある場合も、その部分だ...
>a=b+(9-1)
8b 05 50 0b 42 00 83 c0 08 89 05 4c 0b 42 00
(len=15)
8b_05_50_0b_42_00; // EAX=b;
83_c0_08; // EAX=EAX+8;
89_05_4c_0b_42_00; // a=EAX;
** (2) プログラムの説明
-isConst()関数に2行追加
--これは負の数や文字列リテラルを定数だと認識するように拡...
-calcConst1()
--これは単項演算子の定数計算をするものです。
--もし渡されたトークンが定数なら計算結果のトークンを返し...
--定数でなければ0を返します。
-calcConst2()
--これは二項演算子の定数計算をするものです。
--もし渡されたトークンが2つとも定数なら計算結果のトークン...
--そうでなければ定数計算はできないので0を返します。
-これらがそろった後は、演算時にこれを呼び出して、もし0以...
-a=b+c;みたいなシンプルな計算の場合に、b+cの部分が定数計...
** (3) 成果の比較
-上記みたいなのはすごく特別でレアケースなのか、それともよ...
-サイズが小さくなったからいいとか悪いとかではなく、「サイ...
||HL-13a|HL-14|HL-14a|HL-15|HL-15a|HL-16|
|mandel.c|RIGHT:1087|RIGHT:1007|RIGHT:942|RIGHT:768|RIGHT...
|maze.c|RIGHT:2192|RIGHT:2192|RIGHT:2192|RIGHT:1770|RIGHT...
|kcube.c|RIGHT:4623|RIGHT:4623|RIGHT:4623|RIGHT:3695|RIGH...
|invader.c|RIGHT:3260|RIGHT:3260|RIGHT:3260|RIGHT:2750|RI...
** 次回に続く
-次回: [[a21_txt02_6a]]
*こめんと欄
#comment
終了行:
* 「10日くらいでできる!プログラミング言語自作入門」の続...
-(by [[K]], 2021.04.29)
** (1) HL-16
-HL-15aで「print 1+2*3」をJITコンパイルするとこうなります。
>print 1+2*3
b8 02 00 00 00 6b c0 03 89 05 a0 0a 42 00 b8 01 00 00 00...
(len=34)
-この機械語を整理するとこうなります。
b8_02_00_00_00_00; // EAX=2;
6b_c0_03; // EAX=EAX*3;
89_05_a0_0a_42_00; // _t0=EAX;
b8_01_00_00_00_00; // EAX=1;
03_05_a0_0a_42_00; // EAX=EAX+_t0;
89_44_24_00; // [ESP+0]=EAX;
e8_8f_27_c6_ff; // CALL sub_print;
-つまり、一生懸命に式を計算しているのです。当たり前ですけ...
-でも、こんな定数式は別に実行時に計算しなくたっていいはず...
b8_07_00_00_00; // EAX=7;
89_44_24_00; // [ESP+0]=EAX;
e8_8f_27_c6_ff; // CALL sub_print;
-みたいにJITコンパイルできたらかっこいいと思いませんか?...
-ということで、それを実現するのがHL-16の目標です。
----
-[1]isConst()関数に2行追加
int isConst(int i)
{
if ('0' <= ts[i][0] && ts[i][0] <= '9') return 1;
+ if (ts[i][0] == '-' && '0' <= ts[i][1] && ts[i][1] <...
+ if (ts[i][0] == 34) return 1;
return 0;
}
-[2]getConstM()関数の後に以下の記述を追加
int calcConst1(int op, int a)
{
int v = 0, va = var[a];
char s[100];
if (isConst(a) == 0) return 0;
switch (op) {
case TcMinus: v = - va; break;
}
sprintf(s, "%d", v);
return getTc(s, strlen(s));
}
int calcConst2(int op, int a, int b)
{
int v = 0, va = var[a], vb = var[b];
char s[100];
if (isConst(a) == 0 || isConst(b) == 0) return 0;
switch (op) {
case TcEEq: v = va == vb; break;
case TcNEq: v = va != vb; break;
case TcLt: v = va < vb; break;
case TcGe: v = va >= vb; break;
case TcLe: v = va <= vb; break;
case TcGt: v = va > vb; break;
case TcPlus: v = va + vb; break;
case TcMinus: v = va - vb; break;
case TcAster: v = va * vb; break;
case TcSlash: v = va / vb; break;
case TcPerce: v = va % vb; break;
case TcAnd: v = va & vb; break;
case TcShr: v = va >> vb; break;
}
sprintf(s, "%d", v);
return getTc(s, strlen(s));
}
-[3]exprSub1()関数に3行追加
int exprSub1(int i, int priority, int op) // 二項演算子...
{
int j, k;
epc++;
j = exprSub(priority);
+ k = calcConst2(op, i, j);
+ if (k == 0) {
k = tmpAlloc();
putIcX86(opBin[op - TcEEq], &var[k], &var[i], &v...
+ }
tmpFree(i);
tmpFree(j);
if (i < 0 || j < 0) return -1;
return k;
}
-[4]exprSub()関数に3行追加
} else if (tc[epc] == TcMinus) { // 単項マイナス.
epc++;
e0 = exprSub(2);
+ i = calcConst1(TcMinus, e0);
+ if (i == 0) {
i = tmpAlloc();
putIcX86("8b_%1m0; f7_d8; 89_%0m0;", &var[i]...
+ }
-[5]compile()関数に9行追加
} else if (phrCmp( 2, "!!*0 = !!*1 !!*2 !!*3;", ...
+ i = calcConst2(tc[wpc[2]], tc[wpc[1]], tc[wp...
+ if (i == 0) {
putIcX86(opBin[tc[wpc[2]] - TcEEq], &var...
+ } else {
+ if (regVar(&var[tc[wpc[0]]]) < 0) {
+ putIcX86("%1L11; 89_&8:%0m0;", &var[...
+ } else {
+ putIcX86("%0L00; 8b_&8:%1m0;", &var[...
+ }
+ }
----
-以上すべての改造を終えると、プログラムは1065行になります。
-それでは効果を確認してみます。
>print 1+2*3
b8 07 00 00 00 89 44 24 00 e8 f4 28 2f fe
(len=14)
-こんなふうにちゃんと定数式が計算されて7がいきなり渡され...
-以下の例のように、部分的に定数式がある場合も、その部分だ...
>a=b+(9-1)
8b 05 50 0b 42 00 83 c0 08 89 05 4c 0b 42 00
(len=15)
8b_05_50_0b_42_00; // EAX=b;
83_c0_08; // EAX=EAX+8;
89_05_4c_0b_42_00; // a=EAX;
** (2) プログラムの説明
-isConst()関数に2行追加
--これは負の数や文字列リテラルを定数だと認識するように拡...
-calcConst1()
--これは単項演算子の定数計算をするものです。
--もし渡されたトークンが定数なら計算結果のトークンを返し...
--定数でなければ0を返します。
-calcConst2()
--これは二項演算子の定数計算をするものです。
--もし渡されたトークンが2つとも定数なら計算結果のトークン...
--そうでなければ定数計算はできないので0を返します。
-これらがそろった後は、演算時にこれを呼び出して、もし0以...
-a=b+c;みたいなシンプルな計算の場合に、b+cの部分が定数計...
** (3) 成果の比較
-上記みたいなのはすごく特別でレアケースなのか、それともよ...
-サイズが小さくなったからいいとか悪いとかではなく、「サイ...
||HL-13a|HL-14|HL-14a|HL-15|HL-15a|HL-16|
|mandel.c|RIGHT:1087|RIGHT:1007|RIGHT:942|RIGHT:768|RIGHT...
|maze.c|RIGHT:2192|RIGHT:2192|RIGHT:2192|RIGHT:1770|RIGHT...
|kcube.c|RIGHT:4623|RIGHT:4623|RIGHT:4623|RIGHT:3695|RIGH...
|invader.c|RIGHT:3260|RIGHT:3260|RIGHT:3260|RIGHT:2750|RI...
** 次回に続く
-次回: [[a21_txt02_6a]]
*こめんと欄
#comment
ページ名: