From b8601031f33e7f0cb904eddbc9ea45b34dde6fb2 Mon Sep 17 00:00:00 2001 From: Connor Olding Date: Sun, 10 Apr 2016 05:08:41 -0700 Subject: [PATCH] add named relative labels --- lips/Lexer.lua | 14 ++++++++----- lips/Preproc.lua | 54 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/lips/Lexer.lua b/lips/Lexer.lua index 005cf1a..29e9bfe 100644 --- a/lips/Lexer.lua +++ b/lips/Lexer.lua @@ -396,21 +396,25 @@ function Lexer:lex(_yield) elseif self.chr == '+' or self.chr == '-' then local sign_chr = self.chr local sign = sign_chr == '+' and 1 or -1 - local buff = self:read_chars('%'..self.chr) - if #buff == 1 and self.chr == ':' then + local signs = self:read_chars('%'..self.chr) + local name = '' + if self.chr:find('[%a_]') then + name = self:read_chars('[%w_]') + end + if #signs == 1 and self.chr == ':' then self:nextc() - yield('RELLABEL', sign_chr) + yield('RELLABEL', signs..name) else self:read_spaces() local n = self:read_number() if n then yield('NUM', sign*n) - elseif #buff == 1 then + elseif #signs == 1 and name == '' then -- this could be a RELLABELSYM -- we'll have to let the preproc figure it out yield('UNARY', sign) else - yield('RELLABELSYM', sign*#buff) + yield('RELLABELSYM', signs..name) end end else diff --git a/lips/Preproc.lua b/lips/Preproc.lua index 37db636..f10fb38 100644 --- a/lips/Preproc.lua +++ b/lips/Preproc.lua @@ -5,6 +5,27 @@ local util = require "lips.util" local Muncher = require "lips.Muncher" local Token = require "lips.Token" +local abs = math.abs + +local function signs(s) + local start, end_ = s:find('[+-]+') + if start ~= 1 then + return 0 + end + if s:sub(1, 1) == '+' then + return end_ + elseif s:sub(1, 1) == '-' then + return -end_ + end +end + +local function RelativeLabel(index, name) + return { + index = index, + name = name, + } +end + local Preproc = util.Class(Muncher) function Preproc:init(options) self.options = options or {} @@ -30,6 +51,7 @@ function Preproc:process(tokens) self:error('unary operators cannot be chained') elseif peek.tt == 'EOL' or peek.tt == 'SEP' then t.tt = 'RELLABELSYM' + t.tok = sign == 1 and '+' or sign == -1 and '-' elseif peek.tt == 'DEFSYM' then t = self:advance() else @@ -52,10 +74,12 @@ function Preproc:process(tokens) end insert(new_tokens, self:token(tt, tok * sign)) 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) + local label = t.tok or '' + local rl = RelativeLabel(#new_tokens + 1, label:sub(2)) + if label:sub(1, 1) == '+' then + insert(plus_labels, rl) + elseif label:sub(1, 1) == '-' then + insert(minus_labels, rl) else error('Internal Error: unexpected token for relative label') end @@ -72,29 +96,35 @@ function Preproc:process(tokens) if t.tt == 'RELLABEL' then t.tt = 'LABEL' -- exploits the fact that user labels can't begin with a number - t.tok = tostring(i) + local name = t.tok:sub(2) + t.tok = tostring(i)..name elseif t.tt == 'RELLABELSYM' then t.tt = 'LABELSYM' - local rel = t.tok + local rel = signs(t.tok) + if rel == 0 then + error('Internal Error: relative label without signs') + end + local name = t.tok:sub(abs(rel) + 1) 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 + for _, rl in ipairs(plus_labels) do + if rl.name == name and rl.index > i then seen = seen + 1 if seen == rel then - t.tok = tostring(label_i) + t.tok = tostring(rl.index)..name break end end end else - for _, label_i in ipairs(minus_labels) do - if label_i < i then + for _, rl in ipairs(minus_labels) do + if rl.name == name and rl.index < i then seen = seen - 1 if seen == rel then - t.tok = tostring(label_i) + t.tok = tostring(rl.index)..name break end end