Browse code

(asma) Rebalance the rune tree.

Andrew Alderwick authored on 10/11/2022 23:47:14
Showing 3 changed files
... ...
@@ -1,196 +1,103 @@
1
-local spairs
2
-spairs = function(t)
3
-  local keys
4
-  do
1
+local output = assert(io.open('.asma.tal', 'w'))
2
+local process_subtree
3
+process_subtree = function(items)
4
+  local middle = math.floor(#items / 2 + 1.25)
5
+  local node = items[middle]
6
+  if not node then
7
+    return 
8
+  end
9
+  node.left = process_subtree((function()
5 10
     local _accum_0 = { }
6 11
     local _len_0 = 1
7
-    for k in pairs(t) do
8
-      _accum_0[_len_0] = k
9
-      _len_0 = _len_0 + 1
10
-    end
11
-    keys = _accum_0
12
-  end
13
-  table.sort(keys)
14
-  local i = 0
15
-  return function()
16
-    i = i + 1
17
-    return keys[i], t[keys[i]]
18
-  end
19
-end
20
-local trees = {
21
-  ['asma-opcodes'] = { }
22
-}
23
-local opcodes_in_order = { }
24
-do
25
-  local wanted = false
26
-  for l in assert(io.lines('src/uxnasm.c')) do
27
-    if l == 'static char ops[][4] = {' then
28
-      wanted = true
29
-    elseif wanted then
30
-      if l == '};' then
31
-        break
32
-      end
33
-      for w in l:gmatch('[^%s",][^%s",][^%s",]') do
34
-        if w ~= '---' then
35
-          trees['asma-opcodes'][w] = {
36
-            ('"%s 00'):format(w),
37
-            ''
38
-          }
39
-        end
40
-        table.insert(opcodes_in_order, w)
12
+    for i, item in ipairs(items) do
13
+      if i < middle then
14
+        _accum_0[_len_0] = item
15
+        _len_0 = _len_0 + 1
41 16
       end
42 17
     end
43
-  end
44
-  assert(#opcodes_in_order == 32, 'didn\'t find 32 opcodes in assembler code!')
45
-end
46
-do
47
-  local representation = setmetatable({
48
-    ['&'] = '26 00 ( & )'
49
-  }, {
50
-    __index = function(self, c)
51
-      return ("'%s 00"):format(c)
52
-    end
53
-  })
54
-  local process
55
-  process = function(label, t)
56
-    trees[label] = { }
57
-    for k, v in pairs(t) do
58
-      trees[label][('%02x'):format(k:byte())] = {
59
-        representation[k],
60
-        (':%s'):format(v)
61
-      }
18
+    return _accum_0
19
+  end)())
20
+  node.right = process_subtree((function()
21
+    local _accum_0 = { }
22
+    local _len_0 = 1
23
+    for i, item in ipairs(items) do
24
+      if i > middle then
25
+        _accum_0[_len_0] = item
26
+        _len_0 = _len_0 + 1
27
+      end
62 28
     end
63
-  end
64
-  process('asma-first-char-normal', {
65
-    ['%'] = 'asma-macro-define',
66
-    ['|'] = 'asma-pad-absolute',
67
-    ['$'] = 'asma-pad-relative',
68
-    ['@'] = 'asma-label-define',
69
-    ['&'] = 'asma-sublabel-define',
70
-    ['#'] = 'asma-literal-hex',
71
-    ['.'] = 'asma-literal-zero-addr',
72
-    [','] = 'asma-literal-rel-addr',
73
-    [';'] = 'asma-literal-abs-addr',
74
-    [':'] = 'asma-abs-addr',
75
-    ["'"] = 'asma-raw-char',
76
-    ['"'] = 'asma-raw-word',
77
-    ['{'] = 'asma-ignore',
78
-    ['}'] = 'asma-ignore',
79
-    ['['] = 'asma-ignore',
80
-    [']'] = 'asma-ignore',
81
-    ['('] = 'asma-comment-start',
82
-    [')'] = 'asma-comment-end',
83
-    ['~'] = 'asma-include'
84
-  })
85
-  process('asma-first-char-macro', {
86
-    ['('] = 'asma-comment-start',
87
-    [')'] = 'asma-comment-end',
88
-    ['{'] = 'asma-ignore',
89
-    ['}'] = 'asma-macro-end'
90
-  })
91
-  process('asma-first-char-comment', {
92
-    ['('] = 'asma-comment-more',
93
-    [')'] = 'asma-comment-less'
94
-  })
29
+    return _accum_0
30
+  end)())
31
+  return node
95 32
 end
96
-local traverse_node
97
-traverse_node = function(t, min, max, lefts, rights)
98
-  local i = math.ceil((min + max) / 2)
99
-  if min < i then
100
-    lefts[t[i]] = (':&%s'):format(traverse_node(t, min, i - 1, lefts, rights))
101
-  end
102
-  if i < max then
103
-    rights[t[i]] = (':&%s'):format(traverse_node(t, i + 1, max, lefts, rights))
104
-  end
105
-  return t[i]
106
-end
107
-local traverse_tree
108
-traverse_tree = function(t)
109
-  local lefts, rights = { }, { }
110
-  local keys
33
+local process_tree
34
+process_tree = function(items)
35
+  local sorted_items
111 36
   do
112 37
     local _accum_0 = { }
113 38
     local _len_0 = 1
114
-    for k in pairs(t) do
115
-      _accum_0[_len_0] = k
39
+    for _index_0 = 1, #items do
40
+      local item = items[_index_0]
41
+      _accum_0[_len_0] = item
116 42
       _len_0 = _len_0 + 1
117 43
     end
118
-    keys = _accum_0
44
+    sorted_items = _accum_0
119 45
   end
120
-  table.sort(keys)
121
-  return lefts, rights, traverse_node(keys, 1, #keys, lefts, rights)
122
-end
123
-local ptr
124
-ptr = function(s)
125
-  if s then
126
-    return (':&%s'):format(s)
46
+  table.sort(sorted_items, function(a, b)
47
+    return a.order < b.order
48
+  end);
49
+  (process_subtree(sorted_items)).label = '&_entry'
50
+  for _index_0 = 1, #items do
51
+    local item = items[_index_0]
52
+    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))
127 53
   end
128
-  return ' $2'
129 54
 end
130
-local ordered_opcodes
131
-ordered_opcodes = function(t)
132
-  local i = 0
133
-  return function()
134
-    i = i + 1
135
-    local v = opcodes_in_order[i]
136
-    if t[v] then
137
-      return v, t[v]
138
-    elseif v then
139
-      return false, {
140
-        '"--- 00',
141
-        ''
142
-      }
55
+local parse_tree
56
+parse_tree = function(it)
57
+  local items = { }
58
+  for l in it do
59
+    if l == '' then
60
+      process_tree(items)
61
+      output:write('\n')
62
+      return 
143 63
     end
144
-  end
145
-end
146
-local printout = true
147
-local fmt
148
-fmt = function(...)
149
-  return (('\t%-11s %-10s %-12s %-14s %s '):format(...):gsub(' +$', '\n'))
150
-end
151
-do
152
-  local _with_0 = assert(io.open('projects/library/asma.tal.tmp', 'w'))
153
-  for l in assert(io.lines('projects/library/asma.tal')) do
154
-    if l:match('--- cut here ---') then
155
-      break
64
+    local item = {
65
+      extra = ''
66
+    }
67
+    item.key, item.rest = l:match('^%s*%S+%s+%S+%s+%S+%s+(%S+)(.*)')
68
+    if item.key:match('^%&') then
69
+      item.extra = (' %s'):format(item.key)
70
+      item.key, item.rest = item.rest:match('^%s+(%S+)(.*)')
156 71
     end
157
-    _with_0:write(l)
158
-    _with_0:write('\n')
159
-  end
160
-  _with_0:write('( --- 8< ------- 8< --- cut here --- 8< ------- 8< --- )\n')
161
-  _with_0:write('(          automatically generated code below          )\n')
162
-  _with_0:write('(          see etc/asma.moon for instructions          )\n')
163
-  _with_0:write('\n(')
164
-  _with_0:write(fmt('label', 'less', 'greater', 'key', 'binary'))
165
-  _with_0:write(fmt('', 'than', 'than', 'string', 'data )'))
166
-  _with_0:write('\n')
167
-  for name, tree in spairs(trees) do
168
-    _with_0:write(('@%s\n'):format(name))
169
-    local lefts, rights, entry = traverse_tree(tree)
170
-    local sort_fn
171
-    if name == 'asma-opcodes' then
172
-      if rights[opcodes_in_order[1]] then
173
-        rights[opcodes_in_order[1]] = rights[opcodes_in_order[1]] .. ' &_disasm'
174
-      else
175
-        rights[opcodes_in_order[1]] = ' $2 &_disasm'
176
-      end
177
-      sort_fn = ordered_opcodes
72
+    if item.key:match('^%"') then
73
+      item.order = item.key:sub(2)
74
+    elseif item.key:match('^%x%x') then
75
+      item.order = string.char(tonumber(item.key, 16))
178 76
     else
179
-      sort_fn = spairs
77
+      error(('unknown key: %q'):format(item.key))
180 78
     end
181
-    for k, v in sort_fn(tree) do
182
-      local label
183
-      if k == entry then
184
-        label = '&_entry'
185
-      elseif k then
186
-        label = ('&%s'):format(k)
187
-      else
188
-        label = ''
189
-      end
190
-      _with_0:write(fmt(label, lefts[k] or ' $2', rights[k] or ' $2', unpack(v)))
79
+    if item.order:match('^%a') then
80
+      item.label = ('&%s'):format(item.order)
81
+    elseif item.order:match('^.$') then
82
+      item.label = ('&%x'):format(item.order:byte())
83
+    else
84
+      error(('unknown label: %q'):format(item.order))
191 85
     end
192
-    _with_0:write('\n')
86
+    item.ref = (':%s'):format(item.label)
87
+    table.insert(items, item)
88
+  end
89
+end
90
+local it = assert(io.lines('projects/library/asma.tal'))
91
+local waiting_for_cut = true
92
+for l in it do
93
+  output:write(l)
94
+  output:write('\n')
95
+  if l:find('--- cut here ---', 1, true) then
96
+    waiting_for_cut = false
97
+  end
98
+  if not waiting_for_cut and '@' == l:sub(1, 1) then
99
+    parse_tree(it)
193 100
   end
194
-  _with_0:close()
195 101
 end
196
-return os.execute('mv projects/library/asma.tal.tmp projects/library/asma.tal')
102
+output:close()
103
+return os.execute('mv .asma.tal projects/library/asma.tal')
... ...
@@ -1,10 +1,7 @@
1 1
 --
2 2
 -- Asma tree helper script
3 3
 --
4
+-- This script balances the trees at the end of projects/library/asma.tal.
4 5
 --
5 6
 -- To run, you need Lua or LuaJIT, and just run etc/asma.lua from the top
6 7
 -- directory of Uxn's git repository:
... ...
@@ -18,145 +15,60 @@
18 15
 -- file changes.
19 16
 --
20 17
 
21
-spairs = (t) ->
22
-	keys = [ k for k in pairs t ]
23
-	table.sort keys
24
-	i = 0
25
-	->
26
-		i = i + 1
27
-		keys[i], t[keys[i]]
18
+output = assert io.open '.asma.tal', 'w'
28 19
 
29
-trees = {
30
-	['asma-opcodes']: {}
31
-}
20
+process_subtree = (items) ->
21
+    middle = math.floor #items / 2 + 1.25
22
+    node = items[middle]
23
+    if not node
24
+        return
25
+    node.left = process_subtree [ item for i, item in ipairs items when i < middle ]
26
+    node.right = process_subtree [ item for i, item in ipairs items when i > middle ]
27
+    node
32 28
 
33
-opcodes_in_order = {}
29
+process_tree = (items) ->
30
+    sorted_items = [ item for item in *items ]
31
+    table.sort sorted_items, (a, b) -> a.order < b.order
32
+    (process_subtree sorted_items).label = '&_entry'
33
+    for item in *items
34
+        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
34 35
 
35
-do -- opcodes
36
-	wanted = false
37
-	for l in assert io.lines 'src/uxnasm.c'
38
-		if l == 'static char ops[][4] = {'
39
-			wanted = true
40
-		elseif wanted
41
-			if l == '};'
42
-				break
43
-			for w in l\gmatch '[^%s",][^%s",][^%s",]'
44
-				if w != '---'
45
-					trees['asma-opcodes'][w] = {
46
-						'"%s 00'\format w
47
-						''
48
-					}
49
-				table.insert opcodes_in_order, w
50
-	assert #opcodes_in_order == 32, 'didn\'t find 32 opcodes in assembler code!'
36
+parse_tree = (it) ->
37
+    items = {}
38
+    for l in it
39
+        if l == ''
40
+            process_tree items
41
+            output\write '\n'
42
+            return
43
+        item = { extra: '' }
44
+        item.key, item.rest = l\match '^%s*%S+%s+%S+%s+%S+%s+(%S+)(.*)'
45
+        if item.key\match '^%&'
46
+            item.extra = ' %s'\format item.key
47
+            item.key, item.rest = item.rest\match '^%s+(%S+)(.*)'
48
+        if item.key\match '^%"'
49
+            item.order = item.key\sub 2
50
+        elseif item.key\match '^%x%x'
51
+            item.order = string.char tonumber item.key, 16
52
+        else
53
+            error 'unknown key: %q'\format item.key
54
+        if item.order\match '^%a'
55
+            item.label = '&%s'\format item.order
56
+        elseif item.order\match '^.$'
57
+            item.label = '&%x'\format item.order\byte!
58
+        else
59
+            error 'unknown label: %q'\format item.order
60
+        item.ref = ':%s'\format item.label
61
+        table.insert items, item
51 62
 
52
-do -- first characters
53
-	representation = setmetatable {
54
-		'&': '26 00 ( & )'
55
-	},
56
-		__index: (c) => "'%s 00"\format c
57
-	process = (label, t) ->
58
-		trees[label] = {}
59
-		for k, v in pairs t
60
-			trees[label]['%02x'\format k\byte!] = {
61
-				representation[k]
62
-				':%s'\format v
63
-			}
64
-	process 'asma-first-char-normal',
65
-		'%': 'asma-macro-define'
66
-		'|': 'asma-pad-absolute'
67
-		'$': 'asma-pad-relative'
68
-		'@': 'asma-label-define'
69
-		'&': 'asma-sublabel-define'
70
-		'#': 'asma-literal-hex'
71
-		'.': 'asma-literal-zero-addr'
72
-		',': 'asma-literal-rel-addr'
73
-		';': 'asma-literal-abs-addr'
74
-		':': 'asma-abs-addr'
75
-		"'": 'asma-raw-char'
76
-		'"': 'asma-raw-word'
77
-		'{': 'asma-ignore'
78
-		'}': 'asma-ignore'
79
-		'[': 'asma-ignore'
80
-		']': 'asma-ignore'
81
-		'(': 'asma-comment-start'
82
-		')': 'asma-comment-end'
83
-		'~': 'asma-include'
84
-	process 'asma-first-char-macro',
85
-		'(': 'asma-comment-start'
86
-		')': 'asma-comment-end'
87
-		'{': 'asma-ignore'
88
-		'}': 'asma-macro-end'
89
-	process 'asma-first-char-comment',
90
-		'(': 'asma-comment-more'
91
-		')': 'asma-comment-less'
92
-
93
-traverse_node = (t, min, max, lefts, rights) ->
94
-	i = math.ceil (min + max) / 2
95
-	if min < i
96
-		lefts[t[i]]  = ':&%s'\format traverse_node t, min, i - 1, lefts, rights
97
-	if i < max
98
-		rights[t[i]] = ':&%s'\format traverse_node t, i + 1, max, lefts, rights
99
-	return t[i]
100
-
101
-traverse_tree = (t) ->
102
-	lefts, rights = {}, {}
103
-	keys = [ k for k in pairs t ]
104
-	table.sort keys
105
-	lefts, rights, traverse_node keys, 1, #keys, lefts, rights
106
-
107
-ptr = (s) ->
108
-	if s
109
-		return ':&%s'\format s
110
-	return ' $2'
111
-
112
-ordered_opcodes = (t) ->
113
-	i = 0
114
-	->
115
-		i = i + 1
116
-		v = opcodes_in_order[i]
117
-		if t[v]
118
-			return v, t[v]
119
-		elseif v
120
-			return false, { '"--- 00', '' }
121
-
122
-printout = true
123
-
124
-fmt = (...) ->
125
-	('\t%-11s %-10s %-12s %-14s %s '\format(...)\gsub ' +$', '\n')
126
-
127
-with assert io.open 'projects/library/asma.tal.tmp', 'w'
128
-	for l in assert io.lines 'projects/library/asma.tal'
129
-		if l\match '--- cut here ---'
130
-			break
131
-		\write l
132
-		\write '\n'
133
-	\write '( --- 8< ------- 8< --- cut here --- 8< ------- 8< --- )\n'
134
-	\write '(          automatically generated code below          )\n'
135
-	\write '(          see etc/asma.moon for instructions          )\n'
136
-	\write '\n('
137
-	\write fmt 'label', 'less', 'greater', 'key', 'binary'
138
-	\write fmt '', 'than', 'than', 'string', 'data )'
139
-	\write '\n'
140
-	for name, tree in spairs trees
141
-		\write '@%s\n'\format name
142
-		lefts, rights, entry = traverse_tree tree
143
-		sort_fn = if name == 'asma-opcodes'
144
-			if rights[opcodes_in_order[1]]
145
-				rights[opcodes_in_order[1]] ..= ' &_disasm'
146
-			else
147
-				rights[opcodes_in_order[1]] = ' $2 &_disasm'
148
-			ordered_opcodes
149
-		else
150
-			spairs
151
-		for k, v in sort_fn tree
152
-			label = if k == entry
153
-				'&_entry'
154
-			elseif k
155
-				'&%s'\format k
156
-			else
157
-				''
158
-			\write fmt label, lefts[k] or ' $2', rights[k] or ' $2', unpack v
159
-		\write '\n'
160
-	\close!
161
-os.execute 'mv projects/library/asma.tal.tmp projects/library/asma.tal'
63
+it = assert io.lines 'projects/library/asma.tal'
64
+waiting_for_cut = true
65
+for l in it
66
+    output\write l
67
+    output\write '\n'
68
+    if l\find '--- cut here ---', 1, true
69
+        waiting_for_cut = false
70
+    if not waiting_for_cut and '@' == l\sub 1, 1
71
+        parse_tree it
72
+output\close!
73
+os.execute 'mv .asma.tal projects/library/asma.tal'
162 74
 
... ...
@@ -908,17 +908,17 @@
908 908
 	&23         :&22        $2          "# 00          :asma-literal-hex
909 909
 	&24         :&23       :&25         "$ 00          :asma-pad-relative
910 910
 	&25          $2         $2          "% 00          :asma-macro-define
911
-	&26         :&24       :&29         26 00 ( & )    :asma-sublabel-define
911
+	&26         :&24       :&2c         26 00 ( & )    :asma-sublabel-define
912 912
 	&28          $2         $2          "( 00          :asma-comment-start
913
-	&29         :&28       :&2c         ") 00          :asma-comment-end
914
-	&2c          $2        :&2d         ", 00          :asma-literal-rel-addr
913
+	&29         :&28        $2          ") 00          :asma-comment-end
914
+	&2c         :&29       :&2d         ", 00          :asma-literal-rel-addr
915 915
 	&2d          $2         $2          "- 00          :asma-zero-addr
916 916
 	&_entry     :&26       :&7b         ". 00          :asma-literal-zero-addr
917 917
 	&3a          $2         $2          ": 00          :asma-abs-addr
918
-	&3b         :&3a       :&3d         "; 00          :asma-literal-abs-addr
919
-	&3d          $2        :&40         "= 00          :asma-abs-addr
918
+	&3b         :&3a        $2          "; 00          :asma-literal-abs-addr
919
+	&3d         :&3b       :&40         "= 00          :asma-abs-addr
920 920
 	&40          $2         $2          "@ 00          :asma-label-define
921
-	&7b         :&3b       :&7d         "{ 00          :asma-ignore
921
+	&7b         :&3d       :&7d         "{ 00          :asma-ignore
922 922
 	&7c          $2         $2          "| 00          :asma-pad-absolute
923 923
 	&7d         :&7c       :&7e         "} 00          :asma-ignore
924 924
 	&7e          $2         $2          "~ 00          :asma-include