From a58ad83c921f19c1cd130b03a1a6c93b054b4e16 Mon Sep 17 00:00:00 2001 From: Connor Olding Date: Sun, 10 Apr 2016 04:03:00 -0700 Subject: [PATCH] implement incbin directive --- README.md | 7 +++++-- lips/Lexer.lua | 21 +++++++++++++++++++++ lips/Parser.lua | 4 +--- lips/util.lua | 12 +++++++----- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index c30ea6b..657fb3a 100644 --- a/README.md +++ b/README.md @@ -237,6 +237,11 @@ include an external assembly file as-is at this position. lips will look for the included file in the directory of the file using the directive. +* `.incbin {filename}` +write an external binary file as-is at this position. +lips will look for the included file +in the directory of the file using the directive. + * `.ascii "some\ntext\0"` writes a string using its characters' ASCII values. a few escapes are currently supported: `\ " a b f n r t v 0` @@ -249,5 +254,3 @@ same as ascii, but with a null byte added to the end. * FLOAT: writes a list of 32-bit floating point numbers until end-of-line. this may not get implemented due to a lack of aliasing in vanilla Lua, and thus accuracy issues. - -* INCBIN: write an external binary file as-is at this position. diff --git a/lips/Lexer.lua b/lips/Lexer.lua index ee8bb5c..005cf1a 100644 --- a/lips/Lexer.lua +++ b/lips/Lexer.lua @@ -278,6 +278,24 @@ function Lexer:lex_include(_yield) sublexer:lex(_yield) end +function Lexer:lex_include_binary(_yield) + self:read_spaces() + local fn + self:lex_string_naive(function(tt, tok) + fn = tok + end) + if self.options.path then + fn = self.options.path..fn + end + -- NOTE: this allocates two tables for each byte. + -- this could easily cause performance issues on big files. + local data = util.readfile(fn, true) + for b in string.gfind(data, '.') do + _yield('DIR', 'BYTE', fn, 0) + _yield('NUM', string.byte(b), fn, 0) + end +end + function Lexer:lex(_yield) local function yield(tt, tok) return _yield(tt, tok, self.fn, self.line) @@ -338,6 +356,9 @@ function Lexer:lex(_yield) if up == 'INC' or up == 'INCASM' or up == 'INCLUDE' then yield('DIR', 'INC') self:lex_include(_yield) + elseif up == 'INCBIN' then + yield('DIR', 'INCBIN') + self:lex_include_binary(_yield) else yield('DIR', up) end diff --git a/lips/Parser.lua b/lips/Parser.lua index 3559b49..a7ab8ad 100644 --- a/lips/Parser.lua +++ b/lips/Parser.lua @@ -54,7 +54,7 @@ function Parser:directive() add(name, self:const().tok) end self:expect_EOL() - elseif name == 'INC' then + elseif name == 'INC' or name == 'INCBIN' then -- noop, handled by lexer elseif name == 'ASCII' or name == 'ASCIIZ' then local bytes = self:string() @@ -65,8 +65,6 @@ function Parser:directive() add('BYTE', 0) end self:expect_EOL() - elseif name == 'INCBIN' then - self:error('unimplemented') elseif name == 'FLOAT' then self:error('unimplemented') else diff --git a/lips/util.lua b/lips/util.lua index e545561..fabd7e9 100644 --- a/lips/util.lua +++ b/lips/util.lua @@ -16,14 +16,16 @@ local function Class(inherit) return setmetatable(class, mt_class) end -local function readfile(fn) - local f = open(fn, 'r') +local function readfile(fn, binary) + local mode = binary and 'rb' or 'r' + local f = open(fn, mode) if not f then - error('could not open assembly file for reading: '..tostring(fn), 2) + local kind = binary and 'binary' or 'assembly' + error('could not open '..kind..' file for reading: '..tostring(fn), 2) end - local asm = f:read('*a') + local data = f:read('*a') f:close() - return asm + return data end local function bitrange(x, lower, upper)