Rubyでコンパイラを作ってみる その2
関数を定義して使えるように拡張しました。
関数の引数とローカル変数はスタック上に置くので、それをアクセスする基準となるベースポインタと、関連するオペコードを追加。
以下のソースプログラムが
int add(a,b){ int x; x = a + b; return x; } int a,b; a = 1; b = 2; print add(a+1,b+2);
構文木はこんなで
[:LIST_STMT . [:DECL_FUNC_INT . . [:FUNC_NAME "add" 0] . . [:LIST_VAR . . . [:VAR "a" 0] . . . [:VAR "b" 0] . . ] . . [:LIST_STMT . . . [:DECL_VAR_INT . . . . [:LIST_VAR . . . . . [:VAR "x" 0] . . . . ] . . . ] . . . [:ASSIGN . . . . [:VAR "x" 0] . . . . [:PLUS . . . . . [:VAR "a" 0] . . . . . [:VAR "b" 0] . . . . ] . . . ] . . . [:RETURN . . . . [:VAR "x" 0] . . . ] . . ] . ] . [:DECL_VAR_INT . . [:LIST_VAR . . . [:VAR "a" 0] . . . [:VAR "b" 0] . . ] . ] . [:ASSIGN . . [:VAR "a" 0] . . [:NUMBER "1" 1] . ] . [:ASSIGN . . [:VAR "b" 0] . . [:NUMBER "2" 2] . ] . [:PRINT . . [:LIST_VAR . . . [:FUNC . . . . [:FUNC_NAME "add" 0] . . . . [:LIST_VAR . . . . . [:PLUS . . . . . . [:VAR "a" 0] . . . . . . [:NUMBER "1" 1] . . . . . ] . . . . . [:PLUS . . . . . . [:VAR "b" 0] . . . . . . [:NUMBER "2" 2] . . . . . ] . . . . ] . . . ] . . ] . ] ]
出力は、こんな感じになります
_VAR _a$ INT 0 _b$ INT 0 _END_VAR _PROG JP L000_PROG_START L001_add: LEASP 1[SP] LDA -3[BP] ; ret_value LDA 2[BP] ; x LDA -1[BP] ; a LDS LDA -2[BP] ; b LDS ADD STS DEL LDA 2[BP] ; x LDS JP L001_RET L001_RET: STS DEL LEASP 1[BP] RET L001_END: L000_PROG_START: LDA _a$ LDI 1 STS DEL LDA _b$ LDI 2 STS DEL LEASP 1[SP] LDA _b$ LDS LDI 2 ADD LDA _a$ LDS LDI 1 ADD PUSH LEABP 0[SP] CALL L001_add POP LEASP -2[SP] PRT STOP _END_PROG
詳細はこちら