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:
parent
3aa5d01a21
commit
2143128628
4 changed files with 140 additions and 136 deletions
96
lips/Expander.lua
Normal file
96
lips/Expander.lua
Normal 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
|
|
@ -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)
|
||||||
|
|
132
lips/Preproc.lua
132
lips/Preproc.lua
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue