hakeの日記

Windows環境でプログラミングの勉強をしています。

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

詳細はこちら