]> git.mdlowis.com Git - proto/aas.git/commitdiff
added parsing rules for if statements and local variables
authorMike Lowis <mike.lowis@gentex.com>
Tue, 21 Nov 2023 19:18:43 +0000 (14:18 -0500)
committerMike Lowis <mike.lowis@gentex.com>
Tue, 21 Nov 2023 19:18:43 +0000 (14:18 -0500)
.gitignore
cerise.m
cerise.rb

index d7756c255cff24d5574076babac93d231312b644..3a9dea076f1dde3f5f1079fd927a84736582b40b 100644 (file)
@@ -1,2 +1,4 @@
 a.out
 *.o
+*.aas
+*.s
index 48e0867252fd0aabd6a1962e18aadd1f7eeb8ddd..a0e98a520d9988041e1cad1a01306508417f5abb 100644 (file)
--- a/cerise.m
+++ b/cerise.m
@@ -1,9 +1,18 @@
 sum(a,b)
 {
-    return a==b
+    def c = 5
+    if (a < b)
+    {
+        set c = 1
+    }
+    else
+    {
+        set c = 0
+    }
+    return c
 }
 
 main()
 {
-    return sum(3,2)
+    return sum(1+1,2)
 }
index 282b05a6826313f5625329dcbde890ca542f9f56..8fad22df236f49120114d44a148e0083a507b909 100755 (executable)
--- a/cerise.rb
+++ b/cerise.rb
@@ -47,13 +47,11 @@ class Lexer
     "true"   => :bool,
     "false"  => :bool,
     "if"     => :if,
-    "then"   => :then,
     "else"   => :else,
-    "end"    => :end,
-    "let"    => :let,
-    "func"   => :func,
-    "in"     => :in,
-    "set!"   => :set,
+    "def"    => :def,
+    "set"    => :set,
+#    "func"   => :func,
+#    "in"     => :in,
     "is"     => :is,
     "return" => :return,
   }
@@ -153,8 +151,10 @@ module IR
   Const  = Struct.new(:loc, :type, :value)
   Var    = Struct.new(:loc, :type, :name)
   Def    = Struct.new(:loc, :type, :name, :value)
+  Set    = Struct.new(:loc, :type, :name, :value)
   Op     = Struct.new(:loc, :type, :op, :left, :right)
   Call   = Struct.new(:loc, :type, :func, :args)
+  If     = Struct.new(:loc, :type, :cond, :then, :else)
 
 #  EnvRef = Struct.new(:loc, :type, :index)
 #  Let    = Struct.new(:loc, :type, :var,  :expr, :body)
@@ -636,10 +636,9 @@ class Parser
     args = function_arglist()
     func = IR::Func.new(name.loc, nil, args, [])
     expect("{")
-    expect(:return);
-    if !matches("}")
-      func.body << IR::Return.new(location, nil, expression())
-    end
+    stmts = statement_list(["}", :return])
+    stmts << return_statement
+    func.body = stmts
     expect("}");
     func
   end
@@ -672,6 +671,94 @@ class Parser
     IR::Var.new(name.pos, nil, name.text.to_sym)
   end
 
+
+  ##
+  # Statements
+  ##
+  def statement_list(terminators)
+    stmts = []
+    while !matches_any(terminators)
+      stmts << statement
+    end
+    stmts
+  end
+
+  def statement()
+    # variable definition
+    # variable assignment
+    # if statement
+    # expression
+
+    if matches(:def)
+      variable_definition()
+    elsif matches(:set)
+      variable_assignment()
+    elsif matches(:if)
+      if_statement()
+    else
+      expression()
+    end
+  end
+
+  def return_statement()
+    loc = location
+    expect(:return);
+    if !matches("}")
+      IR::Return.new(loc, nil, expression())
+    else
+      IR::Return.new(loc, nil, nil)
+    end
+  end
+
+  def variable_definition()
+    loc = location
+    expect(:def)
+    name = identifier()
+    expect ("=")
+    value = expression()
+    IR::Def.new(loc, nil, name, value)
+  end
+
+  def variable_assignment()
+    loc = location
+    expect(:set)
+    name = identifier()
+    expect ("=")
+    value = expression()
+    IR::Set.new(loc, nil, name, value)
+  end
+
+  def if_statement()
+    loc = location
+    expect(:if)
+    cond = expression()
+    then_branch = statement_block()
+    if accept(:else)
+      if matches(:if)
+        else_branch = [ if_statement() ]
+      else
+        else_branch = statement_block()
+      end
+    end
+    IR::If.new(loc, nil, cond, then_branch, else_branch)
+  end
+
+  def statement_block()
+    loc = location
+    stmts = []
+    expect("{")
+    while !matches("}")
+      stmts << statement()
+    end
+    expect("}")
+    return stmts
+  end
+
+
+  ##
+  # Expressions
+  ##
+
   def expression()
     left = simple_expr()
     if matches_any(["==", "!=", "<", "<=", ">", ">="])
@@ -773,6 +860,12 @@ module Codegen
       emit_var(syms, v)
     elsif v.is_a? IR::Call then
       emit_call(syms, v)
+    elsif v.is_a? IR::Def then
+      emit_def(syms, v)
+    elsif v.is_a? IR::Set then
+      emit_set(syms, v)
+    elsif v.is_a? IR::If then
+      emit_if(syms, v)
     else
       raise "code emitting of #{v.class} not implemented"
     end
@@ -822,8 +915,14 @@ module Codegen
 
   def self.emit_var(syms, v)
     sym = syms[v.name]
-    if sym.kind == :param
-      puts "    get_param #{sym.value}"
+    if sym
+      if sym.kind == :param
+        puts "    get_param #{sym.value}"
+      elsif  sym.kind == :local
+        puts "    get_local :#{sym.name}"
+      end
+    else
+      puts "#   invalid var #{v.name}"
     end
   end
 
@@ -839,6 +938,22 @@ module Codegen
       puts "    fcallv"
     end
   end
+
+  def self.emit_def(syms, v)
+    puts "#    def #{v.name} = #{v}"
+    syms.add_sym(
+        v.name.name, v.loc, :local, v.type, v.value)
+    emit(syms, v.value)
+    puts "    set_local :#{v.name.name}"
+  end
+
+  def self.emit_set(syms, v)
+    puts "    set_local :#{v.name.name}"
+  end
+
+  def self.emit_if(syms, v)
+    puts "#    if "
+  end
 end
 
 $parser = Parser.new("cerise.m")