https://github.com/takeisa/uschemer2/tree/v0.02
define命令の追加
Virutal machineにdefine命令を追加した。
命令 | 説明 |
---|---|
(define var) | aレジスタのオブジェクトをシンボルvarで束縛する。 |
define式のコンパイル
define式は(define var val)
(define (func arg0...) body)
の2種類の形式に対応する。
対応するRubyコードは以下の通り。
elsif symbol == :define then
if exp.cdr.car.is_a?(SSymbol) then
# (define var val)
var = exp.cdr.car
val = exp.cdr.cdr.car
compile(val, Define.new(var, next_op))
elsif list?(exp.cdr.car) then
# (define (func arg0...) body)
var = exp.cdr.car.car
args = exp.cdr.car.cdr
body = exp.cdr.cdr.car
val = SCons.new(SSymbol.new(:lambda), SCons.new(args, SCons.new(body)))
compile(val, Define.new(var, next_op))
else
raise "define syntax error"
end
2番目の形式の場合は、
(define (func arg0...) body)
↓
(define func (lambda (arg0...) body))
に変換し、再度コンパイルする。
実行例
$ ruby uschemer.rb> (define (add a b) (+ a b)) ←◆ここでadd関数を定義
#<Instruction::Closure:0x96d8c98
@body=
#<Instruction::Frame:0x96d8cc0
@ret=#<Instruction::Return:0x96d8d88>,
@x=
#<Instruction::Refer:0x96d8cd4
@var=#<SSymbol:0x96d8e3c @value=:a>,
@x=
#<Instruction::Argument:0x96d8ce8
@x=
#<Instruction::Refer:0x96d8cfc
@var=#<SSymbol:0x96d8e14 @value=:b>,
@x=
#<Instruction::Argument:0x96d8d10
@x=
#<Instruction::Refer:0x96d8d60
@var=#<SSymbol:0x96d8e64 @value=:+>,
@x=#<Instruction::Apply:0x96d8d74>>>>>>>,
@env=
#<Env:0x96d96e8
@binds=
[#<VarBind:0x96d96d4
@bind=
{:+=>#<Proc:0x96d9648@uschemer.rb:53 (lambda)>,
:-=>#<Proc:0x96d95f8@uschemer.rb:54 (lambda)>,
:*=>#<Proc:0x96d9594@uschemer.rb:55 (lambda)>,
:/=>#<Proc:0x96d9530@uschemer.rb:56 (lambda)>,
:add=>#<Instruction::Closure:0x96d8c98 ...>}>]>, ←◆define時の環境を持っている
@vars=
#<SCons:0x96d8ef0
@car=#<SSymbol:0x96d8edc @value=:a>,
@cdr=
#<SCons:0x96d8ec8
@car=#<SSymbol:0x96d8ea0 @value=:b>,
@cdr=#<SNilClass:0x927bba0>>>>
> (add 10 20) ←◆ここでadd関数呼び出し
#<SNumber:0x96c2df8 @value=30> ← ◆30が返ってきた。
define式の評価後は、Virtual machineのaレジスタにクロージャのコンパイル結果が格納されているため、
上記のような表示となる。
式をVirtual machineの命令に変換し、関数呼び出しで、それが実行される。
自分で実装して、実際に動かしてみると、なかなか感動的で、かなり楽しい。
0 件のコメント:
コメントを投稿