日記(988)

<前 次>

サンプルのコンパイル結果

そういうことで中間コードを書いてみました。
とりあえず今のアルゴリズムとしては、計算式を見つけたら何はともあれ計算結果を一時変数に入れる、配列に対しては要素に直接値を代入するか要素を変数に代入するだけしかしない(変数名、インデックス、値で3つになるため)、命令を呼び出すときはパラメータをリストで渡して結果を一時変数で受ける、などなど、変換規則も考えつつ書いてみました。

# 例えば、イベントとか
msg("ハローワールド!\nこんにちは世界である!!");
&eee(select("それがどうした", "なるほど", "げこげこ"));

sub eee {
talk("みふみん", "あなたは".$_[0]."とおっしゃるのですね。");
if ($_[0] eq "げこげこ") {
for ($i=0; $i<10; $i++) {
$p = $i*($p+1);
msg($_[0].$p);
}
}
}

$param0[0] = "ハローワールド!\nこんにちは世界である!!";
$temp0 = msg @param0;
$param1[0] = "それがどうした";
$param1[1] = "なるほど";
$param1[2] = "げこげこ";
$temp1 = select @param1;
$param2[0] = $temp1;
@_ = @param2;
gosub eee;
$temp2 = $return;
goto LABEL0;
label eee;
$param2[0] = "みふみん";
$temp3 = "あなたは";
$temp4 = $_[0];
$temp5 = $temp3 . $temp4;
$temp6 = $temp5 . "とおっしゃるのですね。";
$param2[1] = $temp6;
$temp7 = talk @param2;
$temp8 = $_[0];
$temp9 = $temp8 eq "げこげこ";
if (!$temp9) goto LABEL1;
$i = 0;
label LABEL3;
$temp10 = $i < 10;
if (!$temp10) goto LABEL2;
$temp11 = $p + 1;
$temp12 = $i * $temp12;
$p = $temp12;
$temp13 = $_[0];
$temp14 = $temp13 . $p;
$param3[0] = $temp14;
$temp15 = msg @param3;
$i++;
goto LABEL3;
label LABEL2;
label LABEL1;
$return = undef;
return;
label LABEL0;

pseudoPerlコンパイラ

昨日の。
やっぱり中間言語レベルまではコンパイルしたほうがいいかな。
などと思ってます。
だって、逐次解釈とはいったって、式の中に命令が入っていたり、特定の命令で実行する場所が色々な場所に飛んだりして、今どこの何を実行中なのかがある程度プログラムからわからないとうまく動かないんですよ。
例えば2つの関数の結果を受け取って一つの価を返す関数。
f(g(x), h(y))
みたいなのね。
BASICのような逐次解釈じゃ難しいの。
最低限gとhの実行結果を持っておく変数が必要なわけ。
ああなんだかわからなくなってきた。
3番地コードで示される中間コードにコンパイルするの。
Add X Y Z
といったら
X = Y + Z;
と解釈するみたいに。
ん~。
ちょっとサンプルプログラムを手動コンパイルして雰囲気をつかんできますわ。

pseudoPerl

Bomber丸Worldのイベントや戦闘時のキャラクターの行動等はPerlに似たスクリプトで作ることにしました。
なぜPerlっぽいのにしたのか。
第一なぜ既存のプログラミング言語と似たようなものを使うことにしたのか。
完全オリジナルじゃいけなかったのか。
まずやりたいことを考えてみます。
1.計算式を使いたい。
2.イベントでも戦闘でも同じ感覚で記述したい。
3.決まりきった処理は関数のようにして呼び出したい。
4.変数や配列を使いたい。
5.変数は明示的に宣言しなくても使えるようにしたい。
6.数値も文字列も深く気にせず使いたい。
7.長い行は複数行に分けて書きたい。
8.変数と関数の区別を容易に付けたい。
9...きりがない。
もちろん、Perlを完全に実装するなんて無茶なことはしません。
例えば、便利そうでも実装が面倒な連想配列は実装しませんし、数値は解析の容易な整数のみです。
変数の省略も原則として認めませんし、標準関数はほぼ全て新しいものに置き換えられて、ローカル変数なども基本的にありません。
また、Perlは実行時にコンパイルして中間コードを生成し、高速化を図りますが、全体的なスピードが要求されず、多くのスクリプトが次々呼び出されるRPGではインタープリタ式のほうが適切だと思うので今回はコンパイラではなくインタープリタとして作ります。
一応言語仕様そのものは汎用性のあるものに作るつもりなので、出来上がったインタープリタは今後公開することがあるかもしれません。

キャラボックス3

キャラボックスほぼできましたよ。
というわけで使っている様子を写してみました。
すごいですね。ラプソーン一番ですよ。
しかし一位ですら高々1.4KB。原稿用紙3枚半。
やろうと思えばまだまだいけそうですね。

1142776588.png

値の重複を許さない整列された配列

System.Collections.Generic.SortedListって遅い!!
なんちゅう遅さだ!!
O(n)で要素を追加できるからx個のデータの中からn個をを追加するならO(xn)ですむはずなのにものすごく遅い!!
他のSortedDictionaryも同様。
私が欲しかったのは要素の追加が(logn)程度で行える、整列された、値の重複を許さない、値のコレクションだったのですが、どうにもなさそうだったので普通の配列で頑張ってみることにしました。

string[] outArray = new string[1];
int count = 0;
bool found;
foreach (string data in inArray)
{
found = false;
foreach (string item in outArray)
{
if (item == data)
{
found = true;
break;
}
}
if (!found)
{
if (count >= outArray.Length) Array.Resize(ref outArray, count * 2);
outArray[count] = data;
count++;
}
}
Array.Resize(ref outArray, count);
Array.Sort(outArray);
これ、O(n2)の処理なんですがもう感動的な早さです。
本当はゲームのキャラデータの一部から抜き出しているのでinArrayの要素をそのまま使っているのではなく、Sorted~にそのままデータを渡すことができないため一つ一つSorted~クラスにデータを渡していたせいで遅くなったものと考えています。
このアルゴリズムでは最初に値の重複を許さない要素の配列を作って後から整列しています。
最後のソートは元々高速なので実質配列の生成に最も時間がかかっています。
ちなみに、配列を延ばすのにも時間がかかるはずですが、配列の長さの初期値を増やしたところで大して高速化しなかったのでとりあえず最小の1にしています。

死してシカバネ残すマジ

キャラボックス作ってました。
.NETのピクチャボックスだとなんとGIFアニメーションが動くようです。
速度が全体的に鈍いけどかなり便利になってますね。

今日はゼルダの伝説から、ガロを描いてみました。
特に理由もなく。
こういう簡単な服装はええですのお。

1142607078.png

マザークリアしました

ついに・・・ついにマザー1をクリアしましたよっ!
しかしザコの強さに比べてラスボスはたいしたことがありませんでしたね。
低レベルクリアとか一人クリアができるというのはこれゆえか?
何年もかけてプレイしたために最初のほうはほとんど覚えてないからまた今度最初からプレイしてみようかな。
後半のいいムードのイベントが台無しにならないような立派な名前をつけて。
「はぢをしれェ」という名前がまともに通るのはギーグに怒鳴られるシーンだけじゃないか。

<前 次>