1
0
Fork 0
mirror of https://github.com/notwa/mm synced 2024-11-05 00:29:02 -08:00

update lips

This commit is contained in:
Connor Olding 2016-04-10 06:07:06 -07:00
parent f3f27f5676
commit b72b6f3dc3
5 changed files with 134 additions and 34 deletions

View file

@ -12,7 +12,7 @@ function Dumper:init(writer, fn, options)
self.writer = writer
self.fn = fn or '(string)'
self.options = options or {}
self.labels = {}
self.labels = setmetatable({}, {__index=options.labels})
self.commands = {}
self.pos = options.offset or 0
self.lastcommand = nil
@ -22,6 +22,17 @@ function Dumper:error(msg)
error(format('%s:%d: Error: %s', self.fn, self.line, msg), 2)
end
function Dumper:export_labels(t)
for k, v in pairs(self.labels) do
-- only return valid labels; those that don't begin with a number
-- (relative labels are invalid)
if not tostring(k):sub(1, 1):find('%d') then
t[k] = v
end
end
return t
end
function Dumper:advance(by)
self.pos = self.pos + by
end
@ -138,21 +149,25 @@ function Dumper:desym(t)
end
return rel % 0x10000
elseif type(t.tok) == 'number' then
if t.offset then
return t.tok + t.offset
end
return t.tok
elseif t.tt == 'REG' then
assert(data.all_registers[t.tok], 'Internal Error: unknown register')
return data.registers[t.tok] or data.fpu_registers[t.tok] or data.sys_registers[t.tok]
elseif t.tt == 'LABELSYM' then
elseif t.tt == 'LABELSYM' or t.tt == 'LABELREL' then
local label = self.labels[t.tok]
if label == nil then
self:error('undefined label')
end
return label
elseif t.tt == 'LABELREL' then
local label = self.labels[t.tok]
if label == nil then
self:error('undefined label')
if t.offset then
label = label + t.offset
end
if t.tt == 'LABELSYM' then
return label
end
label = label % 0x80000000
local pos = self.pos % 0x80000000
local rel = floor(label/4) - 1 - floor(pos/4)

View file

@ -89,6 +89,10 @@ function Lexer:read_chars(pattern)
return buff
end
function Lexer:read_spaces()
return self:read_chars('[ \t]')
end
function Lexer:read_decimal()
local buff = self:read_chars('%d')
local num = tonumber(buff)
@ -262,7 +266,7 @@ function Lexer:lex_string_naive(yield) -- no escape sequences
end
function Lexer:lex_include(_yield)
self:read_chars('%s')
self:read_spaces()
local fn
self:lex_string_naive(function(tt, tok)
fn = tok
@ -274,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)
@ -334,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
@ -371,16 +396,25 @@ function Lexer:lex(_yield)
elseif self.chr == '+' or self.chr == '-' then
local sign_chr = self.chr
local sign = sign_chr == '+' and 1 or -1
local buff = self:read_chars('%'..self.chr)
if #buff == 1 and self.chr == ':' then
local signs = self:read_chars('%'..self.chr)
local name = ''
if self.chr:find('[%a_]') then
name = self:read_chars('[%w_]')
end
if #signs == 1 and self.chr == ':' then
self:nextc()
yield('RELLABEL', sign_chr)
yield('RELLABEL', signs..name)
else
self:read_spaces()
local n = self:read_number()
if n then
yield('NUM', sign*n)
elseif #signs == 1 and name == '' then
-- this could be a RELLABELSYM
-- we'll have to let the preproc figure it out
yield('UNARY', sign)
else
yield('RELLABELSYM', sign*#buff)
yield('RELLABELSYM', signs..name)
end
end
else

View file

@ -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
@ -179,6 +177,7 @@ function Parser:instruction()
elseif overrides[name] then
overrides[name](self, name)
elseif h[2] == 'tob' then -- TODO: or h[2] == 'Tob' then
-- handle all the addressing modes for lw/sw-like instructions
local lui = data.instructions['LUI']
local addu = data.instructions['ADDU']
local args = {}
@ -191,6 +190,9 @@ function Parser:instruction()
local lui_args = {}
local addu_args = {}
local o = self:const()
if self.tt == 'NUM' then
o:set('offset', self:const().tok)
end
args.offset = self:token(o)
if not o.portion then
args.offset:set('portion', 'lower')
@ -274,6 +276,9 @@ function Parser:parse(asm)
self:error('unexpected token (unknown instruction?)')
end
end
if self.options.labels then
self.dumper:export_labels(self.options.labels)
end
return self.dumper:dump()
end

View file

@ -5,6 +5,27 @@ local util = require "lips.util"
local Muncher = require "lips.Muncher"
local Token = require "lips.Token"
local abs = math.abs
local function signs(s)
local start, end_ = s:find('[+-]+')
if start ~= 1 then
return 0
end
if s:sub(1, 1) == '+' then
return end_
elseif s:sub(1, 1) == '-' then
return -end_
end
end
local function RelativeLabel(index, name)
return {
index = index,
name = name,
}
end
local Preproc = util.Class(Muncher)
function Preproc:init(options)
self.options = options or {}
@ -17,11 +38,26 @@ function Preproc:process(tokens)
local plus_labels = {} -- constructed forwards
local minus_labels = {} -- constructed backwards
-- first pass: resolve defines, collect relative labels
-- first pass: resolve unary ops, defines, and collect relative labels
local new_tokens = {}
self.i = 0
while self.i < #self.tokens do
local t = self:advance()
local sign = 1
if t.tt == 'UNARY' then
sign = t.tok
local peek = self.tokens[self.i + 1]
if peek.tt == 'UNARY' then
self:error('unary operators cannot be chained')
elseif peek.tt == 'EOL' or peek.tt == 'SEP' then
t.tt = 'RELLABELSYM'
t.tok = sign == 1 and '+' or sign == -1 and '-'
elseif peek.tt == 'DEFSYM' then
t = self:advance()
else
self:error('expected a symbolic constant after unary operator')
end
end
if t.tt == nil then
error('Internal Error: missing token')
elseif t.tt == 'DEF' then
@ -36,12 +72,14 @@ function Preproc:process(tokens)
if tok == nil then
self:error('undefined define') -- uhhh nice wording
end
insert(new_tokens, self:token(tt, tok))
insert(new_tokens, self:token(tt, tok * sign))
elseif t.tt == 'RELLABEL' then
if t.tok == '+' then
insert(plus_labels, #new_tokens + 1)
elseif t.tok == '-' then
insert(minus_labels, 1, #new_tokens + 1)
local label = t.tok or ''
local rl = RelativeLabel(#new_tokens + 1, label:sub(2))
if label:sub(1, 1) == '+' then
insert(plus_labels, rl)
elseif label:sub(1, 1) == '-' then
insert(minus_labels, rl)
else
error('Internal Error: unexpected token for relative label')
end
@ -58,29 +96,35 @@ function Preproc:process(tokens)
if t.tt == 'RELLABEL' then
t.tt = 'LABEL'
-- exploits the fact that user labels can't begin with a number
t.tok = tostring(i)
local name = t.tok:sub(2)
t.tok = tostring(i)..name
elseif t.tt == 'RELLABELSYM' then
t.tt = 'LABELSYM'
local rel = t.tok
local rel = signs(t.tok)
if rel == 0 then
error('Internal Error: relative label without signs')
end
local name = t.tok:sub(abs(rel) + 1)
local seen = 0
-- TODO: don't iterate over *every* label, just the ones nearby
if rel > 0 then
for _, label_i in ipairs(plus_labels) do
if label_i > i then
for _, rl in ipairs(plus_labels) do
if rl.name == name and rl.index > i then
seen = seen + 1
if seen == rel then
t.tok = tostring(label_i)
t.tok = tostring(rl.index)..name
break
end
end
end
else
for _, label_i in ipairs(minus_labels) do
if label_i < i then
for _, rl in ipairs(minus_labels) do
if rl.name == name and rl.index < i then
seen = seen - 1
if seen == rel then
t.tok = tostring(label_i)
t.tok = tostring(rl.index)..name
break
end
end

View file

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