]> git.mdlowis.com Git - proto/cerise-c.git/commitdiff
implemented dependency compilation and linking of final executable
authorMike Lowis <mike.lowis@gentex.com>
Tue, 22 Oct 2024 18:03:37 +0000 (14:03 -0400)
committerMike Lowis <mike.lowis@gentex.com>
Tue, 22 Oct 2024 18:03:37 +0000 (14:03 -0400)
Foo.c [new file with mode: 0644]
Foo.m [new file with mode: 0644]
Int.c
Int.m
cerise-c.rb
lib/codegen.rb
lib/compiler.rb
lib/parser.rb
lib/sym_table.rb
lib/value.rb

diff --git a/Foo.c b/Foo.c
new file mode 100644 (file)
index 0000000..7c5e134
--- /dev/null
+++ b/Foo.c
@@ -0,0 +1,9 @@
+#include <runtime.h>
+
+Value Foo_Bar();
+
+Value Foo_Bar() {
+    Value _t0 = MakeInt(42);
+    return _t0;
+}
+
diff --git a/Foo.m b/Foo.m
new file mode 100644 (file)
index 0000000..f55aba6
--- /dev/null
+++ b/Foo.m
@@ -0,0 +1,6 @@
+module Foo
+
+Bar() : int
+{
+    return  42
+}
\ No newline at end of file
diff --git a/Int.c b/Int.c
index e480373eb75cc77029885ab0f6c84cac81dadbb6..9a749133a642931452b34e65df1492e888131c90 100644 (file)
--- a/Int.c
+++ b/Int.c
@@ -1,9 +1,13 @@
 #include <runtime.h>
 
+Value Foo_Bar();
+
 Value Int_SumInts(Value a, Value b);
 
 Value Int_SumInts(Value a, Value b) {
     Value _t0 = OpAdd(a, b);
-    return _t0;
+    Value _t1 = Foo_Bar();
+    Value _t2 = OpAdd(_t0, _t1);
+    return _t2;
 }
 
diff --git a/Int.m b/Int.m
index c1f959c6e83108c21e51a1defada4c162e2a57ae..12ae3f643d37fe3b5f521eaa89f77e03e11b848e 100644 (file)
--- a/Int.m
+++ b/Int.m
@@ -1,6 +1,12 @@
 module Int
 
+imports (
+  "Foo.m"
+)
+
+exports (SumInts)
+
 SumInts(a : int, b : int) : int
 {
-    return a + b
+    return a + b + Foo.Bar()
 }
index a25e97457800bc11f0b3b2d212901816db7e4b70..6e2a3c0815f76bb122a904c31e9f6a96bb184bcb 100755 (executable)
@@ -31,4 +31,4 @@ require_relative 'lib/type_checker'
 require_relative 'lib/codegen'
 require_relative 'lib/compiler'
 
-ARGV.each {|p| Compiler.compile(p) }
\ No newline at end of file
+ARGV.each {|p| Compiler.compile_and_link(p) }
\ No newline at end of file
index 5463556639dca11d582620541218101f1d332a63..90485045071d3ec6f7a9357eb60b8b7b3190d64b 100644 (file)
@@ -12,13 +12,20 @@ class Codegen
     @temp = 0
     @indent = 1
     @output = $stdout
-#    @state = State.new(parser, 0, [], parser.syms, 0, 1)
   end
 
   def output(outpath)
     @output = File.open(outpath, "wb")
 
     puts "#include <runtime.h>\n\n"
+    (@parser.imported_modules || {}).values.each do |mod|
+      @syms[mod[:name]].type.exports.each do |name, val|
+        args = val.type[0..-2].map{|e| "Value" }.join(", ")
+        puts "Value #{symname(val)}(#{args});"
+      end
+      puts ""
+    end
+
     @syms.each do |name, val|
       args = val.value.args.map{|e| "Value #{e.name}" }.join(", ")
       puts "Value #{symname(val)}(#{args});"
@@ -240,9 +247,7 @@ class Codegen
   def lookup_func(func)
     if func.is_a? IR::Var then
       if func.module then
-        mod = @syms[func.module]
-        modsym = mod.type.exports[func.name]
-        value = SymTable::Symbol.new(func.module, func.name, nil, modsym[:kind], modsym[:type], nil)
+        value = @syms[func.module].type.exports[func.name]
       else
         value = @syms[func.name]
       end
index 127d7f678497e38ef1d35951a8804d281aa3b2d1..6d46483ff00bee87b2fb76a05d1502b4b991eed8 100644 (file)
@@ -7,23 +7,45 @@ module Compiler
   ]
 
   def self.compile(path)
-    out_path = path.sub(/\.[^.]+$/,'.c')
+    c_path = path.sub(/\.[^.]+$/,'.c')
+    o_path = path.sub(/\.[^.]+$/,'.o')
     parser   = Parser.new(path)
     checker  = TypeChecker.new(parser)
     codegen  = Codegen.new(parser)
-    codegen.output(out_path)
-    `gcc -c -I. -O1 -o cerise-c.o #{out_path}`
-    Value::Module.new(parser.module, parser.symbols)
+    puts "Compiling #{path}"
+    codegen.output(c_path)
+    `gcc -c -I. -O1 -o #{o_path} #{c_path}`
+    Value::Module.new(parser.module, o_path, parser.imported_modules, parser.symbols)
   end
 
   def self.import(path)
     PATH.each do |root|
       p = "#{root}/#{path}"
-      puts p
       if File.exist?(p)
         return Compiler.compile(p)
       end
     end
     raise "could not find #{path} in search paths"
   end
+
+  def self.dependency_list(imports)
+    imports.map {|k,v| dependency_list(v[:deps]) + [v[:out_path]] }
+  end
+
+  def self.compile_and_link(path)
+    mod = self.compile(path)
+    deps = dependency_list(mod.imports) + [mod.out_path]
+    deps = deps.flatten.map{|e| e.sub(/\.[^.]+$/, '.o') }
+    binname = File.basename(path).sub(/\.[^.]+$/, '')
+
+    if mod.exports[:Main]
+      # TODO: generate and compile a main here...
+      File.open("main.c", "wb") do |f|
+        f.puts '#include "runtime.h"'
+        f.puts "ENTRYPOINT(#{mod.name}_Main)"
+      end
+      `gcc -c -I. -O1 -o main.o main.c`
+      `gcc -I. -O1 -o #{binname} #{deps.join(" ")} main.o libruntime.a`
+    end
+  end
 end
\ No newline at end of file
index 6ffacfe728afe044106d814be4352eb13a56f3b5..36c42b96e70f98b8eb489ccb30bd92a40b28871b 100644 (file)
@@ -4,6 +4,7 @@
 class Parser
   attr_accessor :syms
   attr_accessor :checker
+  attr_accessor :imported_modules
   attr_reader   :path
   attr_reader   :module
 
@@ -11,23 +12,16 @@ class Parser
     @path = path
     @syms = SymTable.new
     @checker = TypeChecker.new(self)
-
-    syms.add_builtin(:bool,   0, :type, :bool)
-
-#    syms.add_builtin(:void,   0, :type, :void)
-#    syms.add_builtin(:int,    0, :type, :int)
-#    syms.add_builtin(:string, 0, :type, :string)
-#    syms.add_builtin(:float,  0, :type, :float)
-#    syms.add_builtin(:Length, :func, nil, nil)
-#    syms.add_builtin(:Error,  :func, [:any, :void], nil)
-
     parse_file(path)
   end
 
   def symbols()
-    @syms.globals.map do |k,v|
-      [k, {kind: v.kind, type: v.type}]
-    end.to_h
+    syms = SymTable.new
+    syms.module_name = @module
+    @syms.globals.each do |k,v|
+      syms.add_sym(k, v.loc, v.kind, v.type, nil)
+    end
+    syms
   end
 
   def linenum(pos)
@@ -117,6 +111,7 @@ class Parser
   def toplevel
     expect :module
     @module = expect(:ident).text.to_sym
+    syms.module_name = @module
     imports
     exports
     while !matches(:eof)
@@ -145,7 +140,7 @@ class Parser
 
   def imports
     if accept(:imports)
-      @imports = []
+      @imported_modules = {}
       expect("(")
       while !matches(")")
         modpath = module_path()
@@ -156,7 +151,11 @@ class Parser
             mod,
             nil
         )
-        @imports << modpath
+        @imported_modules[modpath] = {
+          name: mod.name,
+          out_path: mod.out_path,
+          deps: (mod.imports || {})
+        }
         expect(",") if not matches(")")
       end
       expect(")")
@@ -176,7 +175,6 @@ class Parser
         expect(",") if not matches(")")
       end
       expect(")")
-      pp @exports
     end
   end
 
@@ -450,10 +448,9 @@ class Parser
       elsif tok.type == :void
         IR::Const.new(tok.pos, :void, :void)
       elsif tok.type == :ident
-        varname = IR::Var.new(tok.pos, nil, tok.text.to_sym)
+        varname = IR::Var.new(tok.pos, nil, tok.text.to_sym, nil)
         if accept(".")
           mod = syms[varname.name]
-          pp mod
           if mod.kind != :module
             error("accessing field in object that is neither a record nor a module")
           end
index 0ddcbe7a80be62e6499f0e4bb0411d4febe69e6e..de12d163067d8212322fe69d08bdf03f8266ed62 100644 (file)
@@ -4,6 +4,8 @@
 class SymTable
   Symbol = Struct.new(:module, :name, :loc, :kind, :type, :value)
 
+  attr_accessor :module_name
+
   def initialize()
     @scopes = [{}, {}]
   end
@@ -49,12 +51,12 @@ class SymTable
 
   def add_builtin(name, kind, type, value)
     @scopes[0][name] =
-      Symbol.new(nil, name, 0, kind, type, value)
+      Symbol.new(@module_name, name, 0, kind, type, value)
   end
 
   def add_sym(name, loc, kind, type, value)
     @scopes.last[name] =
-      Symbol.new(nil, name, loc, kind, type, value)
+      Symbol.new(@module_name, name, loc, kind, type, value)
   end
 
   def each(&block)
index 05065f6f3e569d1b7d1b9595031953125f73a2be..f4b4fdd50e9a46870f749fee08e87058848c1f89 100644 (file)
@@ -6,7 +6,7 @@ module Value
   Type  = Struct.new(:form, :fields, :base, :size)
   Field = Struct.new(:type, :offset)
 
-  Module = Struct.new(:name, :exports)
+  Module = Struct.new(:name, :out_path,  :imports, :exports)
 
   # Base type definitions
   Void   = Type.new(:void,  nil, nil, 0)