view Idea @ 856:d9dd3e6e7c5f

macro compatibility
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Tue, 22 Nov 2011 05:44:49 +0900
parents e60c3d8dadd6
children
line wrap: on
line source


Thu Nov 25 17:27:12 JST 1999

subroutine call がない
局所変数もない
その代わり、大域変数を多用する
大域変数のスコープは局所的
Fortran の用に局所変数は静的に取る
recursion する時には、自分で保存する
subroutine call時のレジスタのセーブも局所的に行う
それは、ちょっと変じゃない?
やっぱりデフォルトのフレームは持ち歩くか?

recursive call とそうでないのを区別するか? 

fp は用意する方が良い

関数定義と同時に、それ専用のfpの構造体を用意する

C をcompileする時には、stackを持ち歩く
    fp = (struct func_state *)stack 
えっと、どこに代入するの? そういう問題もあるわけね。
じゃあ、fpは特別? それは気に入らないな。static 
なfpにすれば良いわけね。

func(void *stack) {
    static struct func_state {
	static struct func_state *fp;
	int local1;
	brahbrah...
    } func_state;     // ここまで hidden
    func_state.fp = (stack -= sizeof(struct func_state));
}

func_state をとってくる演算子があった方が良い? そうね。
    func.state
ぐらい?

fp->local1 みたいなことだけするなら、C と同じになる。

call する時のargument も、
    static な func_state に置く
    stack 上の func_state に置く
という二通りの選択肢がある。Cと互換なら、当然、後者。

Recursive なら後者だが、この言語は状態遷移を記述するから、static
なものでも良いはず。

Internal function は? あってもいいんだけど...

Recursive call する時には、 fp をsaveする必要があるね。
    (--(struct func_state *)stack) = fp;
    call callee(&fp->arg,continuation,stack);
call しても、戻って来ないから... continuation は一般的にはcode
だから... それは Internal function にするか。

continuation に一般的にcompileする方法を考えないといけないか。
self は必要なわけね?

言語の名前も考えないといかんなぁ。

C からのコンパイラも書かないといけないのか...

Mon Dec 13 18:53:04 JST 1999

compiler based で、内部で partial evaluation できる?

func をdatabaseとして扱えないなら、それはできない。

しかし、状態遷移としては取り扱える。

    func.state
    func.code

みたいな形にしてpartial evaluationすれば良い

でも止まるのか?

textual でない、中間的なコード表現があった方が良い? <-> interpreter?

Prolog ではなんでいけないの? --> Unification が重いから

Sat Nov 27 13:50:41 JST 1999

func.state とか作るのだったら、
    struct {
	struct {
	    int i;
	} state;
	state *code = {
	    i = i+1;
	};
    } name;
みたいな形で、それ自体を構造化すれば? で、代入すると部分評価される。
代入も可能。なるほど。
	*name.code;
値はあるわけ? 値は &state でしょうね。
self があれば、
    struct {
	struct {
	    int i;
	} state,
	*code = {
	    self->i = self->i+1;
	};
    } name;
かな。self = state だよね。

union の拡張もあわせて議論すると...

Partial evaluator をセマンティクスや実行系にいれておくことは可能か?

byte code とか仮想マシンだったら可能。そうでない場合は?

いずれにせよ、構造体のタグのunique性を修正しないとだめだな。

ヘッダファイルはどうするの?

Mon Dec 13 18:53:18 JST 1999

library との整合性は?

exec sequence では、
    (--(struct func_state *)stack) = fp;
    call callee(&fp->arg);
という形でpointerだけ渡すの? それは変だよね。

値渡しにするとすれば、複数の値を渡せたほうが良い。

    func(void *stack) {
	static struct func_state {
	    static struct func_state *fp;
	    int local1;
	    brahbrah...
	} func_state;     // ここまで hidden
	func_state.fp = (stack -= sizeof(struct func_state));
    }

の引数自体が、構造体であるべき。

    func(
	struct void *stack
	) {
	static struct func_state {
	    static struct func_state *fp;
	    int local1;
	    brahbrah...
	} func_state;     // ここまで hidden
	func_state.fp = (stack -= sizeof(struct func_state));
    }

で、構造体に register storage を許す。

    func(
	static struct argument {
	    register void *stack;
	    register void *continuation;
	}
	) {
	static struct func_state {
	    static struct func_state *fp;
	    int local1;
	    brahbrah...
	} func_state;     // ここまで hidden
	func_state.fp = (stack -= sizeof(struct func_state));
    }

すると、caller の方も、構造体を引数とするのが自然。

    call caller(
	static struct argument {
	    register void *stack;
	    register void *continuation;
	} arg = {a,b};
    )

みたいな。もちろん、この構造体はインタフェースと呼ばれる。

argument は、callee にあった方が良いけど、caller 側にあっても
良い。register なんかは、そう。

	caller(interface caller_arg = {a,b,c})
みたいなsyntax かな。
	caller->interface = {a,b,c};
	*caller->code;
を、
	caller(a,b,c);
と称する。

function には、interface と code と state があることになる。

state にアクセスする時のlockは? protected state? synchronized state かな?
もちろん、sequential implementationでは、そんなものはいらない。

function {
    interface:
	register int a;
	register struct self self;
    state:
	int b;
	serialized int c;
    code:
	b  = a;
}

int にvoid value を定義する。実装は重くなるけど...

serialized の semantics は?

もう少しmicro-Cに近く! 

carrying state と static state。

Mon Dec 13 19:42:41 JST 1999

interface に register keyword を使うのは、あまりに
実装よりすぎる。でも、でないと状態にできない?
そんなことはないか。やっぱりcaller側のstatic 領域に
直接書き込む?

だとCより遅そう。でも、引数に40個とかかかれたら...

Wed Dec 15 14:09:49 JST 1999

C と互換にする?
	goto function(arguments);
	goto *continuation(arguments);
みたいな感じで。

stackの管理は? どうせ、library との互換はとらないと
いけないんだから...

local 変数がある場合は stack を動かす。でも、戻す奴がいない。
closure 化するか?

return した時の挙動が複雑になる。大域returnするわけだら。

arguments をstatic 領域にかきこむ方式だと互換性がとれない。
stack 上の frame pointer 上にないとダメだから。

両立させるのは無理か? つまり、これだと、呼び出された方の
frame semantics は、C と互換になる。だから、stackの直後に
frame pointer があると思っている (そうか? ) frame pointer
stack pointer に沿って移動した直後に、そこからのoffset
で引数を操作することになる。

つまり、それはだめだったことじゃない? つまり、goto だと、
frame pointer は、stack の直後とは限らないから。前の
frame pointer 相対に引数にアクセスしてくれれば別だけどね。

stack に引数を積むのは容認して、goto の場合は、向こう側で
stack を畳むってのは?  ということは、普通の関数と定義の
方法を変えるってことか。ま、悪くはないか。

すると、goto のsemantics は、C と互換になる。それを受ける
方が異なることをする。それは、なんかおかしいな。それに、
それだと関数呼び出しが軽くならない...

ということは、やはり、C のcall は、call function で
実現して、その他の呼び出しは、すべて、goto 扱いに
する方が正しいだろう。

問題は、この言語の関数をcallされた時だな。dual entry にして、
call の時と、goto の時を区別するか。
	func:	stack processing
	func_goto: normal processing
         ...
みたいな感じ。でも、return はないから...

このあたりも自分で記述できる言語であるべきだよね。その通り。
つまり、C とのstub も自分で記述すると言うことか。

protocol function {
    interface c {
	register "%esp" struct {
	    entry code ret(int);
	    void *fp;
	} *sp;
	register "%ebp" void *fp;
    };
    code function_code {
	fp = sp;
	sp += sizeof(struct local);
	struct local *local = sp;

	local->i = 1;
	goto *fp->ret(local->i),sp=fp;  // return(local->i);
    };
}

みたいな感じでさ。さっすが、アセンブラ。いまいちreturnが汚いけど。
まぁ、return はそのままreturnでもいいけどさ。

あ、これは良いかも知れない。code が複数かけるから。

state 以外は、consistent state であることを保証しない。ってのは?
local 変数は使っても良いけど、call/goto の前後で、値を保証しないか...

うーん、だんだん炸裂してるなぁ。

だから、レジスタに対するマッピングの記述と、そうでない部分の
記述は分離するべきでしょうね。


全部一辺に実装するわけにはいかないからぁ...

Thu Dec 16 13:44:21 JST 1999

lock は状態遷移レベルで実現するのだから、self などを
使ってlockする必要はないはず。

全体の直列化は、状態遷移レベルで、
	lock(storage) -> transition
みたいな形で記述すれば良い。この当たりを、どのように記述するかは
もう少し先送りしよう。


引数はレジスタ渡しにしよう。長い引数は、呼び出し側の領域への
ポインタとする。実装を規定しても良い。そうすれば、varargs
みたいなものはなくなる。だいたい、なんで、そんなものがいるんだろう?
配列を渡せばいいじゃん。

なので、引数は一つ(or 二つ)に限るという方法もある。

とすると、やはり、前もって静的領域や動的領域を確保することは
できない。

この言語では動的領域は自分で確保するわけだから、その点は問題ない。

Thu Dec 16 20:24:55 JST 1999

とすると関数呼び出しは、
	# register save
	# set 1st argument in register %eax
	# set 2nd argument in register %ecx
	# set extra arguments in save area
	# set extra argument pointer in %edx
	    jmp function
という形式になるわけね。second を処理するのはめんどくさいから一つ
にしよう。

えーと、frame pointer はないけど、コンパイルの手順からすると
あった方が良い。しかし、frame pointer そのものをstatic
にとるのはまずい。だから、frame pointer がfirst argument
ということにする方が正しい。とすると引数は、さらに、その
後と言うわけか。
	f(fp,argument)
fp を渡すのにさらにargument をレジスタで渡すのはおかしい。おかしいけど、
ま、良いか。

return しないなら、return type の定義をとるのは変だな。

f(fp,arg1,arg2,arg3) とすると、それぞれが決まったレジスタに入って、
多い分は配列にあると思われる。ふむふむ...
    fp->xx 
でアクセスすれば、そのまま局所変数になる。全部、配列で
送っても良い。

  .set label,value

で as は値をセットするようですね。

関数コールの後は戻って来ないから後始末の心配はしなくてよい。
frame pointer を使ったら自分で面倒を見ること。

だと
	a = atoi(s);
みたいなことはできない...

普通のCの定義と交じると間違いやすい。

とすると、struct と同様に、
	protocol
	code
	interface
	state
を用意するわけね。時間あるのかぁ?

とりあえず、register 渡しのfunction 定義とgoto文を実装する。

code name(register "%ebp" void *arg) {
    goto name(arg);
}
 
ぐらいかな? で、first argument が必ずregisterにのるようにしないと
いけない。register storage class を入れて、
    register "%ebp" void *arg
とかするわけね。

ってことは、まず、レジスタを実装しないといけないわけね。

で、stack を使った演算は、一応、そのままにする? それでも動くはず。
式の途中でgotoは使えないんだから、それでいいはず。

で、それから、これを拡張していく。

interface c {
    register "%ebp" void *arg;
}
code name(interface c) {
    goto name(c.arg);  // c. は省略可能
}

とかね。さらに、

protocol name {
    interface c {
	register "%ebp" void *arg;
    }
    code name(interface c) {
	goto name(arg);
    }
    code name1(interface c) {
	goto name(arg);
    }
}

などとするわけか。なんと、これが C と共存するわけね。うーん。

Fri Dec 31 11:44:03 JST 1999

code でなくて、別な名前のほうが良くない? segment? action?

レジスタ名が入るのは、やっぱりいや。optionalには許す。

interface は構造体のようなものだから... 構造体でいいんじゃない?
構造体の場合は... malloc する? う、うーん。malloc するとして、
いつfree するの?

再入するときには、壊れてていいんじゃない? multi-thread でなければね。
multi thread では、状態は、レジスタ経由または、thread local に持つ
必要がある。static は、だから thread local に持たなくてはならない。
大域変数に割り振っちゃだめ。でも、いまは、やめて

interface は、とりあえず、二つまでの値渡しにしよう。
	self と arg
ですね。

もう少し拡張しやすいコンパイラがいいなぁ。

    code name (c,a)
    struct state *c; struct arg *a;
    {
	goto name(arg);
    }

local 変数は? この互換性の問題かぁ。

KL/1 を意識して、interface は heap に置くことにしても良い。
GC は言語に入れておくべきだが、interfaceは machine independent
であるべき。だとすれば use/forget みたいものはいるだろう。
でも今のところは考える必要はない。

えーと、
    code name (c,a)
    struct state *c; struct arg *a;
    {
	int i;
	goto name(arg);
    }
の時の一時変数iはどうするの? 基本的にはレジスタ割り当てだけど...
使用させない? んー、大胆な御意見。まぁ、やっぱりheapに割り当てちゃう
のが簡単か。でも、どうせ抜ける時にはいらなくなるわけだから...

ほんらい、この変数は、次のcallでは必要無くなるのが普通。

とにかく、レジスタ変数は必要なんでしょう?

だから、GC と合わせて言語を設計すべきだよね。API を規定して、
異なるGCを選択できるようにする。

Sat Jan  1 22:40:22 JST 2000

とーにかく、 storage class register を実装しよう。

    stmode=REGISTER

で、local storage とおなじ扱いとする
	static register? は、ない。

symbol table に storage class をたせば? dsp==EXTRN で判定しているから、
local 変数が36以上あるとおかしくなるぞ?

sc  は GVAR/LVAR だけど、register は LVAR の特殊な奴だから、
sc に入れるほうが正しいか...

Sun Jan  2 01:47:17 JST 2000

register 変数はできました。けど、register を二つ使うと、
一杯になってしまうので、REGISTER6 でコンパイルしないと
結構ひどい。が、register 変数を%esi,%edi に割り当てれば
いいか。

Sun Jan  2 04:43:04 JST 2000

で、
    code name (c,a)
    struct state *c; struct arg *a;
    {
	goto name(c);
    }
の一時変数無しは実装できます。引数は二つまでね。

	.file "tmp.c"
	.version	"01.01"
gcc2_compiled.:
.text
# 
# code name(c,a)
	.align 2
.globl code
code:
	.type	code,@function
#    struct state *c; struct arg *a;
# {
#	goto name(c);
	movl %esi,%esi
	jmp	name
_5:
	.size	code,_5-code
	.ident "Micro-C compiled"

う、すごい。

goto 文がめんどくさい。stack をたたんで、jmp すれば
よいだけだが..

Sun Jan  2 11:17:50 JST 2000

普通のcallをcontinuation baseにすることができる?

Sun Jan  2 20:28:45 JST 2000

goto 文だけど、やはり、一度、expr で生成してから、top level
で jump code を生成しよう。

Tue Jan  4 03:32:55 JST 2000

code をtypeにしないと、
	code *p;
とか書けないね。
	int *p();
と同じだけどさ。


    main(ac,av)
    int ac;
    char *av[];
    {
	goto code1(ac,av);
    }

    code code1(ac,av)
    int ac;
    char *av[];
    {
	if (ac)
	    goto code1(ac,av);
	else
	    goto ac(ac,av);
    }

Tue Jan  4 04:56:56 JST 2000

うーん、なんかレジスタにつむ順序が違う
これは、adecl がreverseにつむから。

code のreturn

やはりcodeはtypeにしないとだめ。

main()
{
    goto code1();
}

とかだと、main に戻って来れない。もちろん、code1() 以降で、
return するわけにはいかない。(main の disp をcode1 は知り得ない)
goto label をcode1の引数に送れば?

main()
{
    goto code1(ret);
ret:
}

これだと、ret がforward labelかどうか分からないけど?

code1 中で使う中間変数を stack 上にとるのは悪くない。しかし、それを
%ebp 経由でアクセスするということは、main の中間変数を壊すということ。
それを防ぐには、main 中のgoto codeで、%ebp を修正してやれば良い。
(今は戻って来ないので問題ない)

code1 のgoto では、戻って来ないから、その必要はない。しかし、
label をcode1 中で渡されると、ちょっと気まずい。

とすると、それは禁止して、main() 中でstackをたたんでからgotoするか?
そうすると、無限後退して、結局、帰れないことになる... うーん。

main() 中のlocal code を許せば、それは解決するが..

main()
{
    goto code1(code2);
    code code2() {
	return;
    }
}

みたいな感じ。でも、そうするとscope rule を変える必要があるので厳しい。
ま、悪くはないけどね。

continuation を明示する方法もある。

main()
{
    goto code1(continuation);
}
code code1(ret) 
code (*ret)();
{
    goto *ret;
}

かな? call/cc ?

label へのgotoを許すのもいいけど、
でも、label を許すと、すごくspaghettiにならない?


Tue Jan  4 11:47:24 JST 2000

continuation じゃなくて、return keyword を使おう。
(実際、continuation と少し違うし)
type が少し変になるけど、まあ良い。

int
main()
{
    goto code1(return);
}
code code1(ret) 
code (*ret)(int);
{
    goto *ret(3);
}

だな。prototype も付けないといけないか。

Tue Jan  4 12:21:44 JST 2000

これだとmethodがすべてstatic になってしまう。dynamic なmethod
呼び出しにするには? dispatcher を自分で作ることになる。かなり
めんどくさいが...

code method(obj,arg)
{
}

か、あるいは、inline にするか... #define のかわりに inline ねぇ。
これはあとで考えて良い。

Tue Jan  4 14:22:19 JST 2000

main の変数を書き潰すのと、goto (*reg)(123) での値は、
register 渡しで、current register にのらないので、
結局、return label は専用に作る必要がある。

Tue Jan  4 18:14:07 JST 2000

stack を継ぎ足して、呼び出す方式を取れば、call by value
のregister 渡しを制限する必要は無くなる。

複数の値を返すことも容易だ。

	.file "tmp.c"
	.version	"01.01"
gcc2_compiled.:
.text
# 
# code name(a,b,c,d,e,f)
	.align 2
.globl code
code:
	.type	code,@function
#    struct arg *a,*b,*c,*d,*e,*f;
# {
#	int g;
#	goto name(a,b,d,e,f);
	jmp	name
_5:
	.size	code,_5-code
	.ident "Micro-C compiled"

おお?!
	%esp  new %esp = old %esp - 12 -4
	%ebp-4     = g
        %esi       = a
        %edi       = b
        %ebp = old %esp   0
        %ebp+4     = c       code_arg_offset=0
        %ebp+8     = d
        %ebp+12    = e
        %ebp+16    = f

interface は付けよう! というか、
	goto name(struct {xxxx})
みたいな感じで良いわけね。どれをregisterにいれるかと言う問題はあるが。

で、どうやってcallすればいいわけ? emit_pushするかわりにpush
する?

うう、これでは、だめか。code argument の数が変わると、
ebp をいちいち動かすことになる。そこにはold sp があるから
そいつもコピーする必要がある。

	%esp  new %esp = old %esp - 20
	%ebp-20   = g
        %esi      = a
        %edi      = b
        %ebp-16   = c code_arg_offset= -16 ((nargs-max_reg)*int_size)
        %ebp-12   = d
        %ebp-8    = e
        %ebp-4    = f
        %ebp = old %esp   0

そうか、function からcallする時には、local 変数を書き潰して良い。

#	goto name(a,b,d,e,f);

	%esp  new %esp = old %esp - 20
	%ebp-20   = g
        %esi      = a
        %edi      = b
        %ebp-16   = c code_arg_offset= -16 ((nargs-max_reg)*int_size)
        %ebp-12   = d
        %ebp-8    = e
        %ebp-4    = f
        %ebp = old %esp   0      disp=0 (*)
         local1 <----16 local variable      
        %edx        -12   <- disp_offset
        %ecx         -8
        %ebx         -4
        %ebp = %esp   0
        %eip          4   <- arg_offset

となる。ということは、pushl %ebp は、間違い。

だけど、%ebp をそのまま使うのは良くない。disp_offset がかかっているから。
だから、もう一度 pushl %ebp したほうがよい。しかし、push する先は、
上の、(*)。
	leave           movl %ebp,%esp
			popl %ebp
じゃなかったか?

Thu Jan  6 13:00:33 JST 2000

できたね。これでとりあえず動くはず。速度は問題だが...
あとは、
	ANSI-C prototype
	ANSI-C prototype check
	Interface Definietion
	GC support
	Direct handling of Frame
だね。簡単に出来そう? たぶん...

Fri Jan  7 09:42:53 JST 2000

goto 文が動いてなかった。あと peep hole optimization version も
作るか?

continuation として label を送れるようにするべきか?
そうすると便利なんだけど、ちょっと、汚いプログラムが
出来るようになる。あと、送り側の環境(frame)を維持する
必要がある。ま、できなくはないか...

そうすると、label が値を持つようになる。
	a = label:;
とか。うーん。label:(a,b,c) {}; みたいな形で、parallel 代入を許すと言う
手もあるね。

こちらの方がCとの相性は良いが... main() { label:(){ ... } }
みたいなnestを許すかどうかと言う問題がある。
変数の参照を許さなければ、特に問題はない。

a = label: は、二重の意味があるなぁ。

言語の名前。DinnerBell II とか? join も入れる?
	code entry_a().entry_b() {}
ですか? parallel call も?

Fri Jan  7 19:53:53 JST 2000

いまのままだと return が環境を持ってないから、大域脱出できない。
まぁ、環境を入れてもいいんだけど、どこに置くかと言う問題が
あるね。

そうじゃなくて、return 側で判断するか? 
	return(ID)
みたいな形でIDで判断する。そうすれば、return 側でID
を見て判断できる。けど...

まぁ、はやり、環境を持って歩く方がいいかなぁ。でも、
引き渡しているから、二つ引き渡して、片方を使われたときに、
反対側が消えてしまうのはいたいよね。今のままならば、
そういうことは起こらない。

continuation 特有の問題を避けるなら、このままでもいいんだが...
continuation や環境は、このシステムでは自分で作ることが
できるからね。

そうなんだけど.... retlabel や retcont は実はオブジェクト
全体に一つあれば良い。

引数を渡すときに、そこに環境へのポインタをいれてやれば良いので、
解決は割と簡単だが、そうすると、例の構造体を引数で渡すと言う
問題を解決する必要がある。

でも、今の実装ならば、まったく同じ変数の構成ならばコピーは
実際には起こらないわけだから問題ないはず。特に、それを保証するために、
interface を実装する必要がある。

return ->
	(void *)old bp
	return address

bp を直接操作できるようにするといいんだけど.... 

Sat Jan  8 08:49:59 JST 2000

今は、code 内ではreturnできないわけだけど。実は、return って、
	code return0(i) int i; { return(i); }
か? 今は禁止してないから書けちゃうよね。どういうcodeが出るんだろう?

doreturn() では retpending をセットしているだけだから、control=1
のまま。で、code の終りにくるのでエラーになる。checkret は、
statement の引数で判断するようにしたほうが合理的だろう。

大域脱出は結構根が深いよね。途中をスキップされてうれしいか?
destructor と同じで、途中のcodeは全部呼びたいのが普通だろう。

bp が同じになるまで return すれば良いわけだよね。
return と同じで、明示的に環境を引き渡すようにするか。
type は void * で良い?

return する時にstackの上限を越えているかどうかを自分でチェックする
必要があるね。誰にreturnするかをcodeで明示すれば良いわけだけど。

	code return0(i) int i; { return(i); }

を許して、そこで、frame pointer を大域あるいは渡した引数と
比較して処理する?
	code return0(i,env) int i; env *env; { 
		if (env==self) return(i); 
	}
あれ? これはおかしいよね。
	code return0(i,env) int i; env *env; { 
		if (env!=self) {
		    env->return();
		    return(i); 
		}
	}
も、なんか変だよなぁ。呼び出しと逆順に帰りたいわけだが...
実際、逆順には帰っているわけだよね。

return の中でこそこそ比較するという技もあるけど。

問題は、destructor に渡す情報だよね。もちろん、self で良いわけだが、
このあたりは、言語外の問題で、それを明示的にしたいから、この言語を
作っているわけなのだから、これを内部で処理するのはおかしい。

	code return0(i) int i; { return(i); }

これだと、return の型が合わないと言う問題が生じるな。簡単には
チェックできない。
	int
	main() {
	    code a() {
	    }
	    code b() {
		return(i);
	    }
	}
にすれば、check はできるようになる。でも、これだと、
	int
	main() {
	    a: {
	    }
	    b: {
		return(i);
	    }
	}
と差がない。module 化を言語外でやるというのが主旨なのだから、これでは
まずい。これは高級アセンブラなのだから。

あそうか、return と、大域脱出時のabortとは、状況が違う。だから、
別なcode を呼び出さないとだめ。あるいは、値で区別するか。これは、
logic programming のfail/success と似ている。
	main() { } abort { ... }
でもいいけど?
	main() {  code abort { ... }; code return { ... }}
かな?

本来、subroutine call自体が、かなりの省略形なわけだから、これは
仕方がない。今のままで通常のsubroutine callをシミュレートできるのか?
	code (struct arg {...},void *sp) {
	    struct env;
	    push(sp,arg);
	    push(env,arg);
	}
できるけど、ちょっと重い。やはり、frame pointer を直接操作しないと
だめ。

goto 文のほうに、env を一緒に送るものを作ったほうがいいのかも。
	goto (*ret)(),environment;
かな。type は? (void *)?
	goto ret(),environment;
にはならないの? そうすれば、自分でthreadを制御できる。environment
の正当性を評価しなくて良いの? まぁ、ねぇ。

これは実装は容易だが... goto といちいち書くのが本当にいいのか?
env に対するoperationがあった方がいいなぁ。push とか?

	code return0(i) int i; { return(i); }

を認めれば、return 擬変数はいらなくなる。

でも、実は、return は、caller の引数の数と一致してないといけない
わけだから、 code return0(i) int i; { return(i); } はだめ。env
と一致してないといけない。ということは分離するとまずいんじゃない?
あれ? そんなはずないな。

Sun Jan  9 01:15:56 JST 2000

やはり、分離してはまずい。もともと、
	goto func(arg);
自体が、
	goto func(arg) with current.env
みたいなものだ。つまり、これは、DinnerBell の、
	self message: arg
と同じ。self->func(arg); でも良い。が、function callと区別が付かないのは
良くない。

そうすると、type code はsize int でなくなる。
	code *p = func;
ではいけなくて、
	code p = {func,env};
でないといけない。実際、
	goto func(arg)
では、current environment を pushl %ebp でstack = current env
に積んでいるわけだから。

いずれにせよ、
	struct p = q;
は実装する必要がある。localな、
	code p = {func,env};
も動くはずだが...

	code (*p)();
	goto (*p)(arg);

はだから少しおかしい。これは、goto がenv を補っていると考えるべき。

このようにすると、常に、
	func,env
の組をcodeとみなすことになる。これは、object と呼ぶべきだ。
ただ、既存のobjectとは別だよな。actor の方が良い?

うーん、これでjoinを入れれば、完璧なDinnerBellだな。並列送信はないけど。

Sun Jan  9 01:40:05 JST 2000

local 変数の初期化はallocation の後に遅らせる必要がある。
nptr に入れられるはずだよね? nptr に初期化フラグを足すか?

文途中で出現するlocal変数の初期化。ちゃんと動いているの?

構造体のcopyは、lcheck を修正すべきでない。

Sun Jan  9 08:49:43 JST 2000

うーん、なんか修正が多いなぁ。あと、関数呼び出し、goto 文の
構造体への対応か。

	goto (*code)();

が、self env を使うのか、code の先の値を使うのかを区別する
必要がある。もし*を使わないとするとlabel(FNAME)との区別が
つかないぞ。あ、でも、環境を持ち歩くことにしたから、label
へもjumpしようと思えばできるね。

並列送信はなくても、この構成ならばstatement単位の並列性を検出するのは
容易だろう。

やればできるけど、この修正の量だと1日じゃ終らないかなぁ。
不動小数点も入れるのでしょう?

Mon Jan 10 09:00:12 JST 2000

引数に構造体を許すには、必ずANSI-Cにする必要がある。難しくは
ないが...

goto 文には label, code, continuation の3つが来る。
	continuation = code + env
			| label +env
なのだが、code/label では、env の内容が異なる。できれば面白いが、
その価値はあるのか?

しかし、code , env を分離するとあまりに危険すぎる。どうせgoto
が危険なんだからいいか? その方が簡単。簡単なら、そっちの方法を
とるべきじゃない? うーん。

return の関数依存性はなくした方が良い。
一つにするのは、pop の問題があるので良くないが...

そうか、ret をenvを指定して戻るようにしたから、leave する必要は
なくなった。そして、push %ebp に相当する部分は、lea -disp(%ebp),%sp
で消去されている。ということは、jump のfunction依存部分はいらない
ということだね。

でも、汚いなぁ。read only属性をhardware supportできればなあ。

sched_yeilds() 相当を書けるかな? lock は?

一応、できたけど、やっぱり汚い。

Wed Jan 12 16:12:27 JST 2000

あは。ANSI prototype はめんどい。
	bexpr()
で、関数での引数の順序と、そのあとの宣言の順序が変わることがある。
そうすると、うしろの方が優先されてしまう。これは、こまる。

そうか、code_arg_offset のような方法だと、ANSI style では、
困ってしまう。

Thu Jan 13 04:46:12 JST 2000

#       goto name(a,b,d,e,f);
        code name { int g; ...

        %esp  new %esp = old %esp - 20
        %ebp-20   = g code's local variable
        %ebp-12   = f <- new_disp
        %ebp-8    = d
        %ebp-4    = d
        %ebp-0    = c
        %edi      = b
        %esi      = a
        %ebp = old %esp   0      disp=0 new env
         local1 <----16 old local variable       ( to be erased )
        %edx        -12   <- disp_offset
        %ecx         -8
        %ebx         -4
        %ebp = %esp   0   <- old env
        %eip          4   <- arg_offset


Thu Jan 13 13:38:24 JST 2000

だいたいできたけど、test/tmp7.c のprintf のtype mismatch は
なんなんだろう?  ASNI の副作用だろうなぁ。

これだと、プロセスの切替えのときには、結構な量のデータを
コピーすることになる。それでもいいんだけど...

それごと、どっかにとって置く。continuationへの参照みたいなもの
ができないかな。

コピーができれば、environment/return の組は動くわけだから、
それへの参照と切替えがあっても良いよね。

Fri Jan 14 12:03:35 JST 2000

Libretto のkeyboardが壊れた... control key が効かない...

printf の参照の問題は解決しました。list2 がlocalなheap
に割り当てているのがいけなかったね。

return の処理は、goto 文で処理するより、environment に
returnto する方が良くはないか?

environment は実は送り先でそれなりの準備が必要。
new-environment() みたいなlibrary があれば、thread にできる。

join は?

funcall を用意すると良いね。

Mon Jan 17 15:23:34 JST 2000

    struct aa f1() {
	return bb;
    }

みたいなのは? 関数の型か代入の型を見て、crn にpointerを渡して、
あとでcopyしてから stack を畳む。

    # 	bb=f1(aaa);
	    movl $bb,%eax
	    pushl %eax
	    movl $aaa,%eax
	    pushl %eax
	    call	main2
	    popl %edx
	    copy %eax,%edx,$400
	    addl $400,%esp
    #     return a1;

あ、でも、それだと、local変数を返したときに困るね。leave; ret;
してはいけなくて...

あ、やっぱり、こういう場合はコピー先をmain2に引き渡しているみたいね。
    void f1(struct aa *ret) {
	*ret = bb ;
	return;
    }
と同じか。これは簡単。
	f1().a[55]
みたいな場合は、局所変数に強制的に取ってしまうみたいね。それはそうだ...
が、うちの実装だとちょっと厳しいか。
	leal $-sizeof(struct),%esp
	pushl %esp
なんだけど、関数呼び出しの途中ではできないから....

    # main(ac,av)
    # int ac;
	    .align 2
    .globl main
    main:
	    .type	main,@function
	    pushl %ebp
	    movl %esp,%ebp
	    pushl %ebx
	    pushl %ecx
	    pushl %edx
    # char *av[];
    # {
    #     register int i;
    #     register char *p;
    #     int j = 3;
    #     struct { int b; void (*c)(struct aa); } q = {3,main1},r;
    # 
    #     j = 3;
	    subl $20,%esp

このsublを後から指定してやればOk。

でも、それだと jump の時にずれない? ずれるか? ずれるね。うーん。
実行時にチェックしてやるのも変だし。

まぁ、それほど必要な機能ではないんだけど。

これもcontinuationを渡してやると言う手法が使えないことはないんだが...

関数呼び出しの最初にやってやればいいか。それでできるかな?


Sun Feb 20 23:59:16 JST 2000

MIPS のcall frame

	$sp = $fp 
			local variables
        		saved register (including $31 = return address)

mask  は使用したレジスタのbit pattern
 -4 は何?

  18                            .mask   0xc0000000,-4
  19                            .fmask  0x00000000,0
  20 0000 D0FFBD27              subu    $sp,$sp,48
  21 0004 2C00BFAF              sw      $31,44($sp)
  22 0008 2800BEAF              sw      $fp,40($sp)
  23 000c 0000000C              move    $fp,$sp
  24 0010 21F0A003              jal     __main
  25 0014 03000224              li      $2,0x00000003           # 3
  26 0018 000082AF              sw      $2,a
  27 001c 04000224              li      $2,0x00000004           # 4
  28 0020 00C082AF              sw      $2,b
  29 0024 05000224              li      $2,0x00000005           # 5
  30 0028 000082A3              sb      $2,c
  31 002c 06000224              li      $2,0x00000006           # 6
  32 0030 08C082A3              sb      $2,d
  33                    $L1:
  34 0034 21E8C003              move    $sp,$fp                 # sp not trusted
 here
  35 0038 2C00BF8F              lw      $31,44($sp)
  36 003c 2800BE8F              lw      $fp,40($sp)
  37 0040 0800E003              addu    $sp,$sp,48
  38 0044 3000BD27              j       $31
  39                            .end    main

これと同じようにするならば、regiterの使用数を最初に調べる必要が
あるのだけど、one path compiler である micro-C では、それは
できない。したがって、enter は後ろでする方が良い。
Mon Jan 20 18:25:27 JST 2003

3年間さわってないのかよ。何やってんだ?

goto 文のバグをとらないといけない。

まず、関数引数の構造体の展開。これは、どうってことないはず。

   goto (*code)(i+1,j,...)

まず、いじらなくてすむ変数を摘出する。

   foreach arg 
      compare

単純演算 ( op+const , pointer , const assign ) などは、ここで検出する。
大半は、そのようになるはず。
レジスタに乗せる分があるから... それには触らないとして...

複雑なものは、前もって計算しておく。(get_register する)
スタック上かレジスタ上に作る。

残りは並列代入となる。再帰的に計算する。

えーと、大きな順にやるんだっけ? 小さな順にやるんだっけ?
    code f( int a, int b, int c ) {
        goto g(b,c,a);
    }
みたいなやつだよね。

    移動するものを一つ検出する。
    そのために移動が必要なものを移動しておく(再帰)
    代入する

こんなんでいいのか? ループしない? するよね。ループしたら
get_register する。

前の例だと、

    g(b,c,a) のbに着目する。
    bに代入するコードを出すと、a が壊れる。
    a が必要かどうかを調べる。それは、引数のリストを見ればわかる。
    その前に、a を移動する。a の移動先を見て、
       空いていれば、移動してOk。しかし、c 
    なので、 c を見る。と b になるので、ループするのがわかるので、
    b を get_register する。
    で、c が移動できる。で、aを移動して、とっておいたbを代入。

Tue Jan 21 22:45:09 JST 2003

とりあえず、jump は複雑すぎる。もっと簡単にすることを考える。
parser 側である程度処理できない?

     goto f(a+3,b(),c);

などを、

     a = a+3;
     b = b();
     goto f(a,b,c);

程度に簡略化する。この時、f(a,b,c) は(できるだけ)、元の
関数の引数リストに近付ける。のは無理なので、単純変数
まで落す。

あまり関係ないか。一時変数はどうせいるわけだし。ってこと
みたいね。

だとすると、元のコードと、そう変わらんね。前のも、そんなに
悪くないってことか。

Wed Jan 22 14:33:12 JST 2003

やっぱり、途中で局所変数を増やしたいよね。

Fri Jan 31 20:30:36 JST 2003

なんか #ifdef / #if がないとだめだな。実装する?
しました。

Tue Feb  4 01:04:12 JST 2003

##      while ((*chptr++ = c = getc(filep->fcb)) != '\n') { 
_1120:
        movl $10,%eax
        movl $8,%ecx
        movl filep,%edx
        addl %ecx,%edx
        movl (%edx),%edx
        pushl %edx
        xchg %edx,%eax     .... edx に$10が入る (なんでxchg?)
        call    getc
        addl $4,%esp
        movl %eax,-20(%ebp)  c に代入
        movl $chptr,%ecx
        pushl %ecx
        popl %ebx
        movl (%ebx),%ecx      ecx にchptrの中身
        addl $1,(%ebx)
        movb %al,(%ecx)
        subl %edx,%eax         eax-edx ($10)
        je      _1119

が壊れる理由なんだけど...

edx,ecx が破壊されちゃうみたいね。

Tue Feb  4 12:17:07 JST 2003

ようやっと直したよ...

use_pointer って、なにもしなくていいんだよね? eax,ebx を避ける
ってことらしいけど。

inline/引数付き #define 欲しくない? 置き換えは、local name stack に積んじゃう。
展開は function  で行う。

getch を工夫する必要はあるが。置き換えスタックが必要。


Wed Feb  5 01:16:00 JST 2003

大域で定義された struct field が大域変数と重なっていると落ちる。
そりゃそうだけど。どうするの? (直した記憶があるんだけどなぁ...)
struct 毎に field 名とoffset/type の組を持てばい良いんだよね。

なんだけど、タグ無しの構造体もあるから、型名の方に付ける必要
もある。というのは、型名のない構造体もあるから。タグ名には、
一応、リストがついている。なんかに使う必要があったんでしょう
ね。あ、めんどう。無条件にやっても大域変数名を汚すのを直すの
が難しい。

ちょっと、あれだけど、「型名.フィールド名」で登録してしまうのはどう?
型名が後で出て来るところが気まずいが...

def で登録するときに、nptrにdispを代入せずに、struct field list
(大域変数) に入れて、type の方に、field list (list3(nptr,offset,
type)) を入れれば良い。

あとは、strop の方でtypeのlistを見るようにすれば良いわけだ。

これなら、簡単に直せるはず。LUSTR/GUSTRなどの区別もなくなるし。

Wed Feb  5 02:10:14 JST 2003

浮動小数点ねぇ。完全なANSI Cにするのは大変。でも、
浮動小数点ぐらいないと。

code generation part を、さらに分割して、
複数のコード対応にしやすいようにする。
おそらく、それほど共有する部分はないけどね。

Sample C code をコンパイルして、その結果から(半分手動で)
Micro CbC code generation part を生成する方法を用意する。



Thu Feb  6 11:47:03 JST 2003

Code Segment を単位として使うときに、大域変数はどういう
ように分けるの? static なんかは意味ないよね。

もちろん、自然にグループ分けされるわけだけど。

あとデータフローだよね。データフローに関しては、
あんまりやってないなぁ

Fri Feb  7 14:36:15 JST 2003

inline では、必らず、局所変数の増加がある。また、inline
は普通の関数として展開しておく必要もあるらしい。(何故?)

#define ねぇ。

   #define c(a,b)  g(a+1,b+1)
   #define g(a,b)  printf("%d %d\n",a+1,b+1);

   main() {
       int a,b;
       a =1; b = 3;
       c(a,b);
   }

local #define がいるんだよね。g の中で a が出て来た時には、
c のa の置き換えは起こってはいけない。ということは、c
の置き換えはg が始まる前に終っている必要がある。dynamic
scope なんだから、assoc の上乗せで良いはず。
macro のlevelを定義して、あるレベルでは、それ以前の展開
を行わないという手法が良いかな。

   c(a,b) =>  a=>"a+1", b=>"b+1"
   g(a,b) =>  (a=>"a+1+1",a=>"a+1"), (b=>"b+1+1",a=>"a+1")

みたいな感じ?

やっぱり関数解析でマクロ処理をやらせるのは無理かな? 先読みされちゃうし。

Sat Feb  8 00:53:52 JST 2003

macro は途中まで書きました。置き換えをマクロが呼び出された
時点で cheap に置くと、それを解消するタイミングがない。
ここだけmallocしても良いが..

chptrsave はlistにする必要がある。list で良い。

やっぱりmacro levelを見て、自分と一致したassoc valueまで
手繰って置換するんでしょう。そうすれば、置き換える必要は無い。
ということは、local_define にmflagsを格納する必要がある。

   c(a,b) =>  a=>"a", b=>"b"
        a=>"a" .. mflag == 1
   g(a,b) =>  (a=>"a+1+1",a=>"a+1"), (b=>"b+1+1",a=>"a+1")
        a=>"a+1" .. mflag == 2
        
macro のもとのnptr が残ってないと、オリジナルを返せない。オ
リジナルは、sc などが破壊されてしまう。ってことは、local macro
は、local table を汚してはいけないってことだよね。ってことは、
macro table は、もとのとは別に用意する必要がある。

#define c(a,b)  g(a+1,b+1)
#define g(a,b)  printf("%d %d\n",a+2,b+2);

main() {
   int a,b;                  a ... local
   a =1; b = 3;
#ifndef a
   c(a,                 a = "a".. macro mflag==1
                        g(a,
                               a="a+1"  mflag==2
                                  ^  a = "a" mflag==1
                        While replacing a in g's body, a should not
                           be replaced to  (original) "a", should be c's a.
      b);                
   /* 3,5 expected */
#endif
}

うーむ。ややこしい。

    main() 
	c(a,b)    mflag++
                         a=>"a" mflag ==1
           g(a,b) mflag++;
                         a=>"a+1" mflag ==2
                             ^ is replaced by c's "a" not g's a;
いったん mflag level n で展開したら、それは mflag level n-1 となる。

Sat Feb  8 18:13:43 JST 2003

いちおう、mflag まではデバッグしたが....  mflag を戻してないんじゃないの?

     ---c(a,b)-----------------------  mflag ==1
          a=>hoge, b=>hoga (mflag==1)
        ----g(ac,bc)-----------------  mflag ==2
              ac=>goge, bc=>goga(mflag==2)
            ----printf(a,b)----------  mflag ==3
                a=>poge, b=>poga(mflag==3)

g が呼び出されると、ac,bc は mflag==1 でのみ置換される。

あるテキストを置き換えると、それは置き換えたマクロのmflag level
(つまり一つ少ないレベル)になる。
置き換え終ったら、元のlevelに戻す。

mflag==2のlevel では、mflag==2のlocal macroの展開しかしない。

置き換えると、mflag level 1 になるので、そこで mflag==1 のlocal
macro を展開する。mflag==0 は常に展開を行う。

Sun Feb  9 11:35:23 JST 2003

うーん、なんかtypeが、list とCHARなどと入混じっているじゃん。
    int save = chptrsave;
で、chptrsave が、$chptrsave になってしまう。

Sun Feb  9 22:33:36 JST 2003


#define car(e) (heap[(int)(e)])
#define cadr(e) (heap[((int)(e))+1])
    car(cadr(e))

だろ。
    car ->  
       #define e cadr(e) (mleve=1)
    cadr ->  
       #define e e (mleve=2)

むぅ。これ、うまくいかないんじゃん。こまったなぁ。

#define c(a,b)  g(a+1,b+1)
#define g(a,b)  printf("%d %d\n",a+1,b+1);
   c(a, b);

こっちもだめじゃん。ふーむ。lisp interpreter のように
作ればいいはずなんだけど。

Mon Feb 10 08:10:25 JST 2003

結局、list base のinterpreter を実装しました。きちゃないが。
前の方法でも、頑張ればできるんでしょうけどね。

Tue Feb 11 13:50:03 JST 2003

struct copy だけど... 関数がstructを返すときに、引数に前もって
積んでおくのでは、そこに値がコピーされてしまうし、あとで、
スタックをたたんで置くときにきまずい。

function call の時に、引数の型のチェックをしてない

type に -1 とheapの引数が混在しているやつだけど..
やっぱまずいんじゃないか?

temporal struct は再利用できるんだけど、dispの変更ができないので
新しく作るしかない。大きいときだけ新しく作るなんていうセコイ
技はあるけど。(そうすると、帰って来た値へのポインタを使えなく
なるが.... 別にいいよね。戻り値それ自身を直接 return する
時もだいじょうぶなはず)

結局、呼出側で、領域を確保して引き渡すことにしました。この方法だと、
代入のときに二度コピーする必要もない。

register  を使用しているかだけじゃなくて、実際にcreg/dregに
値があるかどうかを記憶する必要がある。

Wed Feb 12 11:09:22 JST 2003

それだけどさ... やっぱりアドホックに実現するのは難しいんじゃないの?

まぁねぇ。register の場所の確保と、寿命は別だから、それで
いいんだけど、regs flag だけでなんとかならないのかな。
こういう変更ははまるが虚しい。

Thu Feb 13 18:37:36 JST 2003

さて、そろそろ jump  にとりかかりますか。

構造体の引き渡しのシークエンスに使う局所変数の位置がgccと違う...

そろそろ register は構造体にすべきだね。
    struct register {
        int used;
        int valued;
        char *name;
        char *wname;
        char *bname;
        int type; /* register variable or not */
        int number;
    }
virtual/real は、どうする。

Sat Feb 15 14:00:03 JST 2003

fdecl_struct を構文的に引数が出現するときに行うと、int *f(int
a) などで、* の評価が終る前に、int aが評価されしまう。*obj 
のobj を評価し終らないとfのタイプが確定しない。int*f()[] み
たいな場合があるから。(?) なので、gcc と、そろえるためには、
arg の先頭で fdecl_struct を行う方法ではだめで、fdecl 中であ
とから修正する方が良い。

fix しようにも引数リストなんて、存在しないじゃん!

varargs を実装するのはめんどくさかろう...

rvalue(expr(),type) では、expr() のtypeをrvalueに引き渡せな
い。でも、type を大域変数にすると、rvalueを異なるタイプで呼
び出すときにtypeを変更する必要がある。このrvalueのtype の扱
いは、かなりはまったことがあるので、rvalue(int e,int type)の
方が良いことは確かなんだが... 

struct_push のregisterの扱いが複雑すぎ。なんか、もっと
簡単にならないの?

Sun Feb 16 07:58:23 JST 2003

代入しなくて良いからと言って、ソース
のリストから除いては、上書きを防げない。

Sun Feb 16 22:55:58 JST 2003

vdisp ってなんだったんだ?

Mon Feb 17 12:35:39 JST 2003

並列代入は出来たみたい。代入は小さいものを先にすべきなのか?
まぁ、できりゃいいんだけど、横に避けるものが大きいのはいや
だよね。

Tue Feb 18 11:56:10 JST 2003

overlapped 用の emit_copy
float/double
long long

Tue Feb 18 19:34:31 JST 2003

code argument の符号を反転させると、list2(LVAR,offset)
のoffsetがアドレスの方向と一致しているという前提が
崩れる。それで、構造体の格納順序がずれてしまう...

ということは... def(n) でcodeの時はargumentは、局所変数と同じ
扱いでマイナス符号で処理した方が良い。

できたみたい。でもさ、
   
int main( int ac, char *av[])
{
    int n;
    goto arg1(0,1,2,3,4,return,environment);
}

って、きっと return 文がないと、文句を
言われるよね。むむむ。

post processing する時にoverlapしてないという保証がない。

Wed Feb 19 15:38:55 JST 2003

自分自身とのoverlapを見てないので、
    struct a a,int i
    int i,struct a a
みたいな時に自分自身を壊してしまう。なので、emit_copy
が、ちゃんと方向を見て壊さないように処理する必要がある。

call bcopy でいいじゃん。まね。

Wed Feb 19 20:42:07 JST 2003

楊さんの C2CbC と CbC2C を、micro C に取り込む。各所に、
conv->func(); を埋め込む。conv は、構造体。

    conv:   original
            c2cbc
            cbc2c

とする。なるほど。

Thu May  6 08:32:05 JST 2004

やっぱり library も自分で作らないとね。そうすれば、
CbC only で作れるから。

conv は、あんまり良いアイデアではないみたい。取るか。。。

Thu May 13 12:59:16 JST 2004

byte code interpreter を CbC 自身で書いたら?

それでもやっぱり動かないから、あんまり意味はないんだけど...

C で書いてもいいか。

Wed Dec 22 15:17:49 JST 2004

   reset {
         shift;
   }

ねぇ。 なんで、return 構文にしたのか。しかも別々にしたのか。

  goto ret(value),env;

まぁ、ねぇ。
   try {
       .... goto event ....
   } catch (event) {
   }
をいれてもいいんだけど。

うーむ、いまいちだな。

inline function のreturn,env を実装するっていう技もあるけど。

やっぱり。setjmp = return みたいにする? それはそれで、
やさしいんだけど....


Fri Jan  6 20:26:24 JST 2006

environment = interface frame の切替えを用意しないとね。

Mon Jan 30 21:53:11 JST 2006

    packet_put  .....   fork
	packdet_put(interface hoge);
    packet_get  .....   join
	interface hoga = packdet_get();

      ----> distributed CbC

   Synatx
         code a() { }

         code a(a):b(b) {... }
         ->
             code a() {
                if (b = packet_get() {
                     .....
		} else goto a();
             }

         code a() {
               goto b();
         }

         code a() {
               goto b():d()@dest;
         }
         ->
	     code a() {
		   packet_put(d(),dest);
		   goto b();
	     }





Wed Sep  6 14:59:09 JST 2006

      code hoge(int a, code f(int k,...), ...)
      {
           goto f(a,...);
      }

syntax が汚い... type の指定はなんとかしないとだめだね。

      ...

      int a,

ずれたときのコストがなぁ。良く見えないんだよね。

可能だとは思うんだけど。

      __meta goto {
      }

みたいな感じ?

Sun Nov 26 21:14:57 JST 2006

      | frame pointer               | stack pointer
      v----> argument      local <--|-----v
                                    caller_arg

ではなくて、

      | previous $fp
      |<-intr_size---><--------r1_offset----------->|
      |               | frame pointer               | stack pointer
      v<--- interface-+---- local ----->|<--------->v
              <0          >0              caller_arg

なら、いいんじゃない? caller_arg は sp 相対で積めば良い。
local 変数は max_caller_arg が不定なので sp 相対では積めない。

これだと、frame pointer がgoto で可変になる。interface がarugment
扱いになるので、限りなくsubroutine call に近くなるけど。
(まぁ、そうだよな、そういう狙いだし...)

だったら、完全にfunction callに合わせることも可能なんじゃないか?
可変長引数の場合とまったく同じになる。gcc の(予定ししてる実装と同じ)
これだと、C-- の paraterized goto と、まったく同じになる。

      | previous $fp
      |<-intr_size---><-------------r1_offset------------>|
      |               |frame pointer                      | stack pointer
      v<--- interface-+-------|--- local ----->|<-------->v
              <0      >0  xxx                    caller_arg
                         |frame pointer                      | stack pointer
      v<--- interface----+-------|--- local ----->|<-------->v
              <0         >0  xxx                    caller_arg

caller_arg はsp上に積むと。そうすれば、alloca も問題ない。

これを採用しなかったのは、たぶん、fp を移動しなければならな
いのを嫌ったんだろうな。今は、parse tree 作ってから、code 
生成も可能なので、そうしても良いんだが。

でも、めんどくさいよ。めんどくさい。めんどくさいです。
でも、やるしかない。

これを、やれば、C からの変換もかなりやさしくなるかも知れない。

Sun Nov 26 19:41:38 JST 2006

max interface みたいなのが必要で、そうすれば、local 変数との
相互作用は避けられる。逆に言えば、利用は出来ない。

でも、max_interface は1 path では決まらない。だから、long offset
の時は、ちょっとはまる。特にARMの場合。やっぱり、max_interface
は決め打ちがいいのかな? そうすると、function call から呼ぶ
ときにはまるが... 

offset を 0 側からにすれば、max_interface はfp設定時のみに
なるが、そうすると、interface を変更したときのcopyが発生しやすく
なる。いや、そんなことはないのかな?

      __code f(int a,int b) {
	goto g(int c,int b,int a);
      }

      v<---|----+----local ----->|<-------->v                before f
        a,b
      v<--- interface-+-------|--- local ----->|<-------->v  f
        a,b
      v<--- interface-+-------|--- local ----->|<-------->v  goto g
        a,b,c

みたいな感じですか? 後ろをそろえるわけね。その方が自然か。

これだと、やっぱり、max_interface が問題になる。やっぱり、それで、
fp を下にしてあるんだろうな。

      __code f(int a,int b) {
	goto g(int c,__code *f,int a,int b);
      }

      __code g(int c,__code (*n)(...),...) {
	goto n(...);
      }

      |<----------------------------r1_offset------------>|
      |frame pointer                                      | stack pointer
      v<--- interface---------|--- local ----->|<-------->v  f
        a,b,(n,c)
      |frame pointer                                      | stack pointer
      v<--- interface---------|--- local ----->|<-------->v  goto g
        a,b,fp,n,c
            |frame pointer                                | stack pointer
            v<-interface-+-------|-- local --->|<-------->v  g
        a,b,fp,n,c
       |frame pointer                                     | stack pointer
      v<--- interface---------|--- local ----->|<-------->v  goto n
        a,b

えーと、goto n(...); で、どうやってfp を元に戻すの? ... の位置で、
前の fp を覚えておけば良い。(*)

これだと、function call を、そのまま実現できそうだけど? みたいだね。

      __code f(int a,int b,...) {
	goto g(int c,f,int a,int b,...);
      }

      __code g(int c,__code *n(int a,int b,...),...) {
	goto n(int d,int e,int g,...);
      }

とかすると、無限にstackが延びる。ふーん。

      __code g(int c,__code *n(...),...) {
	goto n(int d,int e);
      }

は、どうする? fp は、そのままなんだろうね。

      |<----------------------------r1_offset------------>|
      |frame pointer                                      | stack pointer
      v<--- interface-+-------|--- local ----->|<---------v  f
        a,b,(n,c)
      |frame pointer                                      | stack pointer
      v<--- interface-+-------|--- local ----->|<---------v  goto g
        a,b,fp,n,c
            |<----------------------r1_offset------------>|
            |frame pointer                                | stack pointer
            v<-interface----+----|-- local --->|<---------v  g
        a,b,fp,n,c
               v<-interface-+----|-- local --->|<---------v  g
               d,e

で、fp は上書きか。それは、良くない。なので、fp の分ずらす。
というよりは、fp の次を指すようにするのが良いのか。

      __code f(int a,int b,...) {
	goto g(int c,__code *f,int a,int b,...);
      }

      __code g(int c,__code (*n)(...),...) {
	goto n(...);
      }

      |<----------------------------r1_offset------------>|
      |frame pointer                                      | stack pointer
      v---- interface-+-------|--- local ----->|<---------v  f
        a,b,(n,c)
      |frame pointer                                      | stack pointer
      v---- interface-+-------|--- local ----->|<---------v  goto g
        a,b,fp,n,c
               |<-------------------r1_offset------------>|
               |frame pointer                             | stack pointer
               v<-interface-+----|-- local --->|<---------v  g
        a,b,fp,n,c
      |frame pointer                                      | stack pointer
      v---- interface-+----------|-- local --->|<---------v  goto n
        a,b

というわけか。frame pointer のオプションがあった方が良いわけだね。

これだと、全体の変更も少なくて済みそうだ。(ほんとうか?)

g の ... の位置を前もって知ることが必須。かなりコードが繁雑に
なるけど。
      __code g(int c,__code n,...) {
の方が良いが、それだと、型のチェックが出来ない。実際には、
かなり繁雑な型を書く羽目になる。typedef すればいいんだけどね。

__code は暗黙のtypedef にする?


これを許すとmax_interfaceの制限は現実的ではない? でもないか...
そのcodeでアクセス限界だからね。だったら、max_interface を
作って、(1024程度?)  いや、やっぱり fp は動かさないとだめ
なので、良くない。

fp を積む場合と、戻す場合との区別は? 結構微妙か。
    goto 側の定義 ...が先に(か同時に)来たら戻す
    goto 側の定義 ...が実引数より後に来たら積む
で、いいわけね?

ちょっと、Semantics が複雑になりすぎる。可能なんだけど。
environment での goto でたまにリセットしないとおかしくなりそう。
Stack 増えている場合は、Warning ぐらいだした方がいいかも。
大域的に見ないとわからない。有限かどうかも。

全部、tail recursive call でやるのと、あまり変わらないかな。
そうすると、c-- のparametarized goto と差がないかも。


あ、そうか。

      __code g(int c,__code *n(int a,int b,...),...) {
	goto n(int d,int e,int g,...);
      }

の n は、自動的に定義された方が便利だろう。

      __code g(int c,...) {
	goto __cotinuation(int d,int e,int g,...);
      }

みたいな感じ。

      go g(int c,int b,...) to hoge(...);

ですか? それは、だめか... だめでもないんだけど、型の設定が
難しすぎる。

K&R style の宣言の方が綺麗なのか...

Sun Nov 26 21:53:05 JST 2006

(*) interface の大きさの増減は、自分のinterface を見れば
わかるはずだよね? だから、fp のsaveは必要ないはずだが...

      __code f(int a,int b,...) {
	goto g(int c,__code *f,int a,int b,...);
      }

      __code g(int c,__code (*n)(...),...) {
	goto n(...);
      }

確かにわかるんだけど、宣言を間違えたときに、おじゃんになる。
どうせ、だめではあるんだが。引数の型は一段階までしか、
チェックしないので、だめだね。


このあたり、理論的な問題があるみたいだな。

    stack を含めた有限な型付け
    と、その表現

って問題があるわけね?

そうか、parallel assignment では、同じ部分を前もって探した
方が効率がよいわけか。(どうせ、やっていることだが)

Sun Nov 26 23:22:12 JST 2006

fp のsave は必要。何故かと言うと、
    goto f(a,b,...)
で、後ろの部分がどれだけあるかは、間接的な引数での
宣言ではわからないから。

stack 上に全部 interface があるなら、良いが、
部分は register に乗っている。

    goto f(a,b,c,...)

としたときに、... の一部はregisterに乗っている。どれだけ
乗っているのかを知る必要があるが、それをfpから推察する
ことはできない。浮動小数点とかの異なる型が散在している
から。

... で引き渡す引数は、メモリに乗っている必要がある。
型が明解なら、レジスタ上でもだいじょぶなはずだが。

明示的な引数に大域的には変換できるはずだけど、open 
な環境では、それはできない。

だとすれば、
    __code f(int a, int b : int h, ...) {
       ...
	goto g(a,b,c : d,e,f,...)
    }
みたいな形で、stack 上に乗せる引数を明示する必要がある。

これは、なんなの?

    : の前の引数は可変に出来ない
    : の後までは可変に出来る

っていうことか。

構造体は、メモリ上に取るとしても..

まぁ、...   のところまでレジスタで、それ以降は、メモリでも
十分だけどね。いずれにせよ、複雑すぎることは確か。

      __code g(int c,__code (*n)(int a,int b,int d,...),...) {
	goto n(int d,int e,int c,...);
      }

で、この... は、すべて、同じものに置き換わるはず。 ... が
入る場合もあるが。

受け側が
	__code c(int d,int e,int c,int k,int j) {}
で定義されているときに、k,j がレジスタに乗っているかも知れず、
乗っていたらダメダメ。なので、可変になる部分を明示する必要がある。

Mon Nov 27 11:17:39 JST 2006

結局、このn の定義と、実際のn の定義がずれることが問題なんだよね。
	__code c(int d,int e,int c,...) {}
で、受けることもあれば、
	__code c(int d,int e,int c,int k,int j) {}
で受けることもある。あるいは、
	__code c(int d,int e,int c,int k,int j,...) {}
とかも。

implements というか、accetps というか、そんな形の別な
宣言がいいのかな。
    __code f(int a, int b : int h, ...) {
でもいいんだが...

Mon Nov 27 11:34:33 JST 2006

      __code f(int a,int b,...) {
	goto g(int c,__code *f,int a,int b,...);
      }

      __code g(int c,__code (*n)(...),...) {
	goto n(...);
      }


g に入るときに、fp は、n の頭になければならない。これを
移動するのは、f の役割。出て行くときには、b の頭に
合わせる必要がある。これは、g の役割。g は、元の頭(fp)
を知らないから、これは取っておく必要がある。差では
判断できない。g 側で取っておくことは可能だが、その
時にも、f 側からずらす大きさを渡す必要がある。

明示しても良いんだけどね...
	goto g(int c,__code *f,__environment,interface &rest),
		__envronment+sizeof(interface);
      __code g(int c,__code (*n)(...),(void*)parent,...) {
	goto n(...),parent;
      }
みたいな形でさ... その方がいいのかな。繁雑だけど。: よりかまし?

: を使う方法だと、: が fp みたいな感じになる。

難しいね。きれいなsyntaxにならない。

Wed Jul 25 14:48:16 JST 2007

inline code __goto みたいな形にすると、

    __goto  hoge();

goto を reflection 出来る。

meta な、interface はどうするの? 

デフォルトで、,.... が入っていると思う方が良い。

     goto hoge(hoge.... , __code (*cont)(i) : meta ...);

             goto cont(i);  -> goto cont(i: meta...);

という感じか?  これがないと、記述がかなり面倒。subroutine とは
違うの?

env の切替えで明示出来ないの? 出来るけど、繁雑なのか。

gcc との相性が良くないのだが...

__code の先行宣言つらすぎる。script で生成するか、compiler で
自動解決する方が良い。

tcc の方が  goto f(); ではなくて、goto (*f)(); を
強制する。これは、けっこう、めんどくさい。

 ... ってのは大域変数みたいなものだよね? ただ、stack scope がある。
なので、sub routine と同じなのでは?