From 2143128628df8e676f86ff5c8fe3db1d100bf2b2 Mon Sep 17 00:00:00 2001 From: Connor Olding Date: Sun, 27 Nov 2016 15:07:48 -0800 Subject: [PATCH] split Preproc expansion into Expander class --- lips/Expander.lua | 96 +++++++++++++++++++++++++ lips/Parser.lua | 6 +- lips/Preproc.lua | 172 +++++++++++---------------------------------- lips/overrides.lua | 2 +- 4 files changed, 140 insertions(+), 136 deletions(-) create mode 100644 lips/Expander.lua diff --git a/lips/Expander.lua b/lips/Expander.lua new file mode 100644 index 0000000..6664654 --- /dev/null +++ b/lips/Expander.lua @@ -0,0 +1,96 @@ +local insert = table.insert + +local path = string.gsub(..., "[^.]+$", "") +local data = require(path.."data") +local overrides = require(path.."overrides") +local Statement = require(path.."Statement") +local Reader = require(path.."Reader") + +local Expander = Reader:extend() +function Expander:init(options) + self.options = options or {} +end + +function Expander:statement(...) + local s = Statement(self.fn, self.line, ...) + return s +end + +function Expander:push(s) + s:validate() + insert(self.statements, s) +end + +function Expander:push_new(...) + self:push(self:statement(...)) +end + +function Expander:pop(kind) + local ret + if kind == nil then + ret = self.s[self.i] + elseif kind == 'CPU' then + ret = self:register(data.registers) + elseif kind == 'DEREF' then + ret = self:deref() + elseif kind == 'CONST' then + ret = self:const() + elseif kind == 'END' then + if self.s[self.i] ~= nil then + self:error('expected EOL; too many arguments') + end + return -- don't increment self.i past end of arguments + else + error('Internal Error: unknown kind, got '..tostring(kind)) + end + self.i = self.i + 1 + return ret +end + +function Expander:expand(statements) + -- fourth pass: expand pseudo-instructions and register arguments + self.statements = {} + for i, s in ipairs(statements) do + self.s = s + self.fn = s.fn + self.line = s.line + if s.type:sub(1, 1) == '!' then + self:push(s) + else + local name = s.type + local h = data.instructions[name] + if h == nil then + error('Internal Error: unknown instruction') + end + + if data.one_register_variants[name] then + self.i = 1 + local a = self:register(data.all_registers) + local b = s[2] + if b == nil or b.tt ~= 'REG' then + insert(s, 2, self:token(a)) + end + elseif data.two_register_variants[name] then + self.i = 1 + local a = self:register(data.all_registers) + local b = self:register(data.all_registers) + local c = s[3] + if c == nil or c.tt ~= 'REG' then + insert(s, 2, self:token(a)) + end + end + + if overrides[name] then + self.i = 1 + overrides[name](self, name) + self:pop('END') + else + self:push(s) + end + end + end + + return self.statements +end + +return Expander diff --git a/lips/Parser.lua b/lips/Parser.lua index 353100f..ba4f86e 100644 --- a/lips/Parser.lua +++ b/lips/Parser.lua @@ -6,6 +6,7 @@ local Token = require(path.."Token") local Lexer = require(path.."Lexer") local Collector = require(path.."Collector") local Preproc = require(path.."Preproc") +local Expander = require(path.."Expander") local Dumper = require(path.."Dumper") local Parser = Base:extend() @@ -50,11 +51,10 @@ function Parser:parse(asm) self.statements = self:tokenize(asm) if self.options.debug_token then self:dump() end - local preproc = Preproc(self.options) - self.statements = preproc:process(self.statements) + self.statements = Preproc(self.options):process(self.statements) if self.options.debug_pre then self:dump() end - self.statements = preproc:expand(self.statements) + self.statements = Expander(self.options):expand(self.statements) if self.options.debug_post then self:dump() end local dumper = Dumper(self.writer, self.options) diff --git a/lips/Preproc.lua b/lips/Preproc.lua index d5def64..a4a9137 100644 --- a/lips/Preproc.lua +++ b/lips/Preproc.lua @@ -2,20 +2,32 @@ local abs = math.abs local insert = table.insert local path = string.gsub(..., "[^.]+$", "") -local data = require(path.."data") -local overrides = require(path.."overrides") -local Statement = require(path.."Statement") -local Reader = require(path.."Reader") +local Base = require(path.."Base") local Expression = require(path.."Expression") local util = require(path.."util") local signs = util.signs -local Preproc = Reader:extend() +local Preproc = Base:extend() function Preproc:init(options) self.options = options or {} end +function Preproc:iter(statements) + assert(statements) + local i = 0 + return function() + i = i + 1 + local s = statements[i] + if s == nil then return end + self.i = i + self.s = s + self.fn = s.fn + self.line = s.line + return s + end +end + function Preproc:lookup(t) if t.tt == 'VARSYM' then local name = t.tok @@ -100,8 +112,6 @@ function Preproc:check(s, i, tt) end function Preproc:process(statements) - self.statements = statements - self.variables = {} self.plus_labels = {} -- constructed forwards self.minus_labels = {} -- constructed backwards @@ -109,39 +119,29 @@ function Preproc:process(statements) -- first pass: resolve variables and collect relative labels local new_statements = {} - for i=1, #self.statements do - local s = self.statements[i] - self.fn = s.fn - self.line = s.line - if s.type:sub(1, 1) == '!' then - -- directive, label, etc. - if s.type == '!VAR' then - local a = self:check(s, 1, 'VAR') - local b = self:check(s, 2, 'NUM') - self.variables[a] = b - elseif s.type == '!LABEL' then - if s[1].tt == 'RELLABEL' then - local label = s[1].tok - local rl = { - index = #new_statements + 1, - name = label:sub(2) - } - local c = label:sub(1, 1) - if c == '+' then - insert(self.plus_labels, rl) - elseif c == '-' then - insert(self.minus_labels, 1, rl) -- remember, it's backwards - else - error('Internal Error: unexpected token for relative label') - end + for s in self:iter(statements) do + -- directive, label, etc. + if s.type == '!VAR' then + local a = self:check(s, 1, 'VAR') + local b = self:check(s, 2, 'NUM') + self.variables[a] = b + elseif s.type == '!LABEL' then + if s[1].tt == 'RELLABEL' then + local label = s[1].tok + local rl = { + index = #new_statements + 1, + name = label:sub(2) + } + local c = label:sub(1, 1) + if c == '+' then + insert(self.plus_labels, rl) + elseif c == '-' then + insert(self.minus_labels, 1, rl) -- remember, it's backwards + else + error('Internal Error: unexpected token for relative label') end - insert(new_statements, s) - else - for j, t in ipairs(s) do - self:lookup(t) - end - insert(new_statements, s) end + insert(new_statements, s) else -- regular instruction for j, t in ipairs(s) do @@ -153,21 +153,14 @@ function Preproc:process(statements) -- second pass: resolve relative labels self.do_labels = true - for i=1, #new_statements do - self.i = i -- make visible to :lookup - local s = new_statements[i] - self.fn = s.fn - self.line = s.line + for s in self:iter(new_statements) do for j, t in ipairs(s) do self:lookup(t) end end -- third pass: evaluate constant expressions - for i=1, #new_statements do - local s = new_statements[i] - self.fn = s.fn - self.line = s.line + for s in self:iter(new_statements) do for j, t in ipairs(s) do if t.tt == 'EXPR' then local expr = Expression() @@ -184,89 +177,4 @@ function Preproc:process(statements) return new_statements end -function Preproc:statement(...) - self.fn = self.s.fn - self.line = self.s.line - local s = Statement(self.fn, self.line, ...) - return s -end - -function Preproc:push(s) - s:validate() - insert(self.statements, s) -end - -function Preproc:push_new(...) - self:push(self:statement(...)) -end - -function Preproc:pop(kind) - local ret - if kind == nil then - ret = self.s[self.i] - elseif kind == 'CPU' then - ret = self:register(data.registers) - elseif kind == 'DEREF' then - ret = self:deref() - elseif kind == 'CONST' then - ret = self:const() - elseif kind == 'END' then - if self.s[self.i] ~= nil then - self:error('expected EOL; too many arguments') - end - return -- don't increment self.i past end of arguments - else - error('Internal Error: unknown kind, got '..tostring(kind)) - end - self.i = self.i + 1 - return ret -end - -function Preproc:expand(statements) - -- fourth pass: expand pseudo-instructions and register arguments - self.statements = {} - for i=1, #statements do - local s = statements[i] - self.s = s - self.fn = s.fn - self.line = s.line - if s.type:sub(1, 1) == '!' then - self:push(s) - else - local name = s.type - local h = data.instructions[name] - if h == nil then - error('Internal Error: unknown instruction') - end - - if data.one_register_variants[name] then - self.i = 1 - local a = self:register(data.all_registers) - local b = s[2] - if b == nil or b.tt ~= 'REG' then - insert(s, 2, self:token(a)) - end - elseif data.two_register_variants[name] then - self.i = 1 - local a = self:register(data.all_registers) - local b = self:register(data.all_registers) - local c = s[3] - if c == nil or c.tt ~= 'REG' then - insert(s, 2, self:token(a)) - end - end - - if overrides[name] then - self.i = 1 - overrides[name](self, name) - self:pop('END') - else - self:push(s) - end - end - end - - return self.statements -end - return Preproc diff --git a/lips/overrides.lua b/lips/overrides.lua index 6077d3e..b4b4f01 100644 --- a/lips/overrides.lua +++ b/lips/overrides.lua @@ -47,7 +47,7 @@ local function li(self, buffer, dest, im) end local overrides = {} --- note: "self" is an instance of Preproc +-- note: "self" is an instance of Expander local function tob_override(self, name) -- handle all the addressing modes for lw/sw-like instructions