Rewritten asma
This commit is contained in:
parent
ce00dc2189
commit
16f51cb876
|
@ -0,0 +1,235 @@
|
|||
local band, bor, lshift, rshift
|
||||
do
|
||||
local _obj_0 = require('bit')
|
||||
band, bor, lshift, rshift = _obj_0.band, _obj_0.bor, _obj_0.lshift, _obj_0.rshift
|
||||
end
|
||||
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-labels'] = { },
|
||||
['asma-opcodes'] = { }
|
||||
}
|
||||
local opcodes_in_order = { }
|
||||
do
|
||||
local wanted = false
|
||||
for l in assert(io.lines('src/assembler.c')) do
|
||||
if l == '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 add_device
|
||||
add_device = function(addr, name, fields)
|
||||
addr = tonumber(addr, 16)
|
||||
local k
|
||||
if name:match('^Audio%x+$') then
|
||||
k = 'asma-ldev-Audio'
|
||||
else
|
||||
k = ('asma-ldev-%s'):format(name)
|
||||
end
|
||||
trees['asma-labels'][name] = {
|
||||
('"%s 00'):format(name),
|
||||
('00%02x :%s/_entry'):format(addr, k)
|
||||
}
|
||||
trees[k] = { }
|
||||
addr = 0
|
||||
for fname, flen in fields:gmatch('%&(%S+) +%$(%x+)') do
|
||||
if fname ~= 'pad' then
|
||||
trees[k][fname] = {
|
||||
('"%s 00'):format(fname),
|
||||
('00%02x'):format(addr)
|
||||
}
|
||||
end
|
||||
addr = addr + tonumber(flen, 16)
|
||||
end
|
||||
end
|
||||
for l in assert(io.lines('projects/examples/blank.usm')) do
|
||||
local f = {
|
||||
l:match('^%|(%x%x) +%@(%S+) +%[ (.*) %]')
|
||||
}
|
||||
if f[1] then
|
||||
add_device(unpack(f))
|
||||
end
|
||||
end
|
||||
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.usm.tmp', 'w'))
|
||||
for l in assert(io.lines('projects/software/asma.usm')) 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 than', 'greater than', 'key', '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('@asma-heap\n\n')
|
||||
_with_0:close()
|
||||
end
|
||||
return os.execute('mv projects/software/asma.usm.tmp projects/software/asma.usm')
|
|
@ -0,0 +1,169 @@
|
|||
import band, bor, lshift, rshift from require 'bit'
|
||||
|
||||
spairs = (t) ->
|
||||
keys = [ k for k in pairs t ]
|
||||
table.sort keys
|
||||
i = 0
|
||||
->
|
||||
i = i + 1
|
||||
keys[i], t[keys[i]]
|
||||
|
||||
trees = {
|
||||
['asma-labels']: {}
|
||||
['asma-opcodes']: {}
|
||||
}
|
||||
|
||||
opcodes_in_order = {}
|
||||
|
||||
do -- opcodes
|
||||
wanted = false
|
||||
for l in assert io.lines 'src/assembler.c'
|
||||
if l == 'char ops[][4] = {'
|
||||
wanted = true
|
||||
elseif wanted
|
||||
if l == '};'
|
||||
break
|
||||
for w in l\gmatch '[^%s",][^%s",][^%s",]'
|
||||
if w != '---'
|
||||
trees['asma-opcodes'][w] = {
|
||||
'"%s 00'\format w
|
||||
''
|
||||
}
|
||||
table.insert opcodes_in_order, w
|
||||
assert #opcodes_in_order == 32, 'didn\'t find 32 opcodes in assembler code!'
|
||||
|
||||
do -- devices -> labels
|
||||
add_device = (addr, name, fields) ->
|
||||
addr = tonumber addr, 16
|
||||
k = if name\match '^Audio%x+$'
|
||||
'asma-ldev-Audio'
|
||||
else
|
||||
'asma-ldev-%s'\format name
|
||||
trees['asma-labels'][name] = {
|
||||
'"%s 00'\format name
|
||||
'00%02x :%s/_entry'\format addr, k
|
||||
}
|
||||
trees[k] = {}
|
||||
addr = 0
|
||||
for fname, flen in fields\gmatch '%&(%S+) +%$(%x+)'
|
||||
if fname != 'pad'
|
||||
trees[k][fname] = {
|
||||
'"%s 00'\format fname,
|
||||
'00%02x'\format addr
|
||||
}
|
||||
addr += tonumber flen, 16
|
||||
for l in assert io.lines 'projects/examples/blank.usm'
|
||||
f = { l\match '^%|(%x%x) +%@(%S+) +%[ (.*) %]' }
|
||||
if f[1]
|
||||
add_device unpack f
|
||||
|
||||
|
||||
do -- first characters
|
||||
representation = setmetatable {
|
||||
'&': '26 00 ( & )'
|
||||
},
|
||||
__index: (c) => "'%s 00"\format c
|
||||
process = (label, t) ->
|
||||
trees[label] = {}
|
||||
for k, v in pairs t
|
||||
trees[label]['%02x'\format k\byte!] = {
|
||||
representation[k]
|
||||
':%s'\format v
|
||||
}
|
||||
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'
|
||||
|
||||
traverse_node = (t, min, max, lefts, rights) ->
|
||||
i = math.ceil (min + max) / 2
|
||||
if min < i
|
||||
lefts[t[i]] = ':&%s'\format traverse_node t, min, i - 1, lefts, rights
|
||||
if i < max
|
||||
rights[t[i]] = ':&%s'\format traverse_node t, i + 1, max, lefts, rights
|
||||
return t[i]
|
||||
|
||||
traverse_tree = (t) ->
|
||||
lefts, rights = {}, {}
|
||||
keys = [ k for k in pairs t ]
|
||||
table.sort keys
|
||||
lefts, rights, traverse_node keys, 1, #keys, lefts, rights
|
||||
|
||||
ptr = (s) ->
|
||||
if s
|
||||
return ':&%s'\format s
|
||||
return ' $2'
|
||||
|
||||
ordered_opcodes = (t) ->
|
||||
i = 0
|
||||
->
|
||||
i = i + 1
|
||||
v = opcodes_in_order[i]
|
||||
if t[v]
|
||||
return v, t[v]
|
||||
elseif v
|
||||
return false, { '"--- 00', '' }
|
||||
|
||||
printout = true
|
||||
|
||||
fmt = (...) ->
|
||||
('\t%-11s %-10s %-12s %-14s %s '\format(...)\gsub ' +$', '\n')
|
||||
|
||||
with assert io.open 'projects/software/asma.usm.tmp', 'w'
|
||||
for l in assert io.lines 'projects/software/asma.usm'
|
||||
if l\match '--- cut here ---'
|
||||
break
|
||||
\write l
|
||||
\write '\n'
|
||||
\write '( --- 8< ------- 8< --- cut here --- 8< ------- 8< --- )\n'
|
||||
\write '( automatically generated code below )\n'
|
||||
\write '( see etc/asma.moon for instructions )\n'
|
||||
\write '\n('
|
||||
\write fmt 'label', 'less than', 'greater than', 'key', 'data )'
|
||||
\write '\n'
|
||||
for name, tree in spairs trees
|
||||
\write '@%s\n'\format name
|
||||
lefts, rights, entry = traverse_tree tree
|
||||
sort_fn = if name == 'asma-opcodes'
|
||||
if rights[opcodes_in_order[1]]
|
||||
rights[opcodes_in_order[1]] ..= ' &_disasm'
|
||||
else
|
||||
rights[opcodes_in_order[1]] = ' $2 &_disasm'
|
||||
ordered_opcodes
|
||||
else
|
||||
spairs
|
||||
for k, v in sort_fn tree
|
||||
label = if k == entry
|
||||
'&_entry'
|
||||
elseif k
|
||||
'&%s'\format k
|
||||
else
|
||||
''
|
||||
\write fmt label, lefts[k] or ' $2', rights[k] or ' $2', unpack v
|
||||
\write '\n'
|
||||
\write '@asma-heap\n\n'
|
||||
\close!
|
||||
os.execute 'mv projects/software/asma.usm.tmp projects/software/asma.usm'
|
||||
|
|
@ -1,350 +0,0 @@
|
|||
local build_dag
|
||||
build_dag = function(t, dag, i, j, level)
|
||||
if dag == nil then
|
||||
dag = { }
|
||||
end
|
||||
if i == nil then
|
||||
i = 1
|
||||
end
|
||||
if j == nil then
|
||||
j = #t
|
||||
end
|
||||
if level == nil then
|
||||
level = 0
|
||||
end
|
||||
if i > j then
|
||||
return
|
||||
end
|
||||
local mid = math.floor((i + j) / 2)
|
||||
dag[t[mid]] = {
|
||||
(build_dag(t, dag, i, mid - 1, level + 1)),
|
||||
(build_dag(t, dag, mid + 1, j, level + 1))
|
||||
}
|
||||
return t[mid], dag
|
||||
end
|
||||
local append_dag
|
||||
append_dag = function(node, dag, k)
|
||||
local i = k > node and 2 or 1
|
||||
local next_node = dag[node][i]
|
||||
if next_node then
|
||||
return append_dag(next_node, dag, k)
|
||||
end
|
||||
dag[node][i] = k
|
||||
dag[k] = { }
|
||||
end
|
||||
local build_dag_from_chars
|
||||
build_dag_from_chars = function(s, ...)
|
||||
local t
|
||||
do
|
||||
local _accum_0 = { }
|
||||
local _len_0 = 1
|
||||
for i = 1, #s do
|
||||
_accum_0[_len_0] = s:sub(i, i)
|
||||
_len_0 = _len_0 + 1
|
||||
end
|
||||
t = _accum_0
|
||||
end
|
||||
table.sort(t)
|
||||
local root, dag = build_dag(t)
|
||||
for i = 1, select('#', ...) do
|
||||
append_dag(root, dag, (select(i, ...)))
|
||||
end
|
||||
return root, dag
|
||||
end
|
||||
local check_terminals
|
||||
check_terminals = function(dag, s)
|
||||
for i = 1, #s do
|
||||
local k = s:sub(i, i)
|
||||
assert(not dag[k][1], ('%s has left child node'):format(k))
|
||||
assert(not dag[k][2], ('%s has right child node'):format(k))
|
||||
end
|
||||
end
|
||||
local dump
|
||||
dump = function(f, root, dag, level)
|
||||
if level == nil then
|
||||
level = 0
|
||||
end
|
||||
if dag[root][1] then
|
||||
dump(f, dag[root][1], dag, level + 1)
|
||||
end
|
||||
f:write((' '):rep(level))
|
||||
f:write(root)
|
||||
f:write('\n')
|
||||
if dag[root][2] then
|
||||
return dump(f, dag[root][2], dag, level + 1)
|
||||
end
|
||||
end
|
||||
local convert = setmetatable({
|
||||
['.'] = 'dot',
|
||||
['\0'] = 'nul'
|
||||
}, {
|
||||
__index = function(self, k)
|
||||
return k
|
||||
end
|
||||
})
|
||||
local write_opcode_tree
|
||||
do
|
||||
local byte_to_opcode = { }
|
||||
local byte = false
|
||||
for l in assert(io.lines('src/assembler.c')) do
|
||||
if l:match('^%s*char%s+ops%[%]%[4%]') then
|
||||
byte = 0
|
||||
elseif l:match('%}') then
|
||||
byte = false
|
||||
elseif byte then
|
||||
for opcode in l:gmatch('"([A-Z-][A-Z-][A-Z-])"') do
|
||||
byte_to_opcode[byte] = opcode
|
||||
byte = byte + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
local order_to_opcode
|
||||
do
|
||||
local _accum_0 = { }
|
||||
local _len_0 = 1
|
||||
for i = 0, #byte_to_opcode do
|
||||
if byte_to_opcode[i] ~= '---' then
|
||||
_accum_0[_len_0] = byte_to_opcode[i]
|
||||
_len_0 = _len_0 + 1
|
||||
end
|
||||
end
|
||||
order_to_opcode = _accum_0
|
||||
end
|
||||
table.sort(order_to_opcode)
|
||||
local root, opcode_to_links = build_dag(order_to_opcode)
|
||||
write_opcode_tree = function(f)
|
||||
f:write(('\t$tree .$op-%s ( opcode tree )\n'):format(root:lower()))
|
||||
f:write('\t$start\n')
|
||||
for i = 0, #byte_to_opcode do
|
||||
local opcode = byte_to_opcode[i]
|
||||
f:write('\t')
|
||||
if opcode ~= '---' then
|
||||
f:write(('$op-%s '):format(opcode:lower()))
|
||||
else
|
||||
f:write(' ')
|
||||
end
|
||||
for j = 1, 2 do
|
||||
if opcode ~= '---' and opcode_to_links[opcode][j] then
|
||||
f:write(('.$op-%s '):format(opcode_to_links[opcode][j]:lower()))
|
||||
else
|
||||
f:write('[ 0000 ] ')
|
||||
end
|
||||
end
|
||||
if i == 0 then
|
||||
f:write('$disasm ')
|
||||
else
|
||||
f:write(' ')
|
||||
end
|
||||
if opcode ~= '---' then
|
||||
f:write(('[ %s ]'):format(opcode))
|
||||
else
|
||||
f:write('[ ??? ]')
|
||||
end
|
||||
if i == 0 then
|
||||
f:write(' $asm')
|
||||
end
|
||||
f:write('\n')
|
||||
end
|
||||
end
|
||||
end
|
||||
local type_byte
|
||||
type_byte = function(size, has_subtree)
|
||||
local n1 = has_subtree and '8' or '0'
|
||||
local n2
|
||||
local _exp_0 = size
|
||||
if '1' == _exp_0 then
|
||||
n2 = '1'
|
||||
elseif '2' == _exp_0 then
|
||||
n2 = '2'
|
||||
else
|
||||
n2 = '0'
|
||||
end
|
||||
return n1 .. n2
|
||||
end
|
||||
local globals = { }
|
||||
local add_globals
|
||||
add_globals = function(root, dag, key_to_label, key_to_contents, pad_before, pad_after)
|
||||
if pad_before == nil then
|
||||
pad_before = ''
|
||||
end
|
||||
if pad_after == nil then
|
||||
pad_after = ''
|
||||
end
|
||||
for k in pairs(dag) do
|
||||
local l = ''
|
||||
if k == root then
|
||||
l = l .. ('@%s\n'):format(key_to_label('root'):gsub('%s', ''))
|
||||
end
|
||||
l = l .. ('@%s '):format(key_to_label(k))
|
||||
for j = 1, 2 do
|
||||
if dag[k][j] then
|
||||
l = l .. ('.%s '):format(key_to_label(dag[k][j]))
|
||||
else
|
||||
l = l .. ('%s[ 0000 ]%s '):format(pad_before, pad_after)
|
||||
end
|
||||
end
|
||||
l = l .. key_to_contents(k)
|
||||
l = l .. '\n'
|
||||
globals[key_to_label(k):gsub('%s', '')] = l
|
||||
end
|
||||
globals[key_to_label('root'):gsub('%s', '')] = ''
|
||||
end
|
||||
do
|
||||
local root, dag = build_dag_from_chars('{}[]%@$;|=~,.^#"\0', '(', ')')
|
||||
check_terminals(dag, ')')
|
||||
local label_name
|
||||
label_name = function(s)
|
||||
return ('normal-%-3s'):format(convert[s])
|
||||
end
|
||||
local label_value
|
||||
label_value = function(k)
|
||||
return ('[ %02x ]'):format(k:byte())
|
||||
end
|
||||
add_globals(root, dag, label_name, label_value, '', ' ')
|
||||
end
|
||||
do
|
||||
local root, dag = build_dag_from_chars('{}', '\0', '(')
|
||||
dump(io.stdout, root, dag)
|
||||
local label_name
|
||||
label_name = function(s)
|
||||
if s == '(' then
|
||||
return 'normal-( '
|
||||
end
|
||||
return ('variable-%s'):format(convert[s])
|
||||
end
|
||||
local label_value
|
||||
label_value = function(k)
|
||||
return ('[ %02x ]'):format(k:byte())
|
||||
end
|
||||
dag['('] = nil
|
||||
add_globals(root, dag, label_name, label_value, '', ' ')
|
||||
end
|
||||
do
|
||||
local root, dag = build_dag_from_chars('{}\0', '(')
|
||||
dump(io.stdout, root, dag)
|
||||
local label_name
|
||||
label_name = function(s)
|
||||
if s == '(' then
|
||||
return 'normal-( '
|
||||
end
|
||||
return ('macro-%-3s'):format(convert[s])
|
||||
end
|
||||
local label_value
|
||||
label_value = function(k)
|
||||
return ('[ %02x ]'):format(k:byte())
|
||||
end
|
||||
dag['('] = nil
|
||||
add_globals(root, dag, label_name, label_value, '', ' ')
|
||||
end
|
||||
do
|
||||
local root, dag = build_dag_from_chars(']\0', '(')
|
||||
dump(io.stdout, root, dag)
|
||||
local label_name
|
||||
label_name = function(s)
|
||||
if s == '(' then
|
||||
return 'normal-( '
|
||||
end
|
||||
return ('data-%-4s'):format(convert[s])
|
||||
end
|
||||
local label_value
|
||||
label_value = function(k)
|
||||
return ('[ %02x ]'):format(k:byte())
|
||||
end
|
||||
dag['('] = nil
|
||||
add_globals(root, dag, label_name, label_value, '', ' ')
|
||||
end
|
||||
local devices = { }
|
||||
local add_device
|
||||
add_device = function(name, fields)
|
||||
local field_sizes
|
||||
do
|
||||
local _tbl_0 = { }
|
||||
for k, size in fields:gmatch('(%S+) (%d+)') do
|
||||
_tbl_0[k] = size
|
||||
end
|
||||
field_sizes = _tbl_0
|
||||
end
|
||||
field_sizes.pad = nil
|
||||
local field_names
|
||||
do
|
||||
local _accum_0 = { }
|
||||
local _len_0 = 1
|
||||
for k in pairs(field_sizes) do
|
||||
_accum_0[_len_0] = k
|
||||
_len_0 = _len_0 + 1
|
||||
end
|
||||
field_names = _accum_0
|
||||
end
|
||||
table.sort(field_names)
|
||||
local root, dag = build_dag(field_names)
|
||||
local label_name
|
||||
label_name = function(k)
|
||||
return ('l-%-14s'):format(name .. '-' .. k)
|
||||
end
|
||||
local label_value
|
||||
label_value = function(k)
|
||||
return ('%-17s [ %s ] .%s.%s'):format(('[ %s 00 ]'):format(k), type_byte(field_sizes[k], false), name, k)
|
||||
end
|
||||
add_globals(root, dag, label_name, label_value, ' ', ' ')
|
||||
return table.insert(devices, name)
|
||||
end
|
||||
local add_devices
|
||||
add_devices = function()
|
||||
table.sort(devices)
|
||||
local root, dag = build_dag(devices)
|
||||
local label_name
|
||||
label_name = function(k)
|
||||
return ('l-%-14s'):format(k)
|
||||
end
|
||||
local label_value
|
||||
label_value = function(k)
|
||||
return ('%-17s [ %s ] .%s .l-%s-root'):format(('[ %s 00 ]'):format(k), type_byte(0, true), k, k)
|
||||
end
|
||||
return add_globals(root, dag, label_name, label_value, ' ', ' ')
|
||||
end
|
||||
local filename = 'projects/software/assembler.usm'
|
||||
local f = assert(io.open(('%s.tmp'):format(filename), 'w'))
|
||||
local state = 'normal'
|
||||
local machine = {
|
||||
normal = function(l)
|
||||
if l:match('%( opcode tree %)') then
|
||||
write_opcode_tree(f)
|
||||
state = 'opcode'
|
||||
elseif l:match('^%@') then
|
||||
if l == '@RESET' then
|
||||
add_devices()
|
||||
end
|
||||
for k in l:gmatch('%@(%S+)') do
|
||||
if globals[k] then
|
||||
f:write(globals[k])
|
||||
globals[k] = nil
|
||||
return
|
||||
end
|
||||
end
|
||||
f:write(l)
|
||||
return f:write('\n')
|
||||
else
|
||||
if l:match('^%|%x%x%x%x %;') then
|
||||
add_device(l:match('%;(%S+) %{ (.*) %}'))
|
||||
end
|
||||
f:write(l)
|
||||
return f:write('\n')
|
||||
end
|
||||
end,
|
||||
opcode = function(l)
|
||||
if not l:match('.') then
|
||||
f:write(l)
|
||||
f:write('\n')
|
||||
state = 'normal'
|
||||
end
|
||||
end
|
||||
}
|
||||
for l in assert(io.lines(filename)) do
|
||||
machine[state](l)
|
||||
end
|
||||
for _, l in pairs(globals) do
|
||||
f:write(l)
|
||||
end
|
||||
f:close()
|
||||
assert(0 == os.execute(('mv %s %s.bak'):format(filename, filename)))
|
||||
return assert(0 == os.execute(('mv %s.tmp %s'):format(filename, filename)))
|
|
@ -1,210 +0,0 @@
|
|||
build_dag = (t, dag = {}, i = 1, j = #t, level = 0) ->
|
||||
if i > j
|
||||
return
|
||||
mid = math.floor (i + j) / 2
|
||||
dag[t[mid]] = {
|
||||
(build_dag t, dag, i, mid - 1, level + 1)
|
||||
(build_dag t, dag, mid + 1, j, level + 1)
|
||||
}
|
||||
t[mid], dag
|
||||
append_dag = (node, dag, k) ->
|
||||
i = k > node and 2 or 1
|
||||
next_node = dag[node][i]
|
||||
if next_node
|
||||
return append_dag next_node, dag, k
|
||||
dag[node][i] = k
|
||||
dag[k] = {}
|
||||
build_dag_from_chars = (s, ...) ->
|
||||
t = [ s\sub i, i for i = 1, #s ]
|
||||
table.sort t
|
||||
root, dag = build_dag t
|
||||
for i = 1, select '#', ...
|
||||
append_dag root, dag, (select i, ...)
|
||||
return root, dag
|
||||
check_terminals = (dag, s) ->
|
||||
for i = 1, #s
|
||||
k = s\sub i, i
|
||||
assert not dag[k][1], '%s has left child node'\format k
|
||||
assert not dag[k][2], '%s has right child node'\format k
|
||||
dump = (f, root, dag, level = 0) ->
|
||||
if dag[root][1]
|
||||
dump f, dag[root][1], dag, level + 1
|
||||
f\write ' '\rep level
|
||||
f\write root
|
||||
f\write '\n'
|
||||
if dag[root][2]
|
||||
dump f, dag[root][2], dag, level + 1
|
||||
|
||||
convert = setmetatable { ['.']: 'dot', ['\0']: 'nul' },
|
||||
__index: (k) => k
|
||||
-- deal with opcodes
|
||||
|
||||
write_opcode_tree = do
|
||||
byte_to_opcode = {}
|
||||
byte = false
|
||||
for l in assert io.lines 'src/assembler.c'
|
||||
if l\match '^%s*char%s+ops%[%]%[4%]'
|
||||
byte = 0
|
||||
elseif l\match '%}'
|
||||
byte = false
|
||||
elseif byte
|
||||
for opcode in l\gmatch '"([A-Z-][A-Z-][A-Z-])"'
|
||||
byte_to_opcode[byte] = opcode
|
||||
byte += 1
|
||||
order_to_opcode = [ byte_to_opcode[i] for i = 0, #byte_to_opcode when byte_to_opcode[i] != '---' ]
|
||||
table.sort order_to_opcode
|
||||
root, opcode_to_links = build_dag order_to_opcode
|
||||
(f) ->
|
||||
f\write '\t$tree .$op-%s ( opcode tree )\n'\format root\lower!
|
||||
f\write '\t$start\n'
|
||||
for i = 0, #byte_to_opcode
|
||||
opcode = byte_to_opcode[i]
|
||||
f\write '\t'
|
||||
if opcode != '---'
|
||||
f\write '$op-%s '\format opcode\lower!
|
||||
else
|
||||
f\write ' '
|
||||
for j = 1, 2
|
||||
if opcode != '---' and opcode_to_links[opcode][j]
|
||||
f\write '.$op-%s '\format opcode_to_links[opcode][j]\lower!
|
||||
else
|
||||
f\write '[ 0000 ] '
|
||||
if i == 0
|
||||
f\write '$disasm '
|
||||
else
|
||||
f\write ' '
|
||||
if opcode != '---'
|
||||
f\write '[ %s ]'\format opcode
|
||||
else
|
||||
f\write '[ ??? ]'
|
||||
if i == 0
|
||||
f\write ' $asm'
|
||||
f\write '\n'
|
||||
|
||||
type_byte = (size, has_subtree) ->
|
||||
n1 = has_subtree and '8' or '0'
|
||||
n2 = switch size
|
||||
when '1'
|
||||
'1'
|
||||
when '2'
|
||||
'2'
|
||||
else
|
||||
'0'
|
||||
n1 .. n2
|
||||
|
||||
globals = {}
|
||||
|
||||
add_globals = (root, dag, key_to_label, key_to_contents, pad_before = '', pad_after = '') ->
|
||||
for k in pairs dag
|
||||
l = ''
|
||||
if k == root
|
||||
l ..= '@%s\n'\format key_to_label('root')\gsub '%s', ''
|
||||
l ..= '@%s '\format key_to_label k
|
||||
for j = 1, 2
|
||||
if dag[k][j]
|
||||
l ..= '.%s '\format key_to_label dag[k][j]
|
||||
else
|
||||
l ..= '%s[ 0000 ]%s '\format pad_before, pad_after
|
||||
l ..= key_to_contents k
|
||||
l ..= '\n'
|
||||
globals[key_to_label(k)\gsub '%s', ''] = l
|
||||
globals[key_to_label('root')\gsub '%s', ''] = ''
|
||||
|
||||
do
|
||||
root, dag = build_dag_from_chars '{}[]%@$;|=~,.^#"\0', '(', ')'
|
||||
check_terminals dag, ')'
|
||||
label_name = (s) -> 'normal-%-3s'\format convert[s]
|
||||
label_value = (k) -> '[ %02x ]'\format k\byte!
|
||||
add_globals root, dag, label_name, label_value, '', ' '
|
||||
|
||||
do
|
||||
root, dag = build_dag_from_chars '{}', '\0', '('
|
||||
dump io.stdout, root, dag
|
||||
label_name = (s) ->
|
||||
if s == '('
|
||||
return 'normal-( '
|
||||
'variable-%s'\format convert[s]
|
||||
label_value = (k) -> '[ %02x ]'\format k\byte!
|
||||
dag['('] = nil
|
||||
add_globals root, dag, label_name, label_value, '', ' '
|
||||
|
||||
do
|
||||
root, dag = build_dag_from_chars '{}\0', '('
|
||||
dump io.stdout, root, dag
|
||||
label_name = (s) ->
|
||||
if s == '('
|
||||
return 'normal-( '
|
||||
'macro-%-3s'\format convert[s]
|
||||
label_value = (k) -> '[ %02x ]'\format k\byte!
|
||||
dag['('] = nil
|
||||
add_globals root, dag, label_name, label_value, '', ' '
|
||||
|
||||
do
|
||||
root, dag = build_dag_from_chars ']\0', '('
|
||||
dump io.stdout, root, dag
|
||||
label_name = (s) ->
|
||||
if s == '('
|
||||
return 'normal-( '
|
||||
'data-%-4s'\format convert[s]
|
||||
label_value = (k) -> '[ %02x ]'\format k\byte!
|
||||
dag['('] = nil
|
||||
add_globals root, dag, label_name, label_value, '', ' '
|
||||
|
||||
devices = {}
|
||||
|
||||
add_device = (name, fields) ->
|
||||
field_sizes = { k, size for k, size in fields\gmatch '(%S+) (%d+)' }
|
||||
field_sizes.pad = nil
|
||||
field_names = [ k for k in pairs field_sizes ]
|
||||
table.sort field_names
|
||||
root, dag = build_dag field_names
|
||||
label_name = (k) -> 'l-%-14s'\format name .. '-' .. k
|
||||
label_value = (k) -> '%-17s [ %s ] .%s.%s'\format '[ %s 00 ]'\format(k), type_byte(field_sizes[k], false), name, k
|
||||
add_globals root, dag, label_name, label_value, ' ', ' '
|
||||
table.insert devices, name
|
||||
|
||||
add_devices = ->
|
||||
table.sort devices
|
||||
root, dag = build_dag devices
|
||||
label_name = (k) -> 'l-%-14s'\format k
|
||||
label_value = (k) -> '%-17s [ %s ] .%s .l-%s-root'\format '[ %s 00 ]'\format(k), type_byte(0, true), k, k
|
||||
add_globals root, dag, label_name, label_value, ' ', ' '
|
||||
|
||||
filename = 'projects/software/assembler.usm'
|
||||
|
||||
f = assert io.open '%s.tmp'\format(filename), 'w'
|
||||
-- f = io.stdout
|
||||
state = 'normal'
|
||||
machine =
|
||||
normal: (l) ->
|
||||
if l\match '%( opcode tree %)'
|
||||
write_opcode_tree f
|
||||
state = 'opcode'
|
||||
elseif l\match '^%@'
|
||||
if l == '@RESET'
|
||||
add_devices!
|
||||
for k in l\gmatch '%@(%S+)'
|
||||
if globals[k]
|
||||
f\write globals[k]
|
||||
globals[k] = nil
|
||||
return
|
||||
f\write l
|
||||
f\write '\n'
|
||||
else
|
||||
if l\match '^%|%x%x%x%x %;'
|
||||
add_device l\match '%;(%S+) %{ (.*) %}'
|
||||
f\write l
|
||||
f\write '\n'
|
||||
opcode: (l) ->
|
||||
if not l\match '.'
|
||||
f\write l
|
||||
f\write '\n'
|
||||
state = 'normal'
|
||||
for l in assert io.lines filename
|
||||
machine[state] l
|
||||
for _, l in pairs globals
|
||||
f\write l
|
||||
f\close!
|
||||
assert 0 == os.execute 'mv %s %s.bak'\format filename, filename
|
||||
assert 0 == os.execute 'mv %s.tmp %s'\format filename, filename
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue