仙台hackathon#02

土曜日は、仙台オータムセミナーの携帯サイトの2009年バージョンの対応をしてきました。
昨日は、片平堂で仙台hackathon#02をしてきました。

今週は結構疲れてたのと計画から離れたことをしてたので進捗具合はそれほどよくなかった。
でも、いずれ必要になることではあるので実りは多かったと思います。

id:yuichi_katahiraさんが再帰がわからないと言ってる理由は Rubyはブロックを多用する高階関数使いまくりな言語だからというのと、スタック食うのと関数(メソッド)呼び出しのオーバーヘッドが大きいから多用しちゃだめってことで使っていなかったという理由がわかりました。


とこれだけだと、アレなので、書いていたスタックマシン等をおいときます。
階乗計算ができるだけの能力を持つVMです。中身の解説は書いている途中なので出来上がったら公開します。

class FactVM
	def initialize(env)
		@stack = []
		@env = env
		@ptr = 0
		@func = :main
		@codes = env[@func]
		@dump = []
	end

	def run
		while true
			p [@func, @codes[@ptr], @stack, @dump]
			case @codes[@ptr]
			when :push
				@stack.push(@codes[@ptr+1])
				@ptr = @ptr + 2
			when :call
				name = @stack.pop()
				@dump.push(@func, @ptr + 1)
				@func = name
				@codes=@env[@func]
				@ptr = 0
			when :mul
				@stack.push(@stack.pop()*@stack.pop())
				@ptr = @ptr + 1
			when :sub
				@stack.push(-@stack.pop()+@stack.pop())
				@ptr = @ptr + 1
			when :ret
				if @dump.length <= 0
					return @stack.pop()
				else
					@ptr = @dump.pop()
					@func = @dump.pop()
					@codes = @env[@func]
				end
			when :pop
				@stack.pop()
				@ptr = @ptr + 1
			when :dup
				@stack.push(@stack[-1])
				@ptr = @ptr + 1
			when :if
				if @stack[-1] != 0
					@ptr = @ptr + @codes[@ptr + 1]
				else
					@ptr = @ptr + 2
				end
			end
		end
	end
end

# def main()
#   fsub(2,1)
# end
#
# def fsub(a,b)
#   a-b
# end
#
# main()
# の計算を行う

p FactVM.new({
	:main => [
		:push, 2,
		:push, 1,
		:push, :fsub,
		:call,
		:ret
	],
	:fsub => [
		:sub,
		:ret
	],
}).run

p FactVM.new({
	:main=>[
		:push, 3,
		:push, :fact,
		:call,
		:ret
	],
	:fact =>[
		:if,6,
			:pop,
			:push, 1,
			:ret,
		:dup,
		:push, 1,
		:sub,
		:push, :fact,
		:call,
		:mul,
		:ret
	],
}).run