commit 02ecc2ee7d412a92701e48a33b9b67ad26bf98a8
parent 4abb47e6e10b679057d30a7bcade58d54b56e525
Author: Andrew Alderwick <andrew@alderwick.co.uk>
Date: Thu, 10 Nov 2022 23:47:14 +0000
(asma) Rebalance the rune tree.
Diffstat:
3 files changed, 141 insertions(+), 322 deletions(-)
diff --git a/etc/asma.lua b/etc/asma.lua
@@ -1,196 +1,103 @@
-local spairs
-spairs = function(t)
- local keys
- do
+local output = assert(io.open('.asma.tal', 'w'))
+local process_subtree
+process_subtree = function(items)
+ local middle = math.floor(#items / 2 + 1.25)
+ local node = items[middle]
+ if not node then
+ return
+ end
+ node.left = process_subtree((function()
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)
+ for i, item in ipairs(items) do
+ if i < middle then
+ _accum_0[_len_0] = item
+ _len_0 = _len_0 + 1
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)
- }
+ return _accum_0
+ end)())
+ node.right = process_subtree((function()
+ local _accum_0 = { }
+ local _len_0 = 1
+ for i, item in ipairs(items) do
+ if i > middle then
+ _accum_0[_len_0] = item
+ _len_0 = _len_0 + 1
+ end
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',
- ['~'] = 'asma-include'
- })
- process('asma-first-char-macro', {
- ['('] = 'asma-comment-start',
- [')'] = 'asma-comment-end',
- ['{'] = 'asma-ignore',
- ['}'] = 'asma-macro-end'
- })
- process('asma-first-char-comment', {
- ['('] = 'asma-comment-more',
- [')'] = 'asma-comment-less'
- })
+ return _accum_0
+ end)())
+ return node
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
+local process_tree
+process_tree = function(items)
+ local sorted_items
do
local _accum_0 = { }
local _len_0 = 1
- for k in pairs(t) do
- _accum_0[_len_0] = k
+ for _index_0 = 1, #items do
+ local item = items[_index_0]
+ _accum_0[_len_0] = item
_len_0 = _len_0 + 1
end
- keys = _accum_0
+ sorted_items = _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)
+ table.sort(sorted_items, function(a, b)
+ return a.order < b.order
+ end);
+ (process_subtree(sorted_items)).label = '&_entry'
+ for _index_0 = 1, #items do
+ local item = items[_index_0]
+ output:write(('\t%-11s %-10s %-12s %s%s\n'):format(item.label, item.left and item.left.ref or ' $2', (item.right and item.right.ref or ' $2') .. item.extra, item.key, item.rest))
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',
- ''
- }
+local parse_tree
+parse_tree = function(it)
+ local items = { }
+ for l in it do
+ if l == '' then
+ process_tree(items)
+ output:write('\n')
+ return
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/library/asma.tal.tmp', 'w'))
- for l in assert(io.lines('projects/library/asma.tal')) do
- if l:match('--- cut here ---') then
- break
+ local item = {
+ extra = ''
+ }
+ item.key, item.rest = l:match('^%s*%S+%s+%S+%s+%S+%s+(%S+)(.*)')
+ if item.key:match('^%&') then
+ item.extra = (' %s'):format(item.key)
+ item.key, item.rest = item.rest:match('^%s+(%S+)(.*)')
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
+ if item.key:match('^%"') then
+ item.order = item.key:sub(2)
+ elseif item.key:match('^%x%x') then
+ item.order = string.char(tonumber(item.key, 16))
else
- sort_fn = spairs
+ error(('unknown key: %q'):format(item.key))
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)))
+ if item.order:match('^%a') then
+ item.label = ('&%s'):format(item.order)
+ elseif item.order:match('^.$') then
+ item.label = ('&%x'):format(item.order:byte())
+ else
+ error(('unknown label: %q'):format(item.order))
end
- _with_0:write('\n')
+ item.ref = (':%s'):format(item.label)
+ table.insert(items, item)
+ end
+end
+local it = assert(io.lines('projects/library/asma.tal'))
+local waiting_for_cut = true
+for l in it do
+ output:write(l)
+ output:write('\n')
+ if l:find('--- cut here ---', 1, true) then
+ waiting_for_cut = false
+ end
+ if not waiting_for_cut and '@' == l:sub(1, 1) then
+ parse_tree(it)
end
- _with_0:close()
end
-return os.execute('mv projects/library/asma.tal.tmp projects/library/asma.tal')
+output:close()
+return os.execute('mv .asma.tal projects/library/asma.tal')
diff --git a/etc/asma.moon b/etc/asma.moon
@@ -1,10 +1,7 @@
--
-- Asma tree helper script
--
--- This script updates the trees at the end of projects/library/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.
+-- This script balances the trees at the end of projects/library/asma.tal.
--
-- To run, you need Lua or LuaJIT, and just run etc/asma.lua from the top
-- directory of Uxn's git repository:
@@ -18,145 +15,60 @@
-- file changes.
--
-spairs = (t) ->
- keys = [ k for k in pairs t ]
- table.sort keys
- i = 0
- ->
- i = i + 1
- keys[i], t[keys[i]]
+output = assert io.open '.asma.tal', 'w'
-trees = {
- ['asma-opcodes']: {}
-}
+process_subtree = (items) ->
+ middle = math.floor #items / 2 + 1.25
+ node = items[middle]
+ if not node
+ return
+ node.left = process_subtree [ item for i, item in ipairs items when i < middle ]
+ node.right = process_subtree [ item for i, item in ipairs items when i > middle ]
+ node
-opcodes_in_order = {}
+process_tree = (items) ->
+ sorted_items = [ item for item in *items ]
+ table.sort sorted_items, (a, b) -> a.order < b.order
+ (process_subtree sorted_items).label = '&_entry'
+ for item in *items
+ output\write '\t%-11s %-10s %-12s %s%s\n'\format item.label, item.left and item.left.ref or ' $2', (item.right and item.right.ref or ' $2') .. item.extra, item.key, item.rest
-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!'
+parse_tree = (it) ->
+ items = {}
+ for l in it
+ if l == ''
+ process_tree items
+ output\write '\n'
+ return
+ item = { extra: '' }
+ item.key, item.rest = l\match '^%s*%S+%s+%S+%s+%S+%s+(%S+)(.*)'
+ if item.key\match '^%&'
+ item.extra = ' %s'\format item.key
+ item.key, item.rest = item.rest\match '^%s+(%S+)(.*)'
+ if item.key\match '^%"'
+ item.order = item.key\sub 2
+ elseif item.key\match '^%x%x'
+ item.order = string.char tonumber item.key, 16
+ else
+ error 'unknown key: %q'\format item.key
+ if item.order\match '^%a'
+ item.label = '&%s'\format item.order
+ elseif item.order\match '^.$'
+ item.label = '&%x'\format item.order\byte!
+ else
+ error 'unknown label: %q'\format item.order
+ item.ref = ':%s'\format item.label
+ table.insert items, item
-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'
- '~': 'asma-include'
- process 'asma-first-char-macro',
- '(': 'asma-comment-start'
- ')': 'asma-comment-end'
- '{': 'asma-ignore'
- '}': 'asma-macro-end'
- process 'asma-first-char-comment',
- '(': 'asma-comment-more'
- ')': 'asma-comment-less'
-
-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/library/asma.tal.tmp', 'w'
- for l in assert io.lines 'projects/library/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'
- \close!
-os.execute 'mv projects/library/asma.tal.tmp projects/library/asma.tal'
+it = assert io.lines 'projects/library/asma.tal'
+waiting_for_cut = true
+for l in it
+ output\write l
+ output\write '\n'
+ if l\find '--- cut here ---', 1, true
+ waiting_for_cut = false
+ if not waiting_for_cut and '@' == l\sub 1, 1
+ parse_tree it
+output\close!
+os.execute 'mv .asma.tal projects/library/asma.tal'
diff --git a/projects/library/asma.tal b/projects/library/asma.tal
@@ -908,17 +908,17 @@
&23 :&22 $2 "# 00 :asma-literal-hex
&24 :&23 :&25 "$ 00 :asma-pad-relative
&25 $2 $2 "% 00 :asma-macro-define
- &26 :&24 :&29 26 00 ( & ) :asma-sublabel-define
+ &26 :&24 :&2c 26 00 ( & ) :asma-sublabel-define
&28 $2 $2 "( 00 :asma-comment-start
- &29 :&28 :&2c ") 00 :asma-comment-end
- &2c $2 :&2d ", 00 :asma-literal-rel-addr
+ &29 :&28 $2 ") 00 :asma-comment-end
+ &2c :&29 :&2d ", 00 :asma-literal-rel-addr
&2d $2 $2 "- 00 :asma-zero-addr
&_entry :&26 :&7b ". 00 :asma-literal-zero-addr
&3a $2 $2 ": 00 :asma-abs-addr
- &3b :&3a :&3d "; 00 :asma-literal-abs-addr
- &3d $2 :&40 "= 00 :asma-abs-addr
+ &3b :&3a $2 "; 00 :asma-literal-abs-addr
+ &3d :&3b :&40 "= 00 :asma-abs-addr
&40 $2 $2 "@ 00 :asma-label-define
- &7b :&3b :&7d "{ 00 :asma-ignore
+ &7b :&3d :&7d "{ 00 :asma-ignore
&7c $2 $2 "| 00 :asma-pad-absolute
&7d :&7c :&7e "} 00 :asma-ignore
&7e $2 $2 "~ 00 :asma-include