From 87c210d61706a689b47676758cab6e3c47f6b934 Mon Sep 17 00:00:00 2001 From: Connor Olding Date: Sat, 23 Apr 2016 02:06:43 -0700 Subject: [PATCH] add .push/.pop directives for basic states --- README.md | 4 ++++ lips/Collector.lua | 6 ++++++ lips/Dumper.lua | 47 ++++++++++++++++++++++++++++++++++++++++++++++ lips/data.lua | 1 + 4 files changed, 58 insertions(+) diff --git a/README.md b/README.md index bf6a8b1..5e4cb48 100644 --- a/README.md +++ b/README.md @@ -224,6 +224,10 @@ defaults to 0x80000000. this allows you to have a PC value different from origin: `PC = origin + base` +* `.push {vars...}` `.pop {vars...}' +pushes or pops variables with an internal stack. +supported variables: org, base, pc. + * `HEX { ... }` write a series of bytes given in hexadecimal. all numbers must be given in hex — no prefix is required. diff --git a/lips/Collector.lua b/lips/Collector.lua index 3bd338d..1e5208e 100644 --- a/lips/Collector.lua +++ b/lips/Collector.lua @@ -85,6 +85,12 @@ function Collector:directive() end if name == 'ORG' or name == 'BASE' then add(name, self:const(nil, 'no labels')) + elseif name == 'PUSH' or name == 'POP' then + add(name, self:const()) + while not self:is_EOL() do + self:optional_comma() + add(name, self:const()) + end elseif name == 'ALIGN' or name == 'SKIP' then if self:is_EOL() and name == 'ALIGN' then add(name) diff --git a/lips/Dumper.lua b/lips/Dumper.lua index 6a2d320..a568fa0 100644 --- a/lips/Dumper.lua +++ b/lips/Dumper.lua @@ -1,6 +1,7 @@ local floor = math.floor local format = string.format local insert = table.insert +local remove = table.remove local unpack = unpack or table.unpack local path = string.gsub(..., "[^.]+$", "") @@ -276,6 +277,7 @@ function Dumper:pc() end function Dumper:load(statements) + local valstack = {} -- for .push/.pop directives local new_statements = {} self.pos = 0 self.base = 0 @@ -296,6 +298,51 @@ function Dumper:load(statements) elseif s.type == '!BASE' then self.base = s[1].tok insert(new_statements, s) + elseif s.type == '!PUSH' or s.type == '!POP' then + local thistype = s.type:sub(2):lower() + for i, t in ipairs(s) do + local name = t.tok + if type(name) ~= 'string' then + self:error('expected state to '..thistype, name) + end + + name = name:lower() + local pushing = s.type == '!PUSH' + if name == 'org' then + if pushing then + insert(valstack, self.pos) + else + self.pos = remove(valstack) + end + elseif name == 'base' then + if pushing then + insert(valstack, self.base) + else + self.base = remove(valstack) + end + elseif name == 'pc' then + if pushing then + insert(valstack, self.pos) + insert(valstack, self.base) + else + self.base = remove(valstack) + self.pos = remove(valstack) + end + else + self:error('unknown state to '..thistype, name) + end + + if self.pos == nil or self.base == nil then + self:error('ran out of values to pop') + end + + if not pushing then + local s = Statement(self.fn, self.line, '!ORG', self.pos) + insert(new_statements, s) + local s = Statement(self.fn, self.line, '!BASE', self.base) + insert(new_statements, s) + end + end elseif s.type == '!ALIGN' or s.type == '!SKIP' then local length, content if s.type == '!ALIGN' then diff --git a/lips/data.lua b/lips/data.lua index b693848..2ce6444 100644 --- a/lips/data.lua +++ b/lips/data.lua @@ -30,6 +30,7 @@ data.fpu_registers = { data.all_directives = { 'ORG', 'BASE', 'ALIGN', 'SKIP', + 'PUSH', 'POP', -- experimental 'ASCII', 'ASCIIZ', 'BYTE', 'HALFWORD', 'WORD', --'HEX', -- excluded here due to different syntax