mirror of
https://github.com/notwa/lips
synced 2024-05-20 17:13:23 -07:00
implement ascii/asciiz directives, basic string lexing
This commit is contained in:
parent
5e12951010
commit
a47c924e75
11
README.md
11
README.md
|
@ -145,14 +145,17 @@ include an external assembly file as-is at this position.
|
||||||
lips will look for the included file
|
lips will look for the included file
|
||||||
in the directory of the file using the directive.
|
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`
|
||||||
|
|
||||||
|
* `.asciiz "some\ntext"`
|
||||||
|
same as ascii, but with a null byte added to the end.
|
||||||
|
|
||||||
### Unimplemented
|
### Unimplemented
|
||||||
|
|
||||||
* FLOAT: writes a list of 32-bit floating point numbers until end-of-line.
|
* 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,
|
this may not get implemented due to a lack of aliasing in vanilla Lua,
|
||||||
and thus accuracy issues.
|
and thus accuracy issues.
|
||||||
|
|
||||||
* ASCII: writes a string using its characters' ASCII values.
|
|
||||||
|
|
||||||
* ASCIIZ: same as ASCII, but with a null byte added to the end.
|
|
||||||
|
|
||||||
* INCBIN: write an external binary file as-is at this position.
|
* INCBIN: write an external binary file as-is at this position.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
local insert = table.insert
|
|
||||||
local floor = math.floor
|
local floor = math.floor
|
||||||
|
local format = string.format
|
||||||
|
local insert = table.insert
|
||||||
|
|
||||||
local data = require "lips.data"
|
local data = require "lips.data"
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,25 @@
|
||||||
local byte = string.byte
|
local byte = string.byte
|
||||||
local char = string.char
|
local char = string.char
|
||||||
local find = string.find
|
local find = string.find
|
||||||
|
local format = string.format
|
||||||
|
local insert = table.insert
|
||||||
local open = io.open
|
local open = io.open
|
||||||
|
|
||||||
local data = require "lips.data"
|
local data = require "lips.data"
|
||||||
|
|
||||||
|
local simple_escapes = {
|
||||||
|
['0'] = 0x00,
|
||||||
|
['\\'] = 0x5C,
|
||||||
|
['"'] = 0x22,
|
||||||
|
['a'] = 0x07,
|
||||||
|
['b'] = 0x08,
|
||||||
|
['f'] = 0x0C,
|
||||||
|
['n'] = 0x0A,
|
||||||
|
['r'] = 0x0D,
|
||||||
|
['t'] = 0x09,
|
||||||
|
['v'] = 0x0B,
|
||||||
|
}
|
||||||
|
|
||||||
local function readfile(fn)
|
local function readfile(fn)
|
||||||
local f = open(fn, 'r')
|
local f = open(fn, 'r')
|
||||||
if not f then
|
if not f then
|
||||||
|
@ -208,12 +223,48 @@ end
|
||||||
function Lexer:lex_string(yield)
|
function Lexer:lex_string(yield)
|
||||||
-- TODO: support escaping
|
-- TODO: support escaping
|
||||||
if self.chr ~= '"' then
|
if self.chr ~= '"' then
|
||||||
self:error("expected opening double quote")
|
self:error('expected opening double quote')
|
||||||
|
end
|
||||||
|
self:nextc()
|
||||||
|
|
||||||
|
local bytes = {}
|
||||||
|
while true do
|
||||||
|
if self.chr == '\n' then
|
||||||
|
self:error('unimplemented')
|
||||||
|
self:nextc()
|
||||||
|
yield('EOL', '\n')
|
||||||
|
elseif self.ord == self.EOF then
|
||||||
|
self:nextc()
|
||||||
|
self:error('unexpected EOF; incomplete string')
|
||||||
|
elseif self.chr == '"' then
|
||||||
|
self:nextc()
|
||||||
|
break
|
||||||
|
elseif self.chr == '\\' then
|
||||||
|
self:nextc()
|
||||||
|
local simple = simple_escapes[self.chr]
|
||||||
|
if simple then
|
||||||
|
insert(bytes, simple)
|
||||||
|
else
|
||||||
|
self:error('unknown escape sequence')
|
||||||
|
end
|
||||||
|
self:nextc()
|
||||||
|
else
|
||||||
|
insert(bytes, byte(self.chr))
|
||||||
|
self:nextc()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
yield('STRING', bytes)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Lexer:lex_string_naive(yield) -- no escape sequences
|
||||||
|
if self.chr ~= '"' then
|
||||||
|
self:error('expected opening double quote')
|
||||||
end
|
end
|
||||||
self:nextc()
|
self:nextc()
|
||||||
local buff = self:read_chars('[^"\n]')
|
local buff = self:read_chars('[^"\n]')
|
||||||
if self.chr ~= '"' then
|
if self.chr ~= '"' then
|
||||||
self:error("expected closing double quote")
|
self:error('expected closing double quote')
|
||||||
end
|
end
|
||||||
self:nextc()
|
self:nextc()
|
||||||
yield('STRING', buff)
|
yield('STRING', buff)
|
||||||
|
@ -222,7 +273,7 @@ end
|
||||||
function Lexer:lex_include(_yield)
|
function Lexer:lex_include(_yield)
|
||||||
self:read_chars('%s')
|
self:read_chars('%s')
|
||||||
local fn
|
local fn
|
||||||
self:lex_string(function(tt, tok)
|
self:lex_string_naive(function(tt, tok)
|
||||||
fn = tok
|
fn = tok
|
||||||
end)
|
end)
|
||||||
if self.options.path then
|
if self.options.path then
|
||||||
|
@ -293,6 +344,8 @@ function Lexer:lex(_yield)
|
||||||
else
|
else
|
||||||
yield('DIR', up)
|
yield('DIR', up)
|
||||||
end
|
end
|
||||||
|
elseif self.chr == '"' then
|
||||||
|
self:lex_string(yield)
|
||||||
elseif self.chr == '@' then
|
elseif self.chr == '@' then
|
||||||
self:nextc()
|
self:nextc()
|
||||||
local buff = self:read_chars('[%w_]')
|
local buff = self:read_chars('[%w_]')
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
local insert = table.insert
|
|
||||||
local format = string.format
|
local format = string.format
|
||||||
|
local insert = table.insert
|
||||||
|
|
||||||
local data = require "lips.data"
|
local data = require "lips.data"
|
||||||
local overrides = require "lips.overrides"
|
local overrides = require "lips.overrides"
|
||||||
|
@ -57,6 +57,15 @@ function Parser:number()
|
||||||
return value
|
return value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Parser:string()
|
||||||
|
if self.tt ~= 'STRING' then
|
||||||
|
self:error('expected string')
|
||||||
|
end
|
||||||
|
local value = self.tok
|
||||||
|
self:advance()
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
|
||||||
function Parser:directive()
|
function Parser:directive()
|
||||||
local name = self.tok
|
local name = self.tok
|
||||||
self:advance()
|
self:advance()
|
||||||
|
@ -84,13 +93,20 @@ function Parser:directive()
|
||||||
self.dumper:add_directive(line, name, self:number())
|
self.dumper:add_directive(line, name, self:number())
|
||||||
end
|
end
|
||||||
self:expect_EOL()
|
self:expect_EOL()
|
||||||
elseif name == 'HEX' then
|
|
||||||
self:error('unimplemented')
|
|
||||||
elseif name == 'INC' then
|
elseif name == 'INC' then
|
||||||
-- noop
|
-- noop, handled by lexer
|
||||||
|
elseif name == 'ASCII' or name == 'ASCIIZ' then
|
||||||
|
local bytes = self:string()
|
||||||
|
for i, number in ipairs(bytes) do
|
||||||
|
self.dumper:add_directive(line, 'BYTE', number)
|
||||||
|
end
|
||||||
|
if name == 'ASCIIZ' then
|
||||||
|
self.dumper:add_directive(line, 'BYTE', 0)
|
||||||
|
end
|
||||||
|
self:expect_EOL()
|
||||||
elseif name == 'INCBIN' then
|
elseif name == 'INCBIN' then
|
||||||
self:error('unimplemented')
|
self:error('unimplemented')
|
||||||
elseif name == 'FLOAT' or name == 'ASCII' or name == 'ASCIIZ' then
|
elseif name == 'FLOAT' then
|
||||||
self:error('unimplemented')
|
self:error('unimplemented')
|
||||||
else
|
else
|
||||||
self:error('unknown directive')
|
self:error('unknown directive')
|
||||||
|
|
Loading…
Reference in New Issue
Block a user