1
0
Fork 0
mirror of https://github.com/notwa/lips synced 2024-05-03 01:53:23 -07:00
lips/lips/Muncher.lua
Connor Olding cdc0f8edb2 add a barebones expression parser
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.
2016-10-14 09:27:19 -07:00

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