mirror of
https://github.com/notwa/mm
synced 2025-02-05 05:23:22 -08:00
update lips
This commit is contained in:
parent
8969788911
commit
3f318bd0db
5 changed files with 97 additions and 76 deletions
|
@ -48,7 +48,7 @@ function Expander:pop(kind)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Expander:expand(statements)
|
function Expander:expand(statements)
|
||||||
-- fourth pass: expand pseudo-instructions and register arguments
|
-- third pass: expand pseudo-instructions and register arguments
|
||||||
self.statements = {}
|
self.statements = {}
|
||||||
for i, s in ipairs(statements) do
|
for i, s in ipairs(statements) do
|
||||||
self.s = s
|
self.s = s
|
||||||
|
|
|
@ -4,6 +4,9 @@ local path = string.gsub(..., "[^.]+$", "")
|
||||||
local Base = require(path.."Base")
|
local Base = require(path.."Base")
|
||||||
|
|
||||||
local Expression = Base:extend()
|
local Expression = Base:extend()
|
||||||
|
function Expression:init(variables)
|
||||||
|
self.variables = variables or {}
|
||||||
|
end
|
||||||
|
|
||||||
Expression.precedence = {
|
Expression.precedence = {
|
||||||
-- python-ish precedence
|
-- python-ish precedence
|
||||||
|
@ -80,6 +83,7 @@ Expression.binary_ops = {
|
||||||
local operators = {}
|
local operators = {}
|
||||||
local operators_maxlen = 0
|
local operators_maxlen = 0
|
||||||
do
|
do
|
||||||
|
-- reorder operators so we can match the longest strings first
|
||||||
for k, v in pairs(Expression.precedence) do
|
for k, v in pairs(Expression.precedence) do
|
||||||
if operators[#k] == nil then
|
if operators[#k] == nil then
|
||||||
operators[#k] = {}
|
operators[#k] = {}
|
||||||
|
@ -150,9 +154,12 @@ function Expression:lex1(str, tokens)
|
||||||
num = tonumber(considered, 2)
|
num = tonumber(considered, 2)
|
||||||
elseif consider('0x[0-9A-Fa-f]+') then
|
elseif consider('0x[0-9A-Fa-f]+') then
|
||||||
num = tonumber(considered, 16)
|
num = tonumber(considered, 16)
|
||||||
elseif consider('0[0-7]+') then
|
elseif consider('0[0-9]+') then
|
||||||
|
if considered:match('[89]') then
|
||||||
|
return "bad octal number: "..considered..here
|
||||||
|
end
|
||||||
num = tonumber(considered, 8)
|
num = tonumber(considered, 8)
|
||||||
elseif consider('[1-9][0-9]*') then
|
elseif consider('[0-9]*') then
|
||||||
num = tonumber(considered)
|
num = tonumber(considered)
|
||||||
end
|
end
|
||||||
if num == nil then
|
if num == nil then
|
||||||
|
@ -169,6 +176,13 @@ function Expression:lex1(str, tokens)
|
||||||
elseif consider_operator() then
|
elseif consider_operator() then
|
||||||
insert(tokens, {type='operator', value=considered})
|
insert(tokens, {type='operator', value=considered})
|
||||||
consume(#considered)
|
consume(#considered)
|
||||||
|
elseif consider('%w+') then
|
||||||
|
local num = self.variables[considered]
|
||||||
|
if num == nil then
|
||||||
|
return 'undefined variable "'..considered..'"'
|
||||||
|
end
|
||||||
|
insert(tokens, {type='number', value=num})
|
||||||
|
consume(#considered)
|
||||||
else
|
else
|
||||||
local chr = rest:sub(1, 1)
|
local chr = rest:sub(1, 1)
|
||||||
return "unexpected character '"..chr.."'"..here
|
return "unexpected character '"..chr.."'"..here
|
||||||
|
|
|
@ -329,6 +329,7 @@ function Lexer:lex_include_binary(_yield)
|
||||||
local data = util.readfile(fn, true)
|
local data = util.readfile(fn, true)
|
||||||
_yield('DIR', 'BIN', fn, 0)
|
_yield('DIR', 'BIN', fn, 0)
|
||||||
_yield('STRING', data, fn, 0)
|
_yield('STRING', data, fn, 0)
|
||||||
|
_yield('EOF', self.EOF, self.fn, self.line)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Lexer:lex_expression(yield)
|
function Lexer:lex_expression(yield)
|
||||||
|
@ -392,6 +393,9 @@ function Lexer:lex(_yield)
|
||||||
yield('SEP', ',')
|
yield('SEP', ',')
|
||||||
elseif self.chr == '[' then
|
elseif self.chr == '[' then
|
||||||
self:nextc()
|
self:nextc()
|
||||||
|
if self.chr:find('%d') then
|
||||||
|
self:error('variable names cannot begin with a number')
|
||||||
|
end
|
||||||
local buff = self:read_chars('[%w_]')
|
local buff = self:read_chars('[%w_]')
|
||||||
if self.chr ~= ']' then
|
if self.chr ~= ']' then
|
||||||
self:error('invalid variable name')
|
self:error('invalid variable name')
|
||||||
|
@ -402,6 +406,13 @@ function Lexer:lex(_yield)
|
||||||
end
|
end
|
||||||
self:nextc()
|
self:nextc()
|
||||||
yield('VAR', buff)
|
yield('VAR', buff)
|
||||||
|
self:read_spaces()
|
||||||
|
if self.chr == '@' then
|
||||||
|
-- old syntax; nothing to do here
|
||||||
|
else
|
||||||
|
buff = self:read_chars('[^;\n]')
|
||||||
|
yield('EXPR', buff)
|
||||||
|
end
|
||||||
elseif self.chr == ']' then
|
elseif self.chr == ']' then
|
||||||
self:error('unmatched closing bracket')
|
self:error('unmatched closing bracket')
|
||||||
elseif self.chr == '(' then
|
elseif self.chr == '(' then
|
||||||
|
@ -433,6 +444,9 @@ function Lexer:lex(_yield)
|
||||||
self:lex_string(yield)
|
self:lex_string(yield)
|
||||||
elseif self.chr == '@' then
|
elseif self.chr == '@' then
|
||||||
self:nextc()
|
self:nextc()
|
||||||
|
if self.chr:find('%d') then
|
||||||
|
self:error('variable names cannot begin with a number')
|
||||||
|
end
|
||||||
local buff = self:read_chars('[%w_]')
|
local buff = self:read_chars('[%w_]')
|
||||||
yield('VARSYM', buff)
|
yield('VARSYM', buff)
|
||||||
elseif self.chr == '%' then
|
elseif self.chr == '%' then
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
local abs = math.abs
|
local abs = math.abs
|
||||||
|
local format = string.format
|
||||||
local insert = table.insert
|
local insert = table.insert
|
||||||
|
|
||||||
local path = string.gsub(..., "[^.]+$", "")
|
local path = string.gsub(..., "[^.]+$", "")
|
||||||
|
@ -13,6 +14,13 @@ function Preproc:init(options)
|
||||||
self.options = options or {}
|
self.options = options or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Preproc:error(msg, got)
|
||||||
|
if got ~= nil then
|
||||||
|
msg = msg..', got '..tostring(got)
|
||||||
|
end
|
||||||
|
error(format('%s:%d: Error: %s', self.fn, self.line, msg), 2)
|
||||||
|
end
|
||||||
|
|
||||||
function Preproc:iter(statements)
|
function Preproc:iter(statements)
|
||||||
assert(statements)
|
assert(statements)
|
||||||
local i = 0
|
local i = 0
|
||||||
|
@ -36,7 +44,10 @@ function Preproc:lookup(t)
|
||||||
if t.tok == nil then
|
if t.tok == nil then
|
||||||
self:error('undefined variable', name)
|
self:error('undefined variable', name)
|
||||||
end
|
end
|
||||||
elseif self.do_labels and t.tt == 'RELLABELSYM' or t.tt == 'RELLABEL' then
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Preproc:resolve(t)
|
||||||
if t.tt == 'RELLABEL' then
|
if t.tt == 'RELLABEL' then
|
||||||
t.tt = 'LABEL'
|
t.tt = 'LABEL'
|
||||||
-- exploits the fact that user labels can't begin with a number
|
-- exploits the fact that user labels can't begin with a number
|
||||||
|
@ -82,28 +93,15 @@ function Preproc:lookup(t)
|
||||||
self:error('could not find appropriate relative label', t.tok)
|
self:error('could not find appropriate relative label', t.tok)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Preproc:check(s, i, tt)
|
function Preproc:check(s, i, tt)
|
||||||
s = s or self.s
|
|
||||||
i = i or self.i
|
|
||||||
local t = s[i]
|
local t = s[i]
|
||||||
if t == nil then
|
if t == nil then
|
||||||
local err = ("expected another argument for %s at position %i"):format(self.s.type, self.i)
|
local err = ("expected another argument for %s at position %i"):format(self.s.type, self.i)
|
||||||
self:error(err)
|
self:error(err)
|
||||||
end
|
end
|
||||||
|
|
||||||
self.fn = t.fn
|
|
||||||
self.line = t.line
|
|
||||||
|
|
||||||
if t.tt ~= tt then
|
|
||||||
self:lookup(t)
|
|
||||||
end
|
|
||||||
|
|
||||||
if t.tt ~= tt then
|
if t.tt ~= tt then
|
||||||
local err = ("argument %i of %s expected type %s"):format(i, s.type, tt)
|
local err = ("argument %i of %s expected type %s"):format(i, s.type, tt)
|
||||||
self:error(err, t.tt)
|
self:error(err, t.tt)
|
||||||
|
@ -111,16 +109,30 @@ function Preproc:check(s, i, tt)
|
||||||
return t.tok
|
return t.tok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Preproc:evaluate(t)
|
||||||
|
if t.tt == 'EXPR' then
|
||||||
|
local result, err = self.expr:eval(t.tok)
|
||||||
|
if err then
|
||||||
|
self:error('failed to evaulate ('..t.tok..')', err)
|
||||||
|
end
|
||||||
|
t.tt = 'NUM'
|
||||||
|
t.tok = result
|
||||||
|
end
|
||||||
|
self:lookup(t)
|
||||||
|
end
|
||||||
|
|
||||||
function Preproc:process(statements)
|
function Preproc:process(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
|
||||||
self.do_labels = false
|
self.expr = Expression(self.variables)
|
||||||
|
|
||||||
-- first pass: resolve variables and collect relative labels
|
-- first pass: resolve variables and collect relative labels
|
||||||
local new_statements = {}
|
local new_statements = {}
|
||||||
for s in self:iter(statements) do
|
for s in self:iter(statements) do
|
||||||
-- directive, label, etc.
|
for j, t in ipairs(s) do
|
||||||
|
self:evaluate(t)
|
||||||
|
end
|
||||||
if s.type == '!VAR' then
|
if s.type == '!VAR' then
|
||||||
local a = self:check(s, 1, 'VAR')
|
local a = self:check(s, 1, 'VAR')
|
||||||
local b = self:check(s, 2, 'NUM')
|
local b = self:check(s, 2, 'NUM')
|
||||||
|
@ -143,34 +155,14 @@ function Preproc:process(statements)
|
||||||
end
|
end
|
||||||
insert(new_statements, s)
|
insert(new_statements, s)
|
||||||
else
|
else
|
||||||
-- regular instruction
|
|
||||||
for j, t in ipairs(s) do
|
|
||||||
self:lookup(t)
|
|
||||||
end
|
|
||||||
insert(new_statements, s)
|
insert(new_statements, s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- second pass: resolve relative labels
|
-- second pass: resolve relative labels
|
||||||
self.do_labels = true
|
|
||||||
for s in self:iter(new_statements) do
|
for s in self:iter(new_statements) do
|
||||||
for j, t in ipairs(s) do
|
for j, t in ipairs(s) do
|
||||||
self:lookup(t)
|
self:resolve(t)
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- third pass: evaluate constant expressions
|
|
||||||
for s in self:iter(new_statements) do
|
|
||||||
for j, t in ipairs(s) do
|
|
||||||
if t.tt == 'EXPR' then
|
|
||||||
local expr = Expression()
|
|
||||||
local result, err = expr:eval(t.tok)
|
|
||||||
if err then
|
|
||||||
self:error('failed to evaulate ('..t.tok..')', err)
|
|
||||||
end
|
|
||||||
t.tt = 'NUM'
|
|
||||||
t.tok = result
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ end
|
||||||
|
|
||||||
TokenIter.arg_types = {
|
TokenIter.arg_types = {
|
||||||
NUM = true,
|
NUM = true,
|
||||||
|
EXPR = true,
|
||||||
REG = true,
|
REG = true,
|
||||||
VARSYM = true,
|
VARSYM = true,
|
||||||
LABELSYM = true,
|
LABELSYM = true,
|
||||||
|
|
Loading…
Add table
Reference in a new issue