mirror of
https://github.com/notwa/mm
synced 2024-11-05 05:59:04 -08:00
reimplement parsing; resolve defines after lexing
This commit is contained in:
parent
d808160d68
commit
86ce3ea0d7
1 changed files with 51 additions and 30 deletions
|
@ -412,7 +412,6 @@ local Dumper = Class()
|
||||||
function Dumper:init(writer, fn)
|
function Dumper:init(writer, fn)
|
||||||
self.writer = writer
|
self.writer = writer
|
||||||
self.fn = fn or '(string)'
|
self.fn = fn or '(string)'
|
||||||
self.defines = {}
|
|
||||||
self.labels = {}
|
self.labels = {}
|
||||||
self.commands = {}
|
self.commands = {}
|
||||||
self.buff = ''
|
self.buff = ''
|
||||||
|
@ -425,6 +424,7 @@ local Parser = Class()
|
||||||
function Parser:init(writer, fn)
|
function Parser:init(writer, fn)
|
||||||
self.fn = fn or '(string)'
|
self.fn = fn or '(string)'
|
||||||
self.dumper = Dumper(writer, fn)
|
self.dumper = Dumper(writer, fn)
|
||||||
|
self.defines = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
function Lexer:error(msg)
|
function Lexer:error(msg)
|
||||||
|
@ -663,6 +663,21 @@ function Parser:error(msg)
|
||||||
error(string.format('%s:%d: Error: %s', self.fn, self.line, msg), 2)
|
error(string.format('%s:%d: Error: %s', self.fn, self.line, msg), 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Parser:advance()
|
||||||
|
self.i = self.i + 1
|
||||||
|
local t = self.tokens[self.i]
|
||||||
|
self.tt = t.tt
|
||||||
|
self.tok = t.tok
|
||||||
|
self.line = t.line
|
||||||
|
return t.tt, t.tok
|
||||||
|
end
|
||||||
|
|
||||||
|
function Parser:lookahead()
|
||||||
|
local t = self.tokens[self.i] + 1
|
||||||
|
if t == nil then return end
|
||||||
|
return t.tt, t.tok
|
||||||
|
end
|
||||||
|
|
||||||
function Parser:is_EOL()
|
function Parser:is_EOL()
|
||||||
return self.tt == 'EOL' or self.tt == 'EOF'
|
return self.tt == 'EOL' or self.tt == 'EOF'
|
||||||
end
|
end
|
||||||
|
@ -698,10 +713,11 @@ function Parser:directive()
|
||||||
self.dumper:add_directive(name, self:number())
|
self.dumper:add_directive(name, self:number())
|
||||||
elseif name == 'ALIGN' or name == 'SKIP' then
|
elseif name == 'ALIGN' or name == 'SKIP' then
|
||||||
local size = self:number()
|
local size = self:number()
|
||||||
if self:optional_comma() then
|
if self:is_EOL() then
|
||||||
self.dumper:add_directive(name, size, self:number())
|
|
||||||
else
|
|
||||||
self.dumper:add_directive(name, size)
|
self.dumper:add_directive(name, size)
|
||||||
|
else
|
||||||
|
self:optional_comma()
|
||||||
|
self.dumper:add_directive(name, size, self:number())
|
||||||
end
|
end
|
||||||
self:expect_EOL()
|
self:expect_EOL()
|
||||||
elseif name == 'BYTE' or name == 'HALFWORD' or name == 'WORD' then
|
elseif name == 'BYTE' or name == 'HALFWORD' or name == 'WORD' then
|
||||||
|
@ -751,7 +767,7 @@ function Parser:deref()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Parser:const(relative)
|
function Parser:const(relative)
|
||||||
if self.tt ~= 'NUM' and self.tt ~= 'DEFSYM' and self.tt ~= 'LABELSYM' then
|
if self.tt ~= 'NUM' and self.tt ~= 'LABELSYM' then
|
||||||
self:error('expected constant')
|
self:error('expected constant')
|
||||||
end
|
end
|
||||||
if relative and self.tt == 'LABELSYM' then
|
if relative and self.tt == 'LABELSYM' then
|
||||||
|
@ -852,11 +868,11 @@ end
|
||||||
function Parser:instruction()
|
function Parser:instruction()
|
||||||
local name = self.tok
|
local name = self.tok
|
||||||
local h = instruction_handlers[name]
|
local h = instruction_handlers[name]
|
||||||
|
self:advance()
|
||||||
|
|
||||||
if h == nil then
|
if h == nil then
|
||||||
self:error('undefined instruction')
|
self:error('undefined instruction')
|
||||||
elseif h == 'LI' or h == 'LA' then
|
elseif h == 'LI' or h == 'LA' then
|
||||||
-- FIXME: probably breaks with defines
|
|
||||||
local lui = instruction_handlers['LUI']
|
local lui = instruction_handlers['LUI']
|
||||||
local addi = instruction_handlers['ADDI']
|
local addi = instruction_handlers['ADDI']
|
||||||
local ori = instruction_handlers['ORI']
|
local ori = instruction_handlers['ORI']
|
||||||
|
@ -866,14 +882,12 @@ function Parser:instruction()
|
||||||
local im = self:const()
|
local im = self:const()
|
||||||
local is_label = im[1] == 'LABELSYM'
|
local is_label = im[1] == 'LABELSYM'
|
||||||
if h == 'LI' and is_label then
|
if h == 'LI' and is_label then
|
||||||
self:error('use LA for addresses')
|
self:error('use LA for labels')
|
||||||
end
|
end
|
||||||
if h == 'LA' and not is_label then
|
if h == 'LA' and not is_label then
|
||||||
self:error('use LI for immediates')
|
self:error('use LI for immediates')
|
||||||
end
|
end
|
||||||
-- FIXME: defines shouldn't need a special case,
|
if h == 'LA' or im[2] >= 0x10000 then
|
||||||
-- we should know their values already.
|
|
||||||
if h == 'LA' or im[1] == 'DEFSYM' or im[2] >= 0x10000 then
|
|
||||||
args.rs = args.rt
|
args.rs = args.rt
|
||||||
args.immediate = {'UPPER', im}
|
args.immediate = {'UPPER', im}
|
||||||
self:format_out(lui[3], lui[1], args, lui[4], lui[5])
|
self:format_out(lui[3], lui[1], args, lui[4], lui[5])
|
||||||
|
@ -897,6 +911,7 @@ function Parser:tokenize()
|
||||||
local lexer = Lexer(self.asm, self.fn)
|
local lexer = Lexer(self.asm, self.fn)
|
||||||
|
|
||||||
self.tokens = {}
|
self.tokens = {}
|
||||||
|
self.i = 0
|
||||||
local line = 1
|
local line = 1
|
||||||
local lex = function()
|
local lex = function()
|
||||||
local t = {line=line}
|
local t = {line=line}
|
||||||
|
@ -918,7 +933,7 @@ function Parser:tokenize()
|
||||||
if tt2 ~= 'NUM' then
|
if tt2 ~= 'NUM' then
|
||||||
self:error('expected number')
|
self:error('expected number')
|
||||||
end
|
end
|
||||||
self.dumper:add_define(tok, tok2)
|
self.defines[tok] = tok2
|
||||||
elseif tt == 'EOL' then
|
elseif tt == 'EOL' then
|
||||||
line = line + 1
|
line = line + 1
|
||||||
elseif tt == 'EOF' then
|
elseif tt == 'EOF' then
|
||||||
|
@ -927,29 +942,42 @@ function Parser:tokenize()
|
||||||
error('Internal Error: missing token', 1)
|
error('Internal Error: missing token', 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- resolve defines
|
||||||
|
for i, t in ipairs(self.tokens) do
|
||||||
|
if t.tt == 'DEFSYM' then
|
||||||
|
t.tt = 'NUM'
|
||||||
|
t.tok = self.defines[t.tok]
|
||||||
|
if t.tok == nil then
|
||||||
|
self:error('undefined define') -- uhhh nice wording
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
function Parser:parse(asm)
|
function Parser:parse(asm)
|
||||||
self.asm = asm
|
self.asm = asm
|
||||||
self:tokenize()
|
self:tokenize()
|
||||||
--require('pt'){self.tokens} -- DEBUG
|
self:advance()
|
||||||
for i, t in pairs(self.tokens) do
|
while true do
|
||||||
self.tt = t.tt
|
if self.tt == 'EOL' then
|
||||||
self.tok = t.tok
|
|
||||||
self.line = t.line
|
|
||||||
if t.tt == 'EOL' then
|
|
||||||
-- empty line
|
-- empty line
|
||||||
elseif t.tt == 'DIR' then
|
self:advance()
|
||||||
|
elseif self.tt == 'DEF' then
|
||||||
|
self:advance()
|
||||||
|
self:advance()
|
||||||
|
elseif self.tt == 'DIR' then
|
||||||
self:directive()
|
self:directive()
|
||||||
elseif t.tt == 'LABEL' then
|
elseif self.tt == 'LABEL' then
|
||||||
self.dumper:add_label(t.tok)
|
self.dumper:add_label(self.tok)
|
||||||
elseif t.tt == 'INSTR' then
|
self:advance()
|
||||||
|
elseif self.tt == 'INSTR' then
|
||||||
self:instruction()
|
self:instruction()
|
||||||
else
|
else
|
||||||
self:error('unexpected token (unknown instruction?)')
|
self:error('unexpected token (unknown instruction?)')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return self.dumper:dump()
|
return self.dumper:dump()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -983,8 +1011,7 @@ function Dumper:add_instruction_r(o, s, t, d, f, c)
|
||||||
self:push_instruction{o, s, t, d, f, c}
|
self:push_instruction{o, s, t, d, f, c}
|
||||||
end
|
end
|
||||||
|
|
||||||
function Dumper:add_define(name, number)
|
function Dumper:define(name, number)
|
||||||
self.defines[name] = number
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Dumper:add_label(name)
|
function Dumper:add_label(name)
|
||||||
|
@ -1065,12 +1092,6 @@ function Dumper:desym(tok)
|
||||||
self:error('branch too far')
|
self:error('branch too far')
|
||||||
end
|
end
|
||||||
return (0x10000 + rel) % 0x10000
|
return (0x10000 + rel) % 0x10000
|
||||||
elseif tok[1] == 'DEFSYM' then
|
|
||||||
local val = self.defines[tok[2]]
|
|
||||||
if val == nil then
|
|
||||||
self:error('unknown define')
|
|
||||||
end
|
|
||||||
return val
|
|
||||||
end
|
end
|
||||||
self:error('failed to desym')
|
self:error('failed to desym')
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue