From 60c320dfea2bb623dbb0c8c1cc7b00979c25234c Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Mon, 6 Aug 2018 21:51:53 -0700 Subject: [PATCH] Add sprites to source code and table. --- programs/basic_sprite.chalk | 9 +++++++++ src/chalk/compiler.cr | 20 +++++++++++++++++--- src/chalk/lexer.cr | 3 +++ src/chalk/parser.cr | 18 ++++++++++++++++-- src/chalk/sprite.cr | 18 +++++++++++++++++- src/chalk/table.cr | 13 ++++++++++++- src/chalk/tree.cr | 8 ++++++++ 7 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 programs/basic_sprite.chalk diff --git a/programs/basic_sprite.chalk b/programs/basic_sprite.chalk new file mode 100644 index 0000000..f91bf9c --- /dev/null +++ b/programs/basic_sprite.chalk @@ -0,0 +1,9 @@ +sprite dum [ +` xx ` +` xx ` +` xx ` +] + +fun main(): u0 { + +} diff --git a/src/chalk/compiler.cr b/src/chalk/compiler.cr index 22f03ac..4d4e18b 100644 --- a/src/chalk/compiler.cr +++ b/src/chalk/compiler.cr @@ -33,8 +33,9 @@ module Chalk @logger.debug("Beginning constant folding") folder = Trees::ConstantFolder.new trees.map! do |tree| + next tree unless tree.is_a?(Trees::TreeFunction) @logger.debug("Constant folding #{tree.name}") - tree.apply(folder).as(Trees::TreeFunction) + tree.apply(folder) end @logger.debug("Done constant folding") return trees @@ -48,8 +49,16 @@ module Chalk table = Table.new @logger.debug("Creating symbol table") trees.each do |tree| - @logger.debug("Storing #{tree.name} in symbol table") - table.set_function tree.name, FunctionEntry.new tree + case tree + when Trees::TreeSprite + @logger.debug("Storing sprite #{tree.name} in symbol table") + table.set_sprite tree.name, SpriteEntry.new tree.sprite + when Trees::TreeFunction + @logger.debug("Storing function #{tree.name} in symbol table") + table.set_function tree.name, FunctionEntry.new tree + else + @logger.debug("Unexpected tree type in input.") + end end @logger.debug("Done creating symbol table") @@ -93,6 +102,11 @@ module Chalk return code end + private def create_code(trees : Array(Trees::Tree), table) + functions = trees.select &.is_a?(Trees::TreeFunction) + return create_code(functions.map &.as(Trees::TreeFunction), table) + end + # Runs in the tree `Ui::OutputMode`. The file is # tokenized and parsed, and the result is printed # to the standard output. diff --git a/src/chalk/lexer.cr b/src/chalk/lexer.cr index 426b6c3..00c4258 100644 --- a/src/chalk/lexer.cr +++ b/src/chalk/lexer.cr @@ -7,6 +7,7 @@ module Chalk Any, Str, Id, + SpriteRow, LitDec, LitBin, LitHex, @@ -54,6 +55,8 @@ module Chalk TokenType::Str.value) @lexer.add_pattern("[a-zA-Z_][a-zA-Z_0-9]*", TokenType::Id.value) + @lexer.add_pattern("`[ x]*`", + TokenType::SpriteRow.value) @lexer.add_pattern("[0-9]+", TokenType::LitDec.value) @lexer.add_pattern("0b[0-1]+", diff --git a/src/chalk/parser.cr b/src/chalk/parser.cr index 3544f08..829d53a 100644 --- a/src/chalk/parser.cr +++ b/src/chalk/parser.cr @@ -6,6 +6,20 @@ module Chalk class Parser include ParserBuilder + private def create_sprite + type(Compiler::TokenType::KwSprite) + .then(type(Compiler::TokenType::Id)) + .then(char('[')) + .then(many(type(Compiler::TokenType::SpriteRow))) + .then(char(']')) + .transform do |array| + array = array.flatten + name = array[1].string + sprite = Compiler::Sprite.new(array[3..array.size - 2].map &.string) + Trees::TreeSprite.new(name, sprite).as(Trees::Tree) + end + end + # Creates a parser for a type. private def create_type either(type(Compiler::TokenType::KwU0), @@ -185,14 +199,14 @@ module Chalk Compiler::TokenType::KwU8 => Compiler::Type::U8, Compiler::TokenType::KwU12 => Compiler::Type::U12 } - Trees::TreeFunction.new(name, params, table[type], code) + Trees::TreeFunction.new(name, params, table[type], code).as(Trees::Tree) end return func end def initialize _, block = create_statement_block - @parser = many(create_func(block, create_type)).as(BasicParser(Array(Trees::TreeFunction))) + @parser = many(either(create_func(block, create_type), create_sprite)).as(BasicParser(Array(Trees::Tree))) end # Parses the given tokens into a tree. diff --git a/src/chalk/sprite.cr b/src/chalk/sprite.cr index ca840d6..d3a7fe0 100644 --- a/src/chalk/sprite.cr +++ b/src/chalk/sprite.cr @@ -1,5 +1,5 @@ module Chalk - module Table + module Compiler class Sprite def initialize @pixels = Hash(UInt8, UInt8).new(default_value: 0_u8) @@ -20,6 +20,22 @@ module Chalk @pixels[i.to_u8] = byte end end + + def initialize(tokens) + raise "Invalid sprite" if tokens.size > 15 + @pixels = Hash(UInt8, UInt8).new(default_value: 0_u8) + tokens.each_with_index do |token, i| + byte = 0_u8 + substring = token[1..token.size - 2] + raise "Invalid sprite" if substring.size > 8 + bit = 0b10000000 + substring.each_char do |char| + byte |= bit if char == 'x' + bit >>= 1 + end + @pixels[i.to_u8] = byte + end + end def set_pixel(x, y) raise "Invalid x-coordinate" if x > 7 diff --git a/src/chalk/table.cr b/src/chalk/table.cr index 9f5b533..7d4da62 100644 --- a/src/chalk/table.cr +++ b/src/chalk/table.cr @@ -1,3 +1,5 @@ +require "./sprite.cr" + module Chalk module Compiler # An entry that represents a function in the symbol table. @@ -32,6 +34,14 @@ module Chalk end end + class SpriteEntry + getter sprite : Sprite + getter addr : Int32 + + def initialize(@sprite, @addr = -1) + end + end + # A symbol table. class Table # Gets the parent of this table. @@ -40,6 +50,7 @@ module Chalk def initialize(@parent : Table? = nil) @functions = {} of String => FunctionEntry @vars = {} of String => VarEntry + @sprites = {} of String => SpriteEntry end macro table_functions(name) @@ -54,10 +65,10 @@ module Chalk table_functions function table_functions var + table_functions sprite def to_s(io) @parent.try &.to_s(io) - io << @data.map { |k, v| k + ": " + v.to_s }.join("\n") end end end diff --git a/src/chalk/tree.cr b/src/chalk/tree.cr index db1b34f..5a59308 100644 --- a/src/chalk/tree.cr +++ b/src/chalk/tree.cr @@ -296,5 +296,13 @@ module Chalk r.reduce(self, [@rvalue.reduce(r)]) end end + + class TreeSprite < Tree + property name : String + property sprite : Compiler::Sprite + + def initialize(@name, @sprite) + end + end end end