1
0
Fork 0
mirror of https://github.com/notwa/lips synced 2024-06-01 23:03:07 -07:00
lips/lips/Preproc.lua

138 lines
4.3 KiB
Lua

local insert = table.insert
local data = require "lips.data"
local util = require "lips.util"
local Muncher = require "lips.Muncher"
local Token = require "lips.Token"
local Preproc = util.Class(Muncher)
function Preproc:init(options)
self.options = options or {}
end
function Preproc:process(tokens)
self.tokens = tokens
local defines = {}
local plus_labels = {} -- constructed forwards
local minus_labels = {} -- constructed backwards
-- first pass: resolve defines, collect relative labels
local new_tokens = {}
self.i = 0
while self.i < #self.tokens do
local t = self:advance()
if t.tt == nil then
error('Internal Error: missing token')
elseif t.tt == 'DEF' then
local t2 = self:advance()
if t2.tt ~= 'NUM' then
self:error('expected number for define')
end
defines[t.tok] = t2.tok
elseif t.tt == 'DEFSYM' then
local tt = 'NUM'
local tok = defines[t.tok]
if tok == nil then
self:error('undefined define') -- uhhh nice wording
end
insert(new_tokens, self:token(tt, tok))
elseif t.tt == 'RELLABEL' then
if t.tok == '+' then
insert(plus_labels, #new_tokens + 1)
elseif t.tok == '-' then
insert(minus_labels, 1, #new_tokens + 1)
else
error('Internal Error: unexpected token for relative label')
end
insert(new_tokens, t)
else
insert(new_tokens, t)
end
end
-- second pass: resolve relative labels
for i, t in ipairs(new_tokens) do
self.fn = t.fn
self.line = t.line
if t.tt == 'RELLABEL' then
t.tt = 'LABEL'
-- exploits the fact that user labels can't begin with a number
t.tok = tostring(i)
elseif t.tt == 'RELLABELSYM' then
t.tt = 'LABELSYM'
local rel = t.tok
local seen = 0
-- TODO: don't iterate over *every* label, just the ones nearby
if rel > 0 then
for _, label_i in ipairs(plus_labels) do
if label_i > i then
seen = seen + 1
if seen == rel then
t.tok = tostring(label_i)
break
end
end
end
else
for _, label_i in ipairs(minus_labels) do
if label_i < i then
seen = seen - 1
if seen == rel then
t.tok = tostring(label_i)
break
end
end
end
end
if seen ~= rel then
self:error('could not find appropriate relative label')
end
end
end
self.tokens = new_tokens
new_tokens = {}
-- third pass: resolve specials
self.i = 0
while self.i < #self.tokens do
local t = self:advance()
if t.tt == 'SPECIAL' then
local name, args = self:special()
-- TODO: split to its own file, not unlike overrides.lua
if name == 'hi' then
if #args ~= 1 then
self:error('%hi expected exactly one argument')
end
local tnew = self:token(args[1]):set('portion', 'upperoff')
insert(new_tokens, tnew)
elseif name == 'up' then
if #args ~= 1 then
self:error('%up expected exactly one argument')
end
local tnew = self:token(args[1]):set('portion', 'upper')
insert(new_tokens, tnew)
elseif name == 'lo' then
if #args ~= 1 then
self:error('%lo expected exactly one argument')
end
local tnew = self:token(args[1]):set('portion', 'lower')
insert(new_tokens, tnew)
else
self:error('unknown special')
end
else
insert(new_tokens, t)
end
end
self.tokens = new_tokens
return self.tokens
end
return Preproc