Refactor some code to split into functions and files.
This commit is contained in:
		
							parent
							
								
									cc82894454
								
							
						
					
					
						commit
						774ab2f92e
					
				| @ -1,7 +1,9 @@ | |||||||
| require "./ir.cr" | require "./ir.cr" | ||||||
|  | require "./emitter.cr" | ||||||
| 
 | 
 | ||||||
| module Chalk | module Chalk | ||||||
|   class CodeGenerator |   class CodeGenerator | ||||||
|  |     include Emitter | ||||||
|     RETURN_REG = 14 |     RETURN_REG = 14 | ||||||
|     STACK_REG = 13 |     STACK_REG = 13 | ||||||
| 
 | 
 | ||||||
| @ -16,78 +18,6 @@ module Chalk | |||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def load(into, value) |  | ||||||
|       inst = LoadInstruction.new into, value.to_i32 |  | ||||||
|       @instructions << inst |  | ||||||
|       return inst |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     private def loadr(into, from) |  | ||||||
|       inst = LoadRegInstruction.new into, from |  | ||||||
|       @instructions << inst |  | ||||||
|       return inst |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     private def op(op, into, from) |  | ||||||
|       inst = OpInstruction.new op, into, from |  | ||||||
|       @instructions << inst |  | ||||||
|       return inst |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     private def opr(op, into, from) |  | ||||||
|       inst = OpRegInstruction.new op, into, from |  | ||||||
|       @instructions << inst |  | ||||||
|       return inst |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     private def sne(l, r) |  | ||||||
|       inst = SkipNeInstruction.new l, r |  | ||||||
|       @instructions << inst |  | ||||||
|       return inst |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     private def jr(o) |  | ||||||
|       inst = JumpRelativeInstruction.new o |  | ||||||
|       @instructions << inst |  | ||||||
|       return inst |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     private def store(up_to) |  | ||||||
|       inst = StoreInstruction.new up_to |  | ||||||
|       @instructions << inst |  | ||||||
|       return inst |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     private def restore(up_to) |  | ||||||
|       inst = RestoreInstruction.new up_to |  | ||||||
|       @instructions << inst |  | ||||||
|       return inst |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     private def ret |  | ||||||
|       inst = ReturnInstruction.new |  | ||||||
|       @instructions << inst |  | ||||||
|       return inst |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     private def call(func) |  | ||||||
|       inst = CallInstruction.new func |  | ||||||
|       @instructions << inst |  | ||||||
|       return inst |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     def setis |  | ||||||
|       inst = SetIStackInstruction.new  |  | ||||||
|       @instructions << inst |  | ||||||
|       return inst |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     def addi(reg) |  | ||||||
|       inst = AddIRegInstruction.new reg |  | ||||||
|       @instructions << inst |  | ||||||
|       return inst |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     def generate!(tree, table, target, free) |     def generate!(tree, table, target, free) | ||||||
|       case tree |       case tree | ||||||
|       when TreeId |       when TreeId | ||||||
| @ -187,38 +117,8 @@ module Chalk | |||||||
|       return false |       return false | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def optimize!(range) |  | ||||||
|       offset = 0 |  | ||||||
|       range.each do |index| |  | ||||||
|         if check_dead(@instructions[index + offset]) |  | ||||||
|           @instructions.delete_at(index + offset) |  | ||||||
|           offset -= 1 |  | ||||||
|         end |  | ||||||
|       end |  | ||||||
|       return offset |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     private def optimize! |  | ||||||
|       block_boundaries = [ @instructions.size ] |  | ||||||
|       @instructions.each_with_index do |inst, i| |  | ||||||
|         if inst.is_a?(JumpRelativeInstruction) |  | ||||||
|             block_boundaries << (inst.offset + i) |  | ||||||
|         end |  | ||||||
|       end |  | ||||||
|       block_boundaries.sort! |  | ||||||
| 
 |  | ||||||
|       previous = 0 |  | ||||||
|       offset = 0 |  | ||||||
|       block_boundaries.each do |boundary| |  | ||||||
|         range = (previous + offset)...(boundary + offset) |  | ||||||
|         offset += optimize!(range) |  | ||||||
|         previous = boundary |  | ||||||
|       end |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     def generate! |     def generate! | ||||||
|       generate!(@function.block, @table, -1, @registers) |       generate!(@function.block, @table, -1, @registers) | ||||||
|       optimize! |  | ||||||
|       return @instructions |       return @instructions | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  | |||||||
| @ -6,40 +6,47 @@ module Chalk | |||||||
|   class Compiler |   class Compiler | ||||||
|     def initialize(@config : Config) |     def initialize(@config : Config) | ||||||
|       @logger = Logger.new STDOUT |       @logger = Logger.new STDOUT | ||||||
|       @lexer = Lexer.new |  | ||||||
|       @parser = Parser.new |  | ||||||
|       @logger.debug("Initialized compiler") |       @logger.debug("Initialized compiler") | ||||||
|       @logger.level = Logger::DEBUG |       @logger.level = Logger::DEBUG | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def create_trees(file) |     private def create_trees(file) | ||||||
|       string = File.read(file) |       string = File.read(file) | ||||||
|       tokens = @lexer.lex string |       @logger.debug("Tokenizing") | ||||||
|  |       lexer = Lexer.new | ||||||
|  |       tokens = lexer.lex string | ||||||
|       if tokens.size == 0 && string != "" |       if tokens.size == 0 && string != "" | ||||||
|         raise "Unable to tokenize file." |         raise "Unable to tokenize file." | ||||||
|       end |       end | ||||||
|       @logger.debug("Finished tokenizing") |       @logger.debug("Finished tokenizing") | ||||||
|       if trees = @parser.parse?(tokens) |       @logger.debug("Beginning parsing") | ||||||
|  |       parser = Parser.new | ||||||
|  |       if trees = parser.parse?(tokens) | ||||||
|         @logger.debug("Finished parsing") |         @logger.debug("Finished parsing") | ||||||
|  |         @logger.debug("Beginning constant folding") | ||||||
|  |         folder = ConstantFolder.new | ||||||
|  |         trees.map! do |tree| | ||||||
|  |             @logger.debug("Constant folding #{tree.name}") | ||||||
|  |             tree.apply(folder).as(TreeFunction) | ||||||
|  |         end | ||||||
|  |         @logger.debug("Done constant folding") | ||||||
|         return trees |         return trees | ||||||
|       end |       end | ||||||
|       raise "Unable to parse file." |       raise "Unable to parse file." | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def process_initial(trees) |     private def create_table(trees) | ||||||
|       table = Table.new |       table = Table.new | ||||||
|       folder = ConstantFolder.new |       @logger.debug("Creating symbol table") | ||||||
|       trees.each do |tree| |       trees.each do |tree| | ||||||
|         tree = tree.as(TreeFunction) |  | ||||||
|         @logger.debug("Constant folding #{tree.name}") |  | ||||||
|         tree = tree.apply(folder).as(TreeFunction) |  | ||||||
|         @logger.debug("Storing #{tree.name} in symbol table") |         @logger.debug("Storing #{tree.name} in symbol table") | ||||||
|         table[tree.name] = FunctionEntry.new tree |         table[tree.name] = FunctionEntry.new tree | ||||||
|       end |       end | ||||||
|  |       @logger.debug("Done creating symbol table") | ||||||
|       return table |       return table | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def generate_code(trees, table) |     private def create_code(trees, table) | ||||||
|       code = {} of String => Array(Instruction) |       code = {} of String => Array(Instruction) | ||||||
|       trees.each do |tree| |       trees.each do |tree| | ||||||
|         tree = tree.as(TreeFunction) |         tree = tree.as(TreeFunction) | ||||||
| @ -58,15 +65,10 @@ module Chalk | |||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def generate_ir |  | ||||||
|       trees = create_trees(@config.file) |  | ||||||
|       table = process_initial(trees) |  | ||||||
|       raise "No main function!" unless table["main"]? |  | ||||||
|       return { table, generate_code(trees, table) } |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     private def run_intermediate |     private def run_intermediate | ||||||
|       table, code = generate_ir |       trees = create_trees(@config.file) | ||||||
|  |       table = create_table(trees) | ||||||
|  |       code = create_code(trees, table) | ||||||
|       code.each do |name, insts| |       code.each do |name, insts| | ||||||
|         puts "Code for #{name}:" |         puts "Code for #{name}:" | ||||||
|         insts.each { |it| puts it } |         insts.each { |it| puts it } | ||||||
| @ -74,12 +76,22 @@ module Chalk | |||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def generate_binary(instructions) |     private def generate_binary(table, instructions, dest) | ||||||
|  |       context = InstructionContext.new table, instructions.size | ||||||
|  |       binary = instructions.map_with_index { |it, i| it.to_bin(context, i).to_u16 } | ||||||
|  |       binary.each do |inst| | ||||||
|  |           first = (inst >> 8).to_u8 | ||||||
|  |           dest.write_byte(first) | ||||||
|  |           second = (inst & 0xff).to_u8 | ||||||
|  |           dest.write_byte(second) | ||||||
|  |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private def run_binary |     private def run_binary | ||||||
|       all_instructions = [] of Instruction |       all_instructions = [] of Instruction | ||||||
|       table, code = generate_ir |       trees = create_trees(@config.file) | ||||||
|  |       table = create_table(trees) | ||||||
|  |       code = create_code(trees, table) | ||||||
|       all_instructions.concat code["main"] |       all_instructions.concat code["main"] | ||||||
|       table["main"]?.as(FunctionEntry).addr = 0 |       table["main"]?.as(FunctionEntry).addr = 0 | ||||||
|       all_instructions << JumpRelativeInstruction.new 0 |       all_instructions << JumpRelativeInstruction.new 0 | ||||||
| @ -89,15 +101,8 @@ module Chalk | |||||||
|         all_instructions.concat(value) |         all_instructions.concat(value) | ||||||
|         all_instructions << ReturnInstruction.new |         all_instructions << ReturnInstruction.new | ||||||
|       end |       end | ||||||
|       context = InstructionContext.new table, all_instructions.size |  | ||||||
|       binary = all_instructions.map_with_index { |it, i| it.to_bin(context, i).to_u16 } |  | ||||||
|       file = File.open("out.ch8", "w") |       file = File.open("out.ch8", "w") | ||||||
|       binary.each do |inst| |       generate_binary(table, all_instructions, file) | ||||||
|           first = (inst >> 8).to_u8 |  | ||||||
|           file.write_byte(first) |  | ||||||
|           second = (inst & 0xff).to_u8 |  | ||||||
|           file.write_byte(second) |  | ||||||
|       end |  | ||||||
|       file.close |       file.close | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										75
									
								
								src/chalk/emitter.cr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/chalk/emitter.cr
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | |||||||
|  | module Chalk | ||||||
|  |     module Emitter | ||||||
|  |         private def load(into, value) | ||||||
|  |             inst = LoadInstruction.new into, value.to_i32 | ||||||
|  |             @instructions << inst | ||||||
|  |             return inst | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         private def loadr(into, from) | ||||||
|  |             inst = LoadRegInstruction.new into, from | ||||||
|  |             @instructions << inst | ||||||
|  |             return inst | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         private def op(op, into, from) | ||||||
|  |             inst = OpInstruction.new op, into, from | ||||||
|  |             @instructions << inst | ||||||
|  |             return inst | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         private def opr(op, into, from) | ||||||
|  |             inst = OpRegInstruction.new op, into, from | ||||||
|  |             @instructions << inst | ||||||
|  |             return inst | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         private def sne(l, r) | ||||||
|  |             inst = SkipNeInstruction.new l, r | ||||||
|  |             @instructions << inst | ||||||
|  |             return inst | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         private def jr(o) | ||||||
|  |             inst = JumpRelativeInstruction.new o | ||||||
|  |             @instructions << inst | ||||||
|  |             return inst | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         private def store(up_to) | ||||||
|  |             inst = StoreInstruction.new up_to | ||||||
|  |             @instructions << inst | ||||||
|  |             return inst | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         private def restore(up_to) | ||||||
|  |             inst = RestoreInstruction.new up_to | ||||||
|  |             @instructions << inst | ||||||
|  |             return inst | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         private def ret | ||||||
|  |             inst = ReturnInstruction.new | ||||||
|  |             @instructions << inst | ||||||
|  |             return inst | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         private def call(func) | ||||||
|  |             inst = CallInstruction.new func | ||||||
|  |             @instructions << inst | ||||||
|  |             return inst | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         private def setis | ||||||
|  |             inst = SetIStackInstruction.new  | ||||||
|  |             @instructions << inst | ||||||
|  |             return inst | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         private def addi(reg) | ||||||
|  |             inst = AddIRegInstruction.new reg | ||||||
|  |             @instructions << inst | ||||||
|  |             return inst | ||||||
|  |         end | ||||||
|  |     end | ||||||
|  | end | ||||||
							
								
								
									
										36
									
								
								src/chalk/optimizer.cr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/chalk/optimizer.cr
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | |||||||
|  | module Chalk | ||||||
|  |     class Optimizer | ||||||
|  |         def initialize(instructions : Array(Instruction)) | ||||||
|  |             @instructions = instructions.dup | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         private def optimize!(range) | ||||||
|  |             offset = 0 | ||||||
|  |             range.each do |index| | ||||||
|  |                 if check_dead(@instructions[index + offset]) | ||||||
|  |                     @instructions.delete_at(index + offset) | ||||||
|  |                     offset -= 1 | ||||||
|  |                 end | ||||||
|  |             end | ||||||
|  |             return offset | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         private def optimize! | ||||||
|  |             block_boundaries = [ @instructions.size ] | ||||||
|  |             @instructions.each_with_index do |inst, i| | ||||||
|  |                 if inst.is_a?(JumpRelativeInstruction) | ||||||
|  |                     block_boundaries << (inst.offset + i) | ||||||
|  |                 end | ||||||
|  |             end | ||||||
|  |             block_boundaries.sort! | ||||||
|  | 
 | ||||||
|  |             previous = 0 | ||||||
|  |             offset = 0 | ||||||
|  |             block_boundaries.each do |boundary| | ||||||
|  |                 range = (previous + offset)...(boundary + offset) | ||||||
|  |                 offset += optimize!(range) | ||||||
|  |                 previous = boundary | ||||||
|  |             end | ||||||
|  |         end | ||||||
|  |     end | ||||||
|  | end | ||||||
| @ -156,14 +156,14 @@ module Chalk | |||||||
|           params = arr[3..arr.size - 5].map &.as(Token).string |           params = arr[3..arr.size - 5].map &.as(Token).string | ||||||
|           code = arr[arr.size - 1].as(Tree) |           code = arr[arr.size - 1].as(Tree) | ||||||
|           type = arr[arr.size - 2].as(Token).type |           type = arr[arr.size - 2].as(Token).type | ||||||
|           TreeFunction.new(name, params, code).as(Tree) |           TreeFunction.new(name, params, code) | ||||||
|         end |         end | ||||||
|       return func |       return func | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def initialize |     def initialize | ||||||
|       _, block = create_statement_block |       _, block = create_statement_block | ||||||
|       @parser = many(create_func(block, create_type)).as(BasicParser(Array(Tree))) |       @parser = many(create_func(block, create_type)).as(BasicParser(Array(TreeFunction))) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def parse?(tokens) |     def parse?(tokens) | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user