198 lines
5.0 KiB
Plaintext
198 lines
5.0 KiB
Plaintext
--
|
|
-- Asma tree helper script
|
|
--
|
|
-- This script updates the trees at the end of projects/software/asma.tal when
|
|
-- Uxn's opcode set changes or new runes (first character of tokens) are
|
|
-- created, so that new changes in the C assembler can be incorporated rapidly
|
|
-- into asma.
|
|
--
|
|
-- To run, you need Lua or LuaJIT, and just run etc/asma.lua from the top
|
|
-- directory of Uxn's git repository:
|
|
--
|
|
-- lua etc/asma.lua
|
|
--
|
|
-- This file is written in MoonScript, which is a language that compiles to
|
|
-- Lua, the same way as e.g. CoffeeScript compiles to JavaScript. Since
|
|
-- installing MoonScript has more dependencies than Lua, the compiled
|
|
-- etc/asma.lua is kept in Uxn's repository and will be kept updated as this
|
|
-- file changes.
|
|
--
|
|
|
|
spairs = (t) ->
|
|
keys = [ k for k in pairs t ]
|
|
table.sort keys
|
|
i = 0
|
|
->
|
|
i = i + 1
|
|
keys[i], t[keys[i]]
|
|
|
|
trees = {
|
|
['asma-opcodes']: {}
|
|
}
|
|
|
|
opcodes_in_order = {}
|
|
|
|
do -- opcodes
|
|
wanted = false
|
|
for l in assert io.lines 'src/uxnasm.c'
|
|
if l == 'static 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 -- 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.tal.tmp', 'w'
|
|
for l in assert io.lines 'projects/software/asma.tal'
|
|
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', 'greater', 'key', 'binary'
|
|
\write fmt '', 'than', 'than', 'string', '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 [[(
|
|
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
|
|
|
|
]]
|
|
\close!
|
|
os.execute 'mv projects/software/asma.tal.tmp projects/software/asma.tal'
|
|
|