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

refactor to use classes; no hardcoded stuff

This commit is contained in:
Connor Olding 2015-11-20 15:27:22 -08:00
parent ebc9987a38
commit cd8ea7b3d7

View file

@ -1,9 +1,23 @@
-- i've lost control of my life
-- lexer and parser somewhat based on http://chunkbake.luaforge.net/
-- instructions: https://github.com/mikeryan/n64dev/tree/master/docs/n64ops
-- CajeASM style assembly; refer to the manual included with CajeASM.
-- lexer and parser are somewhat based on http://chunkbake.luaforge.net/
-- https://github.com/mikeryan/n64dev/tree/master/docs/n64ops
-- cajeasm style assembly
local Class = Class or function(inherit)
local class = {}
local mt_obj = {__index = class}
local mt_class = {
__call = function(self, ...)
local obj = setmetatable({}, mt_obj)
obj:init(...)
return obj
end,
__index = inherit,
}
return setmetatable(class, mt_class)
end
-- TODO: maybe support reg# style too
local registers = {
@ -370,8 +384,8 @@ local instruction_handlers = {
}
at = nil
Lexer = {}
function Lexer:setup(asm)
local Lexer = Class()
function Lexer:init(asm)
self.asm = asm
self.pos = 1
self.line = 1
@ -379,6 +393,19 @@ function Lexer:setup(asm)
self:nextc()
end
local Dumper = Class()
function Dumper:init(writer)
self.writer = writer
self.defines = {}
self.labels = {}
self.lines = {}
end
local Parser = Class()
function Parser:init(writer)
self.dumper = Dumper(writer)
end
function Lexer:error(msg)
error(string.format('%s:%d: Error: %s', 'file.asm', self.line, msg), 2)
end
@ -582,14 +609,13 @@ function Lexer:lex()
end
end
Parser = {}
function Parser:error(msg)
error(string.format('%s:%d: Error: %s', 'file.asm', self.line, msg), 2)
end
function Parser:advance()
self.tt, self.tok = Lexer:lex()
self.line = Lexer.line
self.tt, self.tok = self.lexer:lex()
self.line = self.lexer.line
return self.tt, self.tok
end
@ -625,21 +651,21 @@ function Parser:directive()
local name = self.tok
self:advance()
if name == 'ORG' then
Dumper:add_directive(name, self:number())
self.dumper:add_directive(name, self:number())
elseif name == 'ALIGN' or name == 'SKIP' then
local size = self:number()
if self:optional_comma() then
Dumper:add_directive(name, size, self:number())
self.dumper:add_directive(name, size, self:number())
else
Dumper:add_directive(name, size)
self.dumper:add_directive(name, size)
end
self:expect_EOL()
elseif name == 'BYTE' or name == 'HALFWORD' or name == 'WORD' then
Dumper:add_directive(name, self:number())
self.dumper:add_directive(name, self:number())
while not self:is_EOL() do
self:advance()
self:optional_comma()
Dumper:add_directive(name, self:number())
self.dumper:add_directive(name, self:number())
end
self:expect_EOL()
elseif name == 'HEX' then
@ -706,14 +732,14 @@ function Parser:instruction()
self:optional_comma()
local offset = {'LOWER', self:const()}
local base = self:deref()
Dumper:add_instruction_5_5_16(h[1], base, rt, offset)
self.dumper:add_instruction_5_5_16(h[1], base, rt, offset)
elseif h[2] == argtypes.bfo then
-- OP ft, offset(base)
local ft = self:register(fpu_registers)
self:optional_comma()
local offset = {'LOWER', self:const()}
local base = self:deref()
Dumper:add_instruction_5_5_16(h[1], base, ft, offset)
self.dumper:add_instruction_5_5_16(h[1], base, ft, offset)
elseif h[2] == argtypes.sti then
-- OP rt, rs, immediate
local rt = self:register()
@ -721,7 +747,7 @@ function Parser:instruction()
local rs = self:register()
self:optional_comma()
local immediate = {'LOWER', self:const()}
Dumper:add_instruction_5_5_16(h[1], rs, rt, immediate)
self.dumper:add_instruction_5_5_16(h[1], rs, rt, immediate)
elseif h[2] == argtypes.std then
-- OP rd, rs, rt
local rd = self:register()
@ -730,14 +756,14 @@ function Parser:instruction()
self:optional_comma()
local rt = self:register()
local const = h[3] or self:error('internal error: expected const')
Dumper:add_instruction_5_5_5_11(h[1], rs, rt, rd, const)
self.dumper:add_instruction_5_5_5_11(h[1], rs, rt, rd, const)
elseif h[2] == argtypes.st then
-- OP rs, rt
local rs = self:register()
self:optional_comma()
local rt = self:register()
local const = h[3] or self:error('internal error: expected const')
Dumper:add_instruction_5_5_16(h[1], rs, rt, const)
self.dumper:add_instruction_5_5_16(h[1], rs, rt, const)
elseif h[2] == argtypes.tds then
local rd = self:register()
self:optional_comma()
@ -752,12 +778,12 @@ function Parser:instruction()
rs = self:const()
end
local const = h[3] or self:error('internal error: expected const')
Dumper:add_instruction_5_5_5_5_6(h[1], 0, rt, rd, rs, const)
self.dumper:add_instruction_5_5_5_5_6(h[1], 0, rt, rd, rs, const)
elseif h[2] == argtypes.s then
-- OP rs
local rs = self:register()
local const = h[3] or self:error('internal error: expected const')
Dumper:add_instruction_5_5_16(h[1], rs, 0, const)
self.dumper:add_instruction_5_5_16(h[1], rs, 0, const)
elseif h[2] == argtypes.sto then
-- OP rs, rt, offset
local rs = self:register()
@ -765,7 +791,7 @@ function Parser:instruction()
local rt = self:register()
self:optional_comma()
local offset = self:const('relative')
Dumper:add_instruction_5_5_16(h[1], rs, rt, offset)
self.dumper:add_instruction_5_5_16(h[1], rs, rt, offset)
elseif h[2] == argtypes.stc then
-- OP TEQ rs, rt
local rs = self:register()
@ -775,45 +801,45 @@ function Parser:instruction()
-- FIXME: there's supposed to be 'code' before const
-- but i dunno what it's supposed to be
-- so i'm leaving it as zero here
Dumper:add_instruction_5_5_16(h[1], rs, rt, const)
self.dumper:add_instruction_5_5_16(h[1], rs, rt, const)
elseif h[2] == argtypes.so then
-- OP rs, offset
local rs = self:register()
self:optional_comma()
local offset = self:const('relative')
local const = h[3] or self:error('internal error: expected const')
Dumper:add_instruction_5_5_16(h[1], rs, const, offset)
self.dumper:add_instruction_5_5_16(h[1], rs, const, offset)
elseif h[2] == argtypes.sync then
-- OP
local const = h[3] or self:error('internal error: expected const')
Dumper:add_instruction_26(h[1], const)
self.dumper:add_instruction_26(h[1], const)
elseif h[2] == argtypes.indx then
-- OP target
local target = {'INDEX', self:const()}
Dumper:add_instruction_26(h[1], target)
self.dumper:add_instruction_26(h[1], target)
elseif h[2] == argtypes.lui then
-- OP rt, immediate
local rt = self:register()
self:optional_comma()
local immediate = {'UPPER', self:const()}
Dumper:add_instruction_5_5_16(h[1], 0, rt, immediate)
self.dumper:add_instruction_5_5_16(h[1], 0, rt, immediate)
elseif h[2] == argtypes.mf then
-- OP rd
local rd = self:register()
local const = h[3] or self:error('internal error: expected const')
Dumper:add_instruction_5_5_5_5_6(h[1], 0, 0, rd, 0, const)
self.dumper:add_instruction_5_5_5_5_6(h[1], 0, 0, rd, 0, const)
elseif h[2] == argtypes.jalr then
-- OP rs, rd
local rs = self:register()
self:optional_comma()
local rd = self:register()
local const = h[3] or self:error('internal error: expected const')
Dumper:add_instruction_5_5_5_5_6(h[1], rs, 0, rd, 0, const)
self.dumper:add_instruction_5_5_5_5_6(h[1], rs, 0, rd, 0, const)
local rd = self:register()
elseif h[2] == argtypes.code then
-- OP
local const = h[3] or self:error('internal error: expected const')
Dumper:add_instruction_26(h[1], const)
self.dumper:add_instruction_26(h[1], const)
elseif h[2] == argtypes.movf then
local rt = self:register()
self:optional_comma()
@ -826,7 +852,7 @@ function Parser:instruction()
rd = self:register(fpu_registers)
end
local const = h[3] or self:error('internal error: expected const')
Dumper:add_instruction_5_5_5_5_6(h[1], const, rt, rd, 0, 0)
self.dumper:add_instruction_5_5_5_5_6(h[1], const, rt, rd, 0, 0)
elseif h[2] == argtypes.tsdf then
-- OP fd, fs, ft
local fd = self:register(fpu_registers)
@ -835,7 +861,7 @@ function Parser:instruction()
self:optional_comma()
local ft = self:register(fpu_registers)
local const = h[3] or self:error('internal error: expected const')
Dumper:add_instruction_5_5_5_5_6(h[1], 16, ft, fs, fd, const)
self.dumper:add_instruction_5_5_5_5_6(h[1], 16, ft, fs, fd, const)
elseif h[2] == argtypes.tsdd then
local fd = self:register(fpu_registers)
self:optional_comma()
@ -843,7 +869,7 @@ function Parser:instruction()
self:optional_comma()
local ft = self:register(fpu_registers)
local const = h[3] or self:error('internal error: expected const')
Dumper:add_instruction_5_5_5_5_6(h[1], 17, ft, fs, fd, const)
self.dumper:add_instruction_5_5_5_5_6(h[1], 17, ft, fs, fd, const)
else
self:error('TODO')
end
@ -852,8 +878,7 @@ end
function Parser:parse(asm)
self.asm = asm
Lexer:setup(asm)
Dumper:setup()
self.lexer = Lexer(asm)
self:advance()
while self.tt ~= 'EOF' do
@ -863,11 +888,11 @@ function Parser:parse(asm)
elseif self.tt == 'DEF' then
local name = self.tok
self:advance()
Dumper:add_define(name, self:number())
self.dumper:add_define(name, self:number())
elseif self.tt == 'DIR' then
self:directive()
elseif self.tt == 'LABEL' then
Dumper:add_label(self.tok)
self.dumper:add_label(self.tok)
self:advance()
elseif self.tt == 'INSTR' then
self:instruction()
@ -876,18 +901,13 @@ function Parser:parse(asm)
end
end
return Dumper:dump()
end
Dumper = {}
function Dumper:setup()
self.defines = {}
self.labels = {}
self.lines = {}
return self.dumper:dump()
end
function Dumper:error(msg)
error(string.format('Internal Error: %s', msg), 2)
-- TODO: sometimes internal error, sometimes not.
-- also, we should pass line numbers down to add_instruction.
error(string.format('Dumping Error: %s', msg), 2)
end
function Dumper:push(t)
@ -936,7 +956,7 @@ function Dumper:add_directive(...)
end
function Dumper:print(uw, lw)
print(('%04X%04X'):format(uw, lw))
self.writer(('%04X%04X'):format(uw, lw))
end
function Dumper:desym(tok)
@ -961,7 +981,7 @@ function Dumper:desym(tok)
end
return val
end
print(tok)
--print(tok)
self:error('failed to desym')
end
@ -975,7 +995,7 @@ function Dumper:toval(tok)
end
if type(tok) == 'table' then
if #tok ~= 2 then
print('toval', tok)
--print('toval', tok)
self:error('invalid token')
end
if tok[1] == 'UPPER' then
@ -995,13 +1015,13 @@ function Dumper:toval(tok)
else
val = self:desym(tok[2])*4
end
print('(index)', val)
--print('(index)', val)
return val
else
return self:desym(tok)
end
end
print('toval', tok)
--print('toval', tok)
self:error('invalid value')
end
@ -1011,7 +1031,7 @@ function Dumper:validate(n, bits)
self:error('value is nil')
end
if n > max or n < 0 then
print(("n %08X"):format(math.abs(n)))
--print(("n %08X"):format(math.abs(n)))
self:error('value out of range')
end
end
@ -1087,24 +1107,24 @@ function Dumper:dump()
end
end
function main()
local asm = ''
function assemble(fn, writer)
-- assemble a MIPS R4300i assembly file
-- returns error message on error, or nil on success
writer = writer or io.write
local f = io.open('Moonjump 2.asm', 'r')
local asm = ''
local f = io.open(fn, 'r')
if not f then
f = io.open('inject/Moonjump 2.asm', 'r')
if not f then
error('could not load assembly', 1)
return
end
error('could not read assembly file', 1)
end
asm = f:read('*a')
f:close()
Parser:parse(asm)
end
function main()
local p = Parser(writer)
return p:parse(asm)
end
local ok, msg = pcall(main)
if not ok then
print(msg)
local ok, err = pcall(main)
return err
end