mirror of
https://github.com/notwa/lips
synced 2024-05-18 16:33:22 -07:00
implement basic specials; more refactoring
This commit is contained in:
parent
195236a52c
commit
07c68b6229
|
@ -127,20 +127,20 @@ function Dumper:add_directive(fn, line, name, a, b)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Dumper:desym(tok)
|
function Dumper:desym(t)
|
||||||
if type(tok[2]) == 'number' then
|
if type(t.tok) == 'number' then
|
||||||
return tok[2]
|
return t.tok
|
||||||
elseif tok[1] == 'REG' then
|
elseif t.tt == 'REG' then
|
||||||
assert(data.all_registers[tok[2]], 'Internal Error: unknown register')
|
assert(data.all_registers[t.tok], 'Internal Error: unknown register')
|
||||||
return data.registers[tok[2]] or data.fpu_registers[tok[2]] or data.sys_registers[tok[2]]
|
return data.registers[t.tok] or data.fpu_registers[t.tok] or data.sys_registers[t.tok]
|
||||||
elseif tok[1] == 'LABELSYM' then
|
elseif t.tt == 'LABELSYM' then
|
||||||
local label = self.labels[tok[2]]
|
local label = self.labels[t.tok]
|
||||||
if label == nil then
|
if label == nil then
|
||||||
self:error('undefined label')
|
self:error('undefined label')
|
||||||
end
|
end
|
||||||
return label
|
return label
|
||||||
elseif tok[1] == 'LABELREL' then
|
elseif t.tt == 'LABELREL' then
|
||||||
local label = self.labels[tok[2]]
|
local label = self.labels[t.tok]
|
||||||
if label == nil then
|
if label == nil then
|
||||||
self:error('undefined label')
|
self:error('undefined label')
|
||||||
end
|
end
|
||||||
|
@ -155,31 +155,30 @@ function Dumper:desym(tok)
|
||||||
error('Internal Error: failed to desym')
|
error('Internal Error: failed to desym')
|
||||||
end
|
end
|
||||||
|
|
||||||
function Dumper:toval(tok)
|
function Dumper:toval(t)
|
||||||
assert(type(tok) == 'table', 'Internal Error: invalid value')
|
assert(type(t) == 'table', 'Internal Error: invalid value')
|
||||||
assert(#tok == 2, 'Internal Error: invalid token')
|
|
||||||
|
|
||||||
local val = self:desym(tok)
|
local val = self:desym(t)
|
||||||
|
|
||||||
if tok.index then
|
if t.index then
|
||||||
val = val % 0x80000000
|
val = val % 0x80000000
|
||||||
val = floor(val/4)
|
val = floor(val/4)
|
||||||
end
|
end
|
||||||
if tok.negate then
|
if t.negate then
|
||||||
val = -val
|
val = -val
|
||||||
end
|
end
|
||||||
if tok.negate or tok.signed then
|
if t.negate or t.signed then
|
||||||
if val >= 0x10000 or val < -0x8000 then
|
if val >= 0x10000 or val < -0x8000 then
|
||||||
self:error('value out of range')
|
self:error('value out of range')
|
||||||
end
|
end
|
||||||
val = val % 0x10000
|
val = val % 0x10000
|
||||||
end
|
end
|
||||||
|
|
||||||
if tok.portion == 'upper' then
|
if t.portion == 'upper' then
|
||||||
val = bitrange(val, 16, 31)
|
val = bitrange(val, 16, 31)
|
||||||
elseif tok.portion == 'lower' then
|
elseif t.portion == 'lower' then
|
||||||
val = bitrange(val, 0, 15)
|
val = bitrange(val, 0, 15)
|
||||||
elseif tok.portion == 'upperoff' then
|
elseif t.portion == 'upperoff' then
|
||||||
local upper = bitrange(val, 16, 31)
|
local upper = bitrange(val, 16, 31)
|
||||||
local lower = bitrange(val, 0, 15)
|
local lower = bitrange(val, 0, 15)
|
||||||
if lower >= 0x8000 then
|
if lower >= 0x8000 then
|
||||||
|
@ -202,8 +201,8 @@ function Dumper:validate(n, bits)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Dumper:valvar(tok, bits)
|
function Dumper:valvar(t, bits)
|
||||||
local val = self:toval(tok)
|
local val = self:toval(t)
|
||||||
self:validate(val, bits)
|
self:validate(val, bits)
|
||||||
return val
|
return val
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,7 @@ local insert = table.insert
|
||||||
|
|
||||||
local data = require "lips.data"
|
local data = require "lips.data"
|
||||||
local util = require "lips.util"
|
local util = require "lips.util"
|
||||||
|
local Token = require "lips.Token"
|
||||||
|
|
||||||
local arg_types = {
|
local arg_types = {
|
||||||
NUM = true,
|
NUM = true,
|
||||||
|
@ -19,14 +20,25 @@ function Muncher:error(msg)
|
||||||
error(format('%s:%d: Error: %s', self.fn, self.line, msg), 2)
|
error(format('%s:%d: Error: %s', self.fn, self.line, msg), 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Muncher:token(t, val)
|
||||||
|
-- note: call Token directly if you want to specify fn and line manually
|
||||||
|
if type(t) == 'table' then
|
||||||
|
t.fn = self.fn
|
||||||
|
t.line = self.line
|
||||||
|
return Token(t)
|
||||||
|
else
|
||||||
|
return Token(self.fn, self.line, t, val)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function Muncher:advance()
|
function Muncher:advance()
|
||||||
self.i = self.i + 1
|
self.i = self.i + 1
|
||||||
local t = self.tokens[self.i]
|
self.t = self.tokens[self.i]
|
||||||
self.tt = t.tt
|
self.tt = self.t.tt
|
||||||
self.tok = t.tok
|
self.tok = self.t.tok
|
||||||
self.fn = t.fn
|
self.fn = self.t.fn
|
||||||
self.line = t.line
|
self.line = self.t.line
|
||||||
return t
|
return self.t
|
||||||
end
|
end
|
||||||
|
|
||||||
function Muncher:is_EOL()
|
function Muncher:is_EOL()
|
||||||
|
@ -52,31 +64,31 @@ function Muncher:number()
|
||||||
if self.tt ~= 'NUM' then
|
if self.tt ~= 'NUM' then
|
||||||
self:error('expected number')
|
self:error('expected number')
|
||||||
end
|
end
|
||||||
local value = self.tok
|
local t = self.t
|
||||||
self:advance()
|
self:advance()
|
||||||
return value
|
return self:token(t)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Muncher:string()
|
function Muncher:string()
|
||||||
if self.tt ~= 'STRING' then
|
if self.tt ~= 'STRING' then
|
||||||
self:error('expected string')
|
self:error('expected string')
|
||||||
end
|
end
|
||||||
local value = self.tok
|
local t = self.t
|
||||||
self:advance()
|
self:advance()
|
||||||
return value
|
return self:token(t)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Muncher:register(t)
|
function Muncher:register(registers)
|
||||||
t = t or data.registers
|
registers = registers or data.registers
|
||||||
if self.tt ~= 'REG' then
|
if self.tt ~= 'REG' then
|
||||||
self:error('expected register')
|
self:error('expected register')
|
||||||
end
|
end
|
||||||
local reg = self.tok
|
local t = self.t
|
||||||
if not t[reg] then
|
if not registers[t.tok] then
|
||||||
self:error('wrong type of register')
|
self:error('wrong type of register')
|
||||||
end
|
end
|
||||||
self:advance()
|
self:advance()
|
||||||
return reg
|
return self:token(t)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Muncher:deref()
|
function Muncher:deref()
|
||||||
|
@ -87,13 +99,13 @@ function Muncher:deref()
|
||||||
if self.tt ~= 'REG' then
|
if self.tt ~= 'REG' then
|
||||||
self:error('expected register to dereference')
|
self:error('expected register to dereference')
|
||||||
end
|
end
|
||||||
local reg = self.tok
|
local t = self.t
|
||||||
self:advance()
|
self:advance()
|
||||||
if self.tt ~= 'CLOSE' then
|
if self.tt ~= 'CLOSE' then
|
||||||
self:error('expected closing parenthesis for dereferencing')
|
self:error('expected closing parenthesis for dereferencing')
|
||||||
end
|
end
|
||||||
self:advance()
|
self:advance()
|
||||||
return reg
|
return self:token(t)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Muncher:const(relative, no_label)
|
function Muncher:const(relative, no_label)
|
||||||
|
@ -106,9 +118,9 @@ function Muncher:const(relative, no_label)
|
||||||
if relative and self.tt == 'LABELSYM' then
|
if relative and self.tt == 'LABELSYM' then
|
||||||
self.tt = 'LABELREL'
|
self.tt = 'LABELREL'
|
||||||
end
|
end
|
||||||
local t = {self.tt, self.tok}
|
local t = self.t
|
||||||
self:advance()
|
self:advance()
|
||||||
return t
|
return self:token(t)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Muncher:special()
|
function Muncher:special()
|
||||||
|
@ -133,7 +145,6 @@ function Muncher:special()
|
||||||
insert(args, arg)
|
insert(args, arg)
|
||||||
elseif self.tt == 'CLOSE' then
|
elseif self.tt == 'CLOSE' then
|
||||||
insert(args, arg)
|
insert(args, arg)
|
||||||
self:advance()
|
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
self:error('unexpected token in argument list')
|
self:error('unexpected token in argument list')
|
||||||
|
|
|
@ -3,14 +3,12 @@ local insert = table.insert
|
||||||
local data = require "lips.data"
|
local data = require "lips.data"
|
||||||
local util = require "lips.util"
|
local util = require "lips.util"
|
||||||
local overrides = require "lips.overrides"
|
local overrides = require "lips.overrides"
|
||||||
|
local Token = require "lips.Token"
|
||||||
local Lexer = require "lips.Lexer"
|
local Lexer = require "lips.Lexer"
|
||||||
local Dumper = require "lips.Dumper"
|
local Dumper = require "lips.Dumper"
|
||||||
local Muncher = require "lips.Muncher"
|
local Muncher = require "lips.Muncher"
|
||||||
local Preproc = require "lips.Preproc"
|
local Preproc = require "lips.Preproc"
|
||||||
|
|
||||||
local construct = util.construct
|
|
||||||
local withflag = util.withflag
|
|
||||||
|
|
||||||
local Parser = util.Class(Muncher)
|
local Parser = util.Class(Muncher)
|
||||||
function Parser:init(writer, fn, options)
|
function Parser:init(writer, fn, options)
|
||||||
self.fn = fn or '(string)'
|
self.fn = fn or '(string)'
|
||||||
|
@ -26,7 +24,7 @@ function Parser:directive()
|
||||||
self.dumper:add_directive(self.fn, self.line, ...)
|
self.dumper:add_directive(self.fn, self.line, ...)
|
||||||
end
|
end
|
||||||
if name == 'ORG' then
|
if name == 'ORG' then
|
||||||
add(name, self:number())
|
add(name, self:number().tok)
|
||||||
elseif name == 'ALIGN' or name == 'SKIP' then
|
elseif name == 'ALIGN' or name == 'SKIP' then
|
||||||
if self:is_EOL() and name == 'ALIGN' then
|
if self:is_EOL() and name == 'ALIGN' then
|
||||||
add(name, 0)
|
add(name, 0)
|
||||||
|
@ -36,24 +34,24 @@ function Parser:directive()
|
||||||
add(name, size)
|
add(name, size)
|
||||||
else
|
else
|
||||||
self:optional_comma()
|
self:optional_comma()
|
||||||
add(name, size, self:number())
|
add(name, size, self:number().tok)
|
||||||
end
|
end
|
||||||
self:expect_EOL()
|
self:expect_EOL()
|
||||||
end
|
end
|
||||||
elseif name == 'BYTE' or name == 'HALFWORD' then
|
elseif name == 'BYTE' or name == 'HALFWORD' then
|
||||||
add(name, self:number())
|
add(name, self:number().tok)
|
||||||
while not self:is_EOL() do
|
while not self:is_EOL() do
|
||||||
self:advance()
|
self:advance()
|
||||||
self:optional_comma()
|
self:optional_comma()
|
||||||
add(name, self:number())
|
add(name, self:number().tok)
|
||||||
end
|
end
|
||||||
self:expect_EOL()
|
self:expect_EOL()
|
||||||
elseif name == 'WORD' then -- allow labels in word directives
|
elseif name == 'WORD' then -- allow labels in word directives
|
||||||
add(name, self:const()[2])
|
add(name, self:const().tok)
|
||||||
while not self:is_EOL() do
|
while not self:is_EOL() do
|
||||||
self:advance()
|
self:advance()
|
||||||
self:optional_comma()
|
self:optional_comma()
|
||||||
add(name, self:const()[2])
|
add(name, self:const().tok)
|
||||||
end
|
end
|
||||||
self:expect_EOL()
|
self:expect_EOL()
|
||||||
elseif name == 'INC' then
|
elseif name == 'INC' then
|
||||||
|
@ -100,17 +98,17 @@ function Parser:format_in(informat)
|
||||||
elseif c == 'Z' and not args.rt then
|
elseif c == 'Z' and not args.rt then
|
||||||
args.rt = self:register(data.sys_registers)
|
args.rt = self:register(data.sys_registers)
|
||||||
elseif c == 'o' and not args.offset then
|
elseif c == 'o' and not args.offset then
|
||||||
args.offset = withflag(self:const(), 'signed')
|
args.offset = Token(self:const()):set('signed')
|
||||||
elseif c == 'r' and not args.offset then
|
elseif c == 'r' and not args.offset then
|
||||||
args.offset = withflag(self:const('relative'), 'signed')
|
args.offset = Token(self:const('relative')):set('signed')
|
||||||
elseif c == 'i' and not args.immediate then
|
elseif c == 'i' and not args.immediate then
|
||||||
args.immediate = self:const(nil, 'no label')
|
args.immediate = self:const(nil, 'no label')
|
||||||
elseif c == 'I' and not args.index then
|
elseif c == 'I' and not args.index then
|
||||||
args.index = withflag(self:const(), 'index')
|
args.index = Token(self:const()):set('index')
|
||||||
elseif c == 'k' and not args.immediate then
|
elseif c == 'k' and not args.immediate then
|
||||||
args.immediate = withflag(self:const(nil, 'no label'), 'negate')
|
args.immediate = Token(self:const(nil, 'no label')):set('negate')
|
||||||
elseif c == 'K' and not args.immediate then
|
elseif c == 'K' and not args.immediate then
|
||||||
args.immediate = withflag(self:const(nil, 'no label'), 'signed')
|
args.immediate = Token(self:const(nil, 'no label')):set('signed')
|
||||||
elseif c == 'b' and not args.base then
|
elseif c == 'b' and not args.base then
|
||||||
args.base = self:deref()
|
args.base = self:deref()
|
||||||
else
|
else
|
||||||
|
@ -133,31 +131,31 @@ function Parser:format_out_raw(outformat, first, args, const, formatconst)
|
||||||
for i=1,#outformat do
|
for i=1,#outformat do
|
||||||
local c = outformat:sub(i, i)
|
local c = outformat:sub(i, i)
|
||||||
if c == 'd' then
|
if c == 'd' then
|
||||||
out[#out+1] = construct(args.rd)
|
out[#out+1] = self:token(args.rd)
|
||||||
elseif c == 's' then
|
elseif c == 's' then
|
||||||
out[#out+1] = construct(args.rs)
|
out[#out+1] = self:token(args.rs)
|
||||||
elseif c == 't' then
|
elseif c == 't' then
|
||||||
out[#out+1] = construct(args.rt)
|
out[#out+1] = self:token(args.rt)
|
||||||
elseif c == 'D' then
|
elseif c == 'D' then
|
||||||
out[#out+1] = construct(args.fd)
|
out[#out+1] = self:token(args.fd)
|
||||||
elseif c == 'S' then
|
elseif c == 'S' then
|
||||||
out[#out+1] = construct(args.fs)
|
out[#out+1] = self:token(args.fs)
|
||||||
elseif c == 'T' then
|
elseif c == 'T' then
|
||||||
out[#out+1] = construct(args.ft)
|
out[#out+1] = self:token(args.ft)
|
||||||
elseif c == 'o' then
|
elseif c == 'o' then
|
||||||
out[#out+1] = construct(args.offset)
|
out[#out+1] = self:token(args.offset)
|
||||||
elseif c == 'i' then
|
elseif c == 'i' then
|
||||||
out[#out+1] = construct(args.immediate)
|
out[#out+1] = self:token(args.immediate)
|
||||||
elseif c == 'I' then
|
elseif c == 'I' then
|
||||||
out[#out+1] = construct(args.index)
|
out[#out+1] = self:token(args.index)
|
||||||
elseif c == 'b' then
|
elseif c == 'b' then
|
||||||
out[#out+1] = construct(args.base)
|
out[#out+1] = self:token(args.base)
|
||||||
elseif c == '0' then
|
elseif c == '0' then
|
||||||
out[#out+1] = construct(0)
|
out[#out+1] = self:token(0)
|
||||||
elseif c == 'C' then
|
elseif c == 'C' then
|
||||||
out[#out+1] = construct(const)
|
out[#out+1] = self:token(const)
|
||||||
elseif c == 'F' then
|
elseif c == 'F' then
|
||||||
out[#out+1] = construct(formatconst)
|
out[#out+1] = self:token(formatconst)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local f = lookup[#outformat]
|
local f = lookup[#outformat]
|
||||||
|
@ -193,9 +191,12 @@ function Parser:instruction()
|
||||||
local lui_args = {}
|
local lui_args = {}
|
||||||
local addu_args = {}
|
local addu_args = {}
|
||||||
local o = self:const()
|
local o = self:const()
|
||||||
args.offset = withflag({o[1], o[2]}, 'portion', 'lower')
|
args.offset = self:token(o)
|
||||||
if o[1] == 'LABELSYM' or o[2] >= 0x80000000 then
|
if not o.portion then
|
||||||
lui_args.immediate = withflag({o[1], o[2]}, 'portion', 'upperoff')
|
args.offset:set('portion', 'lower')
|
||||||
|
end
|
||||||
|
if not o.portion and (o.tt == 'LABELSYM' or o.tok >= 0x80000000) then
|
||||||
|
lui_args.immediate = Token(o):set('portion', 'upperoff')
|
||||||
lui_args.rt = 'AT'
|
lui_args.rt = 'AT'
|
||||||
self:format_out(lui, lui_args)
|
self:format_out(lui, lui_args)
|
||||||
if not self:is_EOL() then
|
if not self:is_EOL() then
|
||||||
|
@ -236,11 +237,7 @@ function Parser:tokenize(asm)
|
||||||
end
|
end
|
||||||
assert(a, 'Internal Error: missing token')
|
assert(a, 'Internal Error: missing token')
|
||||||
|
|
||||||
local t = {}
|
local t = Token(c, d, a, b)
|
||||||
t.tt = a
|
|
||||||
t.tok = b
|
|
||||||
t.fn = c
|
|
||||||
t.line = d
|
|
||||||
insert(tokens, t)
|
insert(tokens, t)
|
||||||
|
|
||||||
if t.tt == 'EOF' and t.fn == self.main_fn then
|
if t.tt == 'EOF' and t.fn == self.main_fn then
|
||||||
|
|
|
@ -3,6 +3,7 @@ local insert = table.insert
|
||||||
local data = require "lips.data"
|
local data = require "lips.data"
|
||||||
local util = require "lips.util"
|
local util = require "lips.util"
|
||||||
local Muncher = require "lips.Muncher"
|
local Muncher = require "lips.Muncher"
|
||||||
|
local Token = require "lips.Token"
|
||||||
|
|
||||||
local Preproc = util.Class(Muncher)
|
local Preproc = util.Class(Muncher)
|
||||||
function Preproc:init(options)
|
function Preproc:init(options)
|
||||||
|
@ -35,7 +36,7 @@ function Preproc:process(tokens)
|
||||||
if tok == nil then
|
if tok == nil then
|
||||||
self:error('undefined define') -- uhhh nice wording
|
self:error('undefined define') -- uhhh nice wording
|
||||||
end
|
end
|
||||||
insert(new_tokens, {fn=t.fn, line=t.line, tt=tt, tok=tok})
|
insert(new_tokens, self:token(tt, tok))
|
||||||
elseif t.tt == 'RELLABEL' then
|
elseif t.tt == 'RELLABEL' then
|
||||||
if t.tok == '+' then
|
if t.tok == '+' then
|
||||||
insert(plus_labels, #new_tokens + 1)
|
insert(plus_labels, #new_tokens + 1)
|
||||||
|
@ -99,8 +100,6 @@ function Preproc:process(tokens)
|
||||||
self.i = 0
|
self.i = 0
|
||||||
while self.i < #self.tokens do
|
while self.i < #self.tokens do
|
||||||
local t = self:advance()
|
local t = self:advance()
|
||||||
self.fn = t.fn
|
|
||||||
self.line = t.line
|
|
||||||
if t.tt == 'SPECIAL' then
|
if t.tt == 'SPECIAL' then
|
||||||
local name, args = self:special()
|
local name, args = self:special()
|
||||||
-- TODO: split to its own file, not unlike overrides.lua
|
-- TODO: split to its own file, not unlike overrides.lua
|
||||||
|
@ -108,22 +107,19 @@ function Preproc:process(tokens)
|
||||||
if #args ~= 1 then
|
if #args ~= 1 then
|
||||||
self:error('%hi expected exactly one argument')
|
self:error('%hi expected exactly one argument')
|
||||||
end
|
end
|
||||||
--local tnew = {fn=t.fn, line=t.line, tt='UPPEROFF', tok=args[1]}
|
local tnew = self:token(args[1]):set('portion', 'upperoff')
|
||||||
self:error('unimplemented special')
|
|
||||||
insert(new_tokens, tnew)
|
insert(new_tokens, tnew)
|
||||||
elseif name == 'up' then
|
elseif name == 'up' then
|
||||||
if #args ~= 1 then
|
if #args ~= 1 then
|
||||||
self:error('%up expected exactly one argument')
|
self:error('%up expected exactly one argument')
|
||||||
end
|
end
|
||||||
--local tnew = {fn=t.fn, line=t.line, tt='UPPER', tok=args[1]}
|
local tnew = self:token(args[1]):set('portion', 'upper')
|
||||||
self:error('unimplemented special')
|
|
||||||
insert(new_tokens, tnew)
|
insert(new_tokens, tnew)
|
||||||
elseif name == 'lo' then
|
elseif name == 'lo' then
|
||||||
if #args ~= 1 then
|
if #args ~= 1 then
|
||||||
self:error('%lo expected exactly one argument')
|
self:error('%lo expected exactly one argument')
|
||||||
end
|
end
|
||||||
self:error('unimplemented special')
|
local tnew = self:token(args[1]):set('portion', 'lower')
|
||||||
--local tnew = {fn=t.fn, line=t.line, tt='LOWER', tok=args[1]}
|
|
||||||
insert(new_tokens, tnew)
|
insert(new_tokens, tnew)
|
||||||
else
|
else
|
||||||
self:error('unknown special')
|
self:error('unknown special')
|
||||||
|
|
60
lips/Token.lua
Normal file
60
lips/Token.lua
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
local util = require "lips.util"
|
||||||
|
|
||||||
|
local Token = util.Class()
|
||||||
|
function Token:init(...)
|
||||||
|
local args = {...}
|
||||||
|
if #args == 1 then
|
||||||
|
local t = args[1]
|
||||||
|
if type(t) == 'table' then
|
||||||
|
for k, v in pairs(t) do
|
||||||
|
self[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif #args == 3 then
|
||||||
|
self.fn = args[1]
|
||||||
|
self.line = args[2]
|
||||||
|
local t = args[3]
|
||||||
|
if type(t) == 'table' then
|
||||||
|
self.tt = t[1]
|
||||||
|
self.tok = t[2]
|
||||||
|
elseif type(t) == 'string' then
|
||||||
|
self.tt = 'REG'
|
||||||
|
self.tok = t
|
||||||
|
elseif type(t) == 'number' then
|
||||||
|
self.tt = 'NUM'
|
||||||
|
self.tok = t
|
||||||
|
else
|
||||||
|
error('Internal Error: unknown type to construct', 3)
|
||||||
|
end
|
||||||
|
elseif #args == 4 then
|
||||||
|
self.fn = args[1]
|
||||||
|
self.line = args[2]
|
||||||
|
self.tt = args[3]
|
||||||
|
self.tok = args[4]
|
||||||
|
else
|
||||||
|
error('Internal Error: init takes 1, 3 or 4 arguments', 3)
|
||||||
|
end
|
||||||
|
if not self.fn then
|
||||||
|
error('Internal Error: tokens require a filename', 3)
|
||||||
|
end
|
||||||
|
if not self.line then
|
||||||
|
error('Internal Error: tokens require a line number', 3)
|
||||||
|
end
|
||||||
|
if not self.tt then
|
||||||
|
error('Internal Error: token is missing a type', 3)
|
||||||
|
end
|
||||||
|
if not self.tok then
|
||||||
|
error('Internal Error: token is missing a value', 3)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function Token:set(key, value)
|
||||||
|
if value == nil then
|
||||||
|
value = true
|
||||||
|
end
|
||||||
|
self[key] = value
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
return Token
|
|
@ -4,7 +4,6 @@ local data = require "lips.data"
|
||||||
local util = require "lips.util"
|
local util = require "lips.util"
|
||||||
|
|
||||||
local instructions = data.instructions
|
local instructions = data.instructions
|
||||||
local withflag = util.withflag
|
|
||||||
|
|
||||||
local overrides = {}
|
local overrides = {}
|
||||||
-- note: "self" is an instance of Parser
|
-- note: "self" is an instance of Parser
|
||||||
|
@ -20,26 +19,33 @@ function overrides.LI(self, name)
|
||||||
|
|
||||||
-- for us, this is just semantics. for a "real" assembler,
|
-- for us, this is just semantics. for a "real" assembler,
|
||||||
-- LA could add appropriate RELO LUI/ADDIU directives.
|
-- LA could add appropriate RELO LUI/ADDIU directives.
|
||||||
if im[1] == 'LABELSYM' then
|
if im.tt == 'LABELSYM' then
|
||||||
self:error('use LA for labels')
|
self:error('use LA for labels')
|
||||||
end
|
end
|
||||||
|
|
||||||
im[2] = im[2] % 0x100000000
|
if im.portion then
|
||||||
if im[2] >= 0x10000 and im[2] <= 0xFFFF8000 then
|
args.rs = 'R0'
|
||||||
|
args.immediate = im
|
||||||
|
self:format_out(addiu, args)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
im.tok = im.tok % 0x100000000
|
||||||
|
if im.tok >= 0x10000 and im.tok <= 0xFFFF8000 then
|
||||||
args.rs = args.rt
|
args.rs = args.rt
|
||||||
args.immediate = withflag(im, 'portion', 'upper')
|
args.immediate = self:token(im):set('portion', 'upper')
|
||||||
self:format_out(lui, args)
|
self:format_out(lui, args)
|
||||||
if im[2] % 0x10000 ~= 0 then
|
if im.tok % 0x10000 ~= 0 then
|
||||||
args.immediate = withflag(im, 'portion', 'lower')
|
args.immediate = self:token(im):set('portion', 'lower')
|
||||||
self:format_out(ori, args)
|
self:format_out(ori, args)
|
||||||
end
|
end
|
||||||
elseif im[2] >= 0x8000 and im[2] < 0x10000 then
|
elseif im.tok >= 0x8000 and im.tok < 0x10000 then
|
||||||
args.rs = 'R0'
|
args.rs = 'R0'
|
||||||
args.immediate = withflag(im, 'portion', 'lower')
|
args.immediate = self:token(im):set('portion', 'lower')
|
||||||
self:format_out(ori, args)
|
self:format_out(ori, args)
|
||||||
else
|
else
|
||||||
args.rs = 'R0'
|
args.rs = 'R0'
|
||||||
args.immediate = withflag(im, 'portion', 'lower')
|
args.immediate = self:token(im):set('portion', 'lower')
|
||||||
self:format_out(addiu, args)
|
self:format_out(addiu, args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -53,9 +59,9 @@ function overrides.LA(self, name)
|
||||||
local im = self:const()
|
local im = self:const()
|
||||||
|
|
||||||
args.rs = args.rt
|
args.rs = args.rt
|
||||||
args.immediate = withflag(im, 'portion', 'upperoff')
|
args.immediate = self:token(im):set('portion', 'upperoff')
|
||||||
self:format_out(lui, args)
|
self:format_out(lui, args)
|
||||||
args.immediate = withflag(im, 'portion', 'lower')
|
args.immediate = self:token(im):set('portion', 'lower')
|
||||||
self:format_out(addiu, args)
|
self:format_out(addiu, args)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -87,7 +93,7 @@ function overrides.PUSH(self, name)
|
||||||
if name == 'PUSH' then
|
if name == 'PUSH' then
|
||||||
args.rt = 'SP'
|
args.rt = 'SP'
|
||||||
args.rs = 'SP'
|
args.rs = 'SP'
|
||||||
args.immediate = withflag(#stack*4, 'negate')
|
args.immediate = self:token(#stack*4):set('negate')
|
||||||
self:format_out(addi, args)
|
self:format_out(addi, args)
|
||||||
end
|
end
|
||||||
args.base = 'SP'
|
args.base = 'SP'
|
||||||
|
@ -241,7 +247,7 @@ function overrides.BEQI(self, name)
|
||||||
self:optional_comma()
|
self:optional_comma()
|
||||||
args.immediate = self:const()
|
args.immediate = self:const()
|
||||||
self:optional_comma()
|
self:optional_comma()
|
||||||
args.offset = withflag(self:const('relative'), 'signed')
|
args.offset = self:token(self:const('relative')):set('signed')
|
||||||
|
|
||||||
if reg == 'AT' then
|
if reg == 'AT' then
|
||||||
self:error('register cannot be AT in this pseudo-instruction')
|
self:error('register cannot be AT in this pseudo-instruction')
|
||||||
|
@ -264,7 +270,7 @@ function overrides.BLTI(self, name)
|
||||||
self:optional_comma()
|
self:optional_comma()
|
||||||
args.immediate = self:const()
|
args.immediate = self:const()
|
||||||
self:optional_comma()
|
self:optional_comma()
|
||||||
args.offset = withflag(self:const('relative'), 'signed')
|
args.offset = self:token(self:const('relative')):set('signed')
|
||||||
|
|
||||||
if args.rs == 'AT' then
|
if args.rs == 'AT' then
|
||||||
self:error('register cannot be AT in this pseudo-instruction')
|
self:error('register cannot be AT in this pseudo-instruction')
|
||||||
|
@ -290,7 +296,7 @@ function overrides.BLEI(self, name)
|
||||||
self:optional_comma()
|
self:optional_comma()
|
||||||
args.immediate = self:const()
|
args.immediate = self:const()
|
||||||
self:optional_comma()
|
self:optional_comma()
|
||||||
local offset = withflag(self:const('relative'), 'signed')
|
local offset = self:token(self:const('relative')):set('signed')
|
||||||
|
|
||||||
if reg == 'AT' then
|
if reg == 'AT' then
|
||||||
self:error('register cannot be AT in this pseudo-instruction')
|
self:error('register cannot be AT in this pseudo-instruction')
|
||||||
|
|
|
@ -16,33 +16,6 @@ local function Class(inherit)
|
||||||
return setmetatable(class, mt_class)
|
return setmetatable(class, mt_class)
|
||||||
end
|
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 function readfile(fn)
|
||||||
local f = open(fn, 'r')
|
local f = open(fn, 'r')
|
||||||
if not f then
|
if not f then
|
||||||
|
@ -59,8 +32,6 @@ end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
Class = Class,
|
Class = Class,
|
||||||
construct = construct,
|
|
||||||
withflag = withflag,
|
|
||||||
readfile = readfile,
|
readfile = readfile,
|
||||||
bitrange = bitrange,
|
bitrange = bitrange,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user