a21_txt01_8
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
* 川合のプログラミング言語自作のためのテキスト第三版#8
-(by [[K]], 2021.03.13)
** (1) HL-8
-今回は、ブロックifとfor文を追加します。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
typedef unsigned char *String; // こう書くと String は u...
int loadText(String path, String t, int siz) → HL-4と同...
////////////////////////////////////////////////////////...
#define MAX_TC 1000 // トークンコードの最大値.
String ts[MAX_TC + 1]; // トークンの内容(文字列)を記憶.
int tl[MAX_TC + 1]; // トークンの長さ.
unsigned char tcBuf[(MAX_TC + 1) * 10]; // トークン1つ当...
int tcs = 0, tcb = 0;
int var[MAX_TC + 1]; // 変数.
int getTc(String s, int len) → HL-4と同じなので省略
////////////////////////////////////////////////////////...
int isAlphabetOrNumber(unsigned char c) → HL-2と同じなの...
int lexer(String s, int tc[]) → HL-2と同じなので省略
int tc[10000]; // トークンコード.
enum { TcSemi = 0, TcDot, TcWiCard, Tc0, Tc1, Tc2, Tc3, ...
TcEEq, TcNEq, TcLt, TcGe, TcLe, TcGt, TcPlus, TcMinu...
TcComma, TcExpr, TcExpr0, TcTmp0, TcTmp1, TcTmp2, Tc...
char tcInit[] = "; . !!* 0 1 2 3 4 5 6 7 8 ( ) [ ] { } =...
////////////////////////////////////////////////////////...
int phrCmp_tc[32 * 100], ppc1, wpc[9], wpc1[9]; // ppc1:...
int phrCmp(int pid, String phr, int pc) → HL-7と同じなの...
////////////////////////////////////////////////////////...
typedef int *IntP; // こう書くと IntP は int * の代わり...
enum { OpCpy = 0, OpCeq, OpCne, OpClt, OpCge, OpCle, OpC...
OpAdd1, OpNeg, OpGoto, OpJeq, OpJne, OpJlt, OpJge, O...
IntP ic[10000], *icq; // ic[]:内部コード、icq:ic[]への書...
void putIc(int op, IntP p0, IntP p1, IntP p2, IntP p3) →...
////////////////////////////////////////////////////////...
char tmp_flag[10]; // 一時変数の利用状況を管理.
int tmpAlloc() → HL-7と同じなので省略
void tmpFree(int i) → HL-7と同じなので省略
////////////////////////////////////////////////////////...
int epc, epc1; // exprのためのpcとpc1.
int exprSub(int priority); // exprSub1()が参照するので、...
int expr(int j);
int exprSub1(int i, int priority, int op) → HL-7と同じな...
int exprSub(int priority) → HL-7と同じなので省略
int expr(int j) → HL-7と同じなので省略
////////////////////////////////////////////////////////...
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 +...
putIc(((tc[j + 1] - TcEEq) ^ not) + OpJeq, &var[...
} else {
i = expr(i);
putIc(OpJne - not, &var[label], &var[i], &var[Tc...
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...
enum { BlkIf = 1, BlkFor };
enum { IfLabel0 = 1, IfLabel1 };
enum { ForLopBgn = 1, ForCont, ForBrk, ForLbd0, ForWpc01...
////////////////////////////////////////////////////////...
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] = ...
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[...
} else if (phrCmp(10, "!!*0 = !!*1 + 1; if (!!*2...
putIc(OpLop, &var[tc[wpc[4]]], &var[tc[wpc[0...
} else if (phrCmp( 9, "!!*0 = !!*1 + 1;", pc) &&...
putIc(OpAdd1, &var[tc[wpc[0]]], 0, 0, 0);
} else if (phrCmp( 2, "!!*0 = !!*1 + !!*2;", pc)...
putIc(OpAdd, &var[tc[wpc[0]]], &var[tc[wpc[...
} else if (phrCmp( 3, "!!*0 = !!*1 - !!*2;", pc)...
putIc(OpSub, &var[tc[wpc[0]]], &var[tc[wpc[...
} else if (phrCmp( 4, "print !!**0;", pc)) { // ...
e0 = expr(0);
putIc(OpPrint, &var[e0], 0, 0, 0);
} else if (phrCmp( 0, "!!*0:", pc)) { // ラベル...
var[tc[wpc[0]]] = icq - ic; // ラベルに対応...
} else if (phrCmp( 5, "goto !!*0;", pc)) { // go...
! putIc(OpGoto, &var[tc[wpc[0]]], &var[tc[wpc[...
! } else if (phrCmp( 6, "if (!!**0) goto !!*1;", p...
! 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)) { /...
+ bd += BInfSiz;
+ binf[bd] = BlkIf;
+ binf[bd + IfLabel0] = tmpLabelAlloc(); // 条...
+ binf[bd + IfLabel1] = 0;
+ ifgoto(0, 1, binf[bd + IfLabel0]); // 条件を...
+ } else if (phrCmp(12, "} else {", pc) && binf[bd...
+ binf[bd + IfLabel1] = tmpLabelAlloc(); // el...
+ putIc(OpGoto, &var[binf[bd + IfLabel1]], &va...
+ var[binf[bd + IfLabel0]] = icq - ic; // ラベ...
+ } else if (phrCmp( 13, "}", pc) && binf[bd] == B...
+ if (binf[bd + IfLabel1] == 0) {
+ var[binf[bd + IfLabel0]] = icq - ic; // ...
+ } else {
+ var[binf[bd + IfLabel1]] = icq - ic; // ...
+ }
+ bd -= BInfSiz;
+ } else if (phrCmp(14, "for (!!***0; !!***1; !!**...
+ bd += BInfSiz;
+ binf[bd] = BlkFor; // ブロックのタイプ.
+ binf[bd + ForLopBgn] = tmpLabelAlloc(); // ...
+ binf[bd + ForCont ] = tmpLabelAlloc(); // c...
+ binf[bd + ForBrk ] = tmpLabelAlloc(); // b...
+ 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]); /...
+ }
+ var[binf[bd + ForLopBgn]] = icq - ic; // ラ...
+ } else if (phrCmp(15, "}", pc) && binf[bd] == Bl...
+ var[binf[bd + ForCont]] = icq - ic; // ラベ...
+ i = binf[bd + ForWpc01];
+ j = binf[bd + ForWpc02];
+ if (i + 3 == binf[bd + ForWpc11] && j + 2 ==...
+ // !!***1が「i < ?」かつ、!!***2が「i++...
+ putIc(OpLop, &var[binf[bd + ForLopBgn]],...
+ } 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, IfTure, binf[bd + ForLopBg...
+ } else {
+ putIc(OpGoto, &var[binf[bd + ForLopB...
+ }
+ }
+ var[binf[bd + ForBrk]] = icq - ic; // ラベル...
+ lbd = binf[bd + ForLbd0]; // 以前の値を復元.
+ bd -= BInfSiz;
+ } else if (phrCmp(16, "continue;", pc) && lbd > ...
+ putIc(OpGoto, &var[binf[lbd + ForCont]], &va...
+ } else if (phrCmp(17, "break;", pc) && lbd > 0) {
+ putIc(OpGoto, &var[binf[lbd + ForBrk ]], &va...
+ } else if (phrCmp(18, "if ( !!**0 ) continue;", ...
+ ifgoto(0, IfTrue, binf[lbd + ForCont]);
+ } else if (phrCmp(19, "if ( !!**0 ) break;", pc)...
+ ifgoto(0, IfTrue, binf[lbd + ForBrk ]);
} 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=%...
+ 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) { // 飛び先...
+ icp = *icp[2] + ic;
+ }
! icq[1] = (IntP) icp;
}
}
return icq1 - ic;
err:
printf("syntax error : %s %s %s %s\n", ts[tc[pc]], t...
return -1;
}
void exec()
{
(中略)
+ case OpJge: if (*icp[2] >= *icp[3]) { icp = (In...
+ case OpJle: if (*icp[2] <= *icp[3]) { icp = (In...
+ case OpJgt: if (*icp[2] > *icp[3]) { icp = (In...
(中略)
}
int run(String s) → HL-6と同じなので省略
////////////////////////////////////////////////////////...
int main(int argc, const char **argv) → HL-5と同じなので...
-トータルの行数は557行になっています。
-後で説明しますが、ブロックifとfor文を入れただけではなく...
----
-HL-8では普通にブロックifが使えます。なお、中の文が1文だ...
if (a < 10) {
a = 10;
}
-elseも使えます。でもやっぱり { } は省略できません。
if (a < 20) {
c = c + 1;
} else {
d = d + 1;
}
-面倒になってきたので例は出しませんが、if文の中にif文を入...
-今まで if ~ goto しかなかったので、ラベルを連発しなけれ...
-for文も使えます。しかしこれも { } は省略できません。
for (i = 0; i < 10; i++) {
print i;
}
** (2) HL-8の簡単な説明
-今回からは、HL-8で新規に追加されたもの、変更を加えた部分...
-関数:
--void ifgoto(int i, int not, int label)
---条件式wpc[i]を評価して、その結果に応じてlabel(トーク...
---notはフラグで、IfTrueの場合は、条件が成立した場合に分...
--int tmpLabelAlloc()
---一時ラベル(一時変数のラベル版)を発行してトークンコー...
---一時ラベルは使い終わった後に再利用するということはない...
-変数:
--int tmpLabelNo
---一時ラベルのラベル名を重複なく生成するための通し番号で...
--int binf[], bd, lbd;
---binf[]はblock-info.で、つまりコードブロックの情報です...
---bdやlbdは1ずつ増減するのではなく、BInfSizずつ増減しま...
---binf[bd]は今のコードブロックが何のコードブロックなのか...
---binf[bd - BInfSiz]は今のコードブロックの1つ外側、binf[...
---より詳しい情報は、binf[bd + 1~]に入っています。
---こういう変数がないと、ソースコード中に「 } 」があって...
** (3) ブロックif文について
-ブロックif文のためにcompile()に追加された部分を中心に説...
-まず HL-8 では、ブロックif文を次のように変換することで、...
-[1] if (条件式) { コードブロック#1 } の場合:
if (!条件式) goto _tmpLabel0;
コードブロック#1
_tmpLabel0:
-[2] if (条件式) { コードブロック#1 } else { コードブロッ...
if (!条件式) goto _tmpLabel0;
コードブロック#1
goto _tmpLabel1;
_tmpLabel0:
コードブロック#2;
_tmpLabel1:
-この基本方針がわかれば、あとはそれほど難しくはありません。
-compile()の中を見ていきます。
} else if (phrCmp(11, "if ( !!**0 ) {", pc)) { // ブロ...
bd += BInfSiz;
binf[bd] = BlkIf;
binf[bd + IfLabel0] = tmpLabelAlloc(); // 条件不成立...
binf[bd + IfLabel1] = 0;
ifgoto(0, 1, binf[bd + IfLabel0]); // 条件を満たさな...
-ブロックif文が現れたら、新しいコードブロックが始まるので...
-そして_tmpLabel0を準備します。
-最後に「if (!条件式) goto _tmpLabel0;」に相当する内部コ...
} else if (phrCmp(12, "} else {", pc) && binf[bd] == Blk...
binf[bd + IfLabel1] = tmpLabelAlloc(); // else節の終...
putIc(OpGoto, &var[binf[bd + IfLabel1]], &var[binf[b...
var[binf[bd + IfLabel0]] = icq - ic; // ラベルに対応...
-「 } else { 」が来たら、これは上記の[2]の場合に相当しま...
-_tmpLabel1も必要になるのでそれを準備したのち、goto _tmpL...
--ここで、OpGotoの仕様が変わって、飛び先を二度指定するよ...
-そして、_tmpLabel0のラベルはここだよと宣言します。
-これで「 } else { 」の処理はおしまいです。
} else if (phrCmp( 13, "}", pc) && binf[bd] == BlkIf) {
if (binf[bd + IfLabel1] == 0) {
var[binf[bd + IfLabel0]] = icq - ic; // ラベルに...
} else {
var[binf[bd + IfLabel1]] = icq - ic; // ラベルに...
}
bd -= BInfSiz;
-ブロックif文のコードブロックを閉じたときの処理です。
-これは[1]の場合と[2]の場合とで異なります。
-[1]の場合は、「_tmpLabel0:」の処理をやります。
-[2]の場合は、「_tmpLabel1:」の処理をやります。
-最後にbdをBInfSizだけ減じて、コードブロックを終了します。
** (4) for文について
-上記のブロックif文と似たような方法で、for文も実現してい...
-for文の変換は次のようにしています。
-for(式0; 条件式; 式2) { コードブロック }
式0;
if (!条件式) goto _tmpLabel2; // 最初から条件が成立...
_tmpLabel0:
コードブロック;
_tmpLabel1: // continue命令が来たらここに行かせる.
式2;
if (条件式) goto _tmpLabel0;
_tmpLabel2:
-この基本方針がわかれば、あとはそれほど難しくはありません。
-compile()の中を見ていきます。
} else if (phrCmp(14, "for (!!***0; !!***1; !!***2) {", ...
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]); // 最初か...
}
var[binf[bd + ForLopBgn]] = icq - ic; // ラベルに対...
-for文では、あとで(=コードブロックを閉じるときに)条件...
-「e0 = expr(0);」で 式0 の部分を内部コードとして出力させ...
-そして条件式に何か書いてあれば、条件不成立時にはループに...
-最後に _tmpLabel0: に相当する処理をしています。
} else if (phrCmp(15, "}", pc) && binf[bd] == BlkFor) {
var[binf[bd + ForCont]] = icq - ic; // ラベルに対応...
i = binf[bd + ForWpc01];
j = binf[bd + ForWpc02];
if (i + 3 == binf[bd + ForWpc11] && j + 2 == binf[bd...
// !!***1が「i < ?」かつ、!!***2が「i++」だった...
putIc(OpLop, &var[binf[bd + ForLopBgn]], &var[tc...
} 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]], &v...
}
}
var[binf[bd + ForBrk]] = icq - ic; // ラベルに対応す...
lbd = binf[bd + ForLbd0]; // 以前の値を復元.
bd -= BInfSiz;
-これはfor文のコードブロックを閉じるときの処理です。
-ちょっと長くなっていますが、これはOpLopが使える場合には...
-OpLopを使わない、一般の場合の処理を見れば、「 _tmpLabel1...
-そして最後に「 _tmpLabel2: 」しています。
} else if (phrCmp(16, "continue;", pc) && lbd > 0) {
putIc(OpGoto, &var[binf[lbd + ForCont]], &var[binf[l...
} else if (phrCmp(17, "break;", pc) && lbd > 0) {
putIc(OpGoto, &var[binf[lbd + ForBrk ]], &var[binf[l...
-これはcontinue文とbreak分です。どちらもOpGotoで無条件分...
} else if (phrCmp(18, "if ( !!**0 ) continue;", pc) && ...
ifgoto(0, IfTrue, binf[lbd + ForCont]);
} else if (phrCmp(19, "if ( !!**0 ) break;", pc) && lbd...
ifgoto(0, IfTrue, binf[lbd + ForBrk ]);
-これは条件付きのcontinueとbreak;です。ifgotoで処理してい...
** (5) OpGoto最適化について
-無条件分岐、もしくは条件分岐で、飛び先がいきなり無条件分...
-たとえばこれです。
i = 0;
for (;;) {
i = i + 1;
if (i > 100) break;
if (i % 7 == 0) {
print i;
}
}
-これはそのままでは以下のような感じに読み替えられて内部コ...
i = 0;
_t0:
i = i + 1;
if (i > 100) goto _t2;
if (i % 7 == 0) goto _t1;
print i;
_t1:
goto _t0;
_t2:
-ここで、goto _t1;の部分が気になります。なぜなら、goto _t...
-そういう最適化をやろうというのが、ここでの目標です。
-[1] putIc(OpGoto, A, 0, 0, 0); を putIc(OpGoto, A, A, 0,...
-[2] compile()の最後の「goto先の設定」を以下のように改造...
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) { // 飛び先...
+ icp = *icp[2] + ic;
+ }
! icq[1] = (IntP) icp;
}
}
-これはつまり、goto先がOpGotoだったら、その飛び先を取得す...
-その先がOpGotoならさらにそれも取得しますし、さらに先も見...
-OpGotoのicp[2]は本来は不要なのですが、icp[1]の部分は途中...
** (6) ifgoto()の仕組みについて
-これは短くて簡単な関数ではありますが、説明があったほうが...
void ifgoto(int i, int not, int label)
{
int j = wpc[i];
if (j + 3 == wpc1[i] && TcEEq <= tc[j + 1] && tc[j +...
putIc(((tc[j + 1] - TcEEq) ^ not) + OpJeq, &var[...
} else {
i = expr(i);
putIc(OpJne - not, &var[label], &var[i], &var[Tc...
tmpFree(i);
}
}
-まずnot=0、つまりIfTrueを指定した場合だけを考えます。
-すると、条件式の長さが3で、かつ真ん中が比較演算子の場合...
-そしてそれ以外の場合は、式をexpr(i);で評価した後で、その...
-「式の値がゼロでなければ分岐せよ」なので、これでいいわけ...
-では今度はnot=1、つまりIfFalseを指定した場合だけを考えま...
-条件式の長さが3で、かつ真ん中が比較演算子の場合、
|真ん中の比較演算子(=tc[j+1])|tc[j+1]-TcEEq(→A値)|A値^1(→...
|TcEEq(==)|0|1|OpJne(!=)|
|TcNEq(!=)|1|0|OpJeq(==)|
|TcLt (< )|2|3|OpJge(>=)|
|TcGe (>=)|3|2|OpJlt(< )|
|TcLe (<=)|4|5|OpJgt(> )|
|TcGt (> )|5|4|OpJle(<=)|
-とまあこんな風に計算されるおかげで、ちゃんと期待通り条件...
-それ以外の条件式の時は、OpJne-notがOpJeqになるので、式の...
** 次回に続く
-次回: [[a21_txt01_8a]]
--次回は配列のサポートがメインです。
*こめんと欄
#comment
終了行:
* 川合のプログラミング言語自作のためのテキスト第三版#8
-(by [[K]], 2021.03.13)
** (1) HL-8
-今回は、ブロックifとfor文を追加します。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
typedef unsigned char *String; // こう書くと String は u...
int loadText(String path, String t, int siz) → HL-4と同...
////////////////////////////////////////////////////////...
#define MAX_TC 1000 // トークンコードの最大値.
String ts[MAX_TC + 1]; // トークンの内容(文字列)を記憶.
int tl[MAX_TC + 1]; // トークンの長さ.
unsigned char tcBuf[(MAX_TC + 1) * 10]; // トークン1つ当...
int tcs = 0, tcb = 0;
int var[MAX_TC + 1]; // 変数.
int getTc(String s, int len) → HL-4と同じなので省略
////////////////////////////////////////////////////////...
int isAlphabetOrNumber(unsigned char c) → HL-2と同じなの...
int lexer(String s, int tc[]) → HL-2と同じなので省略
int tc[10000]; // トークンコード.
enum { TcSemi = 0, TcDot, TcWiCard, Tc0, Tc1, Tc2, Tc3, ...
TcEEq, TcNEq, TcLt, TcGe, TcLe, TcGt, TcPlus, TcMinu...
TcComma, TcExpr, TcExpr0, TcTmp0, TcTmp1, TcTmp2, Tc...
char tcInit[] = "; . !!* 0 1 2 3 4 5 6 7 8 ( ) [ ] { } =...
////////////////////////////////////////////////////////...
int phrCmp_tc[32 * 100], ppc1, wpc[9], wpc1[9]; // ppc1:...
int phrCmp(int pid, String phr, int pc) → HL-7と同じなの...
////////////////////////////////////////////////////////...
typedef int *IntP; // こう書くと IntP は int * の代わり...
enum { OpCpy = 0, OpCeq, OpCne, OpClt, OpCge, OpCle, OpC...
OpAdd1, OpNeg, OpGoto, OpJeq, OpJne, OpJlt, OpJge, O...
IntP ic[10000], *icq; // ic[]:内部コード、icq:ic[]への書...
void putIc(int op, IntP p0, IntP p1, IntP p2, IntP p3) →...
////////////////////////////////////////////////////////...
char tmp_flag[10]; // 一時変数の利用状況を管理.
int tmpAlloc() → HL-7と同じなので省略
void tmpFree(int i) → HL-7と同じなので省略
////////////////////////////////////////////////////////...
int epc, epc1; // exprのためのpcとpc1.
int exprSub(int priority); // exprSub1()が参照するので、...
int expr(int j);
int exprSub1(int i, int priority, int op) → HL-7と同じな...
int exprSub(int priority) → HL-7と同じなので省略
int expr(int j) → HL-7と同じなので省略
////////////////////////////////////////////////////////...
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 +...
putIc(((tc[j + 1] - TcEEq) ^ not) + OpJeq, &var[...
} else {
i = expr(i);
putIc(OpJne - not, &var[label], &var[i], &var[Tc...
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...
enum { BlkIf = 1, BlkFor };
enum { IfLabel0 = 1, IfLabel1 };
enum { ForLopBgn = 1, ForCont, ForBrk, ForLbd0, ForWpc01...
////////////////////////////////////////////////////////...
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] = ...
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[...
} else if (phrCmp(10, "!!*0 = !!*1 + 1; if (!!*2...
putIc(OpLop, &var[tc[wpc[4]]], &var[tc[wpc[0...
} else if (phrCmp( 9, "!!*0 = !!*1 + 1;", pc) &&...
putIc(OpAdd1, &var[tc[wpc[0]]], 0, 0, 0);
} else if (phrCmp( 2, "!!*0 = !!*1 + !!*2;", pc)...
putIc(OpAdd, &var[tc[wpc[0]]], &var[tc[wpc[...
} else if (phrCmp( 3, "!!*0 = !!*1 - !!*2;", pc)...
putIc(OpSub, &var[tc[wpc[0]]], &var[tc[wpc[...
} else if (phrCmp( 4, "print !!**0;", pc)) { // ...
e0 = expr(0);
putIc(OpPrint, &var[e0], 0, 0, 0);
} else if (phrCmp( 0, "!!*0:", pc)) { // ラベル...
var[tc[wpc[0]]] = icq - ic; // ラベルに対応...
} else if (phrCmp( 5, "goto !!*0;", pc)) { // go...
! putIc(OpGoto, &var[tc[wpc[0]]], &var[tc[wpc[...
! } else if (phrCmp( 6, "if (!!**0) goto !!*1;", p...
! 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)) { /...
+ bd += BInfSiz;
+ binf[bd] = BlkIf;
+ binf[bd + IfLabel0] = tmpLabelAlloc(); // 条...
+ binf[bd + IfLabel1] = 0;
+ ifgoto(0, 1, binf[bd + IfLabel0]); // 条件を...
+ } else if (phrCmp(12, "} else {", pc) && binf[bd...
+ binf[bd + IfLabel1] = tmpLabelAlloc(); // el...
+ putIc(OpGoto, &var[binf[bd + IfLabel1]], &va...
+ var[binf[bd + IfLabel0]] = icq - ic; // ラベ...
+ } else if (phrCmp( 13, "}", pc) && binf[bd] == B...
+ if (binf[bd + IfLabel1] == 0) {
+ var[binf[bd + IfLabel0]] = icq - ic; // ...
+ } else {
+ var[binf[bd + IfLabel1]] = icq - ic; // ...
+ }
+ bd -= BInfSiz;
+ } else if (phrCmp(14, "for (!!***0; !!***1; !!**...
+ bd += BInfSiz;
+ binf[bd] = BlkFor; // ブロックのタイプ.
+ binf[bd + ForLopBgn] = tmpLabelAlloc(); // ...
+ binf[bd + ForCont ] = tmpLabelAlloc(); // c...
+ binf[bd + ForBrk ] = tmpLabelAlloc(); // b...
+ 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]); /...
+ }
+ var[binf[bd + ForLopBgn]] = icq - ic; // ラ...
+ } else if (phrCmp(15, "}", pc) && binf[bd] == Bl...
+ var[binf[bd + ForCont]] = icq - ic; // ラベ...
+ i = binf[bd + ForWpc01];
+ j = binf[bd + ForWpc02];
+ if (i + 3 == binf[bd + ForWpc11] && j + 2 ==...
+ // !!***1が「i < ?」かつ、!!***2が「i++...
+ putIc(OpLop, &var[binf[bd + ForLopBgn]],...
+ } 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, IfTure, binf[bd + ForLopBg...
+ } else {
+ putIc(OpGoto, &var[binf[bd + ForLopB...
+ }
+ }
+ var[binf[bd + ForBrk]] = icq - ic; // ラベル...
+ lbd = binf[bd + ForLbd0]; // 以前の値を復元.
+ bd -= BInfSiz;
+ } else if (phrCmp(16, "continue;", pc) && lbd > ...
+ putIc(OpGoto, &var[binf[lbd + ForCont]], &va...
+ } else if (phrCmp(17, "break;", pc) && lbd > 0) {
+ putIc(OpGoto, &var[binf[lbd + ForBrk ]], &va...
+ } else if (phrCmp(18, "if ( !!**0 ) continue;", ...
+ ifgoto(0, IfTrue, binf[lbd + ForCont]);
+ } else if (phrCmp(19, "if ( !!**0 ) break;", pc)...
+ ifgoto(0, IfTrue, binf[lbd + ForBrk ]);
} 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=%...
+ 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) { // 飛び先...
+ icp = *icp[2] + ic;
+ }
! icq[1] = (IntP) icp;
}
}
return icq1 - ic;
err:
printf("syntax error : %s %s %s %s\n", ts[tc[pc]], t...
return -1;
}
void exec()
{
(中略)
+ case OpJge: if (*icp[2] >= *icp[3]) { icp = (In...
+ case OpJle: if (*icp[2] <= *icp[3]) { icp = (In...
+ case OpJgt: if (*icp[2] > *icp[3]) { icp = (In...
(中略)
}
int run(String s) → HL-6と同じなので省略
////////////////////////////////////////////////////////...
int main(int argc, const char **argv) → HL-5と同じなので...
-トータルの行数は557行になっています。
-後で説明しますが、ブロックifとfor文を入れただけではなく...
----
-HL-8では普通にブロックifが使えます。なお、中の文が1文だ...
if (a < 10) {
a = 10;
}
-elseも使えます。でもやっぱり { } は省略できません。
if (a < 20) {
c = c + 1;
} else {
d = d + 1;
}
-面倒になってきたので例は出しませんが、if文の中にif文を入...
-今まで if ~ goto しかなかったので、ラベルを連発しなけれ...
-for文も使えます。しかしこれも { } は省略できません。
for (i = 0; i < 10; i++) {
print i;
}
** (2) HL-8の簡単な説明
-今回からは、HL-8で新規に追加されたもの、変更を加えた部分...
-関数:
--void ifgoto(int i, int not, int label)
---条件式wpc[i]を評価して、その結果に応じてlabel(トーク...
---notはフラグで、IfTrueの場合は、条件が成立した場合に分...
--int tmpLabelAlloc()
---一時ラベル(一時変数のラベル版)を発行してトークンコー...
---一時ラベルは使い終わった後に再利用するということはない...
-変数:
--int tmpLabelNo
---一時ラベルのラベル名を重複なく生成するための通し番号で...
--int binf[], bd, lbd;
---binf[]はblock-info.で、つまりコードブロックの情報です...
---bdやlbdは1ずつ増減するのではなく、BInfSizずつ増減しま...
---binf[bd]は今のコードブロックが何のコードブロックなのか...
---binf[bd - BInfSiz]は今のコードブロックの1つ外側、binf[...
---より詳しい情報は、binf[bd + 1~]に入っています。
---こういう変数がないと、ソースコード中に「 } 」があって...
** (3) ブロックif文について
-ブロックif文のためにcompile()に追加された部分を中心に説...
-まず HL-8 では、ブロックif文を次のように変換することで、...
-[1] if (条件式) { コードブロック#1 } の場合:
if (!条件式) goto _tmpLabel0;
コードブロック#1
_tmpLabel0:
-[2] if (条件式) { コードブロック#1 } else { コードブロッ...
if (!条件式) goto _tmpLabel0;
コードブロック#1
goto _tmpLabel1;
_tmpLabel0:
コードブロック#2;
_tmpLabel1:
-この基本方針がわかれば、あとはそれほど難しくはありません。
-compile()の中を見ていきます。
} else if (phrCmp(11, "if ( !!**0 ) {", pc)) { // ブロ...
bd += BInfSiz;
binf[bd] = BlkIf;
binf[bd + IfLabel0] = tmpLabelAlloc(); // 条件不成立...
binf[bd + IfLabel1] = 0;
ifgoto(0, 1, binf[bd + IfLabel0]); // 条件を満たさな...
-ブロックif文が現れたら、新しいコードブロックが始まるので...
-そして_tmpLabel0を準備します。
-最後に「if (!条件式) goto _tmpLabel0;」に相当する内部コ...
} else if (phrCmp(12, "} else {", pc) && binf[bd] == Blk...
binf[bd + IfLabel1] = tmpLabelAlloc(); // else節の終...
putIc(OpGoto, &var[binf[bd + IfLabel1]], &var[binf[b...
var[binf[bd + IfLabel0]] = icq - ic; // ラベルに対応...
-「 } else { 」が来たら、これは上記の[2]の場合に相当しま...
-_tmpLabel1も必要になるのでそれを準備したのち、goto _tmpL...
--ここで、OpGotoの仕様が変わって、飛び先を二度指定するよ...
-そして、_tmpLabel0のラベルはここだよと宣言します。
-これで「 } else { 」の処理はおしまいです。
} else if (phrCmp( 13, "}", pc) && binf[bd] == BlkIf) {
if (binf[bd + IfLabel1] == 0) {
var[binf[bd + IfLabel0]] = icq - ic; // ラベルに...
} else {
var[binf[bd + IfLabel1]] = icq - ic; // ラベルに...
}
bd -= BInfSiz;
-ブロックif文のコードブロックを閉じたときの処理です。
-これは[1]の場合と[2]の場合とで異なります。
-[1]の場合は、「_tmpLabel0:」の処理をやります。
-[2]の場合は、「_tmpLabel1:」の処理をやります。
-最後にbdをBInfSizだけ減じて、コードブロックを終了します。
** (4) for文について
-上記のブロックif文と似たような方法で、for文も実現してい...
-for文の変換は次のようにしています。
-for(式0; 条件式; 式2) { コードブロック }
式0;
if (!条件式) goto _tmpLabel2; // 最初から条件が成立...
_tmpLabel0:
コードブロック;
_tmpLabel1: // continue命令が来たらここに行かせる.
式2;
if (条件式) goto _tmpLabel0;
_tmpLabel2:
-この基本方針がわかれば、あとはそれほど難しくはありません。
-compile()の中を見ていきます。
} else if (phrCmp(14, "for (!!***0; !!***1; !!***2) {", ...
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]); // 最初か...
}
var[binf[bd + ForLopBgn]] = icq - ic; // ラベルに対...
-for文では、あとで(=コードブロックを閉じるときに)条件...
-「e0 = expr(0);」で 式0 の部分を内部コードとして出力させ...
-そして条件式に何か書いてあれば、条件不成立時にはループに...
-最後に _tmpLabel0: に相当する処理をしています。
} else if (phrCmp(15, "}", pc) && binf[bd] == BlkFor) {
var[binf[bd + ForCont]] = icq - ic; // ラベルに対応...
i = binf[bd + ForWpc01];
j = binf[bd + ForWpc02];
if (i + 3 == binf[bd + ForWpc11] && j + 2 == binf[bd...
// !!***1が「i < ?」かつ、!!***2が「i++」だった...
putIc(OpLop, &var[binf[bd + ForLopBgn]], &var[tc...
} 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]], &v...
}
}
var[binf[bd + ForBrk]] = icq - ic; // ラベルに対応す...
lbd = binf[bd + ForLbd0]; // 以前の値を復元.
bd -= BInfSiz;
-これはfor文のコードブロックを閉じるときの処理です。
-ちょっと長くなっていますが、これはOpLopが使える場合には...
-OpLopを使わない、一般の場合の処理を見れば、「 _tmpLabel1...
-そして最後に「 _tmpLabel2: 」しています。
} else if (phrCmp(16, "continue;", pc) && lbd > 0) {
putIc(OpGoto, &var[binf[lbd + ForCont]], &var[binf[l...
} else if (phrCmp(17, "break;", pc) && lbd > 0) {
putIc(OpGoto, &var[binf[lbd + ForBrk ]], &var[binf[l...
-これはcontinue文とbreak分です。どちらもOpGotoで無条件分...
} else if (phrCmp(18, "if ( !!**0 ) continue;", pc) && ...
ifgoto(0, IfTrue, binf[lbd + ForCont]);
} else if (phrCmp(19, "if ( !!**0 ) break;", pc) && lbd...
ifgoto(0, IfTrue, binf[lbd + ForBrk ]);
-これは条件付きのcontinueとbreak;です。ifgotoで処理してい...
** (5) OpGoto最適化について
-無条件分岐、もしくは条件分岐で、飛び先がいきなり無条件分...
-たとえばこれです。
i = 0;
for (;;) {
i = i + 1;
if (i > 100) break;
if (i % 7 == 0) {
print i;
}
}
-これはそのままでは以下のような感じに読み替えられて内部コ...
i = 0;
_t0:
i = i + 1;
if (i > 100) goto _t2;
if (i % 7 == 0) goto _t1;
print i;
_t1:
goto _t0;
_t2:
-ここで、goto _t1;の部分が気になります。なぜなら、goto _t...
-そういう最適化をやろうというのが、ここでの目標です。
-[1] putIc(OpGoto, A, 0, 0, 0); を putIc(OpGoto, A, A, 0,...
-[2] compile()の最後の「goto先の設定」を以下のように改造...
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) { // 飛び先...
+ icp = *icp[2] + ic;
+ }
! icq[1] = (IntP) icp;
}
}
-これはつまり、goto先がOpGotoだったら、その飛び先を取得す...
-その先がOpGotoならさらにそれも取得しますし、さらに先も見...
-OpGotoのicp[2]は本来は不要なのですが、icp[1]の部分は途中...
** (6) ifgoto()の仕組みについて
-これは短くて簡単な関数ではありますが、説明があったほうが...
void ifgoto(int i, int not, int label)
{
int j = wpc[i];
if (j + 3 == wpc1[i] && TcEEq <= tc[j + 1] && tc[j +...
putIc(((tc[j + 1] - TcEEq) ^ not) + OpJeq, &var[...
} else {
i = expr(i);
putIc(OpJne - not, &var[label], &var[i], &var[Tc...
tmpFree(i);
}
}
-まずnot=0、つまりIfTrueを指定した場合だけを考えます。
-すると、条件式の長さが3で、かつ真ん中が比較演算子の場合...
-そしてそれ以外の場合は、式をexpr(i);で評価した後で、その...
-「式の値がゼロでなければ分岐せよ」なので、これでいいわけ...
-では今度はnot=1、つまりIfFalseを指定した場合だけを考えま...
-条件式の長さが3で、かつ真ん中が比較演算子の場合、
|真ん中の比較演算子(=tc[j+1])|tc[j+1]-TcEEq(→A値)|A値^1(→...
|TcEEq(==)|0|1|OpJne(!=)|
|TcNEq(!=)|1|0|OpJeq(==)|
|TcLt (< )|2|3|OpJge(>=)|
|TcGe (>=)|3|2|OpJlt(< )|
|TcLe (<=)|4|5|OpJgt(> )|
|TcGt (> )|5|4|OpJle(<=)|
-とまあこんな風に計算されるおかげで、ちゃんと期待通り条件...
-それ以外の条件式の時は、OpJne-notがOpJeqになるので、式の...
** 次回に続く
-次回: [[a21_txt01_8a]]
--次回は配列のサポートがメインです。
*こめんと欄
#comment
ページ名: