* 「10日くらいでできる!プログラミング言語自作入門」の続編#2-1 (HL-30)
-(by [[K]], 2022.06.17)

** (1) はじめに
-このテキストは、「10日くらいでできる!プログラミング言語自作入門」([[a21_txt01]])の続編にあたります。ですからこの続編テキストのスタート地点は772行の[[HL-9a>a21_txt01_9a]]になります。
-このシリーズでは、言語の実行速度の改善はほとんどしないで、主に言語に新規の命令を追加していきます。
-[[a21_txt02]]のほうの続編で、「はりぼて言語」はJITコンパイラになり見違えるほど速くなったのですが、ここではそこから先を作るのではなく一度HL-9aに戻って、そこからの改造を試みます。・・・なぜそうするのかですが、x86用とx64用に分かれたまま話を続けるのは大変ですし、ARMなどの対応もできていないままなので、ここは一度HL-9aに戻ったほうが有用かなと思ったのです。

-そして、これはごめんなさい案件なのですが、最近ちょっと忙しくて丁寧に書けないので、説明はかなり割愛して書きます。でもここまでをやってきた人なら、何をやっているのかはきっとわかると思います。

** (2) 今回の改造テーマ
-HL-9aでは 10 / 3 の答えは 3 でした。
 >print 10/3
 3
-まあC言語でも整数の割り算では答えは整数になるのが正しいので、これはどこもおかしくはないのですが、しかしやっぱり、 3.3333 みたいな計算もできたらなあなんて思います。C言語でも 10.0 / 3.0 なら答えは 3.3333 になるのです。
-ということで、今回は小数を扱うための準備をして、次の回で計算をできるようにしたいと思います。

** (3-1) lexerの改造(小数の定数を途中で切らないようにする)
-before:
         } else if (isAlphabetOrNumber(s[i])) {  // 1文字目が英数字.
             while (isAlphabetOrNumber(s[i + len]))
                 len++;
         } else if (strchr("=+-*/!%&~|<>?:.#", s[i]) != 0) {  // 1文字目が普通の記号.
-after:
         } else if ('0' <= s[i] && s[i] <= '9') {  // 1文字目が数字.
             while (isAlphabetOrNumber(s[i + len]) || s[i + len] == '.')
                 len++;
         } else if (isAlphabetOrNumber(s[i])) {  // 1文字目が英字.
             while (isAlphabetOrNumber(s[i + len]))
                 len++;
         } else if (strchr("=+-*/!%&~|<>?:.#", s[i]) != 0) {  // 1文字目が普通の記号.
** (3-2) 変数の型を増やす
-before:
 AInt var[MAX_TC + 1];	// 変数.
-after:
 enum { TypInt, TypDbl };
 AInt varTyp[MAX_TC + 1]; // そのトークンは、int型か、double型か?
 AInt var[MAX_TC + 1];	// int変数.
 double varDbl[MAX_TC + 1]; // double変数.

** (3-3) 定数値のセット処理の拡張
-before:
         var[i] = strtol(ts[i], 0, 0);	// 定数だった場合に初期値を設定(定数ではないときは0になる).
         if (ts[i][0] == 34) { // 先頭がダブルクォーテーション
             char *p = malloc(len - 1);
             var[i] = (AInt) p;
             memcpy(p, ts[i] + 1, len - 2); // 手抜き実装.
             p[len - 2] = 0;
         }
-after:
         var[i] = strtol(ts[i], 0, 0);	// 定数だった場合に初期値を設定(定数ではないときは0になる).
         varTyp[i] = TypInt;
         if (ts[i][0] == 34) { // 先頭がダブルクォーテーション
             char *p = malloc(len - 1);
             var[i] = (AInt) p;
             memcpy(p, ts[i] + 1, len - 2); // 手抜き実装.
             p[len - 2] = 0;
         } else if (strchr(ts[i], '.') != 0 && '0' <= ts[i][0] && ts[i][0] <= '9') { // 小数点を含んでいて、先頭が数字.
             varTyp[i] = TypDbl;
             varDbl[i] = strtod(ts[i], 0);
         }

** (3-4) OpPrintd と DblP の宣言の追加
-before:
 typedef AInt *IntP; // こう書くと IntP は AInt * の代わりに使えるようになる.
 
 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, OpOpnWin, OpSetPix0, OpM64s, OpRgb8, OpWait,
     OpXorShift, OpGetPix, OpFilRct0, OpPrm, OpF16Sin, OpF16Cos, OpInkey, OpDrwStr0, OpGprDec, OpBitBlt };
-after:
 typedef AInt *IntP; // こう書くと IntP は AInt * の代わりに使えるようになる.
 typedef double *DblP; // DblP は double * の代わりになる.
 
 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, OpOpnWin, OpSetPix0, OpM64s, OpRgb8, OpWait,
     OpXorShift, OpGetPix, OpFilRct0, OpPrm, OpF16Sin, OpF16Cos, OpInkey, OpDrwStr0, OpGprDec, OpBitBlt,
     OpPrintd };

** (3-5) icpd の宣言と初期化
-before:
     for (;;) {
         switch ((int) icp[0]) {
-after:
     for (;;) {
         DblP *icpd = (DblP *) icp;
         switch ((int) icp[0]) {

** (3-6) OpPrintd 命令の追加
-OpBitBltの処理の後に以下を追加:
         case OpPrintd:
             printf("%f\n", *icpd[1]);
             icp += 5;
             continue;

** (3-7) printfd 命令を追加
- } else if (phrCmp( 8, "!!***0;", pc)) { の前に以下の1行を追加:
         } else if (phrCmpPutIc(35, "printd !!**0;", pc, 0, 1, OpPrintd, &e0)) { 

** (3-8) varP() 関数の追加
- int exprSub1(int i, int priority, int op) の直前に以下の記述を追加:
 IntP varP(AInt i) // トークンコード番号から対応する変数のポインタを求める.
 IntP varP(int i) // トークンコード番号から対応する変数のポインタを求める.
 {
     if (i < 0) return 0; // NULL
     if (varTyp[i] == TypInt) return &var[i];
     if (varTyp[i] == TypDbl) return (IntP) &varDbl[i];
     return 0;
 }

** (3-9) phrCmpPutIc() 関数を書き換え
- &var[ ... ] という記述を varP( ... ) に置換します.
-before:
 int phrCmpPutIc(int pid, String phr, int pc, int *pi, int lenExpr, int op, int *err)
 {
     int e[9], i, i0 = 0;
     if (phrCmp(pid, phr, pc)) {
         e[0] = e[1] = e[2] = e[3] = e[4] = e[5] = e[6] = e[7] = e[8] = 0;
         if (pi != 0) {
             e[0] = *pi = tmpAlloc();
             i0 = 1;
         }
         for (i = i0; i < lenExpr; i++) {
             e[i] = expr(i);
         }
         putIc(op, &var[e[0]], &var[e[1]], &var[e[2]], &var[e[3]]);
         if (lenExpr >= 5) {
             putIc(OpPrm, &var[e[4]], &var[e[5]], &var[e[6]], &var[e[7]]);
         }
         for (i = i0; i < lenExpr; i++) {
             if (e[i] < 0) {
                 *err = -1;
             }
             tmpFree(e[i]);
         }
         return 1;
     }
     return 0;
 }
-after:
 int phrCmpPutIc(int pid, String phr, int pc, int *pi, int lenExpr, int op, int *err)
 {
     int e[9], i, i0 = 0;
     if (phrCmp(pid, phr, pc)) {
         e[0] = e[1] = e[2] = e[3] = e[4] = e[5] = e[6] = e[7] = e[8] = 0;
         if (pi != 0) {
             e[0] = *pi = tmpAlloc();
             i0 = 1;
         }
         for (i = i0; i < lenExpr; i++) {
             e[i] = expr(i);
         }
         putIc(op, varP(e[0]), varP(e[1]), varP(e[2]), varP(e[3]));
         if (lenExpr >= 5) {
             putIc(OpPrm, varP(e[4]), varP(e[5]), varP(e[6]), varP(e[7]));
         }
         for (i = i0; i < lenExpr; i++) {
             if (e[i] < 0) {
                 *err = -1;
             }
             tmpFree(e[i]);
         }
         return 1;
     }
     return 0;
 }


** (4) printd 命令のテスト
 >printd 12.34
 12.340000

** 次回に続く
次回: [[a22_txt03_1a]]

*こめんと欄
#comment

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS