232 lines
5.7 KiB
Lua
232 lines
5.7 KiB
Lua
local spairs
|
|
spairs = function(t)
|
|
local keys
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for k in pairs(t) do
|
|
_accum_0[_len_0] = k
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
keys = _accum_0
|
|
end
|
|
table.sort(keys)
|
|
local i = 0
|
|
return function()
|
|
i = i + 1
|
|
return keys[i], t[keys[i]]
|
|
end
|
|
end
|
|
local trees = {
|
|
['asma-opcodes'] = { }
|
|
}
|
|
local opcodes_in_order = { }
|
|
do
|
|
local wanted = false
|
|
for l in assert(io.lines('src/uxnasm.c')) do
|
|
if l == 'static char ops[][4] = {' then
|
|
wanted = true
|
|
elseif wanted then
|
|
if l == '};' then
|
|
break
|
|
end
|
|
for w in l:gmatch('[^%s",][^%s",][^%s",]') do
|
|
if w ~= '---' then
|
|
trees['asma-opcodes'][w] = {
|
|
('"%s 00'):format(w),
|
|
''
|
|
}
|
|
end
|
|
table.insert(opcodes_in_order, w)
|
|
end
|
|
end
|
|
end
|
|
assert(#opcodes_in_order == 32, 'didn\'t find 32 opcodes in assembler code!')
|
|
end
|
|
do
|
|
local representation = setmetatable({
|
|
['&'] = '26 00 ( & )'
|
|
}, {
|
|
__index = function(self, c)
|
|
return ("'%s 00"):format(c)
|
|
end
|
|
})
|
|
local process
|
|
process = function(label, t)
|
|
trees[label] = { }
|
|
for k, v in pairs(t) do
|
|
trees[label][('%02x'):format(k:byte())] = {
|
|
representation[k],
|
|
(':%s'):format(v)
|
|
}
|
|
end
|
|
end
|
|
process('asma-first-char-normal', {
|
|
['%'] = 'asma-macro-define',
|
|
['|'] = 'asma-pad-absolute',
|
|
['$'] = 'asma-pad-relative',
|
|
['@'] = 'asma-label-define',
|
|
['&'] = 'asma-sublabel-define',
|
|
['#'] = 'asma-literal-hex',
|
|
['.'] = 'asma-literal-zero-addr',
|
|
[','] = 'asma-literal-rel-addr',
|
|
[';'] = 'asma-literal-abs-addr',
|
|
[':'] = 'asma-abs-addr',
|
|
["'"] = 'asma-raw-char',
|
|
['"'] = 'asma-raw-word',
|
|
['{'] = 'asma-ignore',
|
|
['}'] = 'asma-ignore',
|
|
['['] = 'asma-ignore',
|
|
[']'] = 'asma-ignore',
|
|
['('] = 'asma-comment-start',
|
|
[')'] = 'asma-comment-end'
|
|
})
|
|
process('asma-first-char-macro', {
|
|
['('] = 'asma-comment-start',
|
|
[')'] = 'asma-comment-end',
|
|
['{'] = 'asma-ignore',
|
|
['}'] = 'asma-macro-end'
|
|
})
|
|
process('asma-first-char-comment', {
|
|
[')'] = 'asma-comment-end'
|
|
})
|
|
end
|
|
local traverse_node
|
|
traverse_node = function(t, min, max, lefts, rights)
|
|
local i = math.ceil((min + max) / 2)
|
|
if min < i then
|
|
lefts[t[i]] = (':&%s'):format(traverse_node(t, min, i - 1, lefts, rights))
|
|
end
|
|
if i < max then
|
|
rights[t[i]] = (':&%s'):format(traverse_node(t, i + 1, max, lefts, rights))
|
|
end
|
|
return t[i]
|
|
end
|
|
local traverse_tree
|
|
traverse_tree = function(t)
|
|
local lefts, rights = { }, { }
|
|
local keys
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for k in pairs(t) do
|
|
_accum_0[_len_0] = k
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
keys = _accum_0
|
|
end
|
|
table.sort(keys)
|
|
return lefts, rights, traverse_node(keys, 1, #keys, lefts, rights)
|
|
end
|
|
local ptr
|
|
ptr = function(s)
|
|
if s then
|
|
return (':&%s'):format(s)
|
|
end
|
|
return ' $2'
|
|
end
|
|
local ordered_opcodes
|
|
ordered_opcodes = function(t)
|
|
local i = 0
|
|
return function()
|
|
i = i + 1
|
|
local v = opcodes_in_order[i]
|
|
if t[v] then
|
|
return v, t[v]
|
|
elseif v then
|
|
return false, {
|
|
'"--- 00',
|
|
''
|
|
}
|
|
end
|
|
end
|
|
end
|
|
local printout = true
|
|
local fmt
|
|
fmt = function(...)
|
|
return (('\t%-11s %-10s %-12s %-14s %s '):format(...):gsub(' +$', '\n'))
|
|
end
|
|
do
|
|
local _with_0 = assert(io.open('projects/software/asma.tal.tmp', 'w'))
|
|
for l in assert(io.lines('projects/software/asma.tal')) do
|
|
if l:match('--- cut here ---') then
|
|
break
|
|
end
|
|
_with_0:write(l)
|
|
_with_0:write('\n')
|
|
end
|
|
_with_0:write('( --- 8< ------- 8< --- cut here --- 8< ------- 8< --- )\n')
|
|
_with_0:write('( automatically generated code below )\n')
|
|
_with_0:write('( see etc/asma.moon for instructions )\n')
|
|
_with_0:write('\n(')
|
|
_with_0:write(fmt('label', 'less', 'greater', 'key', 'binary'))
|
|
_with_0:write(fmt('', 'than', 'than', 'string', 'data )'))
|
|
_with_0:write('\n')
|
|
for name, tree in spairs(trees) do
|
|
_with_0:write(('@%s\n'):format(name))
|
|
local lefts, rights, entry = traverse_tree(tree)
|
|
local sort_fn
|
|
if name == 'asma-opcodes' then
|
|
if rights[opcodes_in_order[1]] then
|
|
rights[opcodes_in_order[1]] = rights[opcodes_in_order[1]] .. ' &_disasm'
|
|
else
|
|
rights[opcodes_in_order[1]] = ' $2 &_disasm'
|
|
end
|
|
sort_fn = ordered_opcodes
|
|
else
|
|
sort_fn = spairs
|
|
end
|
|
for k, v in sort_fn(tree) do
|
|
local label
|
|
if k == entry then
|
|
label = '&_entry'
|
|
elseif k then
|
|
label = ('&%s'):format(k)
|
|
else
|
|
label = ''
|
|
end
|
|
_with_0:write(fmt(label, lefts[k] or ' $2', rights[k] or ' $2', unpack(v)))
|
|
end
|
|
_with_0:write('\n')
|
|
end
|
|
_with_0:write([[(
|
|
Heap, a large temporary area for keeping track of labels. More complex
|
|
programs need more of this space. If there's insufficient space then the
|
|
assembly process will fail, but having extra space above what the most
|
|
complex program needs provides no benefit.
|
|
|
|
This heap, and the buffers below, are free to be used to hold temporary
|
|
data between assembly runs, and do not need to be initialized with any
|
|
particular contents to use the assembler.
|
|
)
|
|
|
|
@asma-heap
|
|
|
|
|e000 &end
|
|
|
|
(
|
|
Buffer for use with loading source code.
|
|
The minimum size is the length of the longest token plus one, which is
|
|
0x21 to keep the same capability of the C assembler.
|
|
Larger sizes are more efficient, provided there is enough
|
|
heap space to keep track of all the labels.
|
|
)
|
|
|
|
@asma-read-buffer
|
|
|
|
|f800 &end
|
|
|
|
(
|
|
Buffer for use with writing output.
|
|
The minimum size is 1, and larger sizes are more efficient.
|
|
)
|
|
|
|
@asma-write-buffer
|
|
|
|
|ffff &end
|
|
|
|
]])
|
|
_with_0:close()
|
|
end
|
|
return os.execute('mv projects/software/asma.tal.tmp projects/software/asma.tal')
|