59
|
1
|
|
2 Thu Nov 25 17:27:12 JST 1999
|
|
3
|
|
4 subroutine call がない
|
|
5 局所変数もない
|
|
6 その代わり、大域変数を多用する
|
|
7 大域変数のスコープは局所的
|
|
8 Fortran の用に局所変数は静的に取る
|
|
9 recursion する時には、自分で保存する
|
|
10 subroutine call時のレジスタのセーブも局所的に行う
|
|
11 それは、ちょっと変じゃない?
|
|
12 やっぱりデフォルトのフレームは持ち歩くか?
|
|
13
|
|
14 recursive call とそうでないのを区別するか?
|
|
15
|
|
16 fp は用意する方が良い
|
|
17
|
|
18 関数定義と同時に、それ専用のfpの構造体を用意する
|
|
19
|
|
20 C をcompileする時には、stackを持ち歩く
|
|
21 fp = (struct func_state *)stack
|
|
22 えっと、どこに代入するの? そういう問題もあるわけね。
|
|
23 じゃあ、fpは特別? それは気に入らないな。static
|
|
24 なfpにすれば良いわけね。
|
|
25
|
|
26 func(void *stack) {
|
|
27 static struct func_state {
|
|
28 static struct func_state *fp;
|
|
29 int local1;
|
|
30 brahbrah...
|
|
31 } func_state; // ここまで hidden
|
|
32 func_state.fp = (stack -= sizeof(struct func_state));
|
|
33 }
|
|
34
|
|
35 func_state をとってくる演算子があった方が良い? そうね。
|
|
36 func.state
|
|
37 ぐらい?
|
|
38
|
|
39 fp->local1 みたいなことだけするなら、C と同じになる。
|
|
40
|
|
41 call する時のarguemnt も、
|
|
42 static な func_state に置く
|
|
43 stack 上の func_state に置く
|
|
44 という二通りの選択肢がある。Cと互換なら、当然、後者。
|
|
45
|
|
46 Recursive なら後者だが、この言語は状態遷移を記述するから、static
|
|
47 なものでも良いはず。
|
|
48
|
|
49 Internal function は? あってもいいんだけど...
|
|
50
|
|
51 Recursive call する時には、 fp をsaveする必要があるね。
|
|
52 (--(struct func_state *)stack) = fp;
|
|
53 call callee(&fp->arg,continuation,stack);
|
|
54 call しても、戻って来ないから... continuation は一般的にはcode
|
|
55 だから... それは Internal function にするか。
|
|
56
|
|
57 continuation に一般的にcompileする方法を考えないといけないか。
|
|
58 self は必要なわけね?
|
|
59
|
|
60 言語の名前も考えないといかんなぁ。
|
|
61
|
|
62 C からのコンパイラも書かないといけないのか...
|
|
63
|
|
64 Mon Dec 13 18:53:04 JST 1999
|
|
65
|
|
66 compiler based で、内部で partial evaluation できる?
|
|
67
|
|
68 func をdatabaseとして扱えないなら、それはできない。
|
|
69
|
|
70 しかし、状態遷移としては取り扱える。
|
|
71
|
|
72 func.state
|
|
73 func.code
|
|
74
|
|
75 みたいな形にしてpartial evaluationすれば良い
|
|
76
|
|
77 でも止まるのか?
|
|
78
|
|
79 textual でない、中間的なコード表現があった方が良い? <-> interpreter?
|
|
80
|
|
81 Prolog ではなんでいけないの? --> Unification が重いから
|
|
82
|
|
83 Sat Nov 27 13:50:41 JST 1999
|
|
84
|
|
85 func.state とか作るのだったら、
|
|
86 struct {
|
|
87 struct {
|
|
88 int i;
|
|
89 } state;
|
|
90 state *code = {
|
|
91 i = i+1;
|
|
92 };
|
|
93 } name;
|
|
94 みたいな形で、それ自体を構造化すれば? で、代入すると部分評価される。
|
|
95 代入も可能。なるほど。
|
|
96 *name.code;
|
|
97 値はあるわけ? 値は &state でしょうね。
|
|
98 self があれば、
|
|
99 struct {
|
|
100 struct {
|
|
101 int i;
|
|
102 } state,
|
|
103 *code = {
|
|
104 self->i = self->i+1;
|
|
105 };
|
|
106 } name;
|
|
107 かな。self = state だよね。
|
|
108
|
|
109 union の拡張もあわせて議論すると...
|
|
110
|
|
111 Partial evalutator をセマンティクスや実行系にいれておくことは可能か?
|
|
112
|
|
113 byte code とか仮想マシンだったら可能。そうでない場合は?
|
|
114
|
|
115 いずれにせよ、構造体のタグのunique性を修正しないとだめだな。
|
|
116
|
|
117 ヘッダファイルはどうするの?
|
|
118
|
|
119 Mon Dec 13 18:53:18 JST 1999
|
|
120
|
|
121 library との整合性は?
|
|
122
|
|
123 exec sequence では、
|
|
124 (--(struct func_state *)stack) = fp;
|
|
125 call callee(&fp->arg);
|
|
126 という形でpointerだけ渡すの? それは変だよね。
|
|
127
|
|
128 値渡しにするとすれば、複数の値を渡せたほうが良い。
|
|
129
|
|
130 func(void *stack) {
|
|
131 static struct func_state {
|
|
132 static struct func_state *fp;
|
|
133 int local1;
|
|
134 brahbrah...
|
|
135 } func_state; // ここまで hidden
|
|
136 func_state.fp = (stack -= sizeof(struct func_state));
|
|
137 }
|
|
138
|
|
139 の引数自体が、構造体であるべき。
|
|
140
|
|
141 func(
|
|
142 struct void *stack
|
|
143 ) {
|
|
144 static struct func_state {
|
|
145 static struct func_state *fp;
|
|
146 int local1;
|
|
147 brahbrah...
|
|
148 } func_state; // ここまで hidden
|
|
149 func_state.fp = (stack -= sizeof(struct func_state));
|
|
150 }
|
|
151
|
|
152 で、構造体に register storage を許す。
|
|
153
|
|
154 func(
|
|
155 static struct argment {
|
|
156 register void *stack;
|
|
157 register void *continuation;
|
|
158 }
|
|
159 ) {
|
|
160 static struct func_state {
|
|
161 static struct func_state *fp;
|
|
162 int local1;
|
|
163 brahbrah...
|
|
164 } func_state; // ここまで hidden
|
|
165 func_state.fp = (stack -= sizeof(struct func_state));
|
|
166 }
|
|
167
|
|
168 すると、caller の方も、構造体を引数とするのが自然。
|
|
169
|
|
170 call caller(
|
|
171 static struct argment {
|
|
172 register void *stack;
|
|
173 register void *continuation;
|
|
174 } arg = {a,b};
|
|
175 )
|
|
176
|
|
177 みたいな。もちろん、この構造体はインタフェースと呼ばれる。
|
|
178
|
|
179 argument は、callee にあった方が良いけど、caller 側にあっても
|
|
180 良い。register なんかは、そう。
|
|
181
|
|
182 caller(interface caller_arg = {a,b,c})
|
|
183 みたいなsyntax かな。
|
|
184 caller->interface = {a,b,c};
|
|
185 *caller->code;
|
|
186 を、
|
|
187 caller(a,b,c);
|
|
188 と称する。
|
|
189
|
|
190 function には、interface と code と state があることになる。
|
|
191
|
|
192 state にアクセスする時のlockは? protected state? synchonized state かな?
|
|
193 もちろん、sequential implementatoinでは、そんなものはいらない。
|
|
194
|
|
195 function {
|
|
196 interface:
|
|
197 register int a;
|
|
198 register struct self self;
|
|
199 state:
|
|
200 int b;
|
|
201 serialized int c;
|
|
202 code:
|
|
203 b = a;
|
|
204 }
|
|
205
|
|
206 int にvoid value を定義する。実装は重くなるけど...
|
|
207
|
|
208 serialzed の semantics は?
|
|
209
|
|
210 もう少しmicro-Cに近く!
|
|
211
|
|
212 carring state と static state。
|
|
213
|
|
214 Mon Dec 13 19:42:41 JST 1999
|
|
215
|
|
216 interface に regsiter keyword を使うのは、あまりに
|
|
217 実装よりすぎる。でも、でないと状態にできない?
|
|
218 そんなことはないか。やっぱりcaller側のstatic 領域に
|
|
219 直接書き込む?
|
|
220
|
|
221 だとCより遅そう。でも、引数に40個とかかかれたら...
|
|
222
|
|
223 Wed Dec 15 14:09:49 JST 1999
|
|
224
|
|
225 C と互換にする?
|
|
226 goto function(argments);
|
|
227 goto *continuation(argments);
|
|
228 みたいな感じで。
|
|
229
|
|
230 stackの管理は? どうせ、library との互換はとらないと
|
|
231 いけないんだから...
|
|
232
|
|
233 local 変数がある場合は stack を動かす。でも、戻す奴がいない。
|
|
234 closure 化するか?
|
|
235
|
|
236 return した時の挙動が複雑になる。大域returnするわけだら。
|
|
237
|
|
238 argments をstatic 領域にかきこむ方式だと互換性がとれない。
|
|
239 stack 上の frmae pointer 上にないとダメだから。
|
|
240
|
|
241 両立させるのは無理か? つまり、これだと、呼び出された方の
|
|
242 frame semantics は、C と互換になる。だから、stackの直後に
|
|
243 frame pointer があると思っている (そうか? ) frame pointer
|
|
244 stack pointer に沿って移動した直後に、そこからのoffset
|
|
245 で引数を操作することになる。
|
|
246
|
|
247 つまり、それはだめだったことじゃない? つまり、goto だと、
|
|
248 frame pointer は、stack の直後とは限らないから。前の
|
|
249 frmae pointer 相対に引数にアクセスしてくれれば別だけどね。
|
|
250
|
|
251 stack に引数を積むのは容認して、goto の場合は、向こう側で
|
|
252 stack を畳むってのは? ということは、普通の関数と定義の
|
|
253 方法を変えるってことか。ま、悪くはないか。
|
|
254
|
|
255 すると、goto のsemantics は、C と互換になる。それを受ける
|
|
256 方が異なることをする。それは、なんかおかしいな。それに、
|
|
257 それだと関数呼び出しが軽くならない...
|
|
258
|
|
259 ということは、やはり、C のcall は、call funciton で
|
|
260 実現して、その他の呼び出しは、すべて、goto 扱いに
|
|
261 する方が正しいだろう。
|
|
262
|
|
263 問題は、この言語の関数をcallされた時だな。dual entry にして、
|
|
264 call の時と、goto の時を区別するか。
|
|
265 func: stack processing
|
|
266 func_goto: normal processing
|
|
267 ...
|
|
268 みたいな感じ。でも、return はないから...
|
|
269
|
|
270 このあたりも自分で記述できる言語であるべきだよね。その通り。
|
|
271 つまり、C とのstub も自分で記述すると言うことか。
|
|
272
|
|
273 protocol function {
|
|
274 interface c {
|
|
275 register "%esp" struct {
|
|
276 entry code ret(int);
|
|
277 void *fp;
|
|
278 } *sp;
|
|
279 register "%ebp" void *fp;
|
|
280 };
|
|
281 code function_code {
|
|
282 fp = sp;
|
|
283 sp += sizeof(struct local);
|
|
284 struct local *local = sp;
|
|
285
|
|
286 local->i = 1;
|
|
287 goto *fp->ret(local->i),sp=fp; // return(local->i);
|
|
288 };
|
|
289 }
|
|
290
|
|
291 みたいな感じでさ。さっすが、アセンブラ。いまいちreturnが汚いけど。
|
|
292 まぁ、return はそのままreturnでもいいけどさ。
|
|
293
|
|
294 あ、これは良いかも知れない。code が複数かけるから。
|
|
295
|
|
296 state 以外は、consitent state であることを保証しない。ってのは?
|
|
297 local 変数は使っても良いけど、call/goto の前後で、値を保証しないか...
|
|
298
|
|
299 うーん、だんだん炸裂してるなぁ。
|
|
300
|
|
301 だから、レジスタに対するマッピングの記述と、そうでない部分の
|
|
302 記述は分離するべきでしょうね。
|
|
303
|
|
304
|
|
305 全部一辺に実装するわけにはいかないからぁ...
|
|
306
|
|
307 Thu Dec 16 13:44:21 JST 1999
|
|
308
|
|
309 lock は状態遷移レベルで実現するのだから、self などを
|
|
310 使ってlockする必要はないはず。
|
|
311
|
|
312 全体の直列化は、状態遷移レベルで、
|
|
313 lock(storage) -> transition
|
|
314 みたいな形で記述すれば良い。この当たりを、どのように記述するかは
|
|
315 もう少し先送りしよう。
|
|
316
|
|
317
|
|
318 引数はレジスタ渡しにしよう。長い引数は、呼び出し側の領域への
|
|
319 ポインタとする。実装を規定しても良い。そうすれば、varargs
|
|
320 みたいなものはなくなる。だいたい、なんで、そんなものがいるんだろう?
|
|
321 配列を渡せばいいじゃん。
|
|
322
|
|
323 なので、引数は一つ(or 二つ)に限るという方法もある。
|
|
324
|
|
325 とすると、やはり、前もって静的領域や動的領域を確保することは
|
|
326 できない。
|
|
327
|
|
328 この言語では動的領域は自分で確保するわけだから、その点は問題ない。
|
|
329
|
|
330 Thu Dec 16 20:24:55 JST 1999
|
|
331
|
|
332 とすると関数呼び出しは、
|
|
333 # register save
|
|
334 # set 1st argument in register %eax
|
|
335 # set 2nd argument in register %ecx
|
|
336 # set extra aguments in save area
|
|
337 # set extra argument pointer in %edx
|
|
338 jmp function
|
|
339 という形式になるわけね。second を処理するのはめんどくさいから一つ
|
|
340 にしよう。
|
|
341
|
|
342 えーと、frame pointer はないけど、コンパイルの手順からすると
|
|
343 あった方が良い。しかし、frame pointer そのものをstatic
|
|
344 にとるのはまずい。だから、frame pointer がfirst argment
|
|
345 ということにする方が正しい。とすると引数は、さらに、その
|
|
346 後と言うわけか。
|
|
347 f(fp,argment)
|
|
348 fp を渡すのにさらにargment をレジスタで渡すのはおかしい。おかしいけど、
|
|
349 ま、良いか。
|
|
350
|
|
351 return しないなら、return type の定義をとるのは変だな。
|
|
352
|
|
353 f(fp,arg1,arg2,arg3) とすると、それぞれが決まったレジスタに入って、
|
|
354 多い分は配列にあると思われる。ふむふむ...
|
|
355 fp->xx
|
|
356 でアクセスすれば、そのまま局所変数になる。全部、配列で
|
|
357 送っても良い。
|
|
358
|
|
359 .set label,value
|
|
360
|
|
361 で as は値をセットするようですね。
|
|
362
|
|
363 関数コールの後は戻って来ないから後始末の心配はしなくてよい。
|
|
364 frame pointer を使ったら自分で面倒を見ること。
|
|
365
|
|
366 だと
|
|
367 a = atoi(s);
|
|
368 みたいなことはできない...
|
|
369
|
|
370 普通のCの定義と交じると間違いやすい。
|
|
371
|
|
372 とすると、struct と同様に、
|
|
373 protocol
|
|
374 code
|
|
375 interface
|
|
376 state
|
|
377 を用意するわけね。時間あるのかぁ?
|
|
378
|
|
379 とりあえず、register 渡しのfunction 定義とgoto文を実装する。
|
|
380
|
|
381 code name(register "%ebp" void *arg) {
|
|
382 goto name(arg);
|
|
383 }
|
|
384
|
|
385 ぐらいかな? で、first argment が必ずregisterにのるようにしないと
|
|
386 いけない。register storage class を入れて、
|
|
387 register "%ebp" void *arg
|
|
388 とかするわけね。
|
|
389
|
|
390 ってことは、まず、レジスタを実装しないといけないわけね。
|
|
391
|
|
392 で、stack を使った演算は、一応、そのままにする? それでも動くはず。
|
|
393 式の途中でgotoは使えないんだから、それでいいはず。
|
|
394
|
|
395 で、それから、これを拡張していく。
|
|
396
|
|
397 interface c {
|
|
398 register "%ebp" void *arg;
|
|
399 }
|
|
400 code name(interface c) {
|
|
401 goto name(c.arg); // c. は省略可能
|
|
402 }
|
|
403
|
|
404 とかね。さらに、
|
|
405
|
|
406 protocol name {
|
|
407 interface c {
|
|
408 register "%ebp" void *arg;
|
|
409 }
|
|
410 code name(interface c) {
|
|
411 goto name(arg);
|
|
412 }
|
|
413 code name1(interface c) {
|
|
414 goto name(arg);
|
|
415 }
|
|
416 }
|
|
417
|
|
418 などとするわけか。なんと、これが C と共存するわけね。うーん。
|
|
419
|
|
420 Fri Dec 31 11:44:03 JST 1999
|
|
421
|
|
422 code でなくて、別な名前のほうが良くない? segment? action?
|
|
423
|
|
424 レジスタ名が入るのは、やっぱりいや。optionalには許す。
|
|
425
|
|
426 interface は構造体のようなものだから... 構造体でいいんじゃない?
|
|
427 構造体の場合は... malloc する? う、うーん。malloc するとして、
|
|
428 いつfree するの?
|
|
429
|
|
430 再入するときには、壊れてていいんじゃない? multi-thread でなければね。
|
|
431 multi thread では、状態は、レジスタ経由または、thread local に持つ
|
|
432 必要がある。static は、だから thread local に持たなくてはならない。
|
|
433 大域変数に割り振っちゃだめ。でも、いまは、やめて
|
|
434
|
|
435 interface は、とりあえず、二つまでの値渡しにしよう。
|
|
436 self と arg
|
|
437 ですね。
|
|
438
|
|
439 もう少し拡張しやすいコンパイラがいいなぁ。
|
|
440
|
|
441 code name (c,a)
|
|
442 struct state *c; struct arg *a;
|
|
443 {
|
|
444 goto name(arg);
|
|
445 }
|
|
446
|
|
447 local 変数は? この互換性の問題かぁ。
|
|
448
|
|
449 KL/1 を意識して、interface は heap に置くことにしても良い。
|
|
450 GC は言語に入れておくべきだが、interfaceは machine independent
|
|
451 であるべき。だとすれば use/forget みたいものはいるだろう。
|
|
452 でも今のところは考える必要はない。
|
|
453
|
|
454 えーと、
|
|
455 code name (c,a)
|
|
456 struct state *c; struct arg *a;
|
|
457 {
|
|
458 int i;
|
|
459 goto name(arg);
|
|
460 }
|
|
461 の時の一時変数iはどうするの? 基本的にはレジスタ割り当てだけど...
|
|
462 使用させない? んー、大胆な御意見。まぁ、やっぱりheapに割り当てちゃう
|
|
463 のが簡単か。でも、どうせ抜ける時にはいらなくなるわけだから...
|
|
464
|
|
465 ほんらい、この変数は、次のcallでは必要無くなるのが普通。
|
|
466
|
|
467 とにかく、レジスタ変数は必要なんでしょう?
|
|
468
|
|
469 だから、GC と合わせて言語を設計すべきだよね。API を規定して、
|
|
470 異なるGCを選択できるようにする。
|
|
471
|
|
472 Sat Jan 1 22:40:22 JST 2000
|
|
473
|
|
474 とーにかく、 storage class regisgter を実装しよう。
|
|
475
|
|
476 stmode=REGISTER
|
|
477
|
|
478 で、local storage とおなじ扱いとする
|
|
479 static register? は、ない。
|
|
480
|
|
481 symbol table に storage class をたせば? dsp==EXTRN で判定しているから、
|
|
482 local 変数が36以上あるとおかしくなるぞ?
|
|
483
|
|
484 sc は GVAR/LVAR だけど、regsiter は LVAR の特殊な奴だから、
|
|
485 sc に入れるほうが正しいか...
|
|
486
|
|
487 Sun Jan 2 01:47:17 JST 2000
|
|
488
|
|
489 register 変数はできました。けど、regsiter を二つ使うと、
|
|
490 一杯になってしまうので、REGISTER6 でコンパイルしないと
|
|
491 結構ひどい。が、register 変数を%esi,%edi に割り当てれば
|
|
492 いいか。
|
|
493
|
|
494 Sun Jan 2 04:43:04 JST 2000
|
|
495
|
|
496 で、
|
|
497 code name (c,a)
|
|
498 struct state *c; struct arg *a;
|
|
499 {
|
|
500 goto name(c);
|
|
501 }
|
|
502 の一時変数無しは実装できます。引数は二つまでね。
|
|
503
|
|
504 .file "tmp.c"
|
|
505 .version "01.01"
|
|
506 gcc2_compiled.:
|
|
507 .text
|
|
508 #
|
|
509 # code name(c,a)
|
|
510 .align 2
|
|
511 .globl code
|
|
512 code:
|
|
513 .type code,@function
|
|
514 # struct state *c; struct arg *a;
|
|
515 # {
|
|
516 # goto name(c);
|
|
517 movl %esi,%esi
|
|
518 jmp name
|
|
519 _5:
|
|
520 .size code,_5-code
|
|
521 .ident "Micro-C compiled"
|
|
522
|
|
523 う、すごい。
|
|
524
|
|
525 goto 文がめんどくさい。stack をたたんで、jmp すれば
|
|
526 よいだけだが..
|
|
527
|
|
528 Sun Jan 2 11:17:50 JST 2000
|
|
529
|
|
530 普通のcallをcontinuation baseにすることができる?
|
|
531
|
|
532 Sun Jan 2 20:28:45 JST 2000
|
|
533
|
|
534 goto 文だけど、やはり、一度、expr で生成してから、top level
|
|
535 で jump code を生成しよう。
|
|
536
|
|
537 Tue Jan 4 03:32:55 JST 2000
|
|
538
|
|
539 code をtypeにしないと、
|
|
540 code *p;
|
|
541 とか書けないね。
|
|
542 int *p();
|
|
543 と同じだけどさ。
|
|
544
|
|
545
|
|
546 main(ac,av)
|
|
547 int ac;
|
|
548 char *av[];
|
|
549 {
|
|
550 goto code1(ac,av);
|
|
551 }
|
|
552
|
|
553 code code1(ac,av)
|
|
554 int ac;
|
|
555 char *av[];
|
|
556 {
|
|
557 if (ac)
|
|
558 goto code1(ac,av);
|
|
559 else
|
|
560 goto ac(ac,av);
|
|
561 }
|
|
562
|
|
563 Tue Jan 4 04:56:56 JST 2000
|
|
564
|
|
565 うーん、なんかレジスタにつむ順序が違う
|
|
566 これは、adecl がreverseにつむから。
|
|
567
|
|
568 code のretrun
|
|
569
|
|
570 やはりcodeはtypeにしないとだめ。
|
|
571
|
|
572 main()
|
|
573 {
|
|
574 goto code1();
|
|
575 }
|
|
576
|
|
577 とかだと、main に戻って来れない。もちろん、code1() 以降で、
|
|
578 return するわけにはいかない。(main の disp をcode1 は知り得ない)
|
|
579 goto label をcode1の引数に送れば?
|
|
580
|
|
581 main()
|
|
582 {
|
|
583 goto code1(ret);
|
|
584 ret:
|
|
585 }
|
|
586
|
|
587 これだと、ret がforward labelかどうか分からないけど?
|
|
588
|
|
589 code1 中で使う中間変数を stack 上にとるのは悪くない。しかし、それを
|
|
590 %ebp 経由でアクセスするということは、main の中間変数を壊すということ。
|
|
591 それを防ぐには、main 中のgoto codeで、%ebp を修正してやれば良い。
|
|
592 (今は戻って来ないので問題ない)
|
|
593
|
|
594 code1 のgoto では、戻って来ないから、その必要はない。しかし、
|
|
595 label をcode1 中で渡されると、ちょっと気まずい。
|
|
596
|
|
597 とすると、それは禁止して、main() 中でstackをたたんでからgotoするか?
|
|
598 そうすると、無限後退して、結局、帰れないことになる... うーん。
|
|
599
|
|
600 main() 中のlocal code を許せば、それは解決するが..
|
|
601
|
|
602 main()
|
|
603 {
|
|
604 goto code1(code2);
|
|
605 code code2() {
|
|
606 return;
|
|
607 }
|
|
608 }
|
|
609
|
|
610 みたいな感じ。でも、そうするとscope rule を変える必要があるので厳しい。
|
|
611 ま、悪くはないけどね。
|
|
612
|
|
613 continuation を明示する方法もある。
|
|
614
|
|
615 main()
|
|
616 {
|
|
617 goto code1(continuation);
|
|
618 }
|
|
619 code code1(ret)
|
|
620 code (*ret)();
|
|
621 {
|
|
622 goto *ret;
|
|
623 }
|
|
624
|
|
625 かな? call/cc ?
|
|
626
|
|
627 label へのgotoを許すのもいいけど、
|
|
628 でも、label を許すと、すごくspagettyにならない?
|
|
629
|
|
630
|
|
631 Tue Jan 4 11:47:24 JST 2000
|
|
632
|
|
633 contiunation じゃなくて、return keyword を使おう。
|
|
634 (実際、continuation と少し違うし)
|
|
635 type が少し変になるけど、まあ良い。
|
|
636
|
|
637 int
|
|
638 main()
|
|
639 {
|
|
640 goto code1(return);
|
|
641 }
|
|
642 code code1(ret)
|
|
643 code (*ret)(int);
|
|
644 {
|
|
645 goto *ret(3);
|
|
646 }
|
|
647
|
|
648 だな。prototype も付けないといけないか。
|
|
649
|
|
650 Tue Jan 4 12:21:44 JST 2000
|
|
651
|
|
652 これだとmethodがすべてstatic になってしまう。dynamic なmethod
|
|
653 呼び出しにするには? dipatcher を自分で作ることになる。かなり
|
|
654 めんどくさいが...
|
|
655
|
|
656 code method(obj,arg)
|
|
657 {
|
|
658 }
|
|
659
|
|
660 か、あるいは、inline にするか... #define のかわりに inline ねぇ。
|
|
661 これはあとで考えて良い。
|
|
662
|
|
663 Tue Jan 4 14:22:19 JST 2000
|
|
664
|
|
665 main の変数を書き潰すのと、gotgo (*reg)(123) での値は、
|
|
666 register 渡しで、current register にのらないので、
|
|
667 結局、return label は専用に作る必要がある。
|
|
668
|
|
669 Tue Jan 4 18:14:07 JST 2000
|
|
670
|
|
671 stack を継ぎ足して、呼び出す方式を取れば、call by value
|
|
672 のregister 渡しを制限する必要は無くなる。
|
|
673
|
|
674 複数の値を返すことも容易だ。
|
|
675
|
|
676 .file "tmp.c"
|
|
677 .version "01.01"
|
|
678 gcc2_compiled.:
|
|
679 .text
|
|
680 #
|
|
681 # code name(a,b,c,d,e,f)
|
|
682 .align 2
|
|
683 .globl code
|
|
684 code:
|
|
685 .type code,@function
|
|
686 # struct arg *a,*b,*c,*d,*e,*f;
|
|
687 # {
|
|
688 # int g;
|
|
689 # goto name(a,b,d,e,f);
|
|
690 jmp name
|
|
691 _5:
|
|
692 .size code,_5-code
|
|
693 .ident "Micro-C compiled"
|
|
694
|
|
695 おお?!
|
|
696 %esp new %esp = old %esp - 12 -4
|
|
697 %ebp-4 = g
|
|
698 %esi = a
|
|
699 %edi = b
|
|
700 %ebp = old %esp 0
|
|
701 %ebp+4 = c code_arg_offset=0
|
|
702 %ebp+8 = d
|
|
703 %ebp+12 = e
|
|
704 %ebp+16 = f
|
|
705
|
|
706 interface は付けよう! というか、
|
|
707 goto name(struct {xxxx})
|
|
708 みたいな感じで良いわけね。どれをregisterにいれるかと言う問題はあるが。
|
|
709
|
|
710 で、どうやってcallすればいいわけ? emit_pushするかわりにpush
|
|
711 する?
|
|
712
|
|
713 うう、これでは、だめか。code argument の数が変わると、
|
|
714 ebp をいちいち動かすことになる。そこにはold sp があるから
|
|
715 そいつもコピーする必要がある。
|
|
716
|
|
717 %esp new %esp = old %esp - 20
|
|
718 %ebp-20 = g
|
|
719 %esi = a
|
|
720 %edi = b
|
|
721 %ebp-16 = c code_arg_offset= -16 ((nargs-max_reg)*int_size)
|
|
722 %ebp-12 = d
|
|
723 %ebp-8 = e
|
|
724 %ebp-4 = f
|
|
725 %ebp = old %esp 0
|
|
726
|
|
727 そうか、function からcallする時には、local 変数を書き潰して良い。
|
|
728
|
|
729 # goto name(a,b,d,e,f);
|
|
730
|
|
731 %esp new %esp = old %esp - 20
|
|
732 %ebp-20 = g
|
|
733 %esi = a
|
|
734 %edi = b
|
|
735 %ebp-16 = c code_arg_offset= -16 ((nargs-max_reg)*int_size)
|
|
736 %ebp-12 = d
|
|
737 %ebp-8 = e
|
|
738 %ebp-4 = f
|
|
739 %ebp = old %esp 0 disp=0 (*)
|
|
740 local1 <----16 local variable
|
|
741 %edx -12 <- disp_offset
|
|
742 %ecx -8
|
|
743 %ebx -4
|
|
744 %ebp = %esp 0
|
|
745 %eip 4 <- arg_offset
|
|
746
|
|
747 となる。ということは、pushl %ebp は、間違い。
|
|
748
|
|
749 だけど、%ebp をそのまま使うのは良くない。disp_offset がかかっているから。
|
|
750 だから、もう一度 pushl %ebp したほうがよい。しかし、push する先は、
|
|
751 上の、(*)。
|
|
752 leave movl %ebp,%esp
|
|
753 popl %ebp
|
|
754 じゃなかったか?
|
|
755
|
|
756 Thu Jan 6 13:00:33 JST 2000
|
|
757
|
|
758 できたね。これでとりあえず動くはず。速度は問題だが...
|
|
759 あとは、
|
|
760 ANSI-C prototype
|
|
761 ANSI-C prototype check
|
|
762 Interface Definietion
|
|
763 GC support
|
|
764 Direct handling of Frame
|
|
765 だね。簡単に出来そう? たぶん...
|
|
766
|
|
767 Fri Jan 7 09:42:53 JST 2000
|
|
768
|
|
769 goto 文が動いてなかった。あと peep hole optimization version も
|
|
770 作るか?
|
|
771
|
|
772 continuation として label を送れるようにするべきか?
|
|
773 そうすると便利なんだけど、ちょっと、汚いプログラムが
|
|
774 出来るようになる。あと、送り側の環境(frame)を維持する
|
|
775 必要がある。ま、できなくはないか...
|
|
776
|
|
777 そうすると、label が値を持つようになる。
|
|
778 a = label:;
|
|
779 とか。うーん。label:(a,b,c) {}; みたいな形で、parallel 代入を許すと言う
|
|
780 手もあるね。
|
|
781
|
|
782 こちらの方がCとの相性は良いが... main() { label:(){ ... } }
|
|
783 みたいなnestを許すかどうかと言う問題がある。
|
|
784 変数の参照を許さなければ、特に問題はない。
|
|
785
|
|
786 a = label: は、二重の意味があるなぁ。
|
|
787
|
|
788 言語の名前。DinnerBell II とか? join も入れる?
|
|
789 code entry_a().entry_b() {}
|
|
790 ですか? parallel call も?
|
|
791
|
|
792 Fri Jan 7 19:53:53 JST 2000
|
|
793
|
|
794 いまのままだと return が環境を持ってないから、大域脱出できない。
|
|
795 まぁ、環境を入れてもいいんだけど、どこに置くかと言う問題が
|
|
796 あるね。
|
|
797
|
|
798 そうじゃなくて、return 側で判断するか?
|
|
799 retrun(ID)
|
|
800 みたいな形でIDで判断する。そうすれば、return 側でID
|
|
801 を見て判断できる。けど...
|
|
802
|
|
803 まぁ、はやり、環境を持って歩く方がいいかなぁ。でも、
|
|
804 引き渡しているから、二つ引き渡して、片方を使われたときに、
|
|
805 反対側が消えてしまうのはいたいよね。今のままならば、
|
|
806 そういうことは起こらない。
|
|
807
|
|
808 continuation 特有の問題を避けるなら、このままでもいいんだが...
|
|
809 contrinuation や環境は、このシステムでは自分で作ることが
|
|
810 できるからね。
|
|
811
|
|
812 そうなんだけど.... retlabel や retcont は実はオブジェクト
|
|
813 全体に一つあれば良い。
|
|
814
|
|
815 引数を渡すときに、そこに環境へのポインタをいれてやれば良いので、
|
|
816 解決は割と簡単だが、そうすると、例の構造体を引数で渡すと言う
|
|
817 問題を解決する必要がある。
|
|
818
|
|
819 でも、今の実装ならば、まったく同じ変数の構成ならばコピーは
|
|
820 実際には起こらないわけだから問題ないはず。特に、それを保証するために、
|
|
821 interface を実装する必要がある。
|
|
822
|
|
823 return ->
|
|
824 (void *)old bp
|
|
825 return address
|
|
826
|
|
827 bp を直接操作できるようにするといいんだけど....
|
|
828
|
|
829 Sat Jan 8 08:49:59 JST 2000
|
|
830
|
|
831 今は、code 内ではreturnできないわけだけど。実は、return って、
|
|
832 code return0(i) int i; { return(i); }
|
|
833 か? 今は禁止してないから書けちゃうよね。どういうcodeが出るんだろう?
|
|
834
|
|
835 doreturn() では retpending をセットしているだけだから、control=1
|
|
836 のまま。で、code の終りにくるのでエラーになる。checkret は、
|
|
837 statement の引数で判断するようにしたほうが合理的だろう。
|
|
838
|
|
839 大域脱出は結構根が深いよね。途中をスキップされてうれしいか?
|
|
840 destructor と同じで、途中のcodeは全部呼びたいのが普通だろう。
|
|
841
|
|
842 bp が同じになるまで return すれば良いわけだよね。
|
|
843 return と同じで、明示的に環境を引き渡すようにするか。
|
|
844 type は void * で良い?
|
|
845
|
|
846 return する時にstackの上限を越えているかどうかを自分でチェックする
|
|
847 必要があるね。誰にreturnするかをcodeで明示すれば良いわけだけど。
|
|
848
|
|
849 code return0(i) int i; { return(i); }
|
|
850
|
|
851 を許して、そこで、frame pointer を大域あるいは渡した引数と
|
|
852 比較して処理する?
|
|
853 code return0(i,env) int i; env *env; {
|
|
854 if (env==self) return(i);
|
|
855 }
|
|
856 あれ? これはおかしいよね。
|
|
857 code return0(i,env) int i; env *env; {
|
|
858 if (env!=self) {
|
|
859 env->return();
|
|
860 return(i);
|
|
861 }
|
|
862 }
|
|
863 も、なんか変だよなぁ。呼び出しと逆順に帰りたいわけだが...
|
|
864 実際、逆順には帰っているわけだよね。
|
|
865
|
|
866 return の中でこそこそ比較するという技もあるけど。
|
|
867
|
|
868 問題は、destructor に渡す情報だよね。もちろん、self で良いわけだが、
|
|
869 このあたりは、言語外の問題で、それを明示的にしたいから、この言語を
|
|
870 作っているわけなのだから、これを内部で処理するのはおかしい。
|
|
871
|
|
872 code return0(i) int i; { return(i); }
|
|
873
|
|
874 これだと、return の型が合わないと言う問題が生じるな。簡単には
|
|
875 チェックできない。
|
|
876 int
|
|
877 main() {
|
|
878 code a() {
|
|
879 }
|
|
880 code b() {
|
|
881 return(i);
|
|
882 }
|
|
883 }
|
|
884 にすれば、check はできるようになる。でも、これだと、
|
|
885 int
|
|
886 main() {
|
|
887 a: {
|
|
888 }
|
|
889 b: {
|
|
890 return(i);
|
|
891 }
|
|
892 }
|
|
893 と差がない。module 化を言語外でやるというのが主旨なのだから、これでは
|
|
894 まずい。これは高級アセンブラなのだから。
|
|
895
|
|
896 あそうか、return と、大域脱出時のabortとは、状況が違う。だから、
|
|
897 別なcode を呼び出さないとだめ。あるいは、値で区別するか。これは、
|
|
898 logic programming のfail/success と似ている。
|
|
899 main() { } abort { ... }
|
|
900 でもいいけど?
|
|
901 main() { code abort { ... }; code return { ... }}
|
|
902 かな?
|
|
903
|
|
904 本来、subroutine call自体が、かなりの省略形なわけだから、これは
|
|
905 仕方がない。今のままで通常のsubroutine callをシミュレートできるのか?
|
|
906 code (struct arg {...},void *sp) {
|
|
907 struct env;
|
|
908 push(sp,arg);
|
|
909 push(env,arg);
|
|
910 }
|
|
911 できるけど、ちょっと重い。やはり、frame pointer を直接操作しないと
|
|
912 だめ。
|
|
913
|
|
914 goto 文のほうに、env を一緒に送るものを作ったほうがいいのかも。
|
|
915 goto (*ret)(),environment;
|
|
916 かな。type は? (void *)?
|
|
917 goto ret(),environment;
|
|
918 にはならないの? そうすれば、自分でthreadを制御できる。environment
|
|
919 の正当性を評価しなくて良いの? まぁ、ねぇ。
|
|
920
|
|
921 これは実装は容易だが... goto といちいち書くのが本当にいいのか?
|
|
922 env に対するoperationがあった方がいいなぁ。push とか?
|
|
923
|
|
924 code return0(i) int i; { return(i); }
|
|
925
|
|
926 を認めれば、return 擬変数はいらなくなる。
|
|
927
|
|
928 でも、実は、return は、caller の引数の数と一致してないといけない
|
|
929 わけだから、 code return0(i) int i; { return(i); } はだめ。env
|
|
930 と一致してないといけない。ということは分離するとまずいんじゃない?
|
|
931 あれ? そんなはずないな。
|
|
932
|
|
933 Sun Jan 9 01:15:56 JST 2000
|
|
934
|
|
935 やはり、分離してはまずい。もともと、
|
|
936 goto func(arg);
|
|
937 自体が、
|
|
938 goto func(arg) with current.env
|
|
939 みたいなものだ。つまり、これは、DinnerBell の、
|
|
940 self message: arg
|
|
941 と同じ。self->func(arg); でも良い。が、function callと区別が付かないのは
|
|
942 良くない。
|
|
943
|
|
944 そうすると、type code はsize int でなくなる。
|
|
945 code *p = func;
|
|
946 ではいけなくて、
|
|
947 code p = {func,env};
|
|
948 でないといけない。実際、
|
|
949 goto func(arg)
|
|
950 では、current environment を pushl %ebp でstack = current env
|
|
951 に積んでいるわけだから。
|
|
952
|
|
953 いずれにせよ、
|
|
954 struct p = q;
|
|
955 は実装する必要がある。localな、
|
|
956 code p = {func,env};
|
|
957 も動くはずだが...
|
|
958
|
|
959 code (*p)();
|
|
960 goto (*p)(arg);
|
|
961
|
|
962 はだから少しおかしい。これは、goto がenv を補っていると考えるべき。
|
|
963
|
|
964 このようにすると、常に、
|
|
965 func,env
|
|
966 の組をcodeとみなすことになる。これは、object と呼ぶべきだ。
|
|
967 ただ、既存のobjectとは別だよな。actor の方が良い?
|
|
968
|
|
969 うーん、これでjoinを入れれば、完璧なDinnerBellだな。並列送信はないけど。
|
|
970
|
|
971 Sun Jan 9 01:40:05 JST 2000
|
|
972
|
|
973 local 変数の初期化はallocation の後に遅らせる必要がある。
|
|
974 nptr に入れられるはずだよね? nptr に初期化フラグを足すか?
|
|
975
|
|
976 文途中で出現するlocal変数の初期化。ちゃんと動いているの?
|
|
977
|
|
978 構造体のcopyは、lcheck を修正すべきでない。
|
|
979
|
|
980 Sun Jan 9 08:49:43 JST 2000
|
|
981
|
|
982 うーん、なんか修正が多いなぁ。あと、関数呼び出し、goto 文の
|
|
983 構造体への対応か。
|
|
984
|
|
985 goto (*code)();
|
|
986
|
|
987 が、self env を使うのか、code の先の値を使うのかを区別する
|
|
988 必要がある。もし*を使わないとするとlabel(FNAME)との区別が
|
|
989 つかないぞ。あ、でも、環境を持ち歩くことにしたから、label
|
|
990 へもjumpしようと思えばできるね。
|
|
991
|
|
992 並列送信はなくても、この構成ならばstatement単位の並列性を検出するのは
|
|
993 容易だろう。
|
|
994
|
|
995 やればできるけど、この修正の量だと1日じゃ終らないかなぁ。
|
|
996 不動小数点も入れるのでしょう?
|
|
997
|
|
998 Mon Jan 10 09:00:12 JST 2000
|
|
999
|
|
1000 引数に構造体を許すには、必ずANSI-Cにする必要がある。難しくは
|
|
1001 ないが...
|
|
1002
|
|
1003 goto 文には label, code, continuation の3つが来る。
|
|
1004 continuation = code + env
|
|
1005 | label +env
|
|
1006 なのだが、code/label では、env の内容が異なる。できれば面白いが、
|
|
1007 その価値はあるのか?
|
|
1008
|
|
1009 しかし、code , env を分離するとあまりに危険すぎる。どうせgoto
|
|
1010 が危険なんだからいいか? その方が簡単。簡単なら、そっちの方法を
|
|
1011 とるべきじゃない? うーん。
|
|
1012
|
|
1013 return の関数依存性はなくした方が良い。
|
|
1014 一つにするのは、pop の問題があるので良くないが...
|
|
1015
|
|
1016 そうか、ret をenvを指定して戻るようにしたから、leave する必要は
|
|
1017 なくなった。そして、push %ebp に相当する部分は、lea -disp(%ebp),%sp
|
|
1018 で消去されている。ということは、jump のfunction依存部分はいらない
|
|
1019 ということだね。
|
|
1020
|
|
1021 でも、汚いなぁ。read only属性をhardware supportできればなあ。
|
|
1022
|
|
1023 sched_yeilds() 相当を書けるかな? lock は?
|
|
1024
|
|
1025 一応、できたけど、やっぱり汚い。
|
|
1026
|
|
1027 Wed Jan 12 16:12:27 JST 2000
|
|
1028
|
|
1029 あは。ANSI prototype はめんどい。
|
|
1030 bexpr()
|
|
1031 で、関数での引数の順序と、そのあとの宣言の順序が変わることがある。
|
|
1032 そうすると、うしろの方が優先されてしまう。これは、こまる。
|
|
1033
|
|
1034 そうか、code_arg_offset のような方法だと、ANSI style では、
|
|
1035 困ってしまう。
|
|
1036
|
|
1037 Thu Jan 13 04:46:12 JST 2000
|
|
1038
|
|
1039 # goto name(a,b,d,e,f);
|
|
1040 code name { int g; ...
|
|
1041
|
|
1042 %esp new %esp = old %esp - 20
|
|
1043 %ebp-20 = g code's local variable
|
|
1044 %ebp-12 = f <- new_disp
|
|
1045 %ebp-8 = d
|
|
1046 %ebp-4 = d
|
|
1047 %ebp-0 = c
|
|
1048 %edi = b
|
|
1049 %esi = a
|
|
1050 %ebp = old %esp 0 disp=0 new env
|
|
1051 local1 <----16 old local variable ( to be erased )
|
|
1052 %edx -12 <- disp_offset
|
|
1053 %ecx -8
|
|
1054 %ebx -4
|
|
1055 %ebp = %esp 0 <- old env
|
|
1056 %eip 4 <- arg_offset
|
|
1057
|
|
1058
|
|
1059 Thu Jan 13 13:38:24 JST 2000
|
|
1060
|
|
1061 だいたいできたけど、test/tmp7.c のprintf のtype mismatch は
|
|
1062 なんなんだろう? ASNI の副作用だろうなぁ。
|
|
1063
|
|
1064 これだと、プロセスの切替えのときには、結構な量のデータを
|
|
1065 コピーすることになる。それでもいいんだけど...
|
|
1066
|
|
1067 それごと、どっかにとって置く。continuationへの参照みたいなもの
|
|
1068 ができないかな。
|
|
1069
|
|
1070 コピーができれば、environment/return の組は動くわけだから、
|
|
1071 それへの参照と切替えがあっても良いよね。
|
|
1072
|
|
1073 Fri Jan 14 12:03:35 JST 2000
|
|
1074
|
|
1075 Libretto のkeyboardが壊れた... control key が効かない...
|
|
1076
|
|
1077 printf の参照の問題は解決しました。list2 がlocalなheap
|
|
1078 に割り当てているのがいけなかったね。
|
|
1079
|
|
1080 return の処理は、goto 文で処理するより、environment に
|
|
1081 returnto する方が良くはないか?
|
|
1082
|
|
1083 environment は実は送り先でそれなりの準備が必要。
|
|
1084 new-environment() みたいなlibrary があれば、thread にできる。
|
|
1085
|
|
1086 join は?
|
|
1087
|
|
1088 funcall を用意すると良いね。
|
|
1089
|
|
1090 Mon Jan 17 15:23:34 JST 2000
|
|
1091
|
|
1092 struct aa f1() {
|
|
1093 return bb;
|
|
1094 }
|
|
1095
|
|
1096 みたいなのは? 関数の型か代入の型を見て、crn にpointerを渡して、
|
|
1097 あとでcopyしてから stack を畳む。
|
|
1098
|
|
1099 # bb=f1(aaa);
|
|
1100 movl $bb,%eax
|
|
1101 pushl %eax
|
|
1102 movl $aaa,%eax
|
|
1103 pushl %eax
|
|
1104 call main2
|
|
1105 popl %edx
|
|
1106 copy %eax,%edx,$400
|
|
1107 addl $400,%esp
|
|
1108 # return a1;
|
|
1109
|
|
1110 あ、でも、それだと、local変数を返したときに困るね。leave; ret;
|
|
1111 してはいけなくて...
|
|
1112
|
|
1113 あ、やっぱり、こういう場合はコピー先をmain2に引き渡しているみたいね。
|
|
1114 void f1(struct aa *ret) {
|
|
1115 *ret = bb ;
|
|
1116 return;
|
|
1117 }
|
|
1118 と同じか。これは簡単。
|
|
1119 f1().a[55]
|
|
1120 みたいな場合は、局所変数に強制的に取ってしまうみたいね。それはそうだ...
|
|
1121 が、うちの実装だとちょっと厳しいか。
|
|
1122 leal $-sizeof(struct),%esp
|
|
1123 pushl %esp
|
|
1124 なんだけど、関数呼び出しの途中ではできないから....
|
|
1125
|
|
1126 # main(ac,av)
|
|
1127 # int ac;
|
|
1128 .align 2
|
|
1129 .globl main
|
|
1130 main:
|
|
1131 .type main,@function
|
|
1132 pushl %ebp
|
|
1133 movl %esp,%ebp
|
|
1134 pushl %ebx
|
|
1135 pushl %ecx
|
|
1136 pushl %edx
|
|
1137 # char *av[];
|
|
1138 # {
|
|
1139 # register int i;
|
|
1140 # register char *p;
|
|
1141 # int j = 3;
|
|
1142 # struct { int b; void (*c)(struct aa); } q = {3,main1},r;
|
|
1143 #
|
|
1144 # j = 3;
|
|
1145 subl $20,%esp
|
|
1146
|
|
1147 このsublを後から指定してやればOk。
|
|
1148
|
|
1149 でも、それだと jump の時にずれない? ずれるか? ずれるね。うーん。
|
|
1150 実行時にチェックしてやるのも変だし。
|
|
1151
|
|
1152 まぁ、それほど必要な機能ではないんだけど。
|
|
1153
|
|
1154 これもcontinuationを渡してやると言う手法が使えないことはないんだが...
|
|
1155
|
|
1156 関数呼び出しの最初にやってやればいいか。それでできるかな?
|
|
1157
|
|
1158
|
|
1159 Sun Feb 20 23:59:16 JST 2000
|
|
1160
|
|
1161 MIPS のcall frame
|
|
1162
|
|
1163 $sp = $fp
|
|
1164 local variables
|
|
1165 saved register (including $31 = return address)
|
|
1166
|
|
1167 mask は使用したレジスタのbit pattern
|
|
1168 -4 は何?
|
|
1169
|
|
1170 18 .mask 0xc0000000,-4
|
|
1171 19 .fmask 0x00000000,0
|
|
1172 20 0000 D0FFBD27 subu $sp,$sp,48
|
|
1173 21 0004 2C00BFAF sw $31,44($sp)
|
|
1174 22 0008 2800BEAF sw $fp,40($sp)
|
|
1175 23 000c 0000000C move $fp,$sp
|
|
1176 24 0010 21F0A003 jal __main
|
|
1177 25 0014 03000224 li $2,0x00000003 # 3
|
|
1178 26 0018 000082AF sw $2,a
|
|
1179 27 001c 04000224 li $2,0x00000004 # 4
|
|
1180 28 0020 00C082AF sw $2,b
|
|
1181 29 0024 05000224 li $2,0x00000005 # 5
|
|
1182 30 0028 000082A3 sb $2,c
|
|
1183 31 002c 06000224 li $2,0x00000006 # 6
|
|
1184 32 0030 08C082A3 sb $2,d
|
|
1185 33 $L1:
|
|
1186 34 0034 21E8C003 move $sp,$fp # sp not trusted
|
|
1187 here
|
|
1188 35 0038 2C00BF8F lw $31,44($sp)
|
|
1189 36 003c 2800BE8F lw $fp,40($sp)
|
|
1190 37 0040 0800E003 addu $sp,$sp,48
|
|
1191 38 0044 3000BD27 j $31
|
|
1192 39 .end main
|
|
1193
|
|
1194 これと同じようにするならば、regiterの使用数を最初に調べる必要が
|
|
1195 あるのだけど、one path compiler である micro-C では、それは
|
|
1196 できない。したがって、enter は後ろでする方が良い。
|
67
|
1197
|
59
|
1198 Mon Jan 20 18:25:27 JST 2003
|
|
1199
|
|
1200 3年間さわってないのかよ。何やってんだ?
|
|
1201
|
|
1202 goto 文のバグをとらないといけない。
|
|
1203
|
|
1204 まず、関数引数の構造体の展開。これは、どうってことないはず。
|
|
1205
|
|
1206 goto (*code)(i+1,j,...)
|
|
1207
|
|
1208 まず、いじらなくてすむ変数を摘出する。
|
|
1209
|
|
1210 foreach arg
|
|
1211 compare
|
|
1212
|
|
1213 単純演算 ( op+const , pointer , const assign ) などは、ここで検出する。
|
|
1214 大半は、そのようになるはず。
|
|
1215 レジスタに乗せる分があるから... それには触らないとして...
|
|
1216
|
|
1217 複雑なものは、前もって計算しておく。(get_register する)
|
|
1218 スタック上かレジスタ上に作る。
|
|
1219
|
|
1220 残りは並列代入となる。再帰的に計算する。
|
|
1221
|
|
1222 えーと、大きな順にやるんだっけ? 小さな順にやるんだっけ?
|
|
1223 code f( int a, int b, int c ) {
|
|
1224 goto g(b,c,a);
|
|
1225 }
|
|
1226 みたいなやつだよね。
|
|
1227
|
|
1228 移動するものを一つ検出する。
|
|
1229 そのために移動が必要なものを移動しておく(再帰)
|
|
1230 代入する
|
|
1231
|
|
1232 こんなんでいいのか? ループしない? するよね。ループしたら
|
|
1233 get_register する。
|
|
1234
|
|
1235 前の例だと、
|
|
1236
|
|
1237 g(b,c,a) のbに着目する。
|
|
1238 bに代入するコードを出すと、a が壊れる。
|
|
1239 a が必要かどうかを調べる。それは、引数のリストを見ればわかる。
|
|
1240 その前に、a を移動する。a の移動先を見て、
|
|
1241 空いていれば、移動してOk。しかし、c
|
|
1242 なので、 c を見る。と b になるので、ループするのがわかるので、
|
|
1243 b を get_register する。
|
|
1244 で、c が移動できる。で、aを移動して、とっておいたbを代入。
|
|
1245
|
|
1246 Tue Jan 21 22:45:09 JST 2003
|
|
1247
|
|
1248 とりあえず、jump は複雑すぎる。もっと簡単にすることを考える。
|
|
1249 parser 側である程度処理できない?
|
|
1250
|
|
1251 goto f(a+3,b(),c);
|
|
1252
|
|
1253 などを、
|
|
1254
|
|
1255 a = a+3;
|
|
1256 b = b();
|
|
1257 goto f(a,b,c);
|
|
1258
|
|
1259 程度に簡略化する。この時、f(a,b,c) は(できるだけ)、元の
|
|
1260 関数の引数リストに近付ける。のは無理なので、単純変数
|
|
1261 まで落す。
|
|
1262
|
|
1263 あまり関係ないか。一時変数はどうせいるわけだし。ってこと
|
|
1264 みたいね。
|
|
1265
|
|
1266 だとすると、元のコードと、そう変わらんね。前のも、そんなに
|
|
1267 悪くないってことか。
|
|
1268
|
|
1269 Wed Jan 22 14:33:12 JST 2003
|
|
1270
|
|
1271 やっぱり、途中で局所変数を増やしたいよね。
|
|
1272
|
|
1273 Fri Jan 31 20:30:36 JST 2003
|
|
1274
|
|
1275 なんか #ifdef / #if がないとだめだな。実装する?
|
|
1276 しました。
|
|
1277
|
|
1278 Tue Feb 4 01:04:12 JST 2003
|
|
1279
|
|
1280 ## while ((*chptr++ = c = getc(filep->fcb)) != '\n') {
|
|
1281 _1120:
|
|
1282 movl $10,%eax
|
|
1283 movl $8,%ecx
|
|
1284 movl filep,%edx
|
|
1285 addl %ecx,%edx
|
|
1286 movl (%edx),%edx
|
|
1287 pushl %edx
|
|
1288 xchg %edx,%eax .... edx に$10が入る (なんでxchg?)
|
|
1289 call getc
|
|
1290 addl $4,%esp
|
|
1291 movl %eax,-20(%ebp) c に代入
|
|
1292 movl $chptr,%ecx
|
|
1293 pushl %ecx
|
|
1294 popl %ebx
|
|
1295 movl (%ebx),%ecx ecx にchptrの中身
|
|
1296 addl $1,(%ebx)
|
|
1297 movb %al,(%ecx)
|
|
1298 subl %edx,%eax eax-edx ($10)
|
|
1299 je _1119
|
|
1300
|
|
1301 が壊れる理由なんだけど...
|
|
1302
|
|
1303 edx,ecx が破壊されちゃうみたいね。
|
|
1304
|
|
1305 Tue Feb 4 12:17:07 JST 2003
|
|
1306
|
|
1307 ようやっと直したよ...
|
|
1308
|
|
1309 use_pointer って、なにもしなくていいんだよね? eax,ebx を避ける
|
|
1310 ってことらしいけど。
|
|
1311
|
|
1312 inline/引数付き #define 欲しくない? 置き換えは、local name stack に積んじゃう。
|
|
1313 展開は function で行う。
|
|
1314
|
|
1315 getch を工夫する必要はあるが。置き換えスタックが必要。
|
|
1316
|
|
1317
|
|
1318 Wed Feb 5 01:16:00 JST 2003
|
|
1319
|
|
1320 大域で定義された struct field が大域変数と重なっていると落ちる。
|
|
1321 そりゃそうだけど。どうするの? (直した記憶があるんだけどなぁ...)
|
|
1322 struct 毎に field 名とoffset/type の組を持てばい良いんだよね。
|
|
1323
|
|
1324 なんだけど、タグ無しの構造体もあるから、型名の方に付ける必要
|
|
1325 もある。というのは、型名のない構造体もあるから。タグ名には、
|
|
1326 一応、リストがついている。なんかに使う必要があったんでしょう
|
|
1327 ね。あ、めんどう。無条件にやっても大域変数名を汚すのを直すの
|
|
1328 が難しい。
|
|
1329
|
|
1330 ちょっと、あれだけど、「型名.フィールド名」で登録してしまうのはどう?
|
|
1331 型名が後で出て来るところが気まずいが...
|
|
1332
|
|
1333 def で登録するときに、nptrにdispを代入せずに、struct field list
|
|
1334 (大域変数) に入れて、type の方に、field list (list3(nptr,offset,
|
|
1335 type)) を入れれば良い。
|
|
1336
|
|
1337 あとは、strop の方でtypeのlistを見るようにすれば良いわけだ。
|
|
1338
|
|
1339 これなら、簡単に直せるはず。LUSTR/GUSTRなどの区別もなくなるし。
|
|
1340
|
|
1341 Wed Feb 5 02:10:14 JST 2003
|
|
1342
|
|
1343 浮動小数点ねぇ。完全なANSI Cにするのは大変。でも、
|
|
1344 浮動小数点ぐらいないと。
|
|
1345
|
|
1346 code generation part を、さらに分割して、
|
|
1347 複数のコード対応にしやすいようにする。
|
|
1348 おそらく、それほど共有する部分はないけどね。
|
|
1349
|
|
1350 Sample C code をコンパイルして、その結果から(半分手動で)
|
|
1351 Micro CbC code generation part を生成する方法を用意する。
|
|
1352
|
|
1353
|
|
1354
|
|
1355 Thu Feb 6 11:47:03 JST 2003
|
|
1356
|
|
1357 Code Segement を単位として使うときに、大域変数はどういう
|
|
1358 ように分けるの? static なんかは意味ないよね。
|
|
1359
|
|
1360 もちろん、自然にグループ分けされるわけだけど。
|
|
1361
|
|
1362 あとデータフローだよね。データフローに関しては、
|
|
1363 あんまりやってないなぁ
|
|
1364
|
|
1365 Fri Feb 7 14:36:15 JST 2003
|
|
1366
|
|
1367 inline では、必らず、局所変数の増加がある。また、inline
|
|
1368 は普通の関数として展開しておく必要もあるらしい。(何故?)
|
|
1369
|
|
1370 #define ねぇ。
|
|
1371
|
|
1372 #define c(a,b) g(a+1,b+1)
|
|
1373 #define g(a,b) printf("%d %d\n",a+1,b+1);
|
|
1374
|
|
1375 main() {
|
|
1376 int a,b;
|
|
1377 a =1; b = 3;
|
|
1378 c(a,b);
|
|
1379 }
|
|
1380
|
|
1381 local #define がいるんだよね。g の中で a が出て来た時には、
|
|
1382 c のa の置き換えは起こってはいけない。ということは、c
|
|
1383 の置き換えはg が始まる前に終っている必要がある。dynamic
|
|
1384 scope なんだから、assoc の上乗せで良いはず。
|
|
1385 macro のlevelを定義して、あるレベルでは、それ以前の展開
|
|
1386 を行わないという手法が良いかな。
|
|
1387
|
|
1388 c(a,b) => a=>"a+1", b=>"b+1"
|
|
1389 g(a,b) => (a=>"a+1+1",a=>"a+1"), (b=>"b+1+1",a=>"a+1")
|
|
1390
|
|
1391 みたいな感じ?
|
|
1392
|
|
1393 やっぱり関数解析でマクロ処理をやらせるのは無理かな? 先読みされちゃうし。
|
|
1394
|
|
1395 Sat Feb 8 00:53:52 JST 2003
|
|
1396
|
|
1397 macro は途中まで書きました。置き換えをマクロが呼び出された
|
|
1398 時点で cheap に置くと、それを解消するタイミングがない。
|
|
1399 ここだけmallocしても良いが..
|
|
1400
|
|
1401 chptrsave はlistにする必要がある。list で良い。
|
|
1402
|
|
1403 やっぱりmacro levelを見て、自分と一致したassoc valueまで
|
|
1404 手繰って置換するんでしょう。そうすれば、置き換える必要は無い。
|
|
1405 ということは、local_define にmflagsを格納する必要がある。
|
|
1406
|
|
1407 c(a,b) => a=>"a", b=>"b"
|
|
1408 a=>"a" .. mflag == 1
|
|
1409 g(a,b) => (a=>"a+1+1",a=>"a+1"), (b=>"b+1+1",a=>"a+1")
|
|
1410 a=>"a+1" .. mflag == 2
|
|
1411
|
|
1412 macro のもとのnptr が残ってないと、オリジナルを返せない。オ
|
|
1413 リジナルは、sc などが破壊されてしまう。ってことは、local macro
|
|
1414 は、local table を汚してはいけないってことだよね。ってことは、
|
|
1415 macro table は、もとのとは別に用意する必要がある。
|
|
1416
|
|
1417 #define c(a,b) g(a+1,b+1)
|
|
1418 #define g(a,b) printf("%d %d\n",a+2,b+2);
|
|
1419
|
|
1420 main() {
|
|
1421 int a,b; a ... local
|
|
1422 a =1; b = 3;
|
|
1423 #ifndef a
|
|
1424 c(a, a = "a".. macro mflag==1
|
|
1425 g(a,
|
|
1426 a="a+1" mflag==2
|
|
1427 ^ a = "a" mflag==1
|
|
1428 While replacing a in g's body, a should not
|
|
1429 be replaced to (original) "a", should be c's a.
|
|
1430 b);
|
|
1431 /* 3,5 expected */
|
|
1432 #endif
|
|
1433 }
|
|
1434
|
|
1435 うーむ。ややこしい。
|
|
1436
|
|
1437 main()
|
|
1438 c(a,b) mflag++
|
|
1439 a=>"a" mflag ==1
|
|
1440 g(a,b) mflag++;
|
|
1441 a=>"a+1" mflag ==2
|
|
1442 ^ is replaced by c's "a" not g's a;
|
|
1443 いったん mflag level n で展開したら、それは mflag level n-1 となる。
|
|
1444
|
|
1445 Sat Feb 8 18:13:43 JST 2003
|
|
1446
|
|
1447 いちおう、mflag まではデバッグしたが.... mflag を戻してないんじゃないの?
|
|
1448
|
|
1449 ---c(a,b)----------------------- mflag ==1
|
|
1450 a=>hoge, b=>hoga (mflag==1)
|
|
1451 ----g(ac,bc)----------------- mflag ==2
|
|
1452 ac=>goge, bc=>goga(mflag==2)
|
|
1453 ----printf(a,b)---------- mflag ==3
|
|
1454 a=>poge, b=>poga(mflag==3)
|
|
1455
|
|
1456 g が呼び出されると、ac,bc は mflag==1 でのみ置換される。
|
|
1457
|
|
1458 あるテキストを置き換えると、それは置き換えたマクロのmflag level
|
|
1459 (つまり一つ少ないレベル)になる。
|
|
1460 置き換え終ったら、元のlevelに戻す。
|
|
1461
|
|
1462 mflag==2のlevel では、mflag==2のlocal macroの展開しかしない。
|
|
1463
|
|
1464 置き換えると、mflag level 1 になるので、そこで mflag==1 のlocal
|
|
1465 macro を展開する。mflag==0 は常に展開を行う。
|
|
1466
|
|
1467 Sun Feb 9 11:35:23 JST 2003
|
|
1468
|
|
1469 うーん、なんかtypeが、list とCHARなどと入混じっているじゃん。
|
|
1470 int save = chptrsave;
|
|
1471 で、chptrsave が、$chptrsave になってしまう。
|
|
1472
|
|
1473 Sun Feb 9 22:33:36 JST 2003
|
|
1474
|
|
1475
|
|
1476 #define car(e) (heap[(int)(e)])
|
|
1477 #define cadr(e) (heap[((int)(e))+1])
|
|
1478 car(cadr(e))
|
|
1479
|
|
1480 だろ。
|
|
1481 car ->
|
|
1482 #define e cadr(e) (mleve=1)
|
|
1483 cadr ->
|
|
1484 #define e e (mleve=2)
|
|
1485
|
|
1486 むぅ。これ、うまくいかないんじゃん。こまったなぁ。
|
|
1487
|
|
1488 #define c(a,b) g(a+1,b+1)
|
|
1489 #define g(a,b) printf("%d %d\n",a+1,b+1);
|
|
1490 c(a, b);
|
|
1491
|
|
1492 こっちもだめじゃん。ふーむ。lisp interpreter のように
|
|
1493 作ればいいはずなんだけど。
|
|
1494
|
|
1495 Mon Feb 10 08:10:25 JST 2003
|
|
1496
|
|
1497 結局、list base のinterpreter を実装しました。きちゃないが。
|
|
1498 前の方法でも、頑張ればできるんでしょうけどね。
|
|
1499
|
|
1500 Tue Feb 11 13:50:03 JST 2003
|
|
1501
|
|
1502 struct copy だけど... 関数がstructを返すときに、引数に前もって
|
|
1503 積んでおくのでは、そこに値がコピーされてしまうし、あとで、
|
|
1504 スタックをたたんで置くときにきまずい。
|
|
1505
|
|
1506 function call の時に、引数の型のチェックをしてない
|
|
1507
|
|
1508 type に -1 とheapの引数が混在しているやつだけど..
|
|
1509 やっぱまずいんじゃないか?
|
|
1510
|
|
1511 temproal struct は再利用できるんだけど、dispの変更ができないので
|
|
1512 新しく作るしかない。大きいときだけ新しく作るなんていうセコイ
|
|
1513 技はあるけど。(そうすると、帰って来た値へのポインタを使えなく
|
|
1514 なるが.... 別にいいよね。戻り値それ自身を直接 return する
|
|
1515 時もだいじょうぶなはず)
|
|
1516
|
|
1517 結局、呼出側で、領域を確保して引き渡すことにしました。この方法だと、
|
|
1518 代入のときに二度コピーする必要もない。
|
|
1519
|
|
1520 register を使用しているかだけじゃなくて、実際にcreg/dregに
|
|
1521 値があるかどうかを記憶する必要がある。
|
|
1522
|
|
1523 Wed Feb 12 11:09:22 JST 2003
|
|
1524
|
|
1525 それだけどさ... やっぱりアドホックに実現するのは難しいんじゃないの?
|
|
1526
|
|
1527 まぁねぇ。register の場所の確保と、寿命は別だから、それで
|
|
1528 いいんだけど、regs flag だけでなんとかならないのかな。
|
|
1529 こういう変更ははまるが虚しい。
|
|
1530
|
|
1531 Thu Feb 13 18:37:36 JST 2003
|
|
1532
|
|
1533 さて、そろそろ jump にとりかかりますか。
|
|
1534
|
|
1535 構造体の引き渡しのシークエンスに使う局所変数の位置がgccと違う...
|
|
1536
|
|
1537 そろそろ register は構造体にすべきだね。
|
|
1538 struct register {
|
|
1539 int used;
|
|
1540 int valued;
|
|
1541 char *name;
|
|
1542 char *wname;
|
|
1543 char *bname;
|
|
1544 int type; /* register variable or not */
|
|
1545 int number;
|
|
1546 }
|
|
1547 virtual/real は、どうする。
|
|
1548
|
|
1549 Sat Feb 15 14:00:03 JST 2003
|
|
1550
|
|
1551 fdecl_struct を構文的に引数が出現するときに行うと、int *f(int
|
|
1552 a) などで、* の評価が終る前に、int aが評価されしまう。*obj
|
|
1553 のobj を評価し終らないとfのタイプが確定しない。int*f()[] み
|
|
1554 たいな場合があるから。(?) なので、gcc と、そろえるためには、
|
|
1555 arg の先頭で fdecl_struct を行う方法ではだめで、fdecl 中であ
|
|
1556 とから修正する方が良い。
|
|
1557
|
|
1558 fix しようにも引数リストなんて、存在しないじゃん!
|
|
1559
|
|
1560 varargs を実装するのはめんどくさかろう...
|
|
1561
|
|
1562 rvalue(expr(),type) では、expr() のtypeをrvalueに引き渡せな
|
|
1563 い。でも、type を大域変数にすると、rvalueを異なるタイプで呼
|
|
1564 び出すときにtypeを変更する必要がある。このrvalueのtype の扱
|
|
1565 いは、かなりはまったことがあるので、rvalue(int e,int type)の
|
|
1566 方が良いことは確かなんだが...
|
|
1567
|
|
1568 struct_push のregisterの扱いが複雑すぎ。なんか、もっと
|
|
1569 簡単にならないの?
|
|
1570
|
|
1571 Sun Feb 16 07:58:23 JST 2003
|
|
1572
|
|
1573 代入しなくて良いからと言って、ソース
|
|
1574 のリストから除いては、上書きを防げない。
|
|
1575
|
|
1576 Sun Feb 16 22:55:58 JST 2003
|
|
1577
|
|
1578 vdisp ってなんだったんだ?
|
|
1579
|
|
1580 Mon Feb 17 12:35:39 JST 2003
|
|
1581
|
|
1582 並列代入は出来たみたい。代入は小さいものを先にすべきなのか?
|
|
1583 まぁ、できりゃいいんだけど、横に避けるものが大きいのはいや
|
|
1584 だよね。
|
|
1585
|
|
1586 Tue Feb 18 11:56:10 JST 2003
|
|
1587
|
|
1588 overraped 用の emit_copy
|
|
1589 float/double
|
|
1590 long long
|
|
1591
|
|
1592 Tue Feb 18 19:34:31 JST 2003
|
|
1593
|
|
1594 code argument の符号を反転させると、list2(LVAR,offset)
|
|
1595 のoffsetがアドレスの方向と一致しているという前提が
|
|
1596 崩れる。それで、構造体の格納順序がずれてしまう...
|
|
1597
|
|
1598 ということは... def(n) でcodeの時はargumentは、局所変数と同じ
|
|
1599 扱いでマイナス符号で処理した方が良い。
|
|
1600
|
|
1601 できたみたい。でもさ、
|
|
1602
|
|
1603 int main( int ac, char *av[])
|
|
1604 {
|
|
1605 int n;
|
|
1606 goto arg1(0,1,2,3,4,return,environment);
|
|
1607 }
|
|
1608
|
|
1609 って、きっと return 文がないと、文句を
|
|
1610 言われるよね。むむむ。
|
|
1611
|
|
1612 post processing する時にoverrapしてないという保証がない。
|
|
1613
|
|
1614 Wed Feb 19 15:38:55 JST 2003
|
|
1615
|
|
1616 自分自身とのoverrrapを見てないので、
|
|
1617 struct a a,int i
|
|
1618 int i,struct a a
|
|
1619 みたいな時に自分自身を壊してしまう。なので、emit_copy
|
|
1620 が、ちゃんと方向を見て壊さないように処理する必要がある。
|
|
1621
|
75
|
1622 call bcopy でいいじゃん。まね。
|
64
|
1623
|
|
1624 Wed Feb 19 20:42:07 JST 2003
|
|
1625
|
|
1626 楊さんの C2CbC と CbC2C を、micro C に取り込む。各所に、
|
|
1627 conv->func(); を埋め込む。conv は、構造体。
|
|
1628
|
|
1629 conv: original
|
|
1630 c2cbc
|
|
1631 cbc2c
|
|
1632
|
|
1633 とする。なるほど。
|
|
1634
|
|
1635 Thu Feb 20 05:34:58 JST 2003
|
|
1636
|
|
1637 むぅ。code-ia32 で結構はまった。あと、stack のアライメントが
|
|
1638 ずれるみたい。6809では問題にならなかったんだけどね。
|
|
1639 leave で調整するべき。
|
|
1640
|
66
|
1641
|
|
1642 Thu Feb 20 14:42:46 JST 2003
|
|
1643
|
|
1644 c2cbc,cbc2c なんだけど、いったん、構文木にしてから変換すると、
|
|
1645 結構失われる情報があるけど、いいの? 特に局所変数の名前とか型
|
|
1646 の情報とか。macro もそうだけど。 indent ぐらい保存できないか
|
|
1647 なぁ。式の途中でfunction callする場合も取り扱う必要があるの
|
|
1648 で、構文木にしてから計算するしかないかな。gexpr の代わりに生
|
|
1649 成するようにするか。そうすると、修正するのは、statement と、
|
|
1650 gexpr になる。でも、結局、構文木で型を持ち歩くしかないんじゃ
|
|
1651 ないの? やっぱり変だよ。型の情報がないのは。
|
|
1652
|
|
1653 そうではなくて、exprN() で変換していく方法もある。この方が
|
|
1654 情報が欠落しないので楽だろう。そうすると、修正するのは、
|
|
1655 exprN(),doXXXX()
|
|
1656 となる。これは、量は多い。けど、まぁ、それだけ。この方が
|
|
1657 オリジナルを保存しやすい。
|
|
1658
|
|
1659 中間変数を途中で追加すると、宣言部を前もって出力できなく
|
|
1660 なる。{int a;...} を認めれば良いわけだど。実装は難しくない。
|
|
1661 じゃ、やれば? でも、汚くなるなあ。出力をいったんバッファ
|
|
1662 に貯めれば? どこに? cheapp ですか? 中間変数はいらないん
|
|
1663 じゃないの?
|
|
1664 a = g(i)+a;
|
|
1665 でしょ。
|
|
1666 goto g_1(i,f_1,save_a); }
|
|
1667 code g_1(i,f_1,save_a) { .... goto f_1(ret_value,save_a); }
|
|
1668 code f_1(ret_value,save_a) { a = ret_value+a; ...}
|
|
1669 じゃん。いらないじゃん。。
|
|
1670
|
|
1671
|
|
1672 型を表示するルーチンが必要だね。
|
|
1673
|
|
1674 めんどくさいなぁ。CbCのProlog version とかほしいなぁ。そうすれば、
|
|
1675 変換は簡単。でも、やろうとしてできなかったことでもあるな。
|
|
1676
|
|
1677
|
|
1678 Thu Feb 20 21:13:23 JST 2003
|
|
1679
|
|
1680 MC6809 の mc-codegen.c version は? (ちょっと虚しすぎる?)
|
|
1681 X と D で、use_data_register, use_pointer してやる。
|
|
1682 tosop で、X と D の間の足し算を特別扱いする。
|
|
1683 (なるほど...) MAX_MAX=0でうまく動くのか? やっぱり、1は
|
|
1684 いるよね。できれば、2だよね。
|
|
1685
|
|
1686 結構、浮動小数点も簡単かも。
|
|
1687
|
|
1688 汎用の書き換えツールも便利そう。
|
|
1689
|
|
1690 でも、Prolog version ってのも面白そう。
|
|
1691 code(name,interface(....)) :-
|
|
1692 p()....,goto(name,interface(....)).
|
|
1693 みたいな感じ? 結構、簡単にinterpreterを書けるかも知れない。
|
|
1694 これは、あれだね。thread diagram interpreter と似ている。
|
|
1695
|
|
1696 Fri Feb 21 13:34:17 JST 2003
|
|
1697
|
|
1698 構文要素での書き換えだけど、どれくらいの能力があるの?
|
|
1699 その場での書き換えだけだと、ちょっと低すぎない? それで、
|
|
1700 cbc2c,c2cbc はできるとは思う。
|
|
1701
|
|
1702 まぁいいけど.. chk を無視しているところが結構あるんですけど。
|
|
1703 jmp,enter,leave ...
|
67
|
1704
|
|
1705 Sat Feb 22 13:05:04 JST 2003
|
|
1706
|
|
1707 type の印刷かぁ...
|
|
1708
|
|
1709 conv 系は大半はdefault convが呼ばれる。なので、c.c
|
|
1710 っていうよりは、default.cだよね。必要なところだけ、
|
|
1711 自分で代入すると言う方法が良いだろう。その方が
|
|
1712 ヘッダも一つで済むし。もちろん、object 指向なら
|
|
1713 簡単なんだが...
|
|
1714
|
|
1715
|
|
1716 Sun Feb 23 19:47:41 JST 2003
|
|
1717
|
|
1718 struct のtypeを印刷するんだけど、一回印刷したら、あとは印刷
|
|
1719 しない方が良い。逆に毎回書くなら、tag名type名は、いらないの
|
|
1720 か。
|
|
1721
|
|
1722 とするとtypeの解釈はやめてndeclで処理する? 印刷では、それで
|
|
1723 いいわけだけど。
|
|
1724
|
|
1725 このタイプの印刷だと再帰型は印刷が終了しないんじゃないか?
|
|
1726 しないね。
|
69
|
1727
|
|
1728 Mon Feb 24 02:31:06 JST 2003
|
|
1729
|
|
1730 strings の\nなどを元に戻す必要がある。
|
|
1731
|
|
1732 なんか括弧がわやになってるな。
|
70
|
1733
|
|
1734 Mon Feb 24 11:02:07 JST 2003
|
|
1735
|
73
|
1736 typedef されたタイプは、そちらを使う方が良い。けど、情報が失
|
|
1737 われてしまっているので、どこかにとっておかないとだめだね。dsp
|
|
1738 ?
|
70
|
1739
|
73
|
1740 うーむ、これはなかなか難しい。全サーチしてもいいんじゃないか
|
|
1741 な。遅いけど。少なくともgnptrで定義されたものはサーチすべき
|
|
1742 でしょう。
|
72
|
1743
|
|
1744 indirect function type の表現がなぁ....
|
|
1745
|
73
|
1746 sdecl ではconv を行うので、type_print ではsdeclを経由した場
|
|
1747 合に表示を行ってはいけない。
|
72
|
1748
|
73
|
1749 なんか関数の引数の型の値が微妙に変わるんですけど... やだなぁ...
|
75
|
1750
|
|
1751 まだ、関数定義のtypedefがstructに変わってしまう。gtypedefed
|
|
1752 がうまく動いていない?
|
|
1753
|
|
1754 Mon Feb 24 17:24:31 JST 2003
|
|
1755
|
|
1756 まぁねぇ。やっぱり完全に構文木から再構成した方が
|
|
1757 便利ではあるよね。特に getsym (空白など)と conv->x_()
|
|
1758 との総合作用はめんどくさい。
|
|
1759
|
|
1760 そのためには、局所変数名をtree上で持ち歩く必要がある。
|
|
1761 まぁ、そうすれば良いだけだけど。
|
|
1762
|
|
1763 実際、今のセットで出来るかどうかは、ちょっと怪しい。
|
|
1764 たぶん、buffer に出力するってのをいれればおそらくは
|
|
1765 変換できるだろう。
|
|
1766
|
76
|
1767 式の途中での呼び出しとかを考えると、やっぱり
|
|
1768 構文式から生成しないとだめだろうね。
|
|
1769 (ってことは、まだ、かなりの作業があるってこと.... むぅ...)
|
|
1770 tmp2.c は、通らないし...
|
78
|
1771
|
|
1772 Fri Feb 28 20:32:46 JST 2003
|
|
1773
|
|
1774 で、c2cbc は、途中で float の方を先にやるわけ?
|
|
1775
|
|
1776 Sat Mar 1 22:05:43 JST 2003
|
|
1777
|
|
1778 creg_destroy は、ぜんぜんだめ。これは基本的なアイデアがだめ。
|
|
1779
|
|
1780 long long はstructでいいんじゃない? だめ? で struct 演算を別に
|
|
1781 定義してやる。これは、実装にもよるか。
|
|
1782
|
|
1783 float,long longなんだけど、
|
|
1784 FRGVAR DRGVAR LRGVAR
|
|
1785 などを作る。さらに、
|
|
1786 FMUL DMUL LMUL
|
|
1787 などもいる。型の変換は binop で解釈する。変換も演算になる。
|
|
1788 D2F, D2I, F2D, F2I, I2D, I2F, U2D, U2F
|
|
1789 ぐらいですか?
|
|
1790
|
|
1791 emit_pushは、型を必要とするけど? そうだねぇ。emit_fpush, emit_dpush
|
|
1792 かな?
|
|
1793
|
|
1794 creg にfloat register(or stack) の値を入れればいいんじゃないの?
|
|
1795 それを見て、emit_pushの型を決める。creg は、けっこう、いろんあ
|
|
1796 ものが見ているので、いじらない方がいいじゃないかなぁ。
|
|
1797 そうね。FMULとかがあるなら、それで判断できそう。
|
|
1798
|
|
1799 構文木には型を含めないってのは不便。型を入れれば? そうすれば、
|
|
1800 RGVAR CRGVAR FRGVAR DRGVAR LRGVAR
|
|
1801 ではなく、
|
|
1802 RGVAR
|
|
1803 ですむし。その方が変形も楽だしね。型は、
|
|
1804 CHAR,UNSIGNED, UNSIGNED CHAR, INT, FLOAT, DOUBLE, LONGLONG
|
|
1805 ぐらいですか。
|
|
1806
|
|
1807 emit_data
|
|
1808
|
|
1809 とすると、書き換えが結構あるけど。
|
|
1810
|
|
1811 Sun Mar 2 12:58:38 JST 2003
|
|
1812
|
|
1813 あとはconstantだね。FCONT,DCONSTかな。binopでは
|
|
1814 変換とかも必要なわけだけど。
|
|
1815
|
|
1816 そういえば、shot のload/storeもないね。SRGVAR,SASSとかですか? SASS
|
|
1817 は、すでにあるなぁ。
|
|
1818
|
|
1819 Sun Mar 2 22:01:58 JST 2003
|
|
1820
|
|
1821 あれ?
|
|
1822 conv->_sm();
|
|
1823 (*conv->_sm)();
|
|
1824 の場合は、
|
|
1825 *conv->_sm の値へcallする
|
|
1826 んだけど、
|
|
1827 goto exit1();
|
|
1828 goto (*exit1)();
|
|
1829 の場合は、
|
|
1830 exit1
|
|
1831 の値へjumpするんだよね? およ? なんか勘違いしてる? なんでexit1()
|
|
1832 だとindirectが出て、(*exit1)だと出ないんだろう?
|
|
1833
|
|
1834 この宣言は、
|
|
1835 void (*_sm)();
|
|
1836 であって、
|
|
1837 void _sm();
|
|
1838 はできない? なんで?
|
|
1839
|
|
1840 あぁ、まぁ、いろいろ、めんどくさい。
|
79
|
1841
|
|
1842 やっぱり、arglist の再帰的扱いがちゃんとしてないとだめ。
|
81
|
1843
|
|
1844 うーむ、 enum なんてのもあるのね。やさしいけど、いるのか?
|
|
1845
|
|
1846 code (code *) * みたいなのがあるので、conv は手直しが必要。
|
|
1847
|
|
1848 Mon Mar 3 12:38:08 JST 2003
|
|
1849
|
|
1850 float/duble は順調に進んでるけど、3日はかかるでしょう。
|
|
1851
|
|
1852 binop を書いちゃうとmc-parse.c は、ほとんど終り?!
|
|
1853 代入と関数呼び出しが残っているか。あと single もあるね。
|
|
1854
|
|
1855 emit_push base で書くんだけど、他のCPUではだいぶ様相が
|
|
1856 違うんだろうな。
|
|
1857
|
|
1858 dreg/creg のfloating versionが必要です。( です? )
|
82
|
1859
|
|
1860 Tue Mar 4 14:56:28 JST 2003
|
|
1861
|
|
1862 double のcurrent register は387のスタックを使う。(?)
|
|
1863 関数呼び出し時に387のスタックが保存されるという
|
|
1864 保証は無いので、emit_dpushでは、%esp に保存する。
|
|
1865
|
|
1866 でも、そうすると、代入の後などで387のスタックが
|
|
1867 常に残ることになる。こいつをクリアするコードは
|
|
1868 どこにいれる? free_register でもいいんだけど....
|
|
1869 ううーむ、つかいずらいやつ。ld じゃなくて、
|
|
1870 stack top に代入するオペレーションはないの?
|
|
1871
|
|
1872 (あぁ、でも、なんか、floatは、もうすぐ終っちゃうな... なんか、
|
|
1873 さびし...)
|
|
1874
|
|
1875 Tue Mar 4 23:58:07 JST 2003
|
|
1876
|
|
1877 fmulp とかでは、fpp のstackのつじつまはあう。fstl とかだと、
|
|
1878 合わない。fstpl すればいいんだが、そうすると連続代入でまずくなる。
|
|
1879 値を使うかどうかを代入時に知ることができれば良いんだが。
|
85
|
1880 (use flag で判断することにした)
|
82
|
1881
|
|
1882 結局、freg は、使わなかったね。0が、入っているので直さないとまずいか。
|
|
1883 fregを見て、stack を直すってのは、やっぱり、まずいよな...
|
|
1884
|
|
1885 でも、浮動小数点レジスタを持つCPUの場合はいるんじゃないの?
|
|
1886
|
85
|
1887 Wed Mar 5 11:25:11 JST 2003
|
|
1888
|
|
1889 printf では 引数はdoubleで統一する必要がある。goto() では、
|
|
1890 それをするのはまずい。局所変数と同等だから。ってことは、
|
|
1891
|
|
1892 関数の引数はdoubleにしないとだめなのね。プロトタイプが
|
|
1893 ある時は、その限りでない。(うーむ...)
|
|
1894
|
87
|
1895 (くそ、こいつの副作用が結構出るな...)
|
|
1896
|
85
|
1897 あと、fpp のスタックに頼っているので、overflowした時に
|
|
1898 困らないか? ほとんどの場合でだいじょうぶだが、だめだった
|
|
1899 時にerrorぐらい出せば? でも実行時にしかわからないか...
|
|
1900
|
|
1901 I2D でさ、singned/unsigned の区別がいるね。
|
|
1902
|
|
1903 やっぱり FCONST いるんじゃないの?
|
87
|
1904
|
|
1905 Wed Mar 5 19:51:59 JST 2003
|
|
1906
|
|
1907 副作用以外は終ったけど.... あと、name space が結構重なっている
|
|
1908 んだよね。
|
|
1909 struct tag, struct field
|
|
1910 が重なっているのは結構うっとうしい。gsearc/lsearch のあたりも
|
|
1911 書き直さないとだめかも。
|
|
1912
|
|
1913 あと、list もなぁ。mode の作り方にもよるんでしょうけど。
|
|
1914
|
|
1915 あと、結構、汚いよな...
|
88
|
1916
|
|
1917 Wed Mar 5 21:15:34 JST 2003
|
|
1918
|
|
1919 できたよ。まだ、テストしてない部分はあるけど。局所変数の初期化とか。
|
|
1920 FCONST とか。3日で出来たね。
|
|
1921
|
|
1922 (gcc の方をやった方がいいかなぁ...)
|
89
|
1923 goto.c が通らなくなってるな。
|
|
1924
|
|
1925 Thu Mar 6 14:00:13 JST 2003
|
|
1926
|
|
1927 PowerPCのnon-lazy pointerって、テーブルに入っていてそれを読
|
|
1928 み込む形式なのね。いったん、レジスタに読み込んだら、それを再
|
|
1929 利用する形が良いらしい。ということは、code_gvar にキャッシュ
|
|
1930 を作らないといけない。しかも RLU ですか? (めんどくさ〜)
|
|
1931 でも、そうしないと、
|
|
1932 i = i+1;
|
|
1933 なんてのでも、ひどい目にあってしまう。
|
|
1934
|
|
1935 local variable も最初に move mutilple register で大半は
|
|
1936 レジスタに読み込んじゃうみたいね。pointer で参照されると
|
|
1937 困るんでしょうけど。まぁ、31個もあれば、そういうことを
|
|
1938 してもあまり問題ないのかも知れないけど。
|
|
1939
|
|
1940 creg を破壊しない実装にすれば、少しはましになるんじゃない?
|
|
1941 (IA32では、それは難しいけど)
|
|
1942
|
|
1943 Thu Mar 6 20:50:24 JST 2003
|
|
1944
|
|
1945 やっぱり、使った分だけregisterを保存するようなコードに
|
|
1946 なるみたい。one path で、それをするためには、
|
|
1947 .align 2
|
|
1948 _main0__:
|
|
1949 lwz r5,2136(r1)
|
|
1950 addi r1,r1,2128
|
|
1951 lmw r23,-36(r1)
|
|
1952 mtlr r5
|
|
1953 blr
|
|
1954 .align 2
|
|
1955 .globl _main0
|
|
1956 _main0:
|
|
1957 mflr r2
|
|
1958 stmw r30,-8(r1)
|
|
1959 stw r2,8(r1)
|
|
1960 li r11,0
|
|
1961 stwu r1,-480(r1)
|
|
1962 li r2,100
|
|
1963 mtctr r2
|
|
1964 mr r30,r3
|
|
1965 addi r0,r1,64
|
|
1966 mr r9,r0
|
|
1967 b _main0__;
|
|
1968 とかいう感じにするしかないね。
|
|
1969
|
|
1970 あと引数は、レジスタに積むようになっているみたいだけど... r3 から?
|
|
1971
|
|
1972 mflr r31
|
|
1973 li r0,7
|
|
1974 stw r0,56(r1)
|
|
1975
|
|
1976 だから8個まではレジスタに積むみたいね。
|
|
1977 r3-r10 だね。
|
|
1978
|
|
1979 構造体もregisterにコピーされるのか。そして、向う側で受取の
|
|
1980 コピーを行うわけだね。先頭にreturn structへのポインタがあるのも
|
|
1981 同じ。
|
|
1982
|
|
1983 (うう、memcpyしまくりだ...)
|
|
1984
|
|
1985 浮動小数点もレジスタ渡し見たい。f1から。(なるほど)
|
|
1986
|
|
1987 saveFPってのを呼び出して、 f24-f31をsaveするらしい。
|
|
1988 (31-24)*8 数合わないな?
|
|
1989
|
|
1990 pointer のことを考えると、レジスタだとまずいものもある
|
|
1991 わけだけど。アドレスを取られてからで間に合うんじゃない?
|
|
1992 配列などは、もともとだめだし。場所と値(?)は確保するとして。
|
|
1993
|
|
1994 そうか、逆に、r3-r10 は引数でなければ壊しても良いわけか。
|
|
1995 (それでr9とか良く使われているわけか...)
|
|
1996 ということは足りなくなったら、引数をセーブすれば良いわけね。
|
|
1997 (ってことは、LVAR かつ REGISTER っていう状況があるんじゃん...
|
|
1998 まぁ、そうだけどさ...)
|
|
1999 これは get_register がめんどくさそ。
|
|
2000
|
|
2001 どうも、r11-r12 あたりは自由に使っているらしい。
|
|
2002
|
|
2003 引数を作っている途中で関数呼出しするときは、どうするの?
|
|
2004 r30などに移動するのか?
|
|
2005
|
|
2006 なんか知らんけど、in file call name と out file call name が
|
|
2007 違うみたいね。(sigh...) こんなのなんとかなるのかなぁ。
|
|
2008 全部、stub にしておいて、.set で書き換えるという手もあるけど。
|
|
2009
|
|
2010 (さすがに一日ではできないか...)
|
90
|
2011
|
|
2012 なんか整数から浮動小数点への変換はじぶんでやらないとだめなのね。
|
92
|
2013 これはサブルーチンを呼んだ方がましだ。
|
|
2014
|
|
2015 get_register は絶対失敗しないようにできるんじゃないか?
|
|
2016
|
|
2017 label があると、code_base cache はclearしないといけない。
|
|
2018 それを判断するには fwddef をhookする必要があるけど。
|