Refactor some code to split into functions and files.

This commit is contained in:
Danila Fedorin 2018-07-27 22:50:31 -07:00
parent cc82894454
commit 774ab2f92e
5 changed files with 148 additions and 132 deletions

View File

@ -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

View File

@ -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
View 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
View 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

View File

@ -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)