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 "./emitter.cr" | ||||
| 
 | ||||
| module Chalk | ||||
|   class CodeGenerator | ||||
|     include Emitter | ||||
|     RETURN_REG = 14 | ||||
|     STACK_REG = 13 | ||||
| 
 | ||||
| @ -16,78 +18,6 @@ module Chalk | ||||
|       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) | ||||
|       case tree | ||||
|       when TreeId | ||||
| @ -187,38 +117,8 @@ module Chalk | ||||
|       return false | ||||
|     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! | ||||
|       generate!(@function.block, @table, -1, @registers) | ||||
|       optimize! | ||||
|       return @instructions | ||||
|     end | ||||
|   end | ||||
|  | ||||
| @ -6,40 +6,47 @@ module Chalk | ||||
|   class Compiler | ||||
|     def initialize(@config : Config) | ||||
|       @logger = Logger.new STDOUT | ||||
|       @lexer = Lexer.new | ||||
|       @parser = Parser.new | ||||
|       @logger.debug("Initialized compiler") | ||||
|       @logger.level = Logger::DEBUG | ||||
|     end | ||||
| 
 | ||||
|     private def create_trees(file) | ||||
|       string = File.read(file) | ||||
|       tokens = @lexer.lex string | ||||
|       @logger.debug("Tokenizing") | ||||
|       lexer = Lexer.new | ||||
|       tokens = lexer.lex string | ||||
|       if tokens.size == 0 && string != "" | ||||
|         raise "Unable to tokenize file." | ||||
|       end | ||||
|       @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("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 | ||||
|       end | ||||
|       raise "Unable to parse file." | ||||
|     end | ||||
| 
 | ||||
|     private def process_initial(trees) | ||||
|     private def create_table(trees) | ||||
|       table = Table.new | ||||
|       folder = ConstantFolder.new | ||||
|       @logger.debug("Creating symbol table") | ||||
|       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") | ||||
|         table[tree.name] = FunctionEntry.new tree | ||||
|       end | ||||
|       @logger.debug("Done creating symbol table") | ||||
|       return table | ||||
|     end | ||||
| 
 | ||||
|     private def generate_code(trees, table) | ||||
|     private def create_code(trees, table) | ||||
|       code = {} of String => Array(Instruction) | ||||
|       trees.each do |tree| | ||||
|         tree = tree.as(TreeFunction) | ||||
| @ -58,15 +65,10 @@ module Chalk | ||||
|       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 | ||||
|       table, code = generate_ir | ||||
|       trees = create_trees(@config.file) | ||||
|       table = create_table(trees) | ||||
|       code = create_code(trees, table) | ||||
|       code.each do |name, insts| | ||||
|         puts "Code for #{name}:" | ||||
|         insts.each { |it| puts it } | ||||
| @ -74,12 +76,22 @@ module Chalk | ||||
|       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 | ||||
| 
 | ||||
|     private def run_binary | ||||
|       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"] | ||||
|       table["main"]?.as(FunctionEntry).addr = 0 | ||||
|       all_instructions << JumpRelativeInstruction.new 0 | ||||
| @ -89,15 +101,8 @@ module Chalk | ||||
|         all_instructions.concat(value) | ||||
|         all_instructions << ReturnInstruction.new | ||||
|       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") | ||||
|       binary.each do |inst| | ||||
|           first = (inst >> 8).to_u8 | ||||
|           file.write_byte(first) | ||||
|           second = (inst & 0xff).to_u8 | ||||
|           file.write_byte(second) | ||||
|       end | ||||
|       generate_binary(table, all_instructions, file) | ||||
|       file.close | ||||
|     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 | ||||
|           code = arr[arr.size - 1].as(Tree) | ||||
|           type = arr[arr.size - 2].as(Token).type | ||||
|           TreeFunction.new(name, params, code).as(Tree) | ||||
|           TreeFunction.new(name, params, code) | ||||
|         end | ||||
|       return func | ||||
|     end | ||||
| 
 | ||||
|     def initialize | ||||
|       _, 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 | ||||
| 
 | ||||
|     def parse?(tokens) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user