a23_useSelfMade #6
2023.02.21 Tue #1
- 今日はちょっと忙しいので、ここに書けるほどの成果はなさそうです。
- 昨日からずっと考えているのは、HL-9の改造で、(1)変数一覧とか出したいなあ、(2)型の一覧も出したいなあ、(3)メモリ上にあってまだ開放していないオブジェクトの一覧も出したいなあ、の3点です。・・・まあまずは(1)からかなあ。これは簡単なので。
2023.02.22 Wed #1
- 最近は、easy-Cの有用性は理解されている気がするんだけど、このプロジェクトの主張であるところの「自分で作って自分で使う」はあまり理解されていない気がします・・・。
2023.02.22 Wed #2
- 「たしざんかあど」からランダムに10問を出題して計算練習。
n = 0;
for (i = 1; i <= 10; i++) {
for (;;) {
j = aRnd(9) + 1;
k = aRnd(9) + 1;
if (j + k >= 11) break; // 繰り上がりの練習なので、11以上になるもののみ出題.
}
printf("[%02d] %d+%d=", i, j, k);
m = aInput("");
if (m == j + k) { n++; prs "O\n\n"; } else { prs "X\n\n"; }
}
printf("score=%d/100\n", n * 10);
HL9>run tashi.c
[01] 7+9=16
O
[02] 9+5=14
O
[03] 7+6=15
X
[04] 8+9=17
O
[05] 6+9=
- 小学1年生の宿題をこれでやらせたら、大人側の支援がすごく楽になりました!!
- ちなみに繰り下がりのある引き算版も作りました(似たようなものなので書きませんが)。
2023.02.23 Thr #1
- なんかいろいろアイデアが出てきました。
- [1]コンソールを複数出してマルチタスクみたいなことがしたい。
- [2] a[0-99]=0; みたいな書き方ができるようにしたい。
- [3] {i,j,k} = aRnd(9) + 1; みたいな書き方ができるようになりたい。
2023.02.23 Thr #2
- 昨日のtashi.cですが、小学1年生にやらせていると、たまに連続して同じ問題が出ます。小学1年生がそのたびにプログラムを「ばかだなあ」っていうのでちょっとくやしいです。
- だから改造します。・・・できました、これなら同じ問題は出ません。
int a[100];
for (i = 0; i < 100; i++) { a[i] = 0; }
for (j = 1; j <= 9; j++) {
for (k = 1; k <= 9; k++) {
if (j + k >= 11) { a[j * 10 + k] = 1; } // 繰り上がりの練習なので、11以上になるもののみ出題.
}
}
n = 0;
for (i = 1; i <= 10; i++) {
m = aArgMaxRndInt(a, 0, 100);
j = m / 10; k = m % 10;
a[m] = 0;
printf("[%02d] %d+%d=", i, j, k);
m = aInput("");
if (m == j + k) { n++; prs "O\n\n"; } else { prs "X\n\n"; }
}
printf("score=%d/100\n", n * 10);
2023.02.24 Fri #1
- 「キャラクターを右に動かす」「もしもキャラクターの移動先が岩だったら」みたいに、変数は明示しないけど裏ではキャラクターの座標やどこに何を表示しているかの情報を持っておく方式を、ここではひとまず「隠れ変数方式」と呼ぶことにします。明示的な変数じゃないものを変数の代わりにうまく使っている感じで。
- この隠れ変数方式を極めれば、easy-Cの「変数を使わなくてもできること」はかなり増やせそうです。
- この話をしたら、それはScratchがやっていることに近いのではないかと指摘されました。私もそう思います。Scratchって変数を使わなくてもまあまあ遊べる気がするのですが、それはまさに隠れ変数方式を極めているかなと思うのです。
2023.02.26 Sun #1
2023.02.27 Mon #1
2023.02.28 Tue #1
- なんか自前のスタートアップルーチンを使うと、ダウンロード時にマルウェア判定を受けてしまう・・・。もちろん何も悪いことはしてないのに・・・。じゃあ、gccの標準のスタートアップルーチンで我慢するか・・・。
2023.02.28 Tue #2
2023.03.01 Wed #1
- a23_ec001を更新して、最新版をダウンロードできるようにしました。
- ああしまった、あせって invader.c と blocks.c を入れ忘れたー。・・・まあいいかー。
2023.03.02 Thr #1
- かなり雑な実装にしていますが、とにかく簡易ループ演算子が動くようになりました!
HL9>pr 1:<=5
12345
HL9>pr 1:<5
1234
HL9>s=0;s=s+1:<=100;pr s ← sには1~100の和が入る.
5050
HL9>int a[100]
HL9>pr a[9]
0
HL9>a[0:<100]=1 ← これで全部1になる.
HL9>pr a[9]
1
HL9>a[0] = 0; a[1] = 1; a[(i = 0:<10) + 2] = a[i] + a[i + 1]; printf("%d ", a[1:<10])
1 1 2 3 5 8 13 21 34
HL9>
- あとはこれをいろいろと使ってみて、便利かどうかをじっくり考えます。便利だったら徐々に実装をまともにします。
2023.03.03 Fri #1
- 簡易ループ演算子。かなりfor文の書き方に近いロング形式。
HL9>(i = 0:<=10) { pris i; }
0 1 2 3 4 5 6 7 8 9 10
HL9>int a[100] = { 0, 1 }; (i = 0:<18) { a[i + 2] = a[i] + a[i + 1]; } pris a[0:<20]
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
// 長さ比較.
HL9>(i = 0:<=10) { pris i; } // 簡易ループ演算子の前後にはスペースを入れない(いれても実行できるけど読みにくくなる).
HL9>for (i = 0; i <= 10; i++) { pris i; }
// 13文字節約できている.
- 標準的なC言語のスタイルだと、for文は繰り返し範囲を次の行に段下げして書くけれど、たとえば数学で、k^2のシグマとかを書くときに、シグマとk^2の間に改行を入れたりはしないです。どうしてC言語では改行するほうが自然に見えるのかというと、たぶんforの行が長すぎるんです。その点、簡易ループ演算子のロング形式は、必要最小限の内容になっていて数学のシグマに近い感じなので、改行しないで書いていいと思います。
2023.03.04 Sat #1
- gcc実行モードでも簡易ループ演算子を実装しようとして、うーん、根本的にいろいろ直したくなってきました・・・。
2023.03.06 Mon #1
- 簡易ループ演算子の目的は、プログラムを短くすることです。機能的にはfor文なので、できることが新しく増えるということはありません。
- 今考えている仮説としては、プログラム内での繰り返し処理はかなりの頻度で出てきていて、だからそれを短く書けるようにすると見通しがよくなるのではないかと考えています。
2023.03.07 Tue #1
- 今やりたいと思っている開発。
- [1]KeyValueStore
- [2]簡易ループ演算子をgccからも使えるようにする
- [3]対戦ゲームを作る
- [4]Cコンパイラをうまく使った、CPUに依存しないアセンブラ
- [5]実行中の変数を見えるようにする大掛かりな改造
- この中で[4]と[5]は手を出したら数週間(もしくは数か月)帰ってこられない気がするので今やるべきじゃないよなあ。
- やっぱりまずは[2]を仕上げて、その次に[3]かなあ。
2023.03.08 Wed #1
- easy-Cのプログラムを普通のC言語に変換する、ACA_EasyC_lv2()という内部の関数を書き換え中です。簡易ループ演算子を簡単に実現するために、基本のアルゴリズムを変更してリファクタリングしています。そこそこ書けてきたのですが、さてこれはちゃんと実行できるのかなあ・・・。
2023.03.08 Wed #2
- とりあえず、簡易ループ演算子の(構文2)と(構文3)はgcc実行モードでも動くようになりました!
- 内部を作り直したので、 pr (1+2)*3; もできるようになりました(今までは pr((1+2)*3);と書く必要がありました)。
2023.03.09 Thr #1
- 普通に「a[0:<10]=aRnd(10);」と書けば、なんか適当な10個の乱数が入ります。
- でもそうではなくて、乱数は一度だけ振って、その値をa[0:<10]に入れたいことだってあるかもしれません。そういうときは、「c=aRnd(10);a[0:<10]=c;」と書く必要があります。
- もしくは、while (x < a) { ... } みたいなループがあったときに、xはループとともに値が変わっていって、それでいつかループを脱出するわけですが、もしかしたら変数aもループ内で値が変更されるかもしれません。そういう時に、普通はループの都度、変更されたxと変更されたaで比較をするわけですが、もしかしたらループ開始時のaを使ってループ回数が決まってほしいと思うかもしれれません。
- こういうときも c = a; while (x < c) { ... } とする必要があります。
- この c って面倒じゃないかなと思ったのです。なんかこう、 a[0:<10]=aLoopConst(aRnd(10));って書けたら便利じゃないかなーと。
- 結局何が嫌なのかというと、変数が増えるのが嫌なんです。変数を増やさずに書けるのならそのほうがいいかもなあ、と思ったのです。
2023.03.11 Sat #1
- 簡易ループ演算子の(構文1)もgccモードで動くようになりました!
2023.03.12 Sun #1
- 思いついたことがあって試してみたくなったので実験します。
- gccでは、構造体を引数に取ったり、変数の返値として指定することができます。
- それは前から知っていたのですが、じゃあ仮に8KBの構造体を作ったら、それはどのように受け渡されるのでしょうか。
AClass(AGpc16) { // 汎用(GP)クラス(C). 16はサイズ. この構造体は64Kbitで、2^16=64Kだから.
union {
char c[8192];
double d[1024];
AInt i[16];
};
};
AGpc16 func(AGpc16 x)
{
AGpc16 y;
y.i[10] = x.i[0] + x.i[1];
x.i[1] = 9;
return y;
}
- funcが呼ばれるとき、スタック上の引数は 第一引数がreturn-valueへのポインタになっています。第二引数として8KBのxがあります。・・・なるほど、xへのポインタではなく、x全体のコピーをスタック上に作っているわけかー。
- うん、C言語の仕様に照らせばxの渡し方は正しい気がします。
- 私がこれに興味を持ったのは、可変長の構造体を返すことができたら管理が楽かもしれないと思ったからでした。
- たとえば、2つの文字列を連結して、その文字列を返すという関数を考えます。strcat()が既にあるわけですが、これは結果をどこにしまうのかをプログラマが気を付けなければいけません。でも、AGpc16を使うことにすればこんなことができます。
AGpc16 myStrcat(char *s, char *t)
{
AGpc16 r;
sprintf(r.c, "%s%s", (const char *) s, (const char *) t);
return r;
}
void aMain(AComArg *aCA)
{
puts(myStrcat(myStrcat("abc", "123").c, myStrcat("def", "456").c).c);
}
- これで abc123def456 が出ます・・・のはずだったのですが、gccではエラーになってしまって、これが通りませんでした。・・・うーん、残念。
void aMain(AComArg *aCA)
{
AGpc16 a = myStrcat("abc", "123"), b = myStrcat("def", "456");
AGpc16 c = myStrcat(a.c, b.c);
puts(c.c);
}
2023.03.13 Mon #1
- バイナリデータを簡単に出力したり入力したりできたら便利になるかなあ。デバッグ時には便利かもしれないなあ。
こめんと欄