not (self[key] || {})[:type].nil?
end
- def add_sym(name, loc, kind, type = nil)
+ def add_sym(name, loc, kind, scope = :local, type = nil, value = nil)
self[name] = {
loc: loc,
kind: kind,
- type: type
+ scope: scope,
+ type: type,
+ value: nil
}
end
nil
end
end
-
- def depth
- count = 0
- env = self
- while env.class != Hash
- count += 1
- env = env.parent
- end
- count
- end
-
-# def local(key)
-# method(:[]).super_method.call(key)
-# end
-#
-# def defined_ever?(key)
-# (not (self[key] || {})[:type].nil?)
-# end
-#
-# def defined_locally?(key)
-# (not (local(key) || {})[:type].nil?)
-# end
-#
-# def block_local?(key)
-# (not local(key).nil?)
-# end
-#
-# def global?(key)
-# if @parent.class == Hash
-# block_local?(key)
-# elsif block_local? key
-# false
-# else
-# @parent.global? key
-# end
-# end
-#
-# def local?(key)
-# if @parent.class == Hash
-# false
-# elsif @type == :func
-# block_local? key
-# else
-# @parent.local? key
-# end
-# end
-#
-# def free?(key)
-# (defined_ever? key) and (not local? key) and (not global? key)
-# end
-#
-# def merge!(env)
-# env.each {|k,v| self[k] = v }
-# end
-#
-# def annotate(key, type)
-# self[key] ||= {}
-# self[key][:ann] = type
-# end
-#
-# def annotation(key)
-# (method(:[]).super_method.call(key) || {})[:ann]
-# end
-#
-# def stack()
-# parent = (@parent.is_a?(SymTable) ? @parent.stack : [])
-# ([self] + parent).flatten
-# end
end
module IR
Var = Struct.new(:loc, :type, :name)
Def = Struct.new(:loc, :type, :name, :value)
Op = Struct.new(:loc, :type, :op, :left, :right)
-
+ Call = Struct.new(:loc, :type, :func, :args)
# EnvRef = Struct.new(:loc, :type, :index)
# Let = Struct.new(:loc, :type, :var, :expr, :body)
class Parser
- attr_accessor :exprs
+# attr_accessor :exprs
attr_accessor :syms
attr_accessor :defs
def initialize(path = nil)
@syms = SymTable.new
- syms.add_sym(:void, 0, :type, :void)
- syms.add_sym(:bool, 0, :type, :bool)
- syms.add_sym(:int, 0, :type, :int)
- syms.add_sym(:string, 0, :type, :string)
- syms.add_sym(:float, 0, :type, :float)
+ syms.add_sym(:void, 0, :type, :builtin, :void)
+ syms.add_sym(:bool, 0, :type, :builtin, :bool)
+ syms.add_sym(:int, 0, :type, :builtin, :int)
+ syms.add_sym(:string, 0, :type, :builtin, :string)
+ syms.add_sym(:float, 0, :type, :builtin, :float)
parse_file(path)
end
imports
exports
@defs = {}
+# @syms = SymTable.new
+
while !matches(:eof)
mod_def = toplevel_defintion()
+
+# kind = (case mod_def.value.class
+# when IR::Const.class
+# :const
+# when IR::Var.class
+# :var
+# when IR::Func.class
+# :func
+# else
+# raise "invalid toplevel definition #{mod_def.value.class}"
+# end)
+# @syms.add_sym(
+# mod_def.name.name,
+# 0,
+# kind,
+# :global,
+# nil,
+# mod_def.value)
+
@defs[mod_def.name.name] = mod_def
end
end
def simple_expr()
# Handle unary ops first
- if matches_any(["+", "-"])
+ if matches_any(["+", "-", :not])
op = consume()
left = term()
left = IR::Op.new(op.location, nil, op.text, left, nil)
left = IR::Op.new(location, nil, op.text, left, right)
end
left
-# 269 /* first term and +/- unary ops */
-# 270 if (matches_oneof(p, (int[]){'+', '-', 0}))
-# 271 {
-# 272 int op = consume(p);
-# 273 SsaNode* operand = term(p);
-# 274 check_num(p, operand);
-# 275 expr = ssa_op(p, op, operand, NULL);
-# 276 }
-# 277 else
-# 278 {
-# 279 expr = term(p);
-# 280 }
-# 281
-# 282 /* optional second term and binary ops */
-# 283 while (matches_oneof(p, (int[]){'+', '-', OR, 0}))
-# 284 {
-# 285 int op = consume(p);
-# 286 SsaNode* right = term(p);
-# 287 if (op == OR)
-# 288 {
-# 289 check_bools(p, expr, right);
-# 290 }
-# 291 else
-# 292 {
-# 293 check_nums(p, expr, right);
-# 294 }
-# 295 expr = ssa_op(p, op, expr, right);
-# 296 }
-
end
def term()
end
def factor()
- constant()
+ if accept("(")
+ expr = expression()
+ expect(")")
+ else
+ expr = const_or_ident()
+ end
+
+ # Check for function call
+ if matches("(")
+ expr = func_call(expr)
+ end
+ expr
+ end
+
+ def func_call(expr)
+ call = IR::Call.new(location, nil, expr, [])
+ expect("(")
+ while !matches(")")
+ call.args << expression()
+ expect(",") if !matches(")")
+ end
+ expect(")")
+ call
end
- def constant()
+ def const_or_ident()
tok = consume()
if tok.type == :bool
IR::Const.new(tok.pos, :bool, tok.text == "true")
IR::Const.new(tok.pos, :float, tok.text.to_f)
elsif tok.type == :void
IR::Const.new(tok.pos, :void, :void)
+ elsif tok.type == :ident
+ IR::Var.new(tok.pos, nil, tok.text.to_sym)
else
error("invalid constant")
end
emit_const(v)
elsif v.is_a? IR::Op then
emit_binop(v)
+ elsif v.is_a? IR::Var then
+ emit_var(v)
+ elsif v.is_a? IR::Call then
+ emit_call(v)
else
raise "code emitting of #{v.class} not implemented"
end
raise "not implemented"
end
end
+
+ def self.emit_var(v)
+ puts " #{v.name}"
+ end
+
+ def self.emit_call(v)
+ v.args.reverse.each do |arg|
+ emit(arg)
+ end
+ # TODO: handle args/locals/globals
+ if v.func.is_a? IR::Var
+ puts " call #{v.func.name}"
+ else
+ emit(v.func)
+ emit " callv"
+ end
+ end
end
$parser = Parser.new("cerise.m")
+#pp $parser.syms
+#pp $parser.defs
$parser.defs.each do |name, val|
- puts "func #{name.to_sym.inspect} do"
+ puts "func #{name.to_sym.inspect}, #{val.value.args.length} do"
val.value.body.each do |stmnt|
Codegen.emit(stmnt)
end
- puts "end"
+ puts "end\n\n"
# puts val
end