module IR
- Func = Struct.new(:loc, :type, :args, :body)
+ Func = Struct.new(:loc, :type, :args, :locals, :body)
Return = Struct.new(:loc, :type, :value)
Const = Struct.new(:loc, :type, :value)
Var = Struct.new(:loc, :type, :name)
def function_definition(name)
args = function_arglist()
- func = IR::Func.new(name.loc, nil, args, [])
+ func = IR::Func.new(name.loc, nil, args, [], [])
expect("{")
+ while matches(:def)
+ local = variable_definition()
+ func.locals << local.name.name
+ end
stmts = statement_list(["}", :return])
stmts << return_statement
func.body = stmts
# if statement
# expression
- if matches(:def)
- variable_definition()
- elsif matches(:set)
+ if matches(:set)
variable_assignment()
elsif matches(:if)
if_statement()
end
module Codegen
- @@label_count = 0
+ State = Struct.new(:label, :locals, :syms)
+
+ def self.init(syms)
+ State.new(0, [], syms)
+ end
- def self.genlabel()
- label = @@label_count
- @@label_count = @@label_count + 1
+ def self.genlabel(state)
+ label = state.label
+ state.label = state.label + 1
end
- def self.emit(syms, v)
+ def self.emit(state, v)
if v.is_a? IR::Return then
- emit_return(syms, v)
+ emit_return(state, v)
elsif v.is_a? IR::Const then
- emit_const(syms, v)
+ emit_const(state, v)
elsif v.is_a? IR::Op then
- emit_binop(syms, v)
+ emit_binop(state, v)
elsif v.is_a? IR::Var then
- emit_var(syms, v)
+ emit_var(state, v)
elsif v.is_a? IR::Call then
- emit_call(syms, v)
+ emit_call(state, v)
elsif v.is_a? IR::Def then
- emit_def(syms, v)
+ emit_def(state, v)
elsif v.is_a? IR::Set then
- emit_set(syms, v)
+ emit_set(state, v)
elsif v.is_a? IR::If then
- emit_if(syms, v)
+ emit_if(state, v)
else
raise "code emitting of #{v.class} not implemented"
end
end
- def self.emit_return(syms, v)
- emit(syms, v.value)
+ def self.emit_return(state, v)
+ emit(state, v.value)
puts " retwv"
end
- def self.emit_const(syms, v)
+ def self.emit_const(state, v)
if v.value.is_a? Integer
puts " int #{v.value}"
end
end
- def self.emit_binop(syms, v)
- emit(syms, v.left)
- emit(syms, v.right)
+ def self.emit_binop(state, v)
+ emit(state, v.left)
+ emit(state, v.right)
case v.op
when "+"
puts " addi"
end
end
- def self.emit_var(syms, v)
- sym = syms[v.name]
+ def self.emit_var(state, v)
+ sym = state.syms[v.name]
if sym
if sym.kind == :param
puts " get_param #{sym.value}"
end
end
- def self.emit_call(syms, v)
+ def self.emit_call(state, v)
v.args.reverse.each do |arg|
- emit(syms, arg)
+ emit(state, arg)
end
# TODO: handle args/locals/globals
if v.func.is_a? IR::Var
puts " fcall #{v.func.name.inspect}"
else
- emit(syms, v.func)
+ emit(state, v.func)
puts " fcallv"
end
end
- def self.emit_def(syms, v)
- syms.add_sym(
+ def self.emit_def(state, v)
+ state.add_sym(
v.name.name, v.loc, :local, v.type, v.value)
- emit(syms, v.value)
+ emit(state, v.value)
puts " set_local :#{v.name.name}"
end
- def self.emit_set(syms, v)
+ def self.emit_set(state, v)
puts " set_local :#{v.name.name}"
end
- def self.emit_if(syms, v)
- lbl1 = genlabel()
- lbl2 = genlabel()
- emit(syms, v.cond)
+ def self.emit_if(state, v)
+ lbl1 = genlabel(state)
+ lbl2 = genlabel(state)
+ emit(state, v.cond)
puts " jmp_if0 :L#{lbl1}"
- emit_block(syms, v.then)
+ emit_block(state, v.then)
puts " jmp :L#{lbl2}"
puts "label :L#{lbl1}"
- emit_block(syms, v.else)
+ emit_block(state, v.else)
puts "label :L#{lbl2}"
end
- def self.emit_block(syms, v)
+ def self.emit_block(state, v)
return if v.nil?
v.each do |v|
- emit(syms, v);
+ emit(state, v);
end
end
end
$parser = Parser.new("cerise.m")
+state = Codegen.init($parser.syms)
$parser.syms.each do |name, val|
$parser.syms.open_scope
puts "func #{name.to_sym.inspect}, #{val.value.args.length} do"
+ puts " locals #{val.value.locals.length}" if val.value.locals.length > 0
val.value.args.each_with_index do |name, idx|
$parser.syms.add_sym(
name.name, name.loc, :param, name.type, idx)
end
val.value.body.each do |stmnt|
- Codegen.emit($parser.syms, stmnt)
+ Codegen.emit(state, stmnt)
end
puts "end\n\n"
$parser.syms.close_scope