mirror of
https://github.com/notwa/lips
synced 2024-11-14 09:59:03 -08:00
begin work on specials; big refactor
This commit is contained in:
parent
c0c4d81b5a
commit
195236a52c
9 changed files with 250 additions and 130 deletions
|
@ -1,14 +0,0 @@
|
|||
return 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
|
|
@ -3,12 +3,11 @@ local format = string.format
|
|||
local insert = table.insert
|
||||
|
||||
local data = require "lips.data"
|
||||
local util = require "lips.util"
|
||||
|
||||
local function bitrange(x, lower, upper)
|
||||
return floor(x/2^lower) % 2^(upper - lower + 1)
|
||||
end
|
||||
local bitrange = util.bitrange
|
||||
|
||||
local Dumper = require("lips.Class")()
|
||||
local Dumper = util.Class()
|
||||
function Dumper:init(writer, fn, options)
|
||||
self.writer = writer
|
||||
self.fn = fn or '(string)'
|
||||
|
@ -131,6 +130,9 @@ end
|
|||
function Dumper:desym(tok)
|
||||
if type(tok[2]) == 'number' then
|
||||
return tok[2]
|
||||
elseif tok[1] == 'REG' then
|
||||
assert(data.all_registers[tok[2]], 'Internal Error: unknown register')
|
||||
return data.registers[tok[2]] or data.fpu_registers[tok[2]] or data.sys_registers[tok[2]]
|
||||
elseif tok[1] == 'LABELSYM' then
|
||||
local label = self.labels[tok[2]]
|
||||
if label == nil then
|
||||
|
@ -154,53 +156,40 @@ function Dumper:desym(tok)
|
|||
end
|
||||
|
||||
function Dumper:toval(tok)
|
||||
if tok == nil then
|
||||
self:error('nil value')
|
||||
elseif type(tok) == 'number' then
|
||||
return tok
|
||||
elseif data.all_registers[tok] then
|
||||
return data.registers[tok] or data.fpu_registers[tok] or data.sys_registers[tok]
|
||||
assert(type(tok) == 'table', 'Internal Error: invalid value')
|
||||
assert(#tok == 2, 'Internal Error: invalid token')
|
||||
|
||||
local val = self:desym(tok)
|
||||
|
||||
if tok.index then
|
||||
val = val % 0x80000000
|
||||
val = floor(val/4)
|
||||
end
|
||||
if type(tok) == 'table' then
|
||||
if #tok ~= 2 then
|
||||
self:error('invalid token')
|
||||
end
|
||||
if tok[1] == 'UPPER' then
|
||||
local val = self:desym(tok[2])
|
||||
return bitrange(val, 16, 31)
|
||||
elseif tok[1] == 'LOWER' then
|
||||
local val = self:desym(tok[2])
|
||||
return bitrange(val, 0, 15)
|
||||
elseif tok[1] == 'UPPEROFF' then
|
||||
local val = self:desym(tok[2])
|
||||
local upper = bitrange(val, 16, 31)
|
||||
local lower = bitrange(val, 0, 15)
|
||||
if lower >= 0x8000 then
|
||||
-- accommodate for offsets being signed
|
||||
upper = (upper + 1) % 0x10000
|
||||
end
|
||||
return upper
|
||||
elseif tok[1] == 'SIGNED' then
|
||||
local val = self:desym(tok[2])
|
||||
if val >= 0x10000 or val < -0x8000 then
|
||||
self:error('value out of range')
|
||||
end
|
||||
return val % 0x10000
|
||||
elseif tok[1] == 'NEGATE' then
|
||||
local val = -self:desym(tok[2])
|
||||
if val >= 0x10000 or val < -0x8000 then
|
||||
self:error('value out of range')
|
||||
end
|
||||
return val % 0x10000
|
||||
elseif tok[1] == 'INDEX' then
|
||||
local val = self:desym(tok[2]) % 0x80000000
|
||||
val = floor(val/4)
|
||||
return val
|
||||
else
|
||||
return self:desym(tok)
|
||||
end
|
||||
if tok.negate then
|
||||
val = -val
|
||||
end
|
||||
self:error('invalid value') -- internal error?
|
||||
if tok.negate or tok.signed then
|
||||
if val >= 0x10000 or val < -0x8000 then
|
||||
self:error('value out of range')
|
||||
end
|
||||
val = val % 0x10000
|
||||
end
|
||||
|
||||
if tok.portion == 'upper' then
|
||||
val = bitrange(val, 16, 31)
|
||||
elseif tok.portion == 'lower' then
|
||||
val = bitrange(val, 0, 15)
|
||||
elseif tok.portion == 'upperoff' then
|
||||
local upper = bitrange(val, 16, 31)
|
||||
local lower = bitrange(val, 0, 15)
|
||||
if lower >= 0x8000 then
|
||||
-- accommodate for offsets being signed
|
||||
upper = (upper + 1) % 0x10000
|
||||
end
|
||||
val = upper
|
||||
end
|
||||
|
||||
return val
|
||||
end
|
||||
|
||||
function Dumper:validate(n, bits)
|
||||
|
@ -249,7 +238,7 @@ function Dumper:dump_instruction(t)
|
|||
lw = lw + self:valvar(t[5], 5)*0x40
|
||||
lw = lw + self:valvar(t[6], 6)
|
||||
else
|
||||
error('Internal Error: unknown n-size', 1)
|
||||
error('Internal Error: unknown n-size')
|
||||
end
|
||||
|
||||
return uw, lw
|
||||
|
|
|
@ -3,9 +3,9 @@ local char = string.char
|
|||
local find = string.find
|
||||
local format = string.format
|
||||
local insert = table.insert
|
||||
local open = io.open
|
||||
|
||||
local data = require "lips.data"
|
||||
local util = require "lips.util"
|
||||
|
||||
local simple_escapes = {
|
||||
['0'] = 0x00,
|
||||
|
@ -20,17 +20,7 @@ local simple_escapes = {
|
|||
['v'] = 0x0B,
|
||||
}
|
||||
|
||||
local function readfile(fn)
|
||||
local f = open(fn, 'r')
|
||||
if not f then
|
||||
error('could not open assembly file for reading: '..tostring(fn), 2)
|
||||
end
|
||||
local asm = f:read('*a')
|
||||
f:close()
|
||||
return asm
|
||||
end
|
||||
|
||||
local Lexer = require("lips.Class")()
|
||||
local Lexer = util.Class()
|
||||
function Lexer:init(asm, fn, options)
|
||||
self.asm = asm
|
||||
self.fn = fn or '(string)'
|
||||
|
@ -278,7 +268,7 @@ function Lexer:lex_include(_yield)
|
|||
if self.options.path then
|
||||
fn = self.options.path..fn
|
||||
end
|
||||
local sublexer = Lexer(readfile(fn), fn, self.options)
|
||||
local sublexer = Lexer(util.readfile(fn), fn, self.options)
|
||||
sublexer:lex(_yield)
|
||||
end
|
||||
|
||||
|
@ -348,6 +338,10 @@ function Lexer:lex(_yield)
|
|||
self:nextc()
|
||||
local buff = self:read_chars('[%w_]')
|
||||
yield('DEFSYM', buff)
|
||||
elseif self.chr == '%' then
|
||||
self:nextc()
|
||||
local call = self:read_chars('[%w_]')
|
||||
yield('SPECIAL', call)
|
||||
elseif self.chr:find('[%a_]') then
|
||||
local buff = self:read_chars('[%w_.]')
|
||||
local up = buff:upper()
|
||||
|
|
|
@ -1,7 +1,19 @@
|
|||
local format = string.format
|
||||
local insert = table.insert
|
||||
|
||||
local data = require "lips.data"
|
||||
local Muncher = require("lips.Class")()
|
||||
local util = require "lips.util"
|
||||
|
||||
local arg_types = {
|
||||
NUM = true,
|
||||
REG = true,
|
||||
DEFSYM = true,
|
||||
LABELSYM = true,
|
||||
RELLABELSYM = true,
|
||||
}
|
||||
|
||||
local Muncher = util.Class()
|
||||
-- no base init method
|
||||
|
||||
function Muncher:error(msg)
|
||||
error(format('%s:%d: Error: %s', self.fn, self.line, msg), 2)
|
||||
|
@ -99,4 +111,36 @@ function Muncher:const(relative, no_label)
|
|||
return t
|
||||
end
|
||||
|
||||
function Muncher:special()
|
||||
if self.tt ~= 'SPECIAL' then
|
||||
self:error('expected special name to call')
|
||||
end
|
||||
local name = self.tok
|
||||
self:advance()
|
||||
if self.tt ~= 'OPEN' then
|
||||
self:error('expected opening parenthesis for special call')
|
||||
end
|
||||
|
||||
local args = {}
|
||||
while true do
|
||||
local arg = self:advance()
|
||||
if not arg_types[arg.tt] then
|
||||
self:error('invalid argument type')
|
||||
else
|
||||
self:advance()
|
||||
end
|
||||
if self.tt == 'SEP' then
|
||||
insert(args, arg)
|
||||
elseif self.tt == 'CLOSE' then
|
||||
insert(args, arg)
|
||||
self:advance()
|
||||
break
|
||||
else
|
||||
self:error('unexpected token in argument list')
|
||||
end
|
||||
end
|
||||
|
||||
return name, args
|
||||
end
|
||||
|
||||
return Muncher
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
local insert = table.insert
|
||||
|
||||
local data = require "lips.data"
|
||||
local util = require "lips.util"
|
||||
local overrides = require "lips.overrides"
|
||||
local Lexer = require "lips.Lexer"
|
||||
local Dumper = require "lips.Dumper"
|
||||
local Muncher = require "lips.Muncher"
|
||||
local Preproc = require "lips.Preproc"
|
||||
|
||||
local Parser = require("lips.Class")(Muncher)
|
||||
local construct = util.construct
|
||||
local withflag = util.withflag
|
||||
|
||||
local Parser = util.Class(Muncher)
|
||||
function Parser:init(writer, fn, options)
|
||||
self.fn = fn or '(string)'
|
||||
self.main_fn = self.fn
|
||||
|
@ -96,21 +100,21 @@ function Parser:format_in(informat)
|
|||
elseif c == 'Z' and not args.rt then
|
||||
args.rt = self:register(data.sys_registers)
|
||||
elseif c == 'o' and not args.offset then
|
||||
args.offset = {'SIGNED', self:const()}
|
||||
args.offset = withflag(self:const(), 'signed')
|
||||
elseif c == 'r' and not args.offset then
|
||||
args.offset = {'SIGNED', self:const('relative')}
|
||||
args.offset = withflag(self:const('relative'), 'signed')
|
||||
elseif c == 'i' and not args.immediate then
|
||||
args.immediate = self:const(nil, 'no label')
|
||||
elseif c == 'I' and not args.index then
|
||||
args.index = {'INDEX', self:const()}
|
||||
args.index = withflag(self:const(), 'index')
|
||||
elseif c == 'k' and not args.immediate then
|
||||
args.immediate = {'NEGATE', self:const(nil, 'no label')}
|
||||
args.immediate = withflag(self:const(nil, 'no label'), 'negate')
|
||||
elseif c == 'K' and not args.immediate then
|
||||
args.immediate = {'SIGNED', self:const(nil, 'no label')}
|
||||
args.immediate = withflag(self:const(nil, 'no label'), 'signed')
|
||||
elseif c == 'b' and not args.base then
|
||||
args.base = self:deref()
|
||||
else
|
||||
error('Internal Error: invalid input formatting string', 1)
|
||||
error('Internal Error: invalid input formatting string')
|
||||
end
|
||||
if c2:find('[dstDSTorIikKXYZ]') then
|
||||
self:optional_comma()
|
||||
|
@ -129,36 +133,36 @@ function Parser:format_out_raw(outformat, first, args, const, formatconst)
|
|||
for i=1,#outformat do
|
||||
local c = outformat:sub(i, i)
|
||||
if c == 'd' then
|
||||
out[#out+1] = args.rd
|
||||
out[#out+1] = construct(args.rd)
|
||||
elseif c == 's' then
|
||||
out[#out+1] = args.rs
|
||||
out[#out+1] = construct(args.rs)
|
||||
elseif c == 't' then
|
||||
out[#out+1] = args.rt
|
||||
out[#out+1] = construct(args.rt)
|
||||
elseif c == 'D' then
|
||||
out[#out+1] = args.fd
|
||||
out[#out+1] = construct(args.fd)
|
||||
elseif c == 'S' then
|
||||
out[#out+1] = args.fs
|
||||
out[#out+1] = construct(args.fs)
|
||||
elseif c == 'T' then
|
||||
out[#out+1] = args.ft
|
||||
out[#out+1] = construct(args.ft)
|
||||
elseif c == 'o' then
|
||||
out[#out+1] = args.offset
|
||||
out[#out+1] = construct(args.offset)
|
||||
elseif c == 'i' then
|
||||
out[#out+1] = args.immediate
|
||||
out[#out+1] = construct(args.immediate)
|
||||
elseif c == 'I' then
|
||||
out[#out+1] = args.index
|
||||
out[#out+1] = construct(args.index)
|
||||
elseif c == 'b' then
|
||||
out[#out+1] = args.base
|
||||
out[#out+1] = construct(args.base)
|
||||
elseif c == '0' then
|
||||
out[#out+1] = 0
|
||||
out[#out+1] = construct(0)
|
||||
elseif c == 'C' then
|
||||
out[#out+1] = const
|
||||
out[#out+1] = construct(const)
|
||||
elseif c == 'F' then
|
||||
out[#out+1] = formatconst
|
||||
out[#out+1] = construct(formatconst)
|
||||
end
|
||||
end
|
||||
local f = lookup[#outformat]
|
||||
if f == nil then
|
||||
error('Internal Error: invalid output formatting string', 1)
|
||||
error('Internal Error: invalid output formatting string')
|
||||
end
|
||||
f(self.dumper, self.fn, self.line, first, out[1], out[2], out[3], out[4], out[5])
|
||||
end
|
||||
|
@ -183,15 +187,15 @@ function Parser:instruction()
|
|||
args.rt = self:register()
|
||||
self:optional_comma()
|
||||
if self.tt == 'OPEN' then
|
||||
args.offset = {'NUM', 0}
|
||||
args.offset = 0
|
||||
args.base = self:deref()
|
||||
else -- NUM or LABELSYM
|
||||
local lui_args = {}
|
||||
local addu_args = {}
|
||||
local o = self:const()
|
||||
args.offset = {'LOWER', o}
|
||||
args.offset = withflag({o[1], o[2]}, 'portion', 'lower')
|
||||
if o[1] == 'LABELSYM' or o[2] >= 0x80000000 then
|
||||
lui_args.immediate = {'UPPEROFF', o}
|
||||
lui_args.immediate = withflag({o[1], o[2]}, 'portion', 'upperoff')
|
||||
lui_args.rt = 'AT'
|
||||
self:format_out(lui, lui_args)
|
||||
if not self:is_EOL() then
|
||||
|
@ -246,6 +250,8 @@ function Parser:tokenize(asm)
|
|||
|
||||
local preproc = Preproc(self.options)
|
||||
self.tokens = preproc:process(tokens)
|
||||
|
||||
assert(#self.tokens > 0, 'Internal Error: no tokens after preprocessing')
|
||||
end
|
||||
|
||||
function Parser:parse(asm)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
local insert = table.insert
|
||||
|
||||
local data = require "lips.data"
|
||||
local util = require "lips.util"
|
||||
local Muncher = require "lips.Muncher"
|
||||
|
||||
local Preproc = require("lips.Class")(Muncher)
|
||||
local Preproc = util.Class(Muncher)
|
||||
function Preproc:init(options)
|
||||
self.options = options or {}
|
||||
end
|
||||
|
@ -90,6 +92,47 @@ function Preproc:process(tokens)
|
|||
end
|
||||
end
|
||||
|
||||
self.tokens = new_tokens
|
||||
new_tokens = {}
|
||||
|
||||
-- third pass: resolve specials
|
||||
self.i = 0
|
||||
while self.i < #self.tokens do
|
||||
local t = self:advance()
|
||||
self.fn = t.fn
|
||||
self.line = t.line
|
||||
if t.tt == 'SPECIAL' then
|
||||
local name, args = self:special()
|
||||
-- TODO: split to its own file, not unlike overrides.lua
|
||||
if name == 'hi' then
|
||||
if #args ~= 1 then
|
||||
self:error('%hi expected exactly one argument')
|
||||
end
|
||||
--local tnew = {fn=t.fn, line=t.line, tt='UPPEROFF', tok=args[1]}
|
||||
self:error('unimplemented special')
|
||||
insert(new_tokens, tnew)
|
||||
elseif name == 'up' then
|
||||
if #args ~= 1 then
|
||||
self:error('%up expected exactly one argument')
|
||||
end
|
||||
--local tnew = {fn=t.fn, line=t.line, tt='UPPER', tok=args[1]}
|
||||
self:error('unimplemented special')
|
||||
insert(new_tokens, tnew)
|
||||
elseif name == 'lo' then
|
||||
if #args ~= 1 then
|
||||
self:error('%lo expected exactly one argument')
|
||||
end
|
||||
self:error('unimplemented special')
|
||||
--local tnew = {fn=t.fn, line=t.line, tt='LOWER', tok=args[1]}
|
||||
insert(new_tokens, tnew)
|
||||
else
|
||||
self:error('unknown special')
|
||||
end
|
||||
else
|
||||
insert(new_tokens, t)
|
||||
end
|
||||
end
|
||||
|
||||
self.tokens = new_tokens
|
||||
|
||||
return self.tokens
|
||||
|
|
|
@ -10,20 +10,9 @@ local lips = {
|
|||
]],
|
||||
}
|
||||
|
||||
local open = io.open
|
||||
|
||||
local util = require "lips.util"
|
||||
local Parser = require "lips.Parser"
|
||||
|
||||
local function readfile(fn)
|
||||
local f = open(fn, 'r')
|
||||
if not f then
|
||||
error('could not open assembly file for reading: '..tostring(fn), 2)
|
||||
end
|
||||
local asm = f:read('*a')
|
||||
f:close()
|
||||
return asm
|
||||
end
|
||||
|
||||
function lips.word_writer()
|
||||
local buff = {}
|
||||
local max = -1
|
||||
|
@ -61,7 +50,7 @@ function lips.assemble(fn_or_asm, writer, options)
|
|||
asm = fn_or_asm
|
||||
else
|
||||
fn = fn_or_asm
|
||||
asm = readfile(fn)
|
||||
asm = util.readfile(fn)
|
||||
options.path = fn:match(".*/")
|
||||
end
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
local insert = table.insert
|
||||
|
||||
local data = require "lips.data"
|
||||
local util = require "lips.util"
|
||||
|
||||
local instructions = data.instructions
|
||||
local withflag = util.withflag
|
||||
|
||||
local overrides = {}
|
||||
-- note: "self" is an instance of Parser
|
||||
|
@ -24,19 +27,19 @@ function overrides.LI(self, name)
|
|||
im[2] = im[2] % 0x100000000
|
||||
if im[2] >= 0x10000 and im[2] <= 0xFFFF8000 then
|
||||
args.rs = args.rt
|
||||
args.immediate = {'UPPER', im}
|
||||
args.immediate = withflag(im, 'portion', 'upper')
|
||||
self:format_out(lui, args)
|
||||
if im[2] % 0x10000 ~= 0 then
|
||||
args.immediate = {'LOWER', im}
|
||||
args.immediate = withflag(im, 'portion', 'lower')
|
||||
self:format_out(ori, args)
|
||||
end
|
||||
elseif im[2] >= 0x8000 and im[2] < 0x10000 then
|
||||
args.rs = 'R0'
|
||||
args.immediate = {'LOWER', im}
|
||||
args.immediate = withflag(im, 'portion', 'lower')
|
||||
self:format_out(ori, args)
|
||||
else
|
||||
args.rs = 'R0'
|
||||
args.immediate = {'LOWER', im}
|
||||
args.immediate = withflag(im, 'portion', 'lower')
|
||||
self:format_out(addiu, args)
|
||||
end
|
||||
end
|
||||
|
@ -50,9 +53,9 @@ function overrides.LA(self, name)
|
|||
local im = self:const()
|
||||
|
||||
args.rs = args.rt
|
||||
args.immediate = {'UPPEROFF', im}
|
||||
args.immediate = withflag(im, 'portion', 'upperoff')
|
||||
self:format_out(lui, args)
|
||||
args.immediate = {'LOWER', im}
|
||||
args.immediate = withflag(im, 'portion', 'lower')
|
||||
self:format_out(addiu, args)
|
||||
end
|
||||
|
||||
|
@ -84,14 +87,14 @@ function overrides.PUSH(self, name)
|
|||
if name == 'PUSH' then
|
||||
args.rt = 'SP'
|
||||
args.rs = 'SP'
|
||||
args.immediate = {'NEGATE', {'NUM', #stack*4}}
|
||||
args.immediate = withflag(#stack*4, 'negate')
|
||||
self:format_out(addi, args)
|
||||
end
|
||||
args.base = 'SP'
|
||||
for i, r in ipairs(stack) do
|
||||
args.rt = r
|
||||
if r ~= '' then
|
||||
args.offset = {'NUM', (i - 1)*4}
|
||||
args.offset = (i - 1)*4
|
||||
self:format_out(w, args)
|
||||
end
|
||||
end
|
||||
|
@ -102,7 +105,7 @@ function overrides.PUSH(self, name)
|
|||
if name == 'POP' or name == 'JPOP' then
|
||||
args.rt = 'SP'
|
||||
args.rs = 'SP'
|
||||
args.immediate = {'NUM', #stack*4}
|
||||
args.immediate = #stack*4
|
||||
self:format_out(addi, args)
|
||||
end
|
||||
end
|
||||
|
@ -175,7 +178,7 @@ function overrides.ROL(self, name)
|
|||
end
|
||||
self:format_out(sll, args)
|
||||
args.rd = 'AT'
|
||||
args.immediate = {'NUM', 32 - args.immediate[2]}
|
||||
args.immediate = 32 - args.immediate[2]
|
||||
self:format_out(srl, args)
|
||||
args.rd = left
|
||||
args.rs = left
|
||||
|
@ -202,7 +205,7 @@ function overrides.ROR(self, name)
|
|||
end
|
||||
self:format_out(srl, args)
|
||||
args.rd = 'AT'
|
||||
args.immediate = {'NUM', 32 - args.immediate[2]}
|
||||
args.immediate = 32 - args.immediate[2]
|
||||
self:format_out(sll, args)
|
||||
args.rd = right
|
||||
args.rs = right
|
||||
|
@ -238,7 +241,7 @@ function overrides.BEQI(self, name)
|
|||
self:optional_comma()
|
||||
args.immediate = self:const()
|
||||
self:optional_comma()
|
||||
args.offset = {'SIGNED', self:const('relative')}
|
||||
args.offset = withflag(self:const('relative'), 'signed')
|
||||
|
||||
if reg == 'AT' then
|
||||
self:error('register cannot be AT in this pseudo-instruction')
|
||||
|
@ -261,7 +264,7 @@ function overrides.BLTI(self, name)
|
|||
self:optional_comma()
|
||||
args.immediate = self:const()
|
||||
self:optional_comma()
|
||||
args.offset = {'SIGNED', self:const('relative')}
|
||||
args.offset = withflag(self:const('relative'), 'signed')
|
||||
|
||||
if args.rs == 'AT' then
|
||||
self:error('register cannot be AT in this pseudo-instruction')
|
||||
|
@ -287,7 +290,7 @@ function overrides.BLEI(self, name)
|
|||
self:optional_comma()
|
||||
args.immediate = self:const()
|
||||
self:optional_comma()
|
||||
local offset = {'SIGNED', self:const('relative')}
|
||||
local offset = withflag(self:const('relative'), 'signed')
|
||||
|
||||
if reg == 'AT' then
|
||||
self:error('register cannot be AT in this pseudo-instruction')
|
||||
|
|
66
lips/util.lua
Normal file
66
lips/util.lua
Normal file
|
@ -0,0 +1,66 @@
|
|||
local floor = math.floor
|
||||
local open = io.open
|
||||
|
||||
local function Class(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
|
||||
|
||||
local function construct(t)
|
||||
if type(t) == 'table' then
|
||||
return t
|
||||
elseif type(t) == 'string' then
|
||||
return {'REG', t}
|
||||
elseif type(t) == 'number' then
|
||||
return {'NUM', t}
|
||||
else
|
||||
error('Internal Error: unknown type to construct')
|
||||
end
|
||||
end
|
||||
|
||||
local function withflag(t, key, value)
|
||||
if type(t) == 'table' then
|
||||
t = {t[1], t[2]}
|
||||
else
|
||||
t = construct(t)
|
||||
end
|
||||
if value == nil then
|
||||
value = true
|
||||
end
|
||||
if key ~= nil then
|
||||
t[key] = value
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
local function readfile(fn)
|
||||
local f = open(fn, 'r')
|
||||
if not f then
|
||||
error('could not open assembly file for reading: '..tostring(fn), 2)
|
||||
end
|
||||
local asm = f:read('*a')
|
||||
f:close()
|
||||
return asm
|
||||
end
|
||||
|
||||
local function bitrange(x, lower, upper)
|
||||
return floor(x/2^lower) % 2^(upper - lower + 1)
|
||||
end
|
||||
|
||||
return {
|
||||
Class = Class,
|
||||
construct = construct,
|
||||
withflag = withflag,
|
||||
readfile = readfile,
|
||||
bitrange = bitrange,
|
||||
}
|
Loading…
Reference in a new issue