From: Mike Lowis Date: Tue, 22 Oct 2024 18:03:37 +0000 (-0400) Subject: implemented dependency compilation and linking of final executable X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=24b78905b5436bf21dbf75b2a364d27bce22f9a0;p=proto%2Fcerise-c.git implemented dependency compilation and linking of final executable --- diff --git a/Foo.c b/Foo.c new file mode 100644 index 0000000..7c5e134 --- /dev/null +++ b/Foo.c @@ -0,0 +1,9 @@ +#include + +Value Foo_Bar(); + +Value Foo_Bar() { + Value _t0 = MakeInt(42); + return _t0; +} + diff --git a/Foo.m b/Foo.m new file mode 100644 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 e480373..9a74913 100644 --- a/Int.c +++ b/Int.c @@ -1,9 +1,13 @@ #include +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 c1f959c..12ae3f6 100644 --- 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() } diff --git a/cerise-c.rb b/cerise-c.rb index a25e974..6e2a3c0 100755 --- a/cerise-c.rb +++ b/cerise-c.rb @@ -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 diff --git a/lib/codegen.rb b/lib/codegen.rb index 5463556..9048504 100644 --- a/lib/codegen.rb +++ b/lib/codegen.rb @@ -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 \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 diff --git a/lib/compiler.rb b/lib/compiler.rb index 127d7f6..6d46483 100644 --- a/lib/compiler.rb +++ b/lib/compiler.rb @@ -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 diff --git a/lib/parser.rb b/lib/parser.rb index 6ffacfe..36c42b9 100644 --- a/lib/parser.rb +++ b/lib/parser.rb @@ -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 diff --git a/lib/sym_table.rb b/lib/sym_table.rb index 0ddcbe7..de12d16 100644 --- a/lib/sym_table.rb +++ b/lib/sym_table.rb @@ -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) diff --git a/lib/value.rb b/lib/value.rb index 05065f6..f4b4fdd 100644 --- a/lib/value.rb +++ b/lib/value.rb @@ -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)