From 02ecc2ee7d412a92701e48a33b9b67ad26bf98a8 Mon Sep 17 00:00:00 2001 From: Andrew Alderwick Date: Thu, 10 Nov 2022 23:47:14 +0000 Subject: [PATCH] (asma) Rebalance the rune tree. --- etc/asma.lua | 269 +++++++++++++------------------------- etc/asma.moon | 194 ++++++++------------------- projects/library/asma.tal | 12 +- 3 files changed, 147 insertions(+), 328 deletions(-) diff --git a/etc/asma.lua b/etc/asma.lua index b229b4b..471e1be 100644 --- a/etc/asma.lua +++ b/etc/asma.lua @@ -1,196 +1,103 @@ -local spairs -spairs = function(t) - local keys +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 i, item in ipairs(items) do + if i < middle then + _accum_0[_len_0] = item + _len_0 = _len_0 + 1 + end + end + 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 + return _accum_0 + end)()) + return node +end +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) - local i = 0 - return function() - i = i + 1 - return keys[i], t[keys[i]] + 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 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 +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 - 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) + 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 - }) - 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', - ['~'] = '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' - }) -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/library/asma.tal.tmp', 'w')) - for l in assert(io.lines('projects/library/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 + 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 - _with_0:close() end -return os.execute('mv projects/library/asma.tal.tmp projects/library/asma.tal') +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 +end +output:close() +return os.execute('mv .asma.tal projects/library/asma.tal') diff --git a/etc/asma.moon b/etc/asma.moon index e74d77f..9cadef5 100644 --- 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 index 198b06b..47e843f 100644 --- 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