1
0
Fork 0
mirror of https://github.com/notwa/lips synced 2024-05-16 23:53:22 -07:00
lips/lips/Parser.lua

133 lines
4.0 KiB
Lua
Raw Normal View History

local insert = table.insert
2016-04-14 07:33:33 -07:00
local path = string.gsub(..., "[^.]+$", "")
local data = require(path.."data")
local Base = require(path.."Base")
2016-04-14 07:33:33 -07:00
local Token = require(path.."Token")
local Lexer = require(path.."Lexer")
local Collector = require(path.."Collector")
2016-04-14 07:33:33 -07:00
local Preproc = require(path.."Preproc")
local Dumper = require(path.."Dumper")
local Parser = Base:extend()
function Parser:init(writer, fn, options)
2016-04-20 20:51:26 -07:00
self.writer = writer
self.fn = fn or '(string)'
self.main_fn = self.fn
self.options = options or {}
end
--[[
function Parser:instruction()
local name = self.tok
local h = data.instructions[name]
2016-04-20 02:11:23 -07:00
assert(h, 'Internal Error: undefined instruction')
self:advance()
2016-04-20 02:11:23 -07:00
if overrides[name] then
overrides[name](self, name)
elseif h[2] == 'tob' then -- TODO: or h[2] == 'Tob' then
2016-04-10 02:59:39 -07:00
-- handle all the addressing modes for lw/sw-like instructions
local lui = data.instructions['LUI']
local addu = data.instructions['ADDU']
local args = {}
args.rt = self:register()
self:optional_comma()
if self.tt == 'OPEN' then
2016-01-15 11:15:02 -08:00
args.offset = 0
args.base = self:deref()
else -- NUM or LABELSYM
local lui_args = {}
local addu_args = {}
local o = self:const()
2016-04-10 02:59:39 -07:00
if self.tt == 'NUM' then
o:set('offset', self:const().tok)
end
args.offset = self:token(o)
if not o.portion then
args.offset:set('portion', 'lower')
end
2016-04-20 02:11:23 -07:00
-- attempt to use the fewest possible instructions for this offset
if not o.portion and (o.tt == 'LABELSYM' or o.tok >= 0x80000000) then
lui_args.immediate = Token(o):set('portion', 'upperoff')
lui_args.rt = 'AT'
self:format_out(lui, lui_args)
if not self:is_EOL() then
addu_args.rd = 'AT'
addu_args.rs = 'AT'
addu_args.rt = self:deref()
self:format_out(addu, addu_args)
end
args.base = 'AT'
else
args.base = self:deref()
end
end
self:format_out(h, args)
elseif h[2] ~= nil then
local args = self:format_in(h[2])
self:format_out(h, args)
else
self:error('unimplemented instruction')
end
self:expect_EOL()
end
--]]
function Parser:tokenize(asm)
local lexer = Lexer(asm, self.main_fn, self.options)
local tokens = {}
local loop = true
while loop do
lexer:lex(function(tt, tok, fn, line)
assert(tt, 'Internal Error: missing token')
local t = Token(fn, line, tt, tok)
insert(tokens, t)
-- don't break if this is an included file's EOF
if tt == 'EOF' and fn == self.main_fn then
loop = false
end
end)
end
-- the lexer guarantees an EOL and EOF for a blank file
assert(#tokens > 0, 'Internal Error: no tokens after preprocessing')
local collector = Collector(self.options)
2016-04-20 20:51:26 -07:00
self.statements = collector:collect(tokens, self.main_fn)
end
function Parser:parse(asm)
self:tokenize(asm)
2016-04-20 20:51:26 -07:00
local preproc = Preproc(self.options)
self.statements = preproc:process(self.statements)
--[[ process:
- inline labels? how do you know how far they are?
2016-04-20 20:51:26 -07:00
i guess you can just offset on statements instead
- assemble? dumper gets passed .org .base
--]]
2016-04-20 20:51:26 -07:00
local dumper = Dumper(self.writer, self.options)
self.statements = dumper:load(self.statements)
-- DEBUG
for i, s in ipairs(self.statements) do
local values = ''
for j, v in ipairs(s) do
2016-04-20 20:51:26 -07:00
values = values..'\t'..v.tt..'('..tostring(v.tok)..')'
end
values = values:sub(2)
print(i, s.type, values)
end
2016-04-20 20:51:26 -07:00
--if self.options.labels then
-- dumper:export_labels(self.options.labels)
--end
return dumper:dump()
end
return Parser