Mercurial > hg > CbC > old > device
annotate Idea @ 905:df2d5295218f
comment
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 08 Apr 2014 17:30:05 +0900 |
parents | e60c3d8dadd6 |
children |
rev | line source |
---|---|
0 | 1 |
2 Thu Nov 25 17:27:12 JST 1999 | |
3 | |
724 | 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を持ち歩く | |
0 | 21 fp = (struct func_state *)stack |
724 | 22 えっと、どこに代入するの? そういう問題もあるわけね。 |
23 じゃあ、fpは特別? それは気に入らないな。static | |
24 なfpにすれば良いわけね。 | |
0 | 25 |
26 func(void *stack) { | |
27 static struct func_state { | |
28 static struct func_state *fp; | |
29 int local1; | |
30 brahbrah... | |
724 | 31 } func_state; // ここまで hidden |
0 | 32 func_state.fp = (stack -= sizeof(struct func_state)); |
33 } | |
34 | |
724 | 35 func_state をとってくる演算子があった方が良い? そうね。 |
0 | 36 func.state |
724 | 37 ぐらい? |
38 | |
39 fp->local1 みたいなことだけするなら、C と同じになる。 | |
40 | |
41 call する時のargument も、 | |
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する必要があるね。 | |
0 | 52 (--(struct func_state *)stack) = fp; |
53 call callee(&fp->arg,continuation,stack); | |
724 | 54 call しても、戻って来ないから... continuation は一般的にはcode |
55 だから... それは Internal function にするか。 | |
56 | |
57 continuation に一般的にcompileする方法を考えないといけないか。 | |
58 self は必要なわけね? | |
59 | |
60 言語の名前も考えないといかんなぁ。 | |
61 | |
62 C からのコンパイラも書かないといけないのか... | |
0 | 63 |
64 Mon Dec 13 18:53:04 JST 1999 | |
65 | |
724 | 66 compiler based で、内部で partial evaluation できる? |
67 | |
68 func をdatabaseとして扱えないなら、それはできない。 | |
69 | |
70 しかし、状態遷移としては取り扱える。 | |
0 | 71 |
72 func.state | |
73 func.code | |
74 | |
724 | 75 みたいな形にしてpartial evaluationすれば良い |
76 | |
77 でも止まるのか? | |
78 | |
79 textual でない、中間的なコード表現があった方が良い? <-> interpreter? | |
80 | |
81 Prolog ではなんでいけないの? --> Unification が重いから | |
0 | 82 |
83 Sat Nov 27 13:50:41 JST 1999 | |
84 | |
724 | 85 func.state とか作るのだったら、 |
0 | 86 struct { |
87 struct { | |
88 int i; | |
89 } state; | |
90 state *code = { | |
91 i = i+1; | |
92 }; | |
93 } name; | |
724 | 94 みたいな形で、それ自体を構造化すれば? で、代入すると部分評価される。 |
95 代入も可能。なるほど。 | |
0 | 96 *name.code; |
724 | 97 値はあるわけ? 値は &state でしょうね。 |
98 self があれば、 | |
0 | 99 struct { |
100 struct { | |
101 int i; | |
102 } state, | |
103 *code = { | |
104 self->i = self->i+1; | |
105 }; | |
106 } name; | |
724 | 107 かな。self = state だよね。 |
108 | |
109 union の拡張もあわせて議論すると... | |
110 | |
111 Partial evaluator をセマンティクスや実行系にいれておくことは可能か? | |
112 | |
113 byte code とか仮想マシンだったら可能。そうでない場合は? | |
114 | |
115 いずれにせよ、構造体のタグのunique性を修正しないとだめだな。 | |
116 | |
117 ヘッダファイルはどうするの? | |
0 | 118 |
119 Mon Dec 13 18:53:18 JST 1999 | |
120 | |
724 | 121 library との整合性は? |
122 | |
123 exec sequence では、 | |
0 | 124 (--(struct func_state *)stack) = fp; |
125 call callee(&fp->arg); | |
724 | 126 という形でpointerだけ渡すの? それは変だよね。 |
127 | |
128 値渡しにするとすれば、複数の値を渡せたほうが良い。 | |
0 | 129 |
130 func(void *stack) { | |
131 static struct func_state { | |
132 static struct func_state *fp; | |
133 int local1; | |
134 brahbrah... | |
724 | 135 } func_state; // ここまで hidden |
0 | 136 func_state.fp = (stack -= sizeof(struct func_state)); |
137 } | |
138 | |
724 | 139 の引数自体が、構造体であるべき。 |
0 | 140 |
141 func( | |
142 struct void *stack | |
143 ) { | |
144 static struct func_state { | |
145 static struct func_state *fp; | |
146 int local1; | |
147 brahbrah... | |
724 | 148 } func_state; // ここまで hidden |
0 | 149 func_state.fp = (stack -= sizeof(struct func_state)); |
150 } | |
151 | |
724 | 152 で、構造体に register storage を許す。 |
0 | 153 |
154 func( | |
326 | 155 static struct argument { |
0 | 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... | |
724 | 164 } func_state; // ここまで hidden |
0 | 165 func_state.fp = (stack -= sizeof(struct func_state)); |
166 } | |
167 | |
724 | 168 すると、caller の方も、構造体を引数とするのが自然。 |
0 | 169 |
170 call caller( | |
326 | 171 static struct argument { |
0 | 172 register void *stack; |
173 register void *continuation; | |
174 } arg = {a,b}; | |
175 ) | |
176 | |
724 | 177 みたいな。もちろん、この構造体はインタフェースと呼ばれる。 |
178 | |
179 argument は、callee にあった方が良いけど、caller 側にあっても | |
180 良い。register なんかは、そう。 | |
0 | 181 |
182 caller(interface caller_arg = {a,b,c}) | |
724 | 183 みたいなsyntax かな。 |
0 | 184 caller->interface = {a,b,c}; |
185 *caller->code; | |
724 | 186 を、 |
0 | 187 caller(a,b,c); |
724 | 188 と称する。 |
189 | |
190 function には、interface と code と state があることになる。 | |
191 | |
192 state にアクセスする時のlockは? protected state? synchronized state かな? | |
193 もちろん、sequential implementationでは、そんなものはいらない。 | |
0 | 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 | |
724 | 206 int にvoid value を定義する。実装は重くなるけど... |
207 | |
208 serialized の semantics は? | |
209 | |
210 もう少しmicro-Cに近く! | |
211 | |
212 carrying state と static state。 | |
0 | 213 |
214 Mon Dec 13 19:42:41 JST 1999 | |
215 | |
724 | 216 interface に register keyword を使うのは、あまりに |
217 実装よりすぎる。でも、でないと状態にできない? | |
218 そんなことはないか。やっぱりcaller側のstatic 領域に | |
219 直接書き込む? | |
220 | |
221 だとCより遅そう。でも、引数に40個とかかかれたら... | |
0 | 222 |
223 Wed Dec 15 14:09:49 JST 1999 | |
224 | |
724 | 225 C と互換にする? |
326 | 226 goto function(arguments); |
227 goto *continuation(arguments); | |
724 | 228 みたいな感じで。 |
229 | |
230 stackの管理は? どうせ、library との互換はとらないと | |
231 いけないんだから... | |
232 | |
233 local 変数がある場合は stack を動かす。でも、戻す奴がいない。 | |
234 closure 化するか? | |
235 | |
236 return した時の挙動が複雑になる。大域returnするわけだら。 | |
237 | |
238 arguments をstatic 領域にかきこむ方式だと互換性がとれない。 | |
239 stack 上の frame 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 frame pointer 相対に引数にアクセスしてくれれば別だけどね。 | |
250 | |
251 stack に引数を積むのは容認して、goto の場合は、向こう側で | |
252 stack を畳むってのは? ということは、普通の関数と定義の | |
253 方法を変えるってことか。ま、悪くはないか。 | |
254 | |
255 すると、goto のsemantics は、C と互換になる。それを受ける | |
256 方が異なることをする。それは、なんかおかしいな。それに、 | |
257 それだと関数呼び出しが軽くならない... | |
258 | |
259 ということは、やはり、C のcall は、call function で | |
260 実現して、その他の呼び出しは、すべて、goto 扱いに | |
261 する方が正しいだろう。 | |
262 | |
263 問題は、この言語の関数をcallされた時だな。dual entry にして、 | |
264 call の時と、goto の時を区別するか。 | |
0 | 265 func: stack processing |
266 func_goto: normal processing | |
267 ... | |
724 | 268 みたいな感じ。でも、return はないから... |
269 | |
270 このあたりも自分で記述できる言語であるべきだよね。その通り。 | |
271 つまり、C とのstub も自分で記述すると言うことか。 | |
0 | 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 | |
724 | 291 みたいな感じでさ。さっすが、アセンブラ。いまいちreturnが汚いけど。 |
292 まぁ、return はそのままreturnでもいいけどさ。 | |
293 | |
294 あ、これは良いかも知れない。code が複数かけるから。 | |
295 | |
296 state 以外は、consistent state であることを保証しない。ってのは? | |
297 local 変数は使っても良いけど、call/goto の前後で、値を保証しないか... | |
298 | |
299 うーん、だんだん炸裂してるなぁ。 | |
300 | |
301 だから、レジスタに対するマッピングの記述と、そうでない部分の | |
302 記述は分離するべきでしょうね。 | |
303 | |
304 | |
305 全部一辺に実装するわけにはいかないからぁ... | |
0 | 306 |
307 Thu Dec 16 13:44:21 JST 1999 | |
308 | |
724 | 309 lock は状態遷移レベルで実現するのだから、self などを |
310 使ってlockする必要はないはず。 | |
311 | |
312 全体の直列化は、状態遷移レベルで、 | |
0 | 313 lock(storage) -> transition |
724 | 314 みたいな形で記述すれば良い。この当たりを、どのように記述するかは |
315 もう少し先送りしよう。 | |
316 | |
317 | |
318 引数はレジスタ渡しにしよう。長い引数は、呼び出し側の領域への | |
319 ポインタとする。実装を規定しても良い。そうすれば、varargs | |
320 みたいなものはなくなる。だいたい、なんで、そんなものがいるんだろう? | |
321 配列を渡せばいいじゃん。 | |
322 | |
323 なので、引数は一つ(or 二つ)に限るという方法もある。 | |
324 | |
325 とすると、やはり、前もって静的領域や動的領域を確保することは | |
326 できない。 | |
327 | |
328 この言語では動的領域は自分で確保するわけだから、その点は問題ない。 | |
0 | 329 |
330 Thu Dec 16 20:24:55 JST 1999 | |
331 | |
724 | 332 とすると関数呼び出しは、 |
0 | 333 # register save |
334 # set 1st argument in register %eax | |
335 # set 2nd argument in register %ecx | |
326 | 336 # set extra arguments in save area |
0 | 337 # set extra argument pointer in %edx |
338 jmp function | |
724 | 339 という形式になるわけね。second を処理するのはめんどくさいから一つ |
340 にしよう。 | |
341 | |
342 えーと、frame pointer はないけど、コンパイルの手順からすると | |
343 あった方が良い。しかし、frame pointer そのものをstatic | |
344 にとるのはまずい。だから、frame pointer がfirst argument | |
345 ということにする方が正しい。とすると引数は、さらに、その | |
346 後と言うわけか。 | |
326 | 347 f(fp,argument) |
724 | 348 fp を渡すのにさらにargument をレジスタで渡すのはおかしい。おかしいけど、 |
349 ま、良いか。 | |
350 | |
351 return しないなら、return type の定義をとるのは変だな。 | |
352 | |
353 f(fp,arg1,arg2,arg3) とすると、それぞれが決まったレジスタに入って、 | |
354 多い分は配列にあると思われる。ふむふむ... | |
0 | 355 fp->xx |
724 | 356 でアクセスすれば、そのまま局所変数になる。全部、配列で |
357 送っても良い。 | |
0 | 358 |
359 .set label,value | |
360 | |
724 | 361 で as は値をセットするようですね。 |
362 | |
363 関数コールの後は戻って来ないから後始末の心配はしなくてよい。 | |
364 frame pointer を使ったら自分で面倒を見ること。 | |
365 | |
366 だと | |
0 | 367 a = atoi(s); |
724 | 368 みたいなことはできない... |
369 | |
370 普通のCの定義と交じると間違いやすい。 | |
371 | |
372 とすると、struct と同様に、 | |
0 | 373 protocol |
374 code | |
375 interface | |
376 state | |
724 | 377 を用意するわけね。時間あるのかぁ? |
378 | |
379 とりあえず、register 渡しのfunction 定義とgoto文を実装する。 | |
0 | 380 |
381 code name(register "%ebp" void *arg) { | |
382 goto name(arg); | |
383 } | |
384 | |
724 | 385 ぐらいかな? で、first argument が必ずregisterにのるようにしないと |
386 いけない。register storage class を入れて、 | |
0 | 387 register "%ebp" void *arg |
724 | 388 とかするわけね。 |
389 | |
390 ってことは、まず、レジスタを実装しないといけないわけね。 | |
391 | |
392 で、stack を使った演算は、一応、そのままにする? それでも動くはず。 | |
393 式の途中でgotoは使えないんだから、それでいいはず。 | |
394 | |
395 で、それから、これを拡張していく。 | |
0 | 396 |
397 interface c { | |
398 register "%ebp" void *arg; | |
399 } | |
400 code name(interface c) { | |
724 | 401 goto name(c.arg); // c. は省略可能 |
0 | 402 } |
403 | |
724 | 404 とかね。さらに、 |
0 | 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 | |
724 | 418 などとするわけか。なんと、これが C と共存するわけね。うーん。 |
0 | 419 |
420 Fri Dec 31 11:44:03 JST 1999 | |
421 | |
724 | 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 もう少し拡張しやすいコンパイラがいいなぁ。 | |
0 | 440 |
441 code name (c,a) | |
442 struct state *c; struct arg *a; | |
443 { | |
444 goto name(arg); | |
445 } | |
446 | |
724 | 447 local 変数は? この互換性の問題かぁ。 |
448 | |
449 KL/1 を意識して、interface は heap に置くことにしても良い。 | |
450 GC は言語に入れておくべきだが、interfaceは machine independent | |
451 であるべき。だとすれば use/forget みたいものはいるだろう。 | |
452 でも今のところは考える必要はない。 | |
453 | |
454 えーと、 | |
0 | 455 code name (c,a) |
456 struct state *c; struct arg *a; | |
457 { | |
458 int i; | |
459 goto name(arg); | |
460 } | |
724 | 461 の時の一時変数iはどうするの? 基本的にはレジスタ割り当てだけど... |
462 使用させない? んー、大胆な御意見。まぁ、やっぱりheapに割り当てちゃう | |
463 のが簡単か。でも、どうせ抜ける時にはいらなくなるわけだから... | |
464 | |
465 ほんらい、この変数は、次のcallでは必要無くなるのが普通。 | |
466 | |
467 とにかく、レジスタ変数は必要なんでしょう? | |
468 | |
469 だから、GC と合わせて言語を設計すべきだよね。API を規定して、 | |
470 異なるGCを選択できるようにする。 | |
0 | 471 |
472 Sat Jan 1 22:40:22 JST 2000 | |
473 | |
724 | 474 とーにかく、 storage class register を実装しよう。 |
0 | 475 |
476 stmode=REGISTER | |
477 | |
724 | 478 で、local storage とおなじ扱いとする |
479 static register? は、ない。 | |
480 | |
481 symbol table に storage class をたせば? dsp==EXTRN で判定しているから、 | |
482 local 変数が36以上あるとおかしくなるぞ? | |
483 | |
484 sc は GVAR/LVAR だけど、register は LVAR の特殊な奴だから、 | |
485 sc に入れるほうが正しいか... | |
0 | 486 |
487 Sun Jan 2 01:47:17 JST 2000 | |
488 | |
724 | 489 register 変数はできました。けど、register を二つ使うと、 |
490 一杯になってしまうので、REGISTER6 でコンパイルしないと | |
491 結構ひどい。が、register 変数を%esi,%edi に割り当てれば | |
492 いいか。 | |
0 | 493 |
494 Sun Jan 2 04:43:04 JST 2000 | |
495 | |
724 | 496 で、 |
0 | 497 code name (c,a) |
498 struct state *c; struct arg *a; | |
499 { | |
500 goto name(c); | |
501 } | |
724 | 502 の一時変数無しは実装できます。引数は二つまでね。 |
0 | 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 | |
724 | 523 う、すごい。 |
524 | |
525 goto 文がめんどくさい。stack をたたんで、jmp すれば | |
526 よいだけだが.. | |
0 | 527 |
528 Sun Jan 2 11:17:50 JST 2000 | |
529 | |
724 | 530 普通のcallをcontinuation baseにすることができる? |
0 | 531 |
532 Sun Jan 2 20:28:45 JST 2000 | |
533 | |
724 | 534 goto 文だけど、やはり、一度、expr で生成してから、top level |
535 で jump code を生成しよう。 | |
0 | 536 |
537 Tue Jan 4 03:32:55 JST 2000 | |
538 | |
724 | 539 code をtypeにしないと、 |
0 | 540 code *p; |
724 | 541 とか書けないね。 |
0 | 542 int *p(); |
724 | 543 と同じだけどさ。 |
0 | 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 | |
724 | 565 うーん、なんかレジスタにつむ順序が違う |
566 これは、adecl がreverseにつむから。 | |
567 | |
568 code のreturn | |
569 | |
570 やはりcodeはtypeにしないとだめ。 | |
0 | 571 |
572 main() | |
573 { | |
574 goto code1(); | |
575 } | |
576 | |
724 | 577 とかだと、main に戻って来れない。もちろん、code1() 以降で、 |
578 return するわけにはいかない。(main の disp をcode1 は知り得ない) | |
579 goto label をcode1の引数に送れば? | |
0 | 580 |
581 main() | |
582 { | |
583 goto code1(ret); | |
584 ret: | |
585 } | |
586 | |
724 | 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 を許せば、それは解決するが.. | |
0 | 601 |
602 main() | |
603 { | |
604 goto code1(code2); | |
605 code code2() { | |
606 return; | |
607 } | |
608 } | |
609 | |
724 | 610 みたいな感じ。でも、そうするとscope rule を変える必要があるので厳しい。 |
611 ま、悪くはないけどね。 | |
612 | |
613 continuation を明示する方法もある。 | |
0 | 614 |
615 main() | |
616 { | |
617 goto code1(continuation); | |
618 } | |
619 code code1(ret) | |
620 code (*ret)(); | |
621 { | |
622 goto *ret; | |
623 } | |
624 | |
724 | 625 かな? call/cc ? |
626 | |
627 label へのgotoを許すのもいいけど、 | |
628 でも、label を許すと、すごくspaghettiにならない? | |
0 | 629 |
630 | |
631 Tue Jan 4 11:47:24 JST 2000 | |
632 | |
724 | 633 continuation じゃなくて、return keyword を使おう。 |
634 (実際、continuation と少し違うし) | |
635 type が少し変になるけど、まあ良い。 | |
0 | 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 | |
724 | 648 だな。prototype も付けないといけないか。 |
0 | 649 |
650 Tue Jan 4 12:21:44 JST 2000 | |
651 | |
724 | 652 これだとmethodがすべてstatic になってしまう。dynamic なmethod |
653 呼び出しにするには? dispatcher を自分で作ることになる。かなり | |
654 めんどくさいが... | |
0 | 655 |
656 code method(obj,arg) | |
657 { | |
658 } | |
659 | |
724 | 660 か、あるいは、inline にするか... #define のかわりに inline ねぇ。 |
661 これはあとで考えて良い。 | |
0 | 662 |
663 Tue Jan 4 14:22:19 JST 2000 | |
664 | |
724 | 665 main の変数を書き潰すのと、goto (*reg)(123) での値は、 |
666 register 渡しで、current register にのらないので、 | |
667 結局、return label は専用に作る必要がある。 | |
0 | 668 |
669 Tue Jan 4 18:14:07 JST 2000 | |
670 | |
724 | 671 stack を継ぎ足して、呼び出す方式を取れば、call by value |
672 のregister 渡しを制限する必要は無くなる。 | |
673 | |
674 複数の値を返すことも容易だ。 | |
0 | 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 | |
724 | 695 おお?! |
0 | 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 | |
724 | 706 interface は付けよう! というか、 |
0 | 707 goto name(struct {xxxx}) |
724 | 708 みたいな感じで良いわけね。どれをregisterにいれるかと言う問題はあるが。 |
709 | |
710 で、どうやってcallすればいいわけ? emit_pushするかわりにpush | |
711 する? | |
712 | |
713 うう、これでは、だめか。code argument の数が変わると、 | |
714 ebp をいちいち動かすことになる。そこにはold sp があるから | |
715 そいつもコピーする必要がある。 | |
0 | 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 | |
724 | 727 そうか、function からcallする時には、local 変数を書き潰して良い。 |
0 | 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 | |
724 | 747 となる。ということは、pushl %ebp は、間違い。 |
748 | |
749 だけど、%ebp をそのまま使うのは良くない。disp_offset がかかっているから。 | |
750 だから、もう一度 pushl %ebp したほうがよい。しかし、push する先は、 | |
751 上の、(*)。 | |
0 | 752 leave movl %ebp,%esp |
753 popl %ebp | |
724 | 754 じゃなかったか? |
0 | 755 |
756 Thu Jan 6 13:00:33 JST 2000 | |
757 | |
724 | 758 できたね。これでとりあえず動くはず。速度は問題だが... |
759 あとは、 | |
0 | 760 ANSI-C prototype |
761 ANSI-C prototype check | |
762 Interface Definietion | |
763 GC support | |
764 Direct handling of Frame | |
724 | 765 だね。簡単に出来そう? たぶん... |
0 | 766 |
767 Fri Jan 7 09:42:53 JST 2000 | |
768 | |
724 | 769 goto 文が動いてなかった。あと peep hole optimization version も |
770 作るか? | |
771 | |
772 continuation として label を送れるようにするべきか? | |
773 そうすると便利なんだけど、ちょっと、汚いプログラムが | |
774 出来るようになる。あと、送り側の環境(frame)を維持する | |
775 必要がある。ま、できなくはないか... | |
776 | |
777 そうすると、label が値を持つようになる。 | |
0 | 778 a = label:; |
724 | 779 とか。うーん。label:(a,b,c) {}; みたいな形で、parallel 代入を許すと言う |
780 手もあるね。 | |
781 | |
782 こちらの方がCとの相性は良いが... main() { label:(){ ... } } | |
783 みたいなnestを許すかどうかと言う問題がある。 | |
784 変数の参照を許さなければ、特に問題はない。 | |
785 | |
786 a = label: は、二重の意味があるなぁ。 | |
787 | |
788 言語の名前。DinnerBell II とか? join も入れる? | |
0 | 789 code entry_a().entry_b() {} |
724 | 790 ですか? parallel call も? |
0 | 791 |
792 Fri Jan 7 19:53:53 JST 2000 | |
793 | |
724 | 794 いまのままだと return が環境を持ってないから、大域脱出できない。 |
795 まぁ、環境を入れてもいいんだけど、どこに置くかと言う問題が | |
796 あるね。 | |
797 | |
798 そうじゃなくて、return 側で判断するか? | |
326 | 799 return(ID) |
724 | 800 みたいな形でIDで判断する。そうすれば、return 側でID |
801 を見て判断できる。けど... | |
802 | |
803 まぁ、はやり、環境を持って歩く方がいいかなぁ。でも、 | |
804 引き渡しているから、二つ引き渡して、片方を使われたときに、 | |
805 反対側が消えてしまうのはいたいよね。今のままならば、 | |
806 そういうことは起こらない。 | |
807 | |
808 continuation 特有の問題を避けるなら、このままでもいいんだが... | |
809 continuation や環境は、このシステムでは自分で作ることが | |
810 できるからね。 | |
811 | |
812 そうなんだけど.... retlabel や retcont は実はオブジェクト | |
813 全体に一つあれば良い。 | |
814 | |
815 引数を渡すときに、そこに環境へのポインタをいれてやれば良いので、 | |
816 解決は割と簡単だが、そうすると、例の構造体を引数で渡すと言う | |
817 問題を解決する必要がある。 | |
818 | |
819 でも、今の実装ならば、まったく同じ変数の構成ならばコピーは | |
820 実際には起こらないわけだから問題ないはず。特に、それを保証するために、 | |
821 interface を実装する必要がある。 | |
0 | 822 |
823 return -> | |
824 (void *)old bp | |
825 return address | |
826 | |
724 | 827 bp を直接操作できるようにするといいんだけど.... |
0 | 828 |
829 Sat Jan 8 08:49:59 JST 2000 | |
830 | |
724 | 831 今は、code 内ではreturnできないわけだけど。実は、return って、 |
0 | 832 code return0(i) int i; { return(i); } |
724 | 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で明示すれば良いわけだけど。 | |
0 | 848 |
849 code return0(i) int i; { return(i); } | |
850 | |
724 | 851 を許して、そこで、frame pointer を大域あるいは渡した引数と |
852 比較して処理する? | |
0 | 853 code return0(i,env) int i; env *env; { |
854 if (env==self) return(i); | |
855 } | |
724 | 856 あれ? これはおかしいよね。 |
0 | 857 code return0(i,env) int i; env *env; { |
858 if (env!=self) { | |
859 env->return(); | |
860 return(i); | |
861 } | |
862 } | |
724 | 863 も、なんか変だよなぁ。呼び出しと逆順に帰りたいわけだが... |
864 実際、逆順には帰っているわけだよね。 | |
865 | |
866 return の中でこそこそ比較するという技もあるけど。 | |
867 | |
868 問題は、destructor に渡す情報だよね。もちろん、self で良いわけだが、 | |
869 このあたりは、言語外の問題で、それを明示的にしたいから、この言語を | |
870 作っているわけなのだから、これを内部で処理するのはおかしい。 | |
0 | 871 |
872 code return0(i) int i; { return(i); } | |
873 | |
724 | 874 これだと、return の型が合わないと言う問題が生じるな。簡単には |
875 チェックできない。 | |
0 | 876 int |
877 main() { | |
878 code a() { | |
879 } | |
880 code b() { | |
881 return(i); | |
882 } | |
883 } | |
724 | 884 にすれば、check はできるようになる。でも、これだと、 |
0 | 885 int |
886 main() { | |
887 a: { | |
888 } | |
889 b: { | |
890 return(i); | |
891 } | |
892 } | |
724 | 893 と差がない。module 化を言語外でやるというのが主旨なのだから、これでは |
894 まずい。これは高級アセンブラなのだから。 | |
895 | |
896 あそうか、return と、大域脱出時のabortとは、状況が違う。だから、 | |
897 別なcode を呼び出さないとだめ。あるいは、値で区別するか。これは、 | |
898 logic programming のfail/success と似ている。 | |
0 | 899 main() { } abort { ... } |
724 | 900 でもいいけど? |
0 | 901 main() { code abort { ... }; code return { ... }} |
724 | 902 かな? |
903 | |
904 本来、subroutine call自体が、かなりの省略形なわけだから、これは | |
905 仕方がない。今のままで通常のsubroutine callをシミュレートできるのか? | |
0 | 906 code (struct arg {...},void *sp) { |
907 struct env; | |
908 push(sp,arg); | |
909 push(env,arg); | |
910 } | |
724 | 911 できるけど、ちょっと重い。やはり、frame pointer を直接操作しないと |
912 だめ。 | |
913 | |
914 goto 文のほうに、env を一緒に送るものを作ったほうがいいのかも。 | |
0 | 915 goto (*ret)(),environment; |
724 | 916 かな。type は? (void *)? |
0 | 917 goto ret(),environment; |
724 | 918 にはならないの? そうすれば、自分でthreadを制御できる。environment |
919 の正当性を評価しなくて良いの? まぁ、ねぇ。 | |
920 | |
921 これは実装は容易だが... goto といちいち書くのが本当にいいのか? | |
922 env に対するoperationがあった方がいいなぁ。push とか? | |
0 | 923 |
924 code return0(i) int i; { return(i); } | |
925 | |
724 | 926 を認めれば、return 擬変数はいらなくなる。 |
927 | |
928 でも、実は、return は、caller の引数の数と一致してないといけない | |
929 わけだから、 code return0(i) int i; { return(i); } はだめ。env | |
930 と一致してないといけない。ということは分離するとまずいんじゃない? | |
931 あれ? そんなはずないな。 | |
0 | 932 |
933 Sun Jan 9 01:15:56 JST 2000 | |
934 | |
724 | 935 やはり、分離してはまずい。もともと、 |
0 | 936 goto func(arg); |
724 | 937 自体が、 |
0 | 938 goto func(arg) with current.env |
724 | 939 みたいなものだ。つまり、これは、DinnerBell の、 |
0 | 940 self message: arg |
724 | 941 と同じ。self->func(arg); でも良い。が、function callと区別が付かないのは |
942 良くない。 | |
943 | |
944 そうすると、type code はsize int でなくなる。 | |
0 | 945 code *p = func; |
724 | 946 ではいけなくて、 |
0 | 947 code p = {func,env}; |
724 | 948 でないといけない。実際、 |
0 | 949 goto func(arg) |
724 | 950 では、current environment を pushl %ebp でstack = current env |
951 に積んでいるわけだから。 | |
952 | |
953 いずれにせよ、 | |
0 | 954 struct p = q; |
724 | 955 は実装する必要がある。localな、 |
0 | 956 code p = {func,env}; |
724 | 957 も動くはずだが... |
0 | 958 |
959 code (*p)(); | |
960 goto (*p)(arg); | |
961 | |
724 | 962 はだから少しおかしい。これは、goto がenv を補っていると考えるべき。 |
963 | |
964 このようにすると、常に、 | |
0 | 965 func,env |
724 | 966 の組をcodeとみなすことになる。これは、object と呼ぶべきだ。 |
967 ただ、既存のobjectとは別だよな。actor の方が良い? | |
968 | |
969 うーん、これでjoinを入れれば、完璧なDinnerBellだな。並列送信はないけど。 | |
0 | 970 |
971 Sun Jan 9 01:40:05 JST 2000 | |
972 | |
724 | 973 local 変数の初期化はallocation の後に遅らせる必要がある。 |
974 nptr に入れられるはずだよね? nptr に初期化フラグを足すか? | |
975 | |
976 文途中で出現するlocal変数の初期化。ちゃんと動いているの? | |
977 | |
978 構造体のcopyは、lcheck を修正すべきでない。 | |
0 | 979 |
980 Sun Jan 9 08:49:43 JST 2000 | |
981 | |
724 | 982 うーん、なんか修正が多いなぁ。あと、関数呼び出し、goto 文の |
983 構造体への対応か。 | |
0 | 984 |
985 goto (*code)(); | |
986 | |
724 | 987 が、self env を使うのか、code の先の値を使うのかを区別する |
988 必要がある。もし*を使わないとするとlabel(FNAME)との区別が | |
989 つかないぞ。あ、でも、環境を持ち歩くことにしたから、label | |
990 へもjumpしようと思えばできるね。 | |
991 | |
992 並列送信はなくても、この構成ならばstatement単位の並列性を検出するのは | |
993 容易だろう。 | |
994 | |
995 やればできるけど、この修正の量だと1日じゃ終らないかなぁ。 | |
996 不動小数点も入れるのでしょう? | |
0 | 997 |
998 Mon Jan 10 09:00:12 JST 2000 | |
999 | |
724 | 1000 引数に構造体を許すには、必ずANSI-Cにする必要がある。難しくは |
1001 ないが... | |
1002 | |
1003 goto 文には label, code, continuation の3つが来る。 | |
0 | 1004 continuation = code + env |
1005 | label +env | |
724 | 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 一応、できたけど、やっぱり汚い。 | |
0 | 1026 |
1027 Wed Jan 12 16:12:27 JST 2000 | |
1028 | |
724 | 1029 あは。ANSI prototype はめんどい。 |
0 | 1030 bexpr() |
724 | 1031 で、関数での引数の順序と、そのあとの宣言の順序が変わることがある。 |
1032 そうすると、うしろの方が優先されてしまう。これは、こまる。 | |
1033 | |
1034 そうか、code_arg_offset のような方法だと、ANSI style では、 | |
1035 困ってしまう。 | |
6 | 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 | |
724 | 1061 だいたいできたけど、test/tmp7.c のprintf のtype mismatch は |
1062 なんなんだろう? ASNI の副作用だろうなぁ。 | |
1063 | |
1064 これだと、プロセスの切替えのときには、結構な量のデータを | |
1065 コピーすることになる。それでもいいんだけど... | |
1066 | |
1067 それごと、どっかにとって置く。continuationへの参照みたいなもの | |
1068 ができないかな。 | |
1069 | |
1070 コピーができれば、environment/return の組は動くわけだから、 | |
1071 それへの参照と切替えがあっても良いよね。 | |
7 | 1072 |
8 | 1073 Fri Jan 14 12:03:35 JST 2000 |
1074 | |
724 | 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 を用意すると良いね。 | |
16 | 1089 |
1090 Mon Jan 17 15:23:34 JST 2000 | |
1091 | |
1092 struct aa f1() { | |
1093 return bb; | |
1094 } | |
1095 | |
724 | 1096 みたいなのは? 関数の型か代入の型を見て、crn にpointerを渡して、 |
1097 あとでcopyしてから stack を畳む。 | |
16 | 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 | |
724 | 1110 あ、でも、それだと、local変数を返したときに困るね。leave; ret; |
1111 してはいけなくて... | |
1112 | |
1113 あ、やっぱり、こういう場合はコピー先をmain2に引き渡しているみたいね。 | |
16 | 1114 void f1(struct aa *ret) { |
1115 *ret = bb ; | |
1116 return; | |
1117 } | |
724 | 1118 と同じか。これは簡単。 |
16 | 1119 f1().a[55] |
724 | 1120 みたいな場合は、局所変数に強制的に取ってしまうみたいね。それはそうだ... |
1121 が、うちの実装だとちょっと厳しいか。 | |
16 | 1122 leal $-sizeof(struct),%esp |
1123 pushl %esp | |
724 | 1124 なんだけど、関数呼び出しの途中ではできないから.... |
16 | 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 | |
724 | 1147 このsublを後から指定してやればOk。 |
1148 | |
1149 でも、それだと jump の時にずれない? ずれるか? ずれるね。うーん。 | |
1150 実行時にチェックしてやるのも変だし。 | |
1151 | |
1152 まぁ、それほど必要な機能ではないんだけど。 | |
1153 | |
1154 これもcontinuationを渡してやると言う手法が使えないことはないんだが... | |
1155 | |
1156 関数呼び出しの最初にやってやればいいか。それでできるかな? | |
18 | 1157 |
1158 | |
51 | 1159 Sun Feb 20 23:59:16 JST 2000 |
1160 | |
724 | 1161 MIPS のcall frame |
51 | 1162 |
1163 $sp = $fp | |
1164 local variables | |
1165 saved register (including $31 = return address) | |
1166 | |
724 | 1167 mask は使用したレジスタのbit pattern |
1168 -4 は何? | |
51 | 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 | |
724 | 1194 これと同じようにするならば、regiterの使用数を最初に調べる必要が |
1195 あるのだけど、one path compiler である micro-C では、それは | |
1196 できない。したがって、enter は後ろでする方が良い。 | |
18 | 1197 Mon Jan 20 18:25:27 JST 2003 |
1198 | |
724 | 1199 3年間さわってないのかよ。何やってんだ? |
1200 | |
1201 goto 文のバグをとらないといけない。 | |
1202 | |
1203 まず、関数引数の構造体の展開。これは、どうってことないはず。 | |
18 | 1204 |
1205 goto (*code)(i+1,j,...) | |
1206 | |
724 | 1207 まず、いじらなくてすむ変数を摘出する。 |
18 | 1208 |
1209 foreach arg | |
1210 compare | |
1211 | |
724 | 1212 単純演算 ( op+const , pointer , const assign ) などは、ここで検出する。 |
1213 大半は、そのようになるはず。 | |
1214 レジスタに乗せる分があるから... それには触らないとして... | |
1215 | |
1216 複雑なものは、前もって計算しておく。(get_register する) | |
1217 スタック上かレジスタ上に作る。 | |
1218 | |
1219 残りは並列代入となる。再帰的に計算する。 | |
1220 | |
1221 えーと、大きな順にやるんだっけ? 小さな順にやるんだっけ? | |
18 | 1222 code f( int a, int b, int c ) { |
1223 goto g(b,c,a); | |
1224 } | |
724 | 1225 みたいなやつだよね。 |
1226 | |
1227 移動するものを一つ検出する。 | |
1228 そのために移動が必要なものを移動しておく(再帰) | |
1229 代入する | |
1230 | |
1231 こんなんでいいのか? ループしない? するよね。ループしたら | |
1232 get_register する。 | |
1233 | |
1234 前の例だと、 | |
1235 | |
1236 g(b,c,a) のbに着目する。 | |
1237 bに代入するコードを出すと、a が壊れる。 | |
1238 a が必要かどうかを調べる。それは、引数のリストを見ればわかる。 | |
1239 その前に、a を移動する。a の移動先を見て、 | |
1240 空いていれば、移動してOk。しかし、c | |
1241 なので、 c を見る。と b になるので、ループするのがわかるので、 | |
1242 b を get_register する。 | |
1243 で、c が移動できる。で、aを移動して、とっておいたbを代入。 | |
18 | 1244 |
1245 Tue Jan 21 22:45:09 JST 2003 | |
1246 | |
724 | 1247 とりあえず、jump は複雑すぎる。もっと簡単にすることを考える。 |
1248 parser 側である程度処理できない? | |
18 | 1249 |
1250 goto f(a+3,b(),c); | |
1251 | |
724 | 1252 などを、 |
18 | 1253 |
1254 a = a+3; | |
1255 b = b(); | |
1256 goto f(a,b,c); | |
1257 | |
724 | 1258 程度に簡略化する。この時、f(a,b,c) は(できるだけ)、元の |
1259 関数の引数リストに近付ける。のは無理なので、単純変数 | |
1260 まで落す。 | |
1261 | |
1262 あまり関係ないか。一時変数はどうせいるわけだし。ってこと | |
1263 みたいね。 | |
1264 | |
1265 だとすると、元のコードと、そう変わらんね。前のも、そんなに | |
1266 悪くないってことか。 | |
18 | 1267 |
1268 Wed Jan 22 14:33:12 JST 2003 | |
1269 | |
724 | 1270 やっぱり、途中で局所変数を増やしたいよね。 |
18 | 1271 |
1272 Fri Jan 31 20:30:36 JST 2003 | |
1273 | |
724 | 1274 なんか #ifdef / #if がないとだめだな。実装する? |
1275 しました。 | |
23 | 1276 |
1277 Tue Feb 4 01:04:12 JST 2003 | |
1278 | |
1279 ## while ((*chptr++ = c = getc(filep->fcb)) != '\n') { | |
1280 _1120: | |
1281 movl $10,%eax | |
1282 movl $8,%ecx | |
1283 movl filep,%edx | |
1284 addl %ecx,%edx | |
1285 movl (%edx),%edx | |
1286 pushl %edx | |
724 | 1287 xchg %edx,%eax .... edx に$10が入る (なんでxchg?) |
23 | 1288 call getc |
1289 addl $4,%esp | |
724 | 1290 movl %eax,-20(%ebp) c に代入 |
23 | 1291 movl $chptr,%ecx |
1292 pushl %ecx | |
1293 popl %ebx | |
724 | 1294 movl (%ebx),%ecx ecx にchptrの中身 |
23 | 1295 addl $1,(%ebx) |
1296 movb %al,(%ecx) | |
1297 subl %edx,%eax eax-edx ($10) | |
1298 je _1119 | |
1299 | |
724 | 1300 が壊れる理由なんだけど... |
1301 | |
1302 edx,ecx が破壊されちゃうみたいね。 | |
23 | 1303 |
1304 Tue Feb 4 12:17:07 JST 2003 | |
1305 | |
724 | 1306 ようやっと直したよ... |
1307 | |
1308 use_pointer って、なにもしなくていいんだよね? eax,ebx を避ける | |
1309 ってことらしいけど。 | |
1310 | |
1311 inline/引数付き #define 欲しくない? 置き換えは、local name stack に積んじゃう。 | |
1312 展開は function で行う。 | |
1313 | |
1314 getch を工夫する必要はあるが。置き換えスタックが必要。 | |
25 | 1315 |
1316 | |
1317 Wed Feb 5 01:16:00 JST 2003 | |
1318 | |
724 | 1319 大域で定義された struct field が大域変数と重なっていると落ちる。 |
1320 そりゃそうだけど。どうするの? (直した記憶があるんだけどなぁ...) | |
1321 struct 毎に field 名とoffset/type の組を持てばい良いんだよね。 | |
1322 | |
1323 なんだけど、タグ無しの構造体もあるから、型名の方に付ける必要 | |
1324 もある。というのは、型名のない構造体もあるから。タグ名には、 | |
1325 一応、リストがついている。なんかに使う必要があったんでしょう | |
1326 ね。あ、めんどう。無条件にやっても大域変数名を汚すのを直すの | |
1327 が難しい。 | |
1328 | |
1329 ちょっと、あれだけど、「型名.フィールド名」で登録してしまうのはどう? | |
1330 型名が後で出て来るところが気まずいが... | |
1331 | |
1332 def で登録するときに、nptrにdispを代入せずに、struct field list | |
1333 (大域変数) に入れて、type の方に、field list (list3(nptr,offset, | |
1334 type)) を入れれば良い。 | |
1335 | |
1336 あとは、strop の方でtypeのlistを見るようにすれば良いわけだ。 | |
1337 | |
1338 これなら、簡単に直せるはず。LUSTR/GUSTRなどの区別もなくなるし。 | |
25 | 1339 |
1340 Wed Feb 5 02:10:14 JST 2003 | |
1341 | |
724 | 1342 浮動小数点ねぇ。完全なANSI Cにするのは大変。でも、 |
1343 浮動小数点ぐらいないと。 | |
1344 | |
1345 code generation part を、さらに分割して、 | |
1346 複数のコード対応にしやすいようにする。 | |
1347 おそらく、それほど共有する部分はないけどね。 | |
1348 | |
1349 Sample C code をコンパイルして、その結果から(半分手動で) | |
1350 Micro CbC code generation part を生成する方法を用意する。 | |
25 | 1351 |
1352 | |
1353 | |
26 | 1354 Thu Feb 6 11:47:03 JST 2003 |
25 | 1355 |
724 | 1356 Code Segment を単位として使うときに、大域変数はどういう |
1357 ように分けるの? static なんかは意味ないよね。 | |
1358 | |
1359 もちろん、自然にグループ分けされるわけだけど。 | |
1360 | |
1361 あとデータフローだよね。データフローに関しては、 | |
1362 あんまりやってないなぁ | |
26 | 1363 |
28 | 1364 Fri Feb 7 14:36:15 JST 2003 |
1365 | |
724 | 1366 inline では、必らず、局所変数の増加がある。また、inline |
1367 は普通の関数として展開しておく必要もあるらしい。(何故?) | |
1368 | |
1369 #define ねぇ。 | |
28 | 1370 |
1371 #define c(a,b) g(a+1,b+1) | |
1372 #define g(a,b) printf("%d %d\n",a+1,b+1); | |
1373 | |
1374 main() { | |
1375 int a,b; | |
1376 a =1; b = 3; | |
1377 c(a,b); | |
1378 } | |
1379 | |
724 | 1380 local #define がいるんだよね。g の中で a が出て来た時には、 |
1381 c のa の置き換えは起こってはいけない。ということは、c | |
1382 の置き換えはg が始まる前に終っている必要がある。dynamic | |
1383 scope なんだから、assoc の上乗せで良いはず。 | |
1384 macro のlevelを定義して、あるレベルでは、それ以前の展開 | |
1385 を行わないという手法が良いかな。 | |
28 | 1386 |
1387 c(a,b) => a=>"a+1", b=>"b+1" | |
1388 g(a,b) => (a=>"a+1+1",a=>"a+1"), (b=>"b+1+1",a=>"a+1") | |
1389 | |
724 | 1390 みたいな感じ? |
1391 | |
1392 やっぱり関数解析でマクロ処理をやらせるのは無理かな? 先読みされちゃうし。 | |
28 | 1393 |
1394 Sat Feb 8 00:53:52 JST 2003 | |
1395 | |
724 | 1396 macro は途中まで書きました。置き換えをマクロが呼び出された |
1397 時点で cheap に置くと、それを解消するタイミングがない。 | |
1398 ここだけmallocしても良いが.. | |
1399 | |
1400 chptrsave はlistにする必要がある。list で良い。 | |
1401 | |
1402 やっぱりmacro levelを見て、自分と一致したassoc valueまで | |
1403 手繰って置換するんでしょう。そうすれば、置き換える必要は無い。 | |
1404 ということは、local_define にmflagsを格納する必要がある。 | |
29 | 1405 |
1406 c(a,b) => a=>"a", b=>"b" | |
1407 a=>"a" .. mflag == 1 | |
1408 g(a,b) => (a=>"a+1+1",a=>"a+1"), (b=>"b+1+1",a=>"a+1") | |
1409 a=>"a+1" .. mflag == 2 | |
1410 | |
724 | 1411 macro のもとのnptr が残ってないと、オリジナルを返せない。オ |
1412 リジナルは、sc などが破壊されてしまう。ってことは、local macro | |
1413 は、local table を汚してはいけないってことだよね。ってことは、 | |
1414 macro table は、もとのとは別に用意する必要がある。 | |
29 | 1415 |
1416 #define c(a,b) g(a+1,b+1) | |
1417 #define g(a,b) printf("%d %d\n",a+2,b+2); | |
1418 | |
1419 main() { | |
1420 int a,b; a ... local | |
1421 a =1; b = 3; | |
1422 #ifndef a | |
1423 c(a, a = "a".. macro mflag==1 | |
1424 g(a, | |
1425 a="a+1" mflag==2 | |
1426 ^ a = "a" mflag==1 | |
1427 While replacing a in g's body, a should not | |
1428 be replaced to (original) "a", should be c's a. | |
1429 b); | |
1430 /* 3,5 expected */ | |
1431 #endif | |
1432 } | |
1433 | |
724 | 1434 うーむ。ややこしい。 |
29 | 1435 |
1436 main() | |
1437 c(a,b) mflag++ | |
1438 a=>"a" mflag ==1 | |
1439 g(a,b) mflag++; | |
1440 a=>"a+1" mflag ==2 | |
1441 ^ is replaced by c's "a" not g's a; | |
724 | 1442 いったん mflag level n で展開したら、それは mflag level n-1 となる。 |
29 | 1443 |
30 | 1444 Sat Feb 8 18:13:43 JST 2003 |
29 | 1445 |
724 | 1446 いちおう、mflag まではデバッグしたが.... mflag を戻してないんじゃないの? |
29 | 1447 |
31 | 1448 ---c(a,b)----------------------- mflag ==1 |
1449 a=>hoge, b=>hoga (mflag==1) | |
1450 ----g(ac,bc)----------------- mflag ==2 | |
1451 ac=>goge, bc=>goga(mflag==2) | |
1452 ----printf(a,b)---------- mflag ==3 | |
1453 a=>poge, b=>poga(mflag==3) | |
29 | 1454 |
724 | 1455 g が呼び出されると、ac,bc は mflag==1 でのみ置換される。 |
1456 | |
1457 あるテキストを置き換えると、それは置き換えたマクロのmflag level | |
1458 (つまり一つ少ないレベル)になる。 | |
1459 置き換え終ったら、元のlevelに戻す。 | |
1460 | |
1461 mflag==2のlevel では、mflag==2のlocal macroの展開しかしない。 | |
1462 | |
1463 置き換えると、mflag level 1 になるので、そこで mflag==1 のlocal | |
1464 macro を展開する。mflag==0 は常に展開を行う。 | |
31 | 1465 |
32 | 1466 Sun Feb 9 11:35:23 JST 2003 |
31 | 1467 |
724 | 1468 うーん、なんかtypeが、list とCHARなどと入混じっているじゃん。 |
32 | 1469 int save = chptrsave; |
724 | 1470 で、chptrsave が、$chptrsave になってしまう。 |
33 | 1471 |
1472 Sun Feb 9 22:33:36 JST 2003 | |
1473 | |
1474 | |
1475 #define car(e) (heap[(int)(e)]) | |
1476 #define cadr(e) (heap[((int)(e))+1]) | |
1477 car(cadr(e)) | |
1478 | |
724 | 1479 だろ。 |
33 | 1480 car -> |
1481 #define e cadr(e) (mleve=1) | |
1482 cadr -> | |
1483 #define e e (mleve=2) | |
1484 | |
724 | 1485 むぅ。これ、うまくいかないんじゃん。こまったなぁ。 |
33 | 1486 |
1487 #define c(a,b) g(a+1,b+1) | |
1488 #define g(a,b) printf("%d %d\n",a+1,b+1); | |
1489 c(a, b); | |
1490 | |
724 | 1491 こっちもだめじゃん。ふーむ。lisp interpreter のように |
1492 作ればいいはずなんだけど。 | |
36 | 1493 |
1494 Mon Feb 10 08:10:25 JST 2003 | |
1495 | |
724 | 1496 結局、list base のinterpreter を実装しました。きちゃないが。 |
1497 前の方法でも、頑張ればできるんでしょうけどね。 | |
36 | 1498 |
39 | 1499 Tue Feb 11 13:50:03 JST 2003 |
1500 | |
724 | 1501 struct copy だけど... 関数がstructを返すときに、引数に前もって |
1502 積んでおくのでは、そこに値がコピーされてしまうし、あとで、 | |
1503 スタックをたたんで置くときにきまずい。 | |
1504 | |
1505 function call の時に、引数の型のチェックをしてない | |
1506 | |
1507 type に -1 とheapの引数が混在しているやつだけど.. | |
1508 やっぱまずいんじゃないか? | |
1509 | |
1510 temporal struct は再利用できるんだけど、dispの変更ができないので | |
1511 新しく作るしかない。大きいときだけ新しく作るなんていうセコイ | |
1512 技はあるけど。(そうすると、帰って来た値へのポインタを使えなく | |
1513 なるが.... 別にいいよね。戻り値それ自身を直接 return する | |
1514 時もだいじょうぶなはず) | |
1515 | |
1516 結局、呼出側で、領域を確保して引き渡すことにしました。この方法だと、 | |
1517 代入のときに二度コピーする必要もない。 | |
1518 | |
1519 register を使用しているかだけじゃなくて、実際にcreg/dregに | |
1520 値があるかどうかを記憶する必要がある。 | |
42 | 1521 |
1522 Wed Feb 12 11:09:22 JST 2003 | |
1523 | |
724 | 1524 それだけどさ... やっぱりアドホックに実現するのは難しいんじゃないの? |
1525 | |
1526 まぁねぇ。register の場所の確保と、寿命は別だから、それで | |
1527 いいんだけど、regs flag だけでなんとかならないのかな。 | |
1528 こういう変更ははまるが虚しい。 | |
45 | 1529 |
1530 Thu Feb 13 18:37:36 JST 2003 | |
1531 | |
724 | 1532 さて、そろそろ jump にとりかかりますか。 |
1533 | |
1534 構造体の引き渡しのシークエンスに使う局所変数の位置がgccと違う... | |
1535 | |
1536 そろそろ register は構造体にすべきだね。 | |
45 | 1537 struct register { |
1538 int used; | |
1539 int valued; | |
1540 char *name; | |
1541 char *wname; | |
1542 char *bname; | |
1543 int type; /* register variable or not */ | |
1544 int number; | |
1545 } | |
724 | 1546 virtual/real は、どうする。 |
46
b1c8ac8c308d
fix cascading struct retrun. Now it should be compatible with gcc
kono
parents:
45
diff
changeset
|
1547 |
b1c8ac8c308d
fix cascading struct retrun. Now it should be compatible with gcc
kono
parents:
45
diff
changeset
|
1548 Sat Feb 15 14:00:03 JST 2003 |
b1c8ac8c308d
fix cascading struct retrun. Now it should be compatible with gcc
kono
parents:
45
diff
changeset
|
1549 |
724 | 1550 fdecl_struct を構文的に引数が出現するときに行うと、int *f(int |
1551 a) などで、* の評価が終る前に、int aが評価されしまう。*obj | |
1552 のobj を評価し終らないとfのタイプが確定しない。int*f()[] み | |
1553 たいな場合があるから。(?) なので、gcc と、そろえるためには、 | |
1554 arg の先頭で fdecl_struct を行う方法ではだめで、fdecl 中であ | |
1555 とから修正する方が良い。 | |
1556 | |
1557 fix しようにも引数リストなんて、存在しないじゃん! | |
1558 | |
1559 varargs を実装するのはめんどくさかろう... | |
1560 | |
1561 rvalue(expr(),type) では、expr() のtypeをrvalueに引き渡せな | |
1562 い。でも、type を大域変数にすると、rvalueを異なるタイプで呼 | |
1563 び出すときにtypeを変更する必要がある。このrvalueのtype の扱 | |
1564 いは、かなりはまったことがあるので、rvalue(int e,int type)の | |
1565 方が良いことは確かなんだが... | |
1566 | |
1567 struct_push のregisterの扱いが複雑すぎ。なんか、もっと | |
1568 簡単にならないの? | |
51 | 1569 |
1570 Sun Feb 16 07:58:23 JST 2003 | |
1571 | |
724 | 1572 代入しなくて良いからと言って、ソース |
1573 のリストから除いては、上書きを防げない。 | |
52 | 1574 |
1575 Sun Feb 16 22:55:58 JST 2003 | |
1576 | |
724 | 1577 vdisp ってなんだったんだ? |
52 | 1578 |
1579 Mon Feb 17 12:35:39 JST 2003 | |
1580 | |
724 | 1581 並列代入は出来たみたい。代入は小さいものを先にすべきなのか? |
1582 まぁ、できりゃいいんだけど、横に避けるものが大きいのはいや | |
1583 だよね。 | |
53 | 1584 |
1585 Tue Feb 18 11:56:10 JST 2003 | |
1586 | |
724 | 1587 overlapped 用の emit_copy |
53 | 1588 float/double |
1589 long long | |
1590 | |
1591 Tue Feb 18 19:34:31 JST 2003 | |
1592 | |
724 | 1593 code argument の符号を反転させると、list2(LVAR,offset) |
1594 のoffsetがアドレスの方向と一致しているという前提が | |
1595 崩れる。それで、構造体の格納順序がずれてしまう... | |
1596 | |
1597 ということは... def(n) でcodeの時はargumentは、局所変数と同じ | |
1598 扱いでマイナス符号で処理した方が良い。 | |
1599 | |
1600 できたみたい。でもさ、 | |
53 | 1601 |
1602 int main( int ac, char *av[]) | |
1603 { | |
1604 int n; | |
1605 goto arg1(0,1,2,3,4,return,environment); | |
1606 } | |
1607 | |
724 | 1608 って、きっと return 文がないと、文句を |
1609 言われるよね。むむむ。 | |
1610 | |
1611 post processing する時にoverlapしてないという保証がない。 | |
55 | 1612 |
57 | 1613 Wed Feb 19 15:38:55 JST 2003 |
1614 | |
724 | 1615 自分自身とのoverlapを見てないので、 |
57 | 1616 struct a a,int i |
1617 int i,struct a a | |
724 | 1618 みたいな時に自分自身を壊してしまう。なので、emit_copy |
1619 が、ちゃんと方向を見て壊さないように処理する必要がある。 | |
1620 | |
1621 call bcopy でいいじゃん。まね。 | |
59 | 1622 |
1623 Wed Feb 19 20:42:07 JST 2003 | |
1624 | |
724 | 1625 楊さんの C2CbC と CbC2C を、micro C に取り込む。各所に、 |
1626 conv->func(); を埋め込む。conv は、構造体。 | |
59 | 1627 |
1628 conv: original | |
1629 c2cbc | |
1630 cbc2c | |
1631 | |
724 | 1632 とする。なるほど。 |
245 | 1633 |
1634 Thu May 6 08:32:05 JST 2004 | |
1635 | |
724 | 1636 やっぱり library も自分で作らないとね。そうすれば、 |
1637 CbC only で作れるから。 | |
1638 | |
1639 conv は、あんまり良いアイデアではないみたい。取るか。。。 | |
255 | 1640 |
1641 Thu May 13 12:59:16 JST 2004 | |
1642 | |
724 | 1643 byte code interpreter を CbC 自身で書いたら? |
1644 | |
1645 それでもやっぱり動かないから、あんまり意味はないんだけど... | |
1646 | |
1647 C で書いてもいいか。 | |
465 | 1648 |
1649 Wed Dec 22 15:17:49 JST 2004 | |
1650 | |
1651 reset { | |
1652 shift; | |
1653 } | |
1654 | |
724 | 1655 ねぇ。 なんで、return 構文にしたのか。しかも別々にしたのか。 |
465 | 1656 |
1657 goto ret(value),env; | |
1658 | |
724 | 1659 まぁ、ねぇ。 |
465 | 1660 try { |
1661 .... goto event .... | |
1662 } catch (event) { | |
1663 } | |
724 | 1664 をいれてもいいんだけど。 |
1665 | |
1666 うーむ、いまいちだな。 | |
1667 | |
1668 inline function のreturn,env を実装するっていう技もあるけど。 | |
1669 | |
1670 やっぱり。setjmp = return みたいにする? それはそれで、 | |
1671 やさしいんだけど.... | |
556 | 1672 |
1673 | |
1674 Fri Jan 6 20:26:24 JST 2006 | |
1675 | |
724 | 1676 environment = interface frame の切替えを用意しないとね。 |
556 | 1677 |
606 | 1678 Mon Jan 30 21:53:11 JST 2006 |
1679 | |
1680 packet_put ..... fork | |
1681 packdet_put(interface hoge); | |
1682 packet_get ..... join | |
1683 interface hoga = packdet_get(); | |
1684 | |
1685 ----> distributed CbC | |
1686 | |
1687 Synatx | |
1688 code a() { } | |
1689 | |
1690 code a(a):b(b) {... } | |
1691 -> | |
1692 code a() { | |
1693 if (b = packet_get() { | |
1694 ..... | |
1695 } else goto a(); | |
1696 } | |
1697 | |
1698 code a() { | |
1699 goto b(); | |
1700 } | |
1701 | |
1702 code a() { | |
1703 goto b():d()@dest; | |
1704 } | |
1705 -> | |
1706 code a() { | |
1707 packet_put(d(),dest); | |
1708 goto b(); | |
1709 } | |
1710 | |
1711 | |
1712 | |
1713 | |
1714 | |
615 | 1715 Wed Sep 6 14:59:09 JST 2006 |
606 | 1716 |
615 | 1717 code hoge(int a, code f(int k,...), ...) |
1718 { | |
1719 goto f(a,...); | |
1720 } | |
1721 | |
724 | 1722 syntax が汚い... type の指定はなんとかしないとだめだね。 |
615 | 1723 |
1724 ... | |
1725 | |
1726 int a, | |
1727 | |
724 | 1728 ずれたときのコストがなぁ。良く見えないんだよね。 |
1729 | |
1730 可能だとは思うんだけど。 | |
615 | 1731 |
1732 __meta goto { | |
1733 } | |
1734 | |
724 | 1735 みたいな感じ? |
654 | 1736 |
1737 Sun Nov 26 21:14:57 JST 2006 | |
1738 | |
1739 | frame pointer | stack pointer | |
1740 v----> argument local <--|-----v | |
1741 caller_arg | |
1742 | |
724 | 1743 ではなくて、 |
654 | 1744 |
1745 | previous $fp | |
1746 |<-intr_size---><--------r1_offset----------->| | |
1747 | | frame pointer | stack pointer | |
1748 v<--- interface-+---- local ----->|<--------->v | |
1749 <0 >0 caller_arg | |
1750 | |
724 | 1751 なら、いいんじゃない? caller_arg は sp 相対で積めば良い。 |
1752 local 変数は max_caller_arg が不定なので sp 相対では積めない。 | |
1753 | |
1754 これだと、frame pointer がgoto で可変になる。interface がarugment | |
1755 扱いになるので、限りなくsubroutine call に近くなるけど。 | |
1756 (まぁ、そうだよな、そういう狙いだし...) | |
1757 | |
1758 だったら、完全にfunction callに合わせることも可能なんじゃないか? | |
1759 可変長引数の場合とまったく同じになる。gcc の(予定ししてる実装と同じ) | |
1760 これだと、C-- の paraterized goto と、まったく同じになる。 | |
654 | 1761 |
1762 | previous $fp | |
1763 |<-intr_size---><-------------r1_offset------------>| | |
1764 | |frame pointer | stack pointer | |
1765 v<--- interface-+-------|--- local ----->|<-------->v | |
1766 <0 >0 xxx caller_arg | |
1767 |frame pointer | stack pointer | |
1768 v<--- interface----+-------|--- local ----->|<-------->v | |
1769 <0 >0 xxx caller_arg | |
1770 | |
724 | 1771 caller_arg はsp上に積むと。そうすれば、alloca も問題ない。 |
1772 | |
1773 これを採用しなかったのは、たぶん、fp を移動しなければならな | |
1774 いのを嫌ったんだろうな。今は、parse tree 作ってから、code | |
1775 生成も可能なので、そうしても良いんだが。 | |
1776 | |
1777 でも、めんどくさいよ。めんどくさい。めんどくさいです。 | |
1778 でも、やるしかない。 | |
1779 | |
1780 これを、やれば、C からの変換もかなりやさしくなるかも知れない。 | |
654 | 1781 |
1782 Sun Nov 26 19:41:38 JST 2006 | |
1783 | |
724 | 1784 max interface みたいなのが必要で、そうすれば、local 変数との |
1785 相互作用は避けられる。逆に言えば、利用は出来ない。 | |
1786 | |
1787 でも、max_interface は1 path では決まらない。だから、long offset | |
1788 の時は、ちょっとはまる。特にARMの場合。やっぱり、max_interface | |
1789 は決め打ちがいいのかな? そうすると、function call から呼ぶ | |
1790 ときにはまるが... | |
1791 | |
1792 offset を 0 側からにすれば、max_interface はfp設定時のみに | |
1793 なるが、そうすると、interface を変更したときのcopyが発生しやすく | |
1794 なる。いや、そんなことはないのかな? | |
654 | 1795 |
1796 __code f(int a,int b) { | |
1797 goto g(int c,int b,int a); | |
1798 } | |
1799 | |
1800 v<---|----+----local ----->|<-------->v before f | |
1801 a,b | |
1802 v<--- interface-+-------|--- local ----->|<-------->v f | |
1803 a,b | |
1804 v<--- interface-+-------|--- local ----->|<-------->v goto g | |
1805 a,b,c | |
1806 | |
724 | 1807 みたいな感じですか? 後ろをそろえるわけね。その方が自然か。 |
1808 | |
1809 これだと、やっぱり、max_interface が問題になる。やっぱり、それで、 | |
1810 fp を下にしてあるんだろうな。 | |
654 | 1811 |
1812 __code f(int a,int b) { | |
1813 goto g(int c,__code *f,int a,int b); | |
1814 } | |
1815 | |
1816 __code g(int c,__code (*n)(...),...) { | |
1817 goto n(...); | |
1818 } | |
1819 | |
1820 |<----------------------------r1_offset------------>| | |
1821 |frame pointer | stack pointer | |
1822 v<--- interface---------|--- local ----->|<-------->v f | |
1823 a,b,(n,c) | |
1824 |frame pointer | stack pointer | |
1825 v<--- interface---------|--- local ----->|<-------->v goto g | |
1826 a,b,fp,n,c | |
1827 |frame pointer | stack pointer | |
1828 v<-interface-+-------|-- local --->|<-------->v g | |
1829 a,b,fp,n,c | |
1830 |frame pointer | stack pointer | |
1831 v<--- interface---------|--- local ----->|<-------->v goto n | |
1832 a,b | |
1833 | |
724 | 1834 えーと、goto n(...); で、どうやってfp を元に戻すの? ... の位置で、 |
1835 前の fp を覚えておけば良い。(*) | |
1836 | |
1837 これだと、function call を、そのまま実現できそうだけど? みたいだね。 | |
654 | 1838 |
1839 __code f(int a,int b,...) { | |
1840 goto g(int c,f,int a,int b,...); | |
1841 } | |
1842 | |
1843 __code g(int c,__code *n(int a,int b,...),...) { | |
1844 goto n(int d,int e,int g,...); | |
1845 } | |
1846 | |
724 | 1847 とかすると、無限にstackが延びる。ふーん。 |
654 | 1848 |
1849 __code g(int c,__code *n(...),...) { | |
1850 goto n(int d,int e); | |
1851 } | |
1852 | |
724 | 1853 は、どうする? fp は、そのままなんだろうね。 |
654 | 1854 |
1855 |<----------------------------r1_offset------------>| | |
1856 |frame pointer | stack pointer | |
1857 v<--- interface-+-------|--- local ----->|<---------v f | |
1858 a,b,(n,c) | |
1859 |frame pointer | stack pointer | |
1860 v<--- interface-+-------|--- local ----->|<---------v goto g | |
1861 a,b,fp,n,c | |
1862 |<----------------------r1_offset------------>| | |
1863 |frame pointer | stack pointer | |
1864 v<-interface----+----|-- local --->|<---------v g | |
1865 a,b,fp,n,c | |
1866 v<-interface-+----|-- local --->|<---------v g | |
1867 d,e | |
1868 | |
724 | 1869 で、fp は上書きか。それは、良くない。なので、fp の分ずらす。 |
1870 というよりは、fp の次を指すようにするのが良いのか。 | |
654 | 1871 |
1872 __code f(int a,int b,...) { | |
1873 goto g(int c,__code *f,int a,int b,...); | |
1874 } | |
1875 | |
1876 __code g(int c,__code (*n)(...),...) { | |
1877 goto n(...); | |
1878 } | |
1879 | |
1880 |<----------------------------r1_offset------------>| | |
1881 |frame pointer | stack pointer | |
1882 v---- interface-+-------|--- local ----->|<---------v f | |
1883 a,b,(n,c) | |
1884 |frame pointer | stack pointer | |
1885 v---- interface-+-------|--- local ----->|<---------v goto g | |
1886 a,b,fp,n,c | |
1887 |<-------------------r1_offset------------>| | |
1888 |frame pointer | stack pointer | |
1889 v<-interface-+----|-- local --->|<---------v g | |
1890 a,b,fp,n,c | |
1891 |frame pointer | stack pointer | |
1892 v---- interface-+----------|-- local --->|<---------v goto n | |
1893 a,b | |
1894 | |
724 | 1895 というわけか。frame pointer のオプションがあった方が良いわけだね。 |
1896 | |
1897 これだと、全体の変更も少なくて済みそうだ。(ほんとうか?) | |
1898 | |
1899 g の ... の位置を前もって知ることが必須。かなりコードが繁雑に | |
1900 なるけど。 | |
654 | 1901 __code g(int c,__code n,...) { |
724 | 1902 の方が良いが、それだと、型のチェックが出来ない。実際には、 |
1903 かなり繁雑な型を書く羽目になる。typedef すればいいんだけどね。 | |
1904 | |
1905 __code は暗黙のtypedef にする? | |
1906 | |
1907 | |
1908 これを許すとmax_interfaceの制限は現実的ではない? でもないか... | |
1909 そのcodeでアクセス限界だからね。だったら、max_interface を | |
1910 作って、(1024程度?) いや、やっぱり fp は動かさないとだめ | |
1911 なので、良くない。 | |
1912 | |
1913 fp を積む場合と、戻す場合との区別は? 結構微妙か。 | |
1914 goto 側の定義 ...が先に(か同時に)来たら戻す | |
1915 goto 側の定義 ...が実引数より後に来たら積む | |
1916 で、いいわけね? | |
1917 | |
1918 ちょっと、Semantics が複雑になりすぎる。可能なんだけど。 | |
1919 environment での goto でたまにリセットしないとおかしくなりそう。 | |
1920 Stack 増えている場合は、Warning ぐらいだした方がいいかも。 | |
1921 大域的に見ないとわからない。有限かどうかも。 | |
1922 | |
1923 全部、tail recursive call でやるのと、あまり変わらないかな。 | |
1924 そうすると、c-- のparametarized goto と差がないかも。 | |
1925 | |
1926 | |
1927 あ、そうか。 | |
654 | 1928 |
1929 __code g(int c,__code *n(int a,int b,...),...) { | |
1930 goto n(int d,int e,int g,...); | |
1931 } | |
1932 | |
724 | 1933 の n は、自動的に定義された方が便利だろう。 |
654 | 1934 |
1935 __code g(int c,...) { | |
1936 goto __cotinuation(int d,int e,int g,...); | |
1937 } | |
1938 | |
724 | 1939 みたいな感じ。 |
654 | 1940 |
1941 go g(int c,int b,...) to hoge(...); | |
1942 | |
724 | 1943 ですか? それは、だめか... だめでもないんだけど、型の設定が |
1944 難しすぎる。 | |
1945 | |
1946 K&R style の宣言の方が綺麗なのか... | |
654 | 1947 |
1948 Sun Nov 26 21:53:05 JST 2006 | |
1949 | |
724 | 1950 (*) interface の大きさの増減は、自分のinterface を見れば |
1951 わかるはずだよね? だから、fp のsaveは必要ないはずだが... | |
654 | 1952 |
1953 __code f(int a,int b,...) { | |
1954 goto g(int c,__code *f,int a,int b,...); | |
1955 } | |
1956 | |
1957 __code g(int c,__code (*n)(...),...) { | |
1958 goto n(...); | |
1959 } | |
1960 | |
724 | 1961 確かにわかるんだけど、宣言を間違えたときに、おじゃんになる。 |
1962 どうせ、だめではあるんだが。引数の型は一段階までしか、 | |
1963 チェックしないので、だめだね。 | |
1964 | |
1965 | |
1966 このあたり、理論的な問題があるみたいだな。 | |
1967 | |
1968 stack を含めた有限な型付け | |
1969 と、その表現 | |
1970 | |
1971 って問題があるわけね? | |
1972 | |
1973 そうか、parallel assignment では、同じ部分を前もって探した | |
1974 方が効率がよいわけか。(どうせ、やっていることだが) | |
654 | 1975 |
655 | 1976 Sun Nov 26 23:22:12 JST 2006 |
1977 | |
724 | 1978 fp のsave は必要。何故かと言うと、 |
655 | 1979 goto f(a,b,...) |
724 | 1980 で、後ろの部分がどれだけあるかは、間接的な引数での |
1981 宣言ではわからないから。 | |
1982 | |
1983 stack 上に全部 interface があるなら、良いが、 | |
1984 部分は register に乗っている。 | |
655 | 1985 |
1986 goto f(a,b,c,...) | |
1987 | |
724 | 1988 としたときに、... の一部はregisterに乗っている。どれだけ |
1989 乗っているのかを知る必要があるが、それをfpから推察する | |
1990 ことはできない。浮動小数点とかの異なる型が散在している | |
1991 から。 | |
1992 | |
1993 ... で引き渡す引数は、メモリに乗っている必要がある。 | |
1994 型が明解なら、レジスタ上でもだいじょぶなはずだが。 | |
1995 | |
1996 明示的な引数に大域的には変換できるはずだけど、open | |
1997 な環境では、それはできない。 | |
1998 | |
1999 だとすれば、 | |
655 | 2000 __code f(int a, int b : int h, ...) { |
2001 ... | |
2002 goto g(a,b,c : d,e,f,...) | |
2003 } | |
724 | 2004 みたいな形で、stack 上に乗せる引数を明示する必要がある。 |
2005 | |
2006 これは、なんなの? | |
2007 | |
2008 : の前の引数は可変に出来ない | |
2009 : の後までは可変に出来る | |
2010 | |
2011 っていうことか。 | |
2012 | |
2013 構造体は、メモリ上に取るとしても.. | |
2014 | |
2015 まぁ、... のところまでレジスタで、それ以降は、メモリでも | |
2016 十分だけどね。いずれにせよ、複雑すぎることは確か。 | |
655 | 2017 |
2018 __code g(int c,__code (*n)(int a,int b,int d,...),...) { | |
2019 goto n(int d,int e,int c,...); | |
2020 } | |
2021 | |
724 | 2022 で、この... は、すべて、同じものに置き換わるはず。 ... が |
2023 入る場合もあるが。 | |
2024 | |
2025 受け側が | |
655 | 2026 __code c(int d,int e,int c,int k,int j) {} |
724 | 2027 で定義されているときに、k,j がレジスタに乗っているかも知れず、 |
2028 乗っていたらダメダメ。なので、可変になる部分を明示する必要がある。 | |
655 | 2029 |
2030 Mon Nov 27 11:17:39 JST 2006 | |
2031 | |
724 | 2032 結局、このn の定義と、実際のn の定義がずれることが問題なんだよね。 |
655 | 2033 __code c(int d,int e,int c,...) {} |
724 | 2034 で、受けることもあれば、 |
655 | 2035 __code c(int d,int e,int c,int k,int j) {} |
724 | 2036 で受けることもある。あるいは、 |
655 | 2037 __code c(int d,int e,int c,int k,int j,...) {} |
724 | 2038 とかも。 |
2039 | |
2040 implements というか、accetps というか、そんな形の別な | |
2041 宣言がいいのかな。 | |
655 | 2042 __code f(int a, int b : int h, ...) { |
724 | 2043 でもいいんだが... |
655 | 2044 |
2045 Mon Nov 27 11:34:33 JST 2006 | |
2046 | |
2047 __code f(int a,int b,...) { | |
2048 goto g(int c,__code *f,int a,int b,...); | |
2049 } | |
2050 | |
2051 __code g(int c,__code (*n)(...),...) { | |
2052 goto n(...); | |
2053 } | |
2054 | |
2055 | |
724 | 2056 g に入るときに、fp は、n の頭になければならない。これを |
2057 移動するのは、f の役割。出て行くときには、b の頭に | |
2058 合わせる必要がある。これは、g の役割。g は、元の頭(fp) | |
2059 を知らないから、これは取っておく必要がある。差では | |
2060 判断できない。g 側で取っておくことは可能だが、その | |
2061 時にも、f 側からずらす大きさを渡す必要がある。 | |
2062 | |
2063 明示しても良いんだけどね... | |
655 | 2064 goto g(int c,__code *f,__environment,interface &rest), |
2065 __envronment+sizeof(interface); | |
2066 __code g(int c,__code (*n)(...),(void*)parent,...) { | |
2067 goto n(...),parent; | |
2068 } | |
724 | 2069 みたいな形でさ... その方がいいのかな。繁雑だけど。: よりかまし? |
2070 | |
2071 : を使う方法だと、: が fp みたいな感じになる。 | |
2072 | |
2073 難しいね。きれいなsyntaxにならない。 | |
655 | 2074 |
680 | 2075 Wed Jul 25 14:48:16 JST 2007 |
2076 | |
724 | 2077 inline code __goto みたいな形にすると、 |
680 | 2078 |
2079 __goto hoge(); | |
2080 | |
724 | 2081 goto を reflection 出来る。 |
2082 | |
2083 meta な、interface はどうするの? | |
2084 | |
2085 デフォルトで、,.... が入っていると思う方が良い。 | |
680 | 2086 |
2087 goto hoge(hoge.... , __code (*cont)(i) : meta ...); | |
2088 | |
2089 goto cont(i); -> goto cont(i: meta...); | |
2090 | |
724 | 2091 という感じか? これがないと、記述がかなり面倒。subroutine とは |
2092 違うの? | |
2093 | |
2094 env の切替えで明示出来ないの? 出来るけど、繁雑なのか。 | |
2095 | |
2096 gcc との相性が良くないのだが... | |
2097 | |
2098 __code の先行宣言つらすぎる。script で生成するか、compiler で | |
2099 自動解決する方が良い。 | |
2100 | |
2101 tcc の方が goto f(); ではなくて、goto (*f)(); を | |
2102 強制する。これは、けっこう、めんどくさい。 | |
2103 | |
2104 ... ってのは大域変数みたいなものだよね? ただ、stack scope がある。 | |
2105 なので、sub routine と同じなのでは? | |
2106 | |
2107 | |
2108 | |
2109 | |
2110 | |
2111 | |
2112 | |
2113 | |
2114 | |
2115 |