mirror of
https://github.com/notwa/lips
synced 2024-04-30 00:53:23 -07:00
Connor Olding
f851540b24
reimplement modulo by 0x80000000 for labels. allow numeric label values ("REL") to be "fixed" to bypass label calculation. add offsets after label calculation instead of before. properly check for EOL after all expected arguments have been exhausted. finally, add token properties to debug dumps.
161 lines
3.7 KiB
Lua
161 lines
3.7 KiB
Lua
local format = string.format
|
|
local insert = table.insert
|
|
|
|
local path = string.gsub(..., "[^.]+$", "")
|
|
local data = require(path.."data")
|
|
local Base = require(path.."Base")
|
|
local Token = require(path.."Token")
|
|
|
|
local arg_types = {
|
|
NUM = true,
|
|
REG = true,
|
|
VARSYM = true,
|
|
LABELSYM = true,
|
|
RELLABELSYM = true,
|
|
}
|
|
|
|
local Muncher = Base:extend()
|
|
-- no base init method
|
|
|
|
function Muncher:error(msg, got)
|
|
if got ~= nil then
|
|
msg = msg..', got '..tostring(got)
|
|
end
|
|
error(format('%s:%d: Error: %s', self.fn, self.line, msg), 2)
|
|
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
|
|
local token = Token(t)
|
|
return token
|
|
else
|
|
local token = Token(self.fn, self.line, t, val)
|
|
return token
|
|
end
|
|
end
|
|
|
|
function Muncher:advance()
|
|
self.i = self.i + 1
|
|
self.t = self.tokens[self.i]
|
|
self.tt = self.t.tt
|
|
self.tok = self.t.tok
|
|
self.fn = self.t.fn
|
|
self.line = self.t.line
|
|
return self.t
|
|
end
|
|
|
|
function Muncher:is_EOL()
|
|
return self.tt == 'EOL' or self.tt == 'EOF'
|
|
end
|
|
|
|
function Muncher:expect_EOL()
|
|
if self:is_EOL() then
|
|
self:advance()
|
|
return
|
|
end
|
|
self:error('expected end of line', self.tt)
|
|
end
|
|
|
|
function Muncher:optional_comma()
|
|
if self.tt == 'SEP' and self.tok == ',' then
|
|
self:advance()
|
|
return true
|
|
end
|
|
end
|
|
|
|
function Muncher:number()
|
|
if self.tt ~= 'NUM' then
|
|
self:error('expected number', self.tt)
|
|
end
|
|
local t = self.t
|
|
self:advance()
|
|
return self:token(t)
|
|
end
|
|
|
|
function Muncher:string()
|
|
if self.tt ~= 'STRING' then
|
|
self:error('expected string', self.tt)
|
|
end
|
|
local t = self.t
|
|
self:advance()
|
|
return self:token(t)
|
|
end
|
|
|
|
function Muncher:register(registers)
|
|
registers = registers or data.registers
|
|
if self.tt ~= 'REG' then
|
|
self:error('expected register', self.tt)
|
|
end
|
|
local t = self.t
|
|
if not registers[t.tok] then
|
|
self:error('wrong type of register', t.tok)
|
|
end
|
|
self:advance()
|
|
return self:token(t)
|
|
end
|
|
|
|
function Muncher:deref()
|
|
if self.tt ~= 'OPEN' then
|
|
self:error('expected opening parenthesis for dereferencing', self.tt)
|
|
end
|
|
self:advance()
|
|
if self.tt ~= 'REG' then
|
|
self:error('expected register to dereference', self.tt)
|
|
end
|
|
local t = self.t
|
|
self:advance()
|
|
if self.tt ~= 'CLOSE' then
|
|
self:error('expected closing parenthesis for dereferencing', self.tt)
|
|
end
|
|
self:advance()
|
|
return self:token(t)
|
|
end
|
|
|
|
function Muncher:const(relative, no_label)
|
|
if self.tt ~= 'NUM' and self.tt ~= 'VARSYM' and self.tt ~= 'LABELSYM' then
|
|
self:error('expected constant', self.tt)
|
|
end
|
|
if no_label and self.tt == 'LABELSYM' then
|
|
self:error('labels are not allowed here', self.tt)
|
|
end
|
|
local t = self:token(self.t)
|
|
self:advance()
|
|
return t
|
|
end
|
|
|
|
function Muncher:special()
|
|
if self.tt ~= 'SPECIAL' then
|
|
self:error('expected special name to call', self.tt)
|
|
end
|
|
local name = self.tok
|
|
self:advance()
|
|
if self.tt ~= 'OPEN' then
|
|
self:error('expected opening parenthesis for special call', self.tt)
|
|
end
|
|
|
|
local args = {}
|
|
while true do
|
|
local arg = self:advance()
|
|
if not arg_types[arg.tt] then
|
|
self:error('invalid argument type', arg.tt)
|
|
else
|
|
self:advance()
|
|
end
|
|
if self.tt == 'SEP' then
|
|
insert(args, arg)
|
|
elseif self.tt == 'CLOSE' then
|
|
insert(args, arg)
|
|
break
|
|
else
|
|
self:error('unexpected token in argument list', self.tt)
|
|
end
|
|
end
|
|
|
|
return name, args
|
|
end
|
|
|
|
return Muncher
|