mirror of
https://github.com/notwa/lips
synced 2024-05-03 01:53:23 -07:00
Connor Olding
cdc0f8edb2
at the moment, this probably only works in directives. some of the operators are still unimplemented, and the errors are poor. there will be support for accessing variables in the future.
167 lines
3.8 KiB
Lua
167 lines
3.8 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)
|
|
local good = {
|
|
NUM = true,
|
|
EXPR = true,
|
|
VARSYM = true,
|
|
LABELSYM = true,
|
|
}
|
|
if not good[self.tt] 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
|