1
0
Fork 0
mirror of https://github.com/notwa/lips synced 2024-11-10 11:39:04 -08:00

split Preproc expansion into Expander class

This commit is contained in:
Connor Olding 2016-11-27 15:07:48 -08:00
parent 3aa5d01a21
commit 2143128628
4 changed files with 140 additions and 136 deletions

96
lips/Expander.lua Normal file
View file

@ -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

View file

@ -6,6 +6,7 @@ local Token = require(path.."Token")
local Lexer = require(path.."Lexer") local Lexer = require(path.."Lexer")
local Collector = require(path.."Collector") local Collector = require(path.."Collector")
local Preproc = require(path.."Preproc") local Preproc = require(path.."Preproc")
local Expander = require(path.."Expander")
local Dumper = require(path.."Dumper") local Dumper = require(path.."Dumper")
local Parser = Base:extend() local Parser = Base:extend()
@ -50,11 +51,10 @@ function Parser:parse(asm)
self.statements = self:tokenize(asm) self.statements = self:tokenize(asm)
if self.options.debug_token then self:dump() end if self.options.debug_token then self:dump() end
local preproc = Preproc(self.options) self.statements = Preproc(self.options):process(self.statements)
self.statements = preproc:process(self.statements)
if self.options.debug_pre then self:dump() end 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 if self.options.debug_post then self:dump() end
local dumper = Dumper(self.writer, self.options) local dumper = Dumper(self.writer, self.options)

View file

@ -2,20 +2,32 @@ local abs = math.abs
local insert = table.insert local insert = table.insert
local path = string.gsub(..., "[^.]+$", "") local path = string.gsub(..., "[^.]+$", "")
local data = require(path.."data") local Base = require(path.."Base")
local overrides = require(path.."overrides")
local Statement = require(path.."Statement")
local Reader = require(path.."Reader")
local Expression = require(path.."Expression") local Expression = require(path.."Expression")
local util = require(path.."util") local util = require(path.."util")
local signs = util.signs local signs = util.signs
local Preproc = Reader:extend() local Preproc = Base:extend()
function Preproc:init(options) function Preproc:init(options)
self.options = options or {} self.options = options or {}
end 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) function Preproc:lookup(t)
if t.tt == 'VARSYM' then if t.tt == 'VARSYM' then
local name = t.tok local name = t.tok
@ -100,8 +112,6 @@ function Preproc:check(s, i, tt)
end end
function Preproc:process(statements) function Preproc:process(statements)
self.statements = statements
self.variables = {} self.variables = {}
self.plus_labels = {} -- constructed forwards self.plus_labels = {} -- constructed forwards
self.minus_labels = {} -- constructed backwards self.minus_labels = {} -- constructed backwards
@ -109,11 +119,7 @@ function Preproc:process(statements)
-- first pass: resolve variables and collect relative labels -- first pass: resolve variables and collect relative labels
local new_statements = {} local new_statements = {}
for i=1, #self.statements do for s in self:iter(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. -- directive, label, etc.
if s.type == '!VAR' then if s.type == '!VAR' then
local a = self:check(s, 1, 'VAR') local a = self:check(s, 1, 'VAR')
@ -136,12 +142,6 @@ function Preproc:process(statements)
end end
end end
insert(new_statements, s) insert(new_statements, s)
else
for j, t in ipairs(s) do
self:lookup(t)
end
insert(new_statements, s)
end
else else
-- regular instruction -- regular instruction
for j, t in ipairs(s) do for j, t in ipairs(s) do
@ -153,21 +153,14 @@ function Preproc:process(statements)
-- second pass: resolve relative labels -- second pass: resolve relative labels
self.do_labels = true self.do_labels = true
for i=1, #new_statements do for s in self:iter(new_statements) do
self.i = i -- make visible to :lookup
local s = new_statements[i]
self.fn = s.fn
self.line = s.line
for j, t in ipairs(s) do for j, t in ipairs(s) do
self:lookup(t) self:lookup(t)
end end
end end
-- third pass: evaluate constant expressions -- third pass: evaluate constant expressions
for i=1, #new_statements do for s in self:iter(new_statements) do
local s = new_statements[i]
self.fn = s.fn
self.line = s.line
for j, t in ipairs(s) do for j, t in ipairs(s) do
if t.tt == 'EXPR' then if t.tt == 'EXPR' then
local expr = Expression() local expr = Expression()
@ -184,89 +177,4 @@ function Preproc:process(statements)
return new_statements return new_statements
end 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 return Preproc

View file

@ -47,7 +47,7 @@ local function li(self, buffer, dest, im)
end end
local overrides = {} local overrides = {}
-- note: "self" is an instance of Preproc -- note: "self" is an instance of Expander
local function tob_override(self, name) local function tob_override(self, name)
-- handle all the addressing modes for lw/sw-like instructions -- handle all the addressing modes for lw/sw-like instructions