211 lines
5.5 KiB
Plaintext
211 lines
5.5 KiB
Plaintext
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
|
|
|