1
0
Fork 0
mirror of https://github.com/notwa/lips synced 2024-04-30 00:53:23 -07:00
lips/lips/Muncher.lua
Connor Olding f851540b24 various fixes, mostly for labels
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.
2016-04-24 03:55:12 -07:00

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