]> git.mdlowis.com Git - proto/aas.git/commitdiff
added func calls and paren grouping. argument access is broken and needs some carfule...
authorMichael D. Lowis <mike@mdlowis.com>
Tue, 14 Nov 2023 03:01:20 +0000 (22:01 -0500)
committerMichael D. Lowis <mike@mdlowis.com>
Tue, 14 Nov 2023 03:01:20 +0000 (22:01 -0500)
cerise.m
cerise.rb

index 9c3468fb8782610208121d7e9ab05a4883a59282..8de600348c0f9b8d40e0dbd9a14af3c8b437e452 100644 (file)
--- a/cerise.m
+++ b/cerise.m
@@ -1,4 +1,9 @@
+sum(a,b)
+{
+    return a+b
+}
+
 main()
 {
-    return 42 * 2
+    return sum(1+1,2)
 }
index 513eb6b22f9790dd1dd39b787badc094731664bb..8a342055fd080d0242e8643e2019613fc10a9703 100755 (executable)
--- a/cerise.rb
+++ b/cerise.rb
@@ -107,11 +107,13 @@ class SymTable < Hash
     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
 
@@ -128,74 +130,6 @@ class SymTable < Hash
       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
@@ -205,7 +139,7 @@ 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)
@@ -536,17 +470,17 @@ end
 
 
 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
 
@@ -630,8 +564,29 @@ class Parser
     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
@@ -706,7 +661,7 @@ class Parser
 
   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)
@@ -721,35 +676,6 @@ class Parser
       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()
@@ -763,10 +689,32 @@ class Parser
   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")
@@ -778,6 +726,8 @@ class Parser
       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
@@ -792,6 +742,10 @@ module Codegen
       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
@@ -826,14 +780,33 @@ module Codegen
       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