Browse code

Rewritten asma

Andrew Alderwick authored on 03/05/2021 18:15:06
Showing 5 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,235 @@
1
+local band, bor, lshift, rshift
2
+do
3
+  local _obj_0 = require('bit')
4
+  band, bor, lshift, rshift = _obj_0.band, _obj_0.bor, _obj_0.lshift, _obj_0.rshift
5
+end
6
+local spairs
7
+spairs = function(t)
8
+  local keys
9
+  do
10
+    local _accum_0 = { }
11
+    local _len_0 = 1
12
+    for k in pairs(t) do
13
+      _accum_0[_len_0] = k
14
+      _len_0 = _len_0 + 1
15
+    end
16
+    keys = _accum_0
17
+  end
18
+  table.sort(keys)
19
+  local i = 0
20
+  return function()
21
+    i = i + 1
22
+    return keys[i], t[keys[i]]
23
+  end
24
+end
25
+local trees = {
26
+  ['asma-labels'] = { },
27
+  ['asma-opcodes'] = { }
28
+}
29
+local opcodes_in_order = { }
30
+do
31
+  local wanted = false
32
+  for l in assert(io.lines('src/assembler.c')) do
33
+    if l == 'char ops[][4] = {' then
34
+      wanted = true
35
+    elseif wanted then
36
+      if l == '};' then
37
+        break
38
+      end
39
+      for w in l:gmatch('[^%s",][^%s",][^%s",]') do
40
+        if w ~= '---' then
41
+          trees['asma-opcodes'][w] = {
42
+            ('"%s 00'):format(w),
43
+            ''
44
+          }
45
+        end
46
+        table.insert(opcodes_in_order, w)
47
+      end
48
+    end
49
+  end
50
+  assert(#opcodes_in_order == 32, 'didn\'t find 32 opcodes in assembler code!')
51
+end
52
+do
53
+  local add_device
54
+  add_device = function(addr, name, fields)
55
+    addr = tonumber(addr, 16)
56
+    local k
57
+    if name:match('^Audio%x+$') then
58
+      k = 'asma-ldev-Audio'
59
+    else
60
+      k = ('asma-ldev-%s'):format(name)
61
+    end
62
+    trees['asma-labels'][name] = {
63
+      ('"%s 00'):format(name),
64
+      ('00%02x :%s/_entry'):format(addr, k)
65
+    }
66
+    trees[k] = { }
67
+    addr = 0
68
+    for fname, flen in fields:gmatch('%&(%S+) +%$(%x+)') do
69
+      if fname ~= 'pad' then
70
+        trees[k][fname] = {
71
+          ('"%s 00'):format(fname),
72
+          ('00%02x'):format(addr)
73
+        }
74
+      end
75
+      addr = addr + tonumber(flen, 16)
76
+    end
77
+  end
78
+  for l in assert(io.lines('projects/examples/blank.usm')) do
79
+    local f = {
80
+      l:match('^%|(%x%x) +%@(%S+) +%[ (.*) %]')
81
+    }
82
+    if f[1] then
83
+      add_device(unpack(f))
84
+    end
85
+  end
86
+end
87
+do
88
+  local representation = setmetatable({
89
+    ['&'] = '26 00 ( & )'
90
+  }, {
91
+    __index = function(self, c)
92
+      return ("'%s 00"):format(c)
93
+    end
94
+  })
95
+  local process
96
+  process = function(label, t)
97
+    trees[label] = { }
98
+    for k, v in pairs(t) do
99
+      trees[label][('%02x'):format(k:byte())] = {
100
+        representation[k],
101
+        (':%s'):format(v)
102
+      }
103
+    end
104
+  end
105
+  process('asma-first-char-normal', {
106
+    ['%'] = 'asma-macro-define',
107
+    ['|'] = 'asma-pad-absolute',
108
+    ['$'] = 'asma-pad-relative',
109
+    ['@'] = 'asma-label-define',
110
+    ['&'] = 'asma-sublabel-define',
111
+    ['#'] = 'asma-literal-hex',
112
+    ['.'] = 'asma-literal-zero-addr',
113
+    [','] = 'asma-literal-rel-addr',
114
+    [';'] = 'asma-literal-abs-addr',
115
+    [':'] = 'asma-abs-addr',
116
+    ["'"] = 'asma-raw-char',
117
+    ['"'] = 'asma-raw-word',
118
+    ['{'] = 'asma-ignore',
119
+    ['}'] = 'asma-ignore',
120
+    ['['] = 'asma-ignore',
121
+    [']'] = 'asma-ignore',
122
+    ['('] = 'asma-comment-start',
123
+    [')'] = 'asma-comment-end'
124
+  })
125
+  process('asma-first-char-macro', {
126
+    ['('] = 'asma-comment-start',
127
+    [')'] = 'asma-comment-end',
128
+    ['{'] = 'asma-ignore',
129
+    ['}'] = 'asma-macro-end'
130
+  })
131
+  process('asma-first-char-comment', {
132
+    [')'] = 'asma-comment-end'
133
+  })
134
+end
135
+local traverse_node
136
+traverse_node = function(t, min, max, lefts, rights)
137
+  local i = math.ceil((min + max) / 2)
138
+  if min < i then
139
+    lefts[t[i]] = (':&%s'):format(traverse_node(t, min, i - 1, lefts, rights))
140
+  end
141
+  if i < max then
142
+    rights[t[i]] = (':&%s'):format(traverse_node(t, i + 1, max, lefts, rights))
143
+  end
144
+  return t[i]
145
+end
146
+local traverse_tree
147
+traverse_tree = function(t)
148
+  local lefts, rights = { }, { }
149
+  local keys
150
+  do
151
+    local _accum_0 = { }
152
+    local _len_0 = 1
153
+    for k in pairs(t) do
154
+      _accum_0[_len_0] = k
155
+      _len_0 = _len_0 + 1
156
+    end
157
+    keys = _accum_0
158
+  end
159
+  table.sort(keys)
160
+  return lefts, rights, traverse_node(keys, 1, #keys, lefts, rights)
161
+end
162
+local ptr
163
+ptr = function(s)
164
+  if s then
165
+    return (':&%s'):format(s)
166
+  end
167
+  return ' $2'
168
+end
169
+local ordered_opcodes
170
+ordered_opcodes = function(t)
171
+  local i = 0
172
+  return function()
173
+    i = i + 1
174
+    local v = opcodes_in_order[i]
175
+    if t[v] then
176
+      return v, t[v]
177
+    elseif v then
178
+      return false, {
179
+        '"--- 00',
180
+        ''
181
+      }
182
+    end
183
+  end
184
+end
185
+local printout = true
186
+local fmt
187
+fmt = function(...)
188
+  return (('\t%-11s %-10s %-12s %-14s %s '):format(...):gsub(' +$', '\n'))
189
+end
190
+do
191
+  local _with_0 = assert(io.open('projects/software/asma.usm.tmp', 'w'))
192
+  for l in assert(io.lines('projects/software/asma.usm')) do
193
+    if l:match('--- cut here ---') then
194
+      break
195
+    end
196
+    _with_0:write(l)
197
+    _with_0:write('\n')
198
+  end
199
+  _with_0:write('( --- 8< ------- 8< --- cut here --- 8< ------- 8< --- )\n')
200
+  _with_0:write('(          automatically generated code below          )\n')
201
+  _with_0:write('(          see etc/asma.moon for instructions          )\n')
202
+  _with_0:write('\n(')
203
+  _with_0:write(fmt('label', 'less than', 'greater than', 'key', 'data )'))
204
+  _with_0:write('\n')
205
+  for name, tree in spairs(trees) do
206
+    _with_0:write(('@%s\n'):format(name))
207
+    local lefts, rights, entry = traverse_tree(tree)
208
+    local sort_fn
209
+    if name == 'asma-opcodes' then
210
+      if rights[opcodes_in_order[1]] then
211
+        rights[opcodes_in_order[1]] = rights[opcodes_in_order[1]] .. ' &_disasm'
212
+      else
213
+        rights[opcodes_in_order[1]] = ' $2 &_disasm'
214
+      end
215
+      sort_fn = ordered_opcodes
216
+    else
217
+      sort_fn = spairs
218
+    end
219
+    for k, v in sort_fn(tree) do
220
+      local label
221
+      if k == entry then
222
+        label = '&_entry'
223
+      elseif k then
224
+        label = ('&%s'):format(k)
225
+      else
226
+        label = ''
227
+      end
228
+      _with_0:write(fmt(label, lefts[k] or ' $2', rights[k] or ' $2', unpack(v)))
229
+    end
230
+    _with_0:write('\n')
231
+  end
232
+  _with_0:write('@asma-heap\n\n')
233
+  _with_0:close()
234
+end
235
+return os.execute('mv projects/software/asma.usm.tmp projects/software/asma.usm')
0 236
new file mode 100644
... ...
@@ -0,0 +1,169 @@
1
+import band, bor, lshift, rshift from require 'bit'
2
+
3
+spairs = (t) ->
4
+	keys = [ k for k in pairs t ]
5
+	table.sort keys
6
+	i = 0
7
+	->
8
+		i = i + 1
9
+		keys[i], t[keys[i]]
10
+
11
+trees = {
12
+	['asma-labels']: {}
13
+	['asma-opcodes']: {}
14
+}
15
+
16
+opcodes_in_order = {}
17
+
18
+do -- opcodes
19
+	wanted = false
20
+	for l in assert io.lines 'src/assembler.c'
21
+		if l == 'char ops[][4] = {'
22
+			wanted = true
23
+		elseif wanted
24
+			if l == '};'
25
+				break
26
+			for w in l\gmatch '[^%s",][^%s",][^%s",]'
27
+				if w != '---'
28
+					trees['asma-opcodes'][w] = {
29
+						'"%s 00'\format w
30
+						''
31
+					}
32
+				table.insert opcodes_in_order, w
33
+	assert #opcodes_in_order == 32, 'didn\'t find 32 opcodes in assembler code!'
34
+
35
+do -- devices -> labels
36
+	add_device = (addr, name, fields) ->
37
+		addr = tonumber addr, 16
38
+		k = if name\match '^Audio%x+$'
39
+			'asma-ldev-Audio'
40
+		else
41
+			'asma-ldev-%s'\format name
42
+		trees['asma-labels'][name] = {
43
+			'"%s 00'\format name
44
+			'00%02x :%s/_entry'\format addr, k
45
+		}
46
+		trees[k] = {}
47
+		addr = 0
48
+		for fname, flen in fields\gmatch '%&(%S+) +%$(%x+)'
49
+			if fname != 'pad'
50
+				trees[k][fname] = {
51
+					'"%s 00'\format fname,
52
+					'00%02x'\format addr
53
+				}
54
+			addr += tonumber flen, 16
55
+	for l in assert io.lines 'projects/examples/blank.usm'
56
+		f = { l\match '^%|(%x%x) +%@(%S+) +%[ (.*) %]' }
57
+		if f[1]
58
+			add_device unpack f
59
+
60
+
61
+do -- first characters
62
+	representation = setmetatable {
63
+		'&': '26 00 ( & )'
64
+	},
65
+		__index: (c) => "'%s 00"\format c
66
+	process = (label, t) ->
67
+		trees[label] = {}
68
+		for k, v in pairs t
69
+			trees[label]['%02x'\format k\byte!] = {
70
+				representation[k]
71
+				':%s'\format v
72
+			}
73
+	process 'asma-first-char-normal',
74
+		'%': 'asma-macro-define'
75
+		'|': 'asma-pad-absolute'
76
+		'$': 'asma-pad-relative'
77
+		'@': 'asma-label-define'
78
+		'&': 'asma-sublabel-define'
79
+		'#': 'asma-literal-hex'
80
+		'.': 'asma-literal-zero-addr'
81
+		',': 'asma-literal-rel-addr'
82
+		';': 'asma-literal-abs-addr'
83
+		':': 'asma-abs-addr'
84
+		"'": 'asma-raw-char'
85
+		'"': 'asma-raw-word'
86
+		'{': 'asma-ignore'
87
+		'}': 'asma-ignore'
88
+		'[': 'asma-ignore'
89
+		']': 'asma-ignore'
90
+		'(': 'asma-comment-start'
91
+		')': 'asma-comment-end'
92
+	process 'asma-first-char-macro',
93
+		'(': 'asma-comment-start'
94
+		')': 'asma-comment-end'
95
+		'{': 'asma-ignore'
96
+		'}': 'asma-macro-end'
97
+	process 'asma-first-char-comment',
98
+		')': 'asma-comment-end'
99
+
100
+traverse_node = (t, min, max, lefts, rights) ->
101
+	i = math.ceil (min + max) / 2
102
+	if min < i
103
+		lefts[t[i]]  = ':&%s'\format traverse_node t, min, i - 1, lefts, rights
104
+	if i < max
105
+		rights[t[i]] = ':&%s'\format traverse_node t, i + 1, max, lefts, rights
106
+	return t[i]
107
+
108
+traverse_tree = (t) ->
109
+	lefts, rights = {}, {}
110
+	keys = [ k for k in pairs t ]
111
+	table.sort keys
112
+	lefts, rights, traverse_node keys, 1, #keys, lefts, rights
113
+
114
+ptr = (s) ->
115
+	if s
116
+		return ':&%s'\format s
117
+	return ' $2'
118
+
119
+ordered_opcodes = (t) ->
120
+	i = 0
121
+	->
122
+		i = i + 1
123
+		v = opcodes_in_order[i]
124
+		if t[v]
125
+			return v, t[v]
126
+		elseif v
127
+			return false, { '"--- 00', '' }
128
+
129
+printout = true
130
+
131
+fmt = (...) ->
132
+	('\t%-11s %-10s %-12s %-14s %s '\format(...)\gsub ' +$', '\n')
133
+
134
+with assert io.open 'projects/software/asma.usm.tmp', 'w'
135
+	for l in assert io.lines 'projects/software/asma.usm'
136
+		if l\match '--- cut here ---'
137
+			break
138
+		\write l
139
+		\write '\n'
140
+	\write '( --- 8< ------- 8< --- cut here --- 8< ------- 8< --- )\n'
141
+	\write '(          automatically generated code below          )\n'
142
+	\write '(          see etc/asma.moon for instructions          )\n'
143
+	\write '\n('
144
+	\write fmt 'label', 'less than', 'greater than', 'key', 'data )'
145
+	\write '\n'
146
+	for name, tree in spairs trees
147
+		\write '@%s\n'\format name
148
+		lefts, rights, entry = traverse_tree tree
149
+		sort_fn = if name == 'asma-opcodes'
150
+			if rights[opcodes_in_order[1]]
151
+				rights[opcodes_in_order[1]] ..= ' &_disasm'
152
+			else
153
+				rights[opcodes_in_order[1]] = ' $2 &_disasm'
154
+			ordered_opcodes
155
+		else
156
+			spairs
157
+		for k, v in sort_fn tree
158
+			label = if k == entry
159
+				'&_entry'
160
+			elseif k
161
+				'&%s'\format k
162
+			else
163
+				''
164
+			\write fmt label, lefts[k] or ' $2', rights[k] or ' $2', unpack v
165
+		\write '\n'
166
+	\write '@asma-heap\n\n'
167
+	\close!
168
+os.execute 'mv projects/software/asma.usm.tmp projects/software/asma.usm'
169
+
0 170
deleted file mode 100644
... ...
@@ -1,350 +0,0 @@
1
-local build_dag
2
-build_dag = function(t, dag, i, j, level)
3
-  if dag == nil then
4
-    dag = { }
5
-  end
6
-  if i == nil then
7
-    i = 1
8
-  end
9
-  if j == nil then
10
-    j = #t
11
-  end
12
-  if level == nil then
13
-    level = 0
14
-  end
15
-  if i > j then
16
-    return 
17
-  end
18
-  local mid = math.floor((i + j) / 2)
19
-  dag[t[mid]] = {
20
-    (build_dag(t, dag, i, mid - 1, level + 1)),
21
-    (build_dag(t, dag, mid + 1, j, level + 1))
22
-  }
23
-  return t[mid], dag
24
-end
25
-local append_dag
26
-append_dag = function(node, dag, k)
27
-  local i = k > node and 2 or 1
28
-  local next_node = dag[node][i]
29
-  if next_node then
30
-    return append_dag(next_node, dag, k)
31
-  end
32
-  dag[node][i] = k
33
-  dag[k] = { }
34
-end
35
-local build_dag_from_chars
36
-build_dag_from_chars = function(s, ...)
37
-  local t
38
-  do
39
-    local _accum_0 = { }
40
-    local _len_0 = 1
41
-    for i = 1, #s do
42
-      _accum_0[_len_0] = s:sub(i, i)
43
-      _len_0 = _len_0 + 1
44
-    end
45
-    t = _accum_0
46
-  end
47
-  table.sort(t)
48
-  local root, dag = build_dag(t)
49
-  for i = 1, select('#', ...) do
50
-    append_dag(root, dag, (select(i, ...)))
51
-  end
52
-  return root, dag
53
-end
54
-local check_terminals
55
-check_terminals = function(dag, s)
56
-  for i = 1, #s do
57
-    local k = s:sub(i, i)
58
-    assert(not dag[k][1], ('%s has left child node'):format(k))
59
-    assert(not dag[k][2], ('%s has right child node'):format(k))
60
-  end
61
-end
62
-local dump
63
-dump = function(f, root, dag, level)
64
-  if level == nil then
65
-    level = 0
66
-  end
67
-  if dag[root][1] then
68
-    dump(f, dag[root][1], dag, level + 1)
69
-  end
70
-  f:write(('    '):rep(level))
71
-  f:write(root)
72
-  f:write('\n')
73
-  if dag[root][2] then
74
-    return dump(f, dag[root][2], dag, level + 1)
75
-  end
76
-end
77
-local convert = setmetatable({
78
-  ['.'] = 'dot',
79
-  ['\0'] = 'nul'
80
-}, {
81
-  __index = function(self, k)
82
-    return k
83
-  end
84
-})
85
-local write_opcode_tree
86
-do
87
-  local byte_to_opcode = { }
88
-  local byte = false
89
-  for l in assert(io.lines('src/assembler.c')) do
90
-    if l:match('^%s*char%s+ops%[%]%[4%]') then
91
-      byte = 0
92
-    elseif l:match('%}') then
93
-      byte = false
94
-    elseif byte then
95
-      for opcode in l:gmatch('"([A-Z-][A-Z-][A-Z-])"') do
96
-        byte_to_opcode[byte] = opcode
97
-        byte = byte + 1
98
-      end
99
-    end
100
-  end
101
-  local order_to_opcode
102
-  do
103
-    local _accum_0 = { }
104
-    local _len_0 = 1
105
-    for i = 0, #byte_to_opcode do
106
-      if byte_to_opcode[i] ~= '---' then
107
-        _accum_0[_len_0] = byte_to_opcode[i]
108
-        _len_0 = _len_0 + 1
109
-      end
110
-    end
111
-    order_to_opcode = _accum_0
112
-  end
113
-  table.sort(order_to_opcode)
114
-  local root, opcode_to_links = build_dag(order_to_opcode)
115
-  write_opcode_tree = function(f)
116
-    f:write(('\t$tree   .$op-%s ( opcode tree )\n'):format(root:lower()))
117
-    f:write('\t$start\n')
118
-    for i = 0, #byte_to_opcode do
119
-      local opcode = byte_to_opcode[i]
120
-      f:write('\t')
121
-      if opcode ~= '---' then
122
-        f:write(('$op-%s '):format(opcode:lower()))
123
-      else
124
-        f:write('        ')
125
-      end
126
-      for j = 1, 2 do
127
-        if opcode ~= '---' and opcode_to_links[opcode][j] then
128
-          f:write(('.$op-%s '):format(opcode_to_links[opcode][j]:lower()))
129
-        else
130
-          f:write('[ 0000 ] ')
131
-        end
132
-      end
133
-      if i == 0 then
134
-        f:write('$disasm ')
135
-      else
136
-        f:write('        ')
137
-      end
138
-      if opcode ~= '---' then
139
-        f:write(('[ %s ]'):format(opcode))
140
-      else
141
-        f:write('[ ??? ]')
142
-      end
143
-      if i == 0 then
144
-        f:write(' $asm')
145
-      end
146
-      f:write('\n')
147
-    end
148
-  end
149
-end
150
-local type_byte
151
-type_byte = function(size, has_subtree)
152
-  local n1 = has_subtree and '8' or '0'
153
-  local n2
154
-  local _exp_0 = size
155
-  if '1' == _exp_0 then
156
-    n2 = '1'
157
-  elseif '2' == _exp_0 then
158
-    n2 = '2'
159
-  else
160
-    n2 = '0'
161
-  end
162
-  return n1 .. n2
163
-end
164
-local globals = { }
165
-local add_globals
166
-add_globals = function(root, dag, key_to_label, key_to_contents, pad_before, pad_after)
167
-  if pad_before == nil then
168
-    pad_before = ''
169
-  end
170
-  if pad_after == nil then
171
-    pad_after = ''
172
-  end
173
-  for k in pairs(dag) do
174
-    local l = ''
175
-    if k == root then
176
-      l = l .. ('@%s\n'):format(key_to_label('root'):gsub('%s', ''))
177
-    end
178
-    l = l .. ('@%s '):format(key_to_label(k))
179
-    for j = 1, 2 do
180
-      if dag[k][j] then
181
-        l = l .. ('.%s '):format(key_to_label(dag[k][j]))
182
-      else
183
-        l = l .. ('%s[ 0000 ]%s '):format(pad_before, pad_after)
184
-      end
185
-    end
186
-    l = l .. key_to_contents(k)
187
-    l = l .. '\n'
188
-    globals[key_to_label(k):gsub('%s', '')] = l
189
-  end
190
-  globals[key_to_label('root'):gsub('%s', '')] = ''
191
-end
192
-do
193
-  local root, dag = build_dag_from_chars('{}[]%@$;|=~,.^#"\0', '(', ')')
194
-  check_terminals(dag, ')')
195
-  local label_name
196
-  label_name = function(s)
197
-    return ('normal-%-3s'):format(convert[s])
198
-  end
199
-  local label_value
200
-  label_value = function(k)
201
-    return ('[ %02x ]'):format(k:byte())
202
-  end
203
-  add_globals(root, dag, label_name, label_value, '', '   ')
204
-end
205
-do
206
-  local root, dag = build_dag_from_chars('{}', '\0', '(')
207
-  dump(io.stdout, root, dag)
208
-  local label_name
209
-  label_name = function(s)
210
-    if s == '(' then
211
-      return 'normal-(  '
212
-    end
213
-    return ('variable-%s'):format(convert[s])
214
-  end
215
-  local label_value
216
-  label_value = function(k)
217
-    return ('[ %02x ]'):format(k:byte())
218
-  end
219
-  dag['('] = nil
220
-  add_globals(root, dag, label_name, label_value, '', '   ')
221
-end
222
-do
223
-  local root, dag = build_dag_from_chars('{}\0', '(')
224
-  dump(io.stdout, root, dag)
225
-  local label_name
226
-  label_name = function(s)
227
-    if s == '(' then
228
-      return 'normal-(  '
229
-    end
230
-    return ('macro-%-3s'):format(convert[s])
231
-  end
232
-  local label_value
233
-  label_value = function(k)
234
-    return ('[ %02x ]'):format(k:byte())
235
-  end
236
-  dag['('] = nil
237
-  add_globals(root, dag, label_name, label_value, '', '   ')
238
-end
239
-do
240
-  local root, dag = build_dag_from_chars(']\0', '(')
241
-  dump(io.stdout, root, dag)
242
-  local label_name
243
-  label_name = function(s)
244
-    if s == '(' then
245
-      return 'normal-(  '
246
-    end
247
-    return ('data-%-4s'):format(convert[s])
248
-  end
249
-  local label_value
250
-  label_value = function(k)
251
-    return ('[ %02x ]'):format(k:byte())
252
-  end
253
-  dag['('] = nil
254
-  add_globals(root, dag, label_name, label_value, '', '   ')
255
-end
256
-local devices = { }
257
-local add_device
258
-add_device = function(name, fields)
259
-  local field_sizes
260
-  do
261
-    local _tbl_0 = { }
262
-    for k, size in fields:gmatch('(%S+) (%d+)') do
263
-      _tbl_0[k] = size
264
-    end
265
-    field_sizes = _tbl_0
266
-  end
267
-  field_sizes.pad = nil
268
-  local field_names
269
-  do
270
-    local _accum_0 = { }
271
-    local _len_0 = 1
272
-    for k in pairs(field_sizes) do
273
-      _accum_0[_len_0] = k
274
-      _len_0 = _len_0 + 1
275
-    end
276
-    field_names = _accum_0
277
-  end
278
-  table.sort(field_names)
279
-  local root, dag = build_dag(field_names)
280
-  local label_name
281
-  label_name = function(k)
282
-    return ('l-%-14s'):format(name .. '-' .. k)
283
-  end
284
-  local label_value
285
-  label_value = function(k)
286
-    return ('%-17s [ %s ] .%s.%s'):format(('[ %s 00 ]'):format(k), type_byte(field_sizes[k], false), name, k)
287
-  end
288
-  add_globals(root, dag, label_name, label_value, ' ', '        ')
289
-  return table.insert(devices, name)
290
-end
291
-local add_devices
292
-add_devices = function()
293
-  table.sort(devices)
294
-  local root, dag = build_dag(devices)
295
-  local label_name
296
-  label_name = function(k)
297
-    return ('l-%-14s'):format(k)
298
-  end
299
-  local label_value
300
-  label_value = function(k)
301
-    return ('%-17s [ %s ] .%s .l-%s-root'):format(('[ %s 00 ]'):format(k), type_byte(0, true), k, k)
302
-  end
303
-  return add_globals(root, dag, label_name, label_value, ' ', '        ')
304
-end
305
-local filename = 'projects/software/assembler.usm'
306
-local f = assert(io.open(('%s.tmp'):format(filename), 'w'))
307
-local state = 'normal'
308
-local machine = {
309
-  normal = function(l)
310
-    if l:match('%( opcode tree %)') then
311
-      write_opcode_tree(f)
312
-      state = 'opcode'
313
-    elseif l:match('^%@') then
314
-      if l == '@RESET' then
315
-        add_devices()
316
-      end
317
-      for k in l:gmatch('%@(%S+)') do
318
-        if globals[k] then
319
-          f:write(globals[k])
320
-          globals[k] = nil
321
-          return 
322
-        end
323
-      end
324
-      f:write(l)
325
-      return f:write('\n')
326
-    else
327
-      if l:match('^%|%x%x%x%x %;') then
328
-        add_device(l:match('%;(%S+) %{ (.*) %}'))
329
-      end
330
-      f:write(l)
331
-      return f:write('\n')
332
-    end
333
-  end,
334
-  opcode = function(l)
335
-    if not l:match('.') then
336
-      f:write(l)
337
-      f:write('\n')
338
-      state = 'normal'
339
-    end
340
-  end
341
-}
342
-for l in assert(io.lines(filename)) do
343
-  machine[state](l)
344
-end
345
-for _, l in pairs(globals) do
346
-  f:write(l)
347
-end
348
-f:close()
349
-assert(0 == os.execute(('mv %s %s.bak'):format(filename, filename)))
350
-return assert(0 == os.execute(('mv %s.tmp %s'):format(filename, filename)))
351 0
deleted file mode 100644
... ...
@@ -1,210 +0,0 @@
1
-build_dag = (t, dag = {}, i = 1, j = #t, level = 0) ->
2
-	if i > j
3
-		return
4
-	mid = math.floor (i + j) / 2
5
-	dag[t[mid]] = {
6
-		(build_dag t, dag, i, mid - 1, level + 1)
7
-		(build_dag t, dag, mid + 1, j, level + 1)
8
-	}
9
-	t[mid], dag
10
-append_dag = (node, dag, k) ->
11
-	i = k > node and 2 or 1
12
-	next_node = dag[node][i]
13
-	if next_node
14
-		return append_dag next_node, dag, k
15
-	dag[node][i] = k
16
-	dag[k] = {}
17
-build_dag_from_chars = (s, ...) ->
18
-	t = [ s\sub i, i for i = 1, #s ]
19
-	table.sort t
20
-	root, dag = build_dag t
21
-	for i = 1, select '#', ...
22
-		append_dag root, dag, (select i, ...)
23
-	return root, dag
24
-check_terminals = (dag, s) ->
25
-	for i = 1, #s
26
-		k = s\sub i, i
27
-		assert not dag[k][1], '%s has left child node'\format k
28
-		assert not dag[k][2], '%s has right child node'\format k
29
-dump = (f, root, dag, level = 0) ->
30
-	if dag[root][1]
31
-		dump f, dag[root][1], dag, level + 1
32
-	f\write '    '\rep level
33
-	f\write root
34
-	f\write '\n'
35
-	if dag[root][2]
36
-		dump f, dag[root][2], dag, level + 1
37
-
38
-convert = setmetatable { ['.']: 'dot', ['\0']: 'nul' },
39
-	__index: (k) => k
40
-
41
-write_opcode_tree = do
42
-	byte_to_opcode = {}
43
-	byte = false
44
-	for l in assert io.lines 'src/assembler.c'
45
-		if l\match '^%s*char%s+ops%[%]%[4%]'
46
-			byte = 0
47
-		elseif l\match '%}'
48
-			byte = false
49
-		elseif byte
50
-			for opcode in l\gmatch '"([A-Z-][A-Z-][A-Z-])"'
51
-				byte_to_opcode[byte] = opcode
52
-				byte += 1
53
-	order_to_opcode = [ byte_to_opcode[i] for i = 0, #byte_to_opcode when byte_to_opcode[i] != '---' ]
54
-	table.sort order_to_opcode
55
-	root, opcode_to_links = build_dag order_to_opcode
56
-	(f) ->
57
-		f\write '\t$tree   .$op-%s ( opcode tree )\n'\format root\lower!
58
-		f\write '\t$start\n'
59
-		for i = 0, #byte_to_opcode
60
-			opcode = byte_to_opcode[i]
61
-			f\write '\t'
62
-			if opcode != '---'
63
-				f\write '$op-%s '\format opcode\lower!
64
-			else
65
-				f\write '        '
66
-			for j = 1, 2
67
-				if opcode != '---' and opcode_to_links[opcode][j]
68
-					f\write '.$op-%s '\format opcode_to_links[opcode][j]\lower!
69
-				else
70
-					f\write '[ 0000 ] '
71
-			if i == 0
72
-				f\write '$disasm '
73
-			else
74
-				f\write '        '
75
-			if opcode != '---'
76
-				f\write '[ %s ]'\format opcode
77
-			else
78
-				f\write '[ ??? ]'
79
-			if i == 0
80
-				f\write ' $asm'
81
-			f\write '\n'
82
-
83
-type_byte = (size, has_subtree) ->
84
-	n1 = has_subtree and '8' or '0'
85
-	n2 = switch size
86
-		when '1'
87
-			'1'
88
-		when '2'
89
-			'2'
90
-		else
91
-			'0'
92
-	n1 .. n2
93
-
94
-globals = {}
95
-
96
-add_globals = (root, dag, key_to_label, key_to_contents, pad_before = '', pad_after = '') ->
97
-	for k in pairs dag
98
-		l = ''
99
-		if k == root
100
-			l ..= '@%s\n'\format key_to_label('root')\gsub '%s', ''
101
-		l ..= '@%s '\format key_to_label k
102
-		for j = 1, 2
103
-			if dag[k][j]
104
-				l ..= '.%s '\format key_to_label dag[k][j]
105
-			else
106
-				l ..= '%s[ 0000 ]%s '\format pad_before, pad_after
107
-		l ..= key_to_contents k
108
-		l ..= '\n'
109
-		globals[key_to_label(k)\gsub '%s', ''] = l
110
-	globals[key_to_label('root')\gsub '%s', ''] = ''
111
-
112
-do
113
-	root, dag = build_dag_from_chars '{}[]%@$;|=~,.^#"\0', '(', ')'
114
-	check_terminals dag, ')'
115
-	label_name = (s) -> 'normal-%-3s'\format convert[s]
116
-	label_value = (k) -> '[ %02x ]'\format k\byte!
117
-	add_globals root, dag, label_name, label_value, '', '   '
118
-
119
-do
120
-	root, dag = build_dag_from_chars '{}', '\0', '('
121
-	dump io.stdout, root, dag
122
-	label_name = (s) ->
123
-		if s == '('
124
-			return 'normal-(  '
125
-		'variable-%s'\format convert[s]
126
-	label_value = (k) -> '[ %02x ]'\format k\byte!
127
-	dag['('] = nil
128
-	add_globals root, dag, label_name, label_value, '', '   '
129
-
130
-do
131
-	root, dag = build_dag_from_chars '{}\0', '('
132
-	dump io.stdout, root, dag
133
-	label_name = (s) ->
134
-		if s == '('
135
-			return 'normal-(  '
136
-		'macro-%-3s'\format convert[s]
137
-	label_value = (k) -> '[ %02x ]'\format k\byte!
138
-	dag['('] = nil
139
-	add_globals root, dag, label_name, label_value, '', '   '
140
-
141
-do
142
-	root, dag = build_dag_from_chars ']\0', '('
143
-	dump io.stdout, root, dag
144
-	label_name = (s) ->
145
-		if s == '('
146
-			return 'normal-(  '
147
-		'data-%-4s'\format convert[s]
148
-	label_value = (k) -> '[ %02x ]'\format k\byte!
149
-	dag['('] = nil
150
-	add_globals root, dag, label_name, label_value, '', '   '
151
-
152
-devices = {}
153
-
154
-add_device = (name, fields) ->
155
-	field_sizes = { k, size for k, size in fields\gmatch '(%S+) (%d+)' }
156
-	field_sizes.pad = nil
157
-	field_names = [ k for k in pairs field_sizes ]
158
-	table.sort field_names
159
-	root, dag = build_dag field_names
160
-	label_name = (k) -> 'l-%-14s'\format name .. '-' .. k
161
-	label_value = (k) -> '%-17s [ %s ] .%s.%s'\format '[ %s 00 ]'\format(k), type_byte(field_sizes[k], false), name, k
162
-	add_globals root, dag, label_name, label_value, ' ', '        '
163
-	table.insert devices, name
164
-
165
-add_devices = ->
166
-	table.sort devices
167
-	root, dag = build_dag devices
168
-	label_name = (k) -> 'l-%-14s'\format k
169
-	label_value = (k) -> '%-17s [ %s ] .%s .l-%s-root'\format '[ %s 00 ]'\format(k), type_byte(0, true), k, k
170
-	add_globals root, dag, label_name, label_value, ' ', '        '
171
-
172
-filename = 'projects/software/assembler.usm'
173
-
174
-f = assert io.open '%s.tmp'\format(filename), 'w'
175
-state = 'normal'
176
-machine =
177
-	normal: (l) ->
178
-		if l\match '%( opcode tree %)'
179
-			write_opcode_tree f
180
-			state = 'opcode'
181
-		elseif l\match '^%@'
182
-			if l == '@RESET'
183
-				add_devices!
184
-			for k in l\gmatch '%@(%S+)'
185
-				if globals[k]
186
-					f\write globals[k]
187
-					globals[k] = nil
188
-					return
189
-			f\write l
190
-			f\write '\n'
191
-		else
192
-			if l\match '^%|%x%x%x%x %;'
193
-				add_device l\match '%;(%S+) %{ (.*) %}'
194
-			f\write l
195
-			f\write '\n'
196
-	opcode: (l) ->
197
-		if not l\match '.'
198
-			f\write l
199
-			f\write '\n'
200
-			state = 'normal'
201
-for l in assert io.lines filename
202
-	machine[state] l
203
-for _, l in pairs globals
204
-	f\write l
205
-f\close!
206
-assert 0 == os.execute 'mv %s %s.bak'\format filename, filename
207
-assert 0 == os.execute 'mv %s.tmp %s'\format filename, filename
208
-
... ...
@@ -1,910 +1,753 @@
1
-( asma: in-Uxn assembler (not working yet, in progress) )
2
-
3
-%HCF { #0000 DIV }
4
-%SHORT_FLAG { #20 }
5
-%RETURN_FLAG { #40 }
6
-
7 1
 ( devices )
8 2
 
9
-|00 @System [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ]
10
-|10 @Console [ &vector $2 &pad $6 &char $1 &byte $1 &short $2 &string $2 ]
11
-|20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &color $1 ]
12
-|30 @Audio [ &wave $2 &envelope $2 &pad $4 &volume $1 &pitch $1 &play $1 &value $2 &delay $2 &finish $1 ]
13
-|80 @Controller [ &vector $2 &button $1 &key $1 ]
14
-|90 @Mouse [ &vector $2 &x $2 &y $2 &state $1 &chord $1 ]
15
-|a0 @File [ &vector $2 &success $2 &offset $2 &pad $2 &name $2 &length $2 &load $2 &save $2 ]
16
-|b0 @DateTime [ &year $2 &month $1 &day $1 &hour $1 &minute $1 &second $1 &dotw $1 &doty $2 &isdst $1 ]
17
-
18
-( variables )
19
-
20
-|0000
21
-
22
-@tree [ &search-key $2 &max-key-len $1 ]
23
-@assembler [ &pass $1 &state $1 &token $2 &scope-len $1 &scope $80 &heap $2 &addr $2 &subtree $2 &field_size $2 &var_size $2 &field $2 ]
3
+|10 @Console    [ &pad    $8 &char     $1 &byte   $1 &short $2 &string $2 ]
4
+|a0 @File       [ &vector $2 &success  $2 &offset $2 &pad   $2 &name  $2 &length $2 &load $2 &save $2 ]
24 5
 
25 6
 ( vectors )
26 7
 
27
-|0100 ,RESET JMP
28
-
29
-@RESET
30
-	;assembler-heap-start .assembler/heap POK2
31
-
32
-	;&read-filename ,assemble-file JSR
33
-	HCF
34
-
35
-	HCF
36
-
37
-	&read-filename [ "projects/software/noodle.usm 00 ]
38
-
39
-@assemble-file ( filename-ptr* -- )
8
+|0100
9
+
10
+%asma-IF-ERROR { ;asma/error LDA2 ORA }
11
+
12
+@reset
13
+	;asma-init-assembler JSR2
14
+	;&filename ,asma-assemble-file-pass JSR
15
+	asma-IF-ERROR ,asma-print-error JNZ
16
+	;asma-init-assembler-pass JSR2
17
+	;&filename ,asma-assemble-file-pass JSR
18
+	asma-IF-ERROR ,asma-print-error JNZ
19
+	BRK
20
+
21
+	&filename
22
+		( "test.usm 00 )
23
+		"projects/software/noodle.usm 00
24
+
25
+@asma-print-error ( -- )
26
+	;asma/error LDA2 .Console/string DEO2
27
+	#3a .Console/char DEO
28
+	#20 .Console/char DEO
29
+	;asma/orig-token LDA2 .Console/string DEO2
30
+	;&line .Console/string DEO2
31
+	;asma/line LDA2 .Console/short DEO2
32
+	#2e .Console/char DEO
33
+	#0a .Console/char DEO
34
+	BRK
35
+
36
+	&line 20 "on 20 "line 20 00
37
+
38
+@asma-assemble-file-pass ( filename-ptr* -- )
40 39
 	#0000
41 40
 
42 41
 	&loop
43 42
 	OVR2 .File/name DEO2
44 43
 	DUP2 .File/offset DEO2
45
-	#0600 .File/length DEO2
46
-	#f000 DUP2 DUP2 .File/load DEO2
47
-	.File/success DEI2 DUP2 #0000 EQU2 ,&end JNZ
48
-	,assemble-chunk JSR
44
+	#0100 .File/length DEO2
45
+	#fe00 DUP2 DUP2 .File/load DEO2
46
+	.File/success DEI2 DUP2 ORA ,&not-end JNZ
47
+	POP2 POP2
48
+	&error
49
+	POP2 POP2 POP2
50
+	JMP2r
51
+
52
+	&not-end
53
+	,asma-assemble-chunk JSR asma-IF-ERROR ,&error JNZ
49 54
 	SUB2 SUB2
50 55
 	,&loop JMP
51 56
 
52
-	&end
53
-	POP2 POP2 POP2 POP2 POP2
54
-	JMP2r
57
+@asma-init-assembler ( -- )
58
+	#ff ;asma/pass STA
59
+	#0000 ;asma/error STA2
60
+	;asma-heap ;asma/heap STA2
61
+	;asma-labels/_entry ;asma-trees/labels STA2
62
+	( FIXME should walk the label tree and remove any in the heap )
63
+	;asma-opcodes/_entry ;asma-trees/opcodes STA2
64
+	#0000 ;asma-trees/macros STA2
55 65
 
56
-@assemble-chunk ( ptr* len* -- assembled-up-to-ptr*  )
57
-	( FIXME we still return on seeing 00 in source code,
58
-	while assemble-file is now binary safe )
59
-	OVR2 ADD2 STH2
60
-	#0001 SUB2
66
+@asma-init-assembler-pass ( -- )
67
+	;asma/pass LDA #01 ADD ;asma/pass STA
68
+	#00 ;asma/state STA
69
+	#0000 ;asma/addr STA2
70
+	#0001 ;asma/line STA2
71
+	JMP2r
61 72
 
62
-	&per-token
63
-	DUP2 STH2
73
+@asma-assemble-chunk ( ptr* len* -- assembled-up-to-ptr* )
74
+	OVR2 ADD2 #0001 SUB2 SWP2 DUP2 STH2
75
+	,&loop JMP
64 76
 
65
-	&loop
77
+	&next-char-pop
78
+	POP
79
+	&next-char
66 80
 	#0001 ADD2
67
-	DUP2 LDA
68
-	#20 GTH ,&loop JNZ
81
+	&loop ( last-ptr* ptr* / start-of-token* )
82
+	OVR2 OVR2 LTH2 ,&end JNZ
83
+	DUP2 LDA ( last-ptr* ptr* char / start-of-token* )
84
+	DUP #20 GTH ,&next-char-pop JNZ
69 85
 
70
-	DUP2 OVR2r STH2r LTS2 ,&valid JNZ
71
-	SWP2r POP2r POP2
72
-	STH2r #0001 ADD2
73
-	JMP2r
86
+	#00 OVR2 ( last-ptr* ptr* char 00 ptr* / start-of-token* )
87
+	STA
88
+	STH2r ,asma-assemble-token JSR asma-IF-ERROR ,&error JNZ
74 89
 
75
-	&valid
76
-	DUP2 LDA #00 OVR2 STA
77
-	STH2r #0001 ADD2 ,assemble-token JSR
78
-	,&per-token JNZ
90
+	#0a NEQ ,&not-newline JNZ
91
+	;asma/line LDA2 #0001 ADD2 ;asma/line STA2
92
+	&not-newline
79 93
 
80
-	POP2r JMP2r
81
-
82
-@assemble-macro ( macro-ptr* -- )
83
-	DUP2 ;strlen JSR2 DUP2 #0000 EQU2 ,&end JNZ
84
-	OVR2 ,assemble-token JSR
85
-	ADD2 #0001 ADD2
86
-	,assemble-macro JMP
94
+	DUP2 #0001 ADD2 STH2 ,&next-char JMP
87 95
 
88 96
 	&end
89
-	POP2 POP2
97
+	POP2 POP2 STH2r
90 98
 	JMP2r
91 99
 
92
-@assemble-token ( string-ptr* -- )
93
-	( get location of tree )
94
-	DUP2
95
-	;state-machine-pointers #00 .assembler/state PEK ;highest-bit JSR2 #0004 MUL2 ADD2
96
-	DUP2 STH2
97
-	( see if first char is recognised )
98
-	SWP2 #01 ;traverse-tree JSR2
99
-	,&not-found JNZ
100
-	( skip first character of token )
101
-	SWP2 #0001 ADD2 .assembler/token POK2
102
-	( tail call handling function defined in tree )
103
-	POP2r JMP2
104
-
105
-	&not-found
106
-	( not interested in incoming-ptr )
107
-	POP2
108
-	.assembler/token POK2
109
-	( tail call default handling function defined in state-machine-pointers )
110
-	LIT2r [ 0002 ] ADD2r LDA2r
100
+	&error
101
+	POP POP2 POP2
111 102
 	JMP2r
112 103
 
113
-@parse-hex-length ( string-ptr* -- value 01 if one or two hex digits
114
-                                OR 00 otherwise )
115
-	DUP2 #0001 ADD2 LDA ,parse-hex-string/try-two JNZ
116
-	LDA ,parse-hex-digit JSR DUP #04 SFT ,parse-hex-string/fail1 JNZ
117
-	#01 JMP2r
104
+@asma [ &pass $1 &state $1 &line $2 &token $2 &orig-token $2 &heap $2 &addr $2 &scope-addr $2 &error $2 ]
105
+@asma-trees [ &labels $2 &macros $2 &opcodes $2 &scope $2 ]
118 106
 
119
-@parse-hex-string ( string-ptr* -- value* 02 if four hex digits
120
-                                OR value 01 if two hex digits
121
-                                OR 00 otherwise )
122
-	DUP2 #0004 ADD2 LDA #00 EQU ,&try-four JNZ
123
-	&try-two
124
-	DUP2 #0002 ADD2 LDA ,&fail2 JNZ
125
-	&known-two
126
-	DUP2 LDA ,parse-hex-digit JSR DUP #04 SFT ,&fail3 JNZ ROT ROT
127
-	#0001 ADD2 LDA ,parse-hex-digit JSR DUP #04 SFT ,&fail2 JNZ
128
-	SWP #40 SFT ORA #01 JMP2r
129
-
130
-	&fail3 POP
131
-	&fail2 POP
132
-	&fail1 POP #00 JMP2r
133
-
134
-	&try-four
135
-	DUP2 #0002 ADD2 ,&known-two JSR ,&maybe-four JNZ
136
-	,&try-two JMP
137
-
138
-	&maybe-four
139
-	ROT ROT ,&known-two JSR ,&four JNZ
140
-	,&fail1 JMP
141
-
142
-	&four
143
-	SWP #02 JMP2r
144
-
145
-@parse-hex-digit ( charcode -- 00-0f if valid hex
146
-                            -- 10-ff otherwise )
147
-	DUP #3a LTH ,&digit JNZ
148
-	DUP #60 GTH ,&lowercase JNZ
149
-	DUP #40 GTH ,&uppercase JNZ
107
+@asma-assemble-token ( string-ptr* -- )
108
+	DUP2 .Console/string DEO2 #0a .Console/char DEO
109
+	DUP2 ;asma/token STA2
110
+	DUP2 ;asma/orig-token STA2
111
+	DUP2 LDA ,&not-empty JNZ
112
+	POP2
150 113
 	JMP2r
151 114
 
152
-	&digit ( #30 is #00 )
153
-	#30 SUB JMP2r
154
-
155
-	&lowercase ( #61 is #0a )
156
-	#57 SUB JMP2r
115
+	&not-empty ( token* / )
116
+	( truncate to one char long )
117
+	#0001 ADD2 ( end* / )
118
+	DUP2 STH2 DUP2r LDAr ( end* / end* char )
119
+	DUP2 STH2 ( end* / end* char end* )
120
+	LITr 00 STH2 ( / end* char end* 00 end* )
121
+	STAr ( / end* char end* )
157 122
 
158
-	&uppercase ( #41 is #0a )
159
-	#37 SUB JMP2r
123
+	( find lowest set bit of assembler/state
124
+	  in C, this would be i & -i )
125
+	#00 ;asma/state LDA DUP2 SUB AND ( tree-offset* / end* )
126
+	DUP2 ;&first-char-trees ADD2 ( tree-offset* incoming-ptr* / end* )
127
+	;asma-traverse-tree JSR2
160 128
 
161
-@find-opcode ( name* -- byte 00 if valid opcode name
162
-                     OR 01 if not found )
163
-	;opcodes/tree SWP2 #03 ,traverse-tree JSR
164
-	,&nomatch JNZ
165
-	;opcodes/asm SUB2 #0007 DIV2
166
-	SWP JMP2r
129
+	( restore truncated char )
130
+	STAr
167 131
 
168
-	&nomatch
169
-	DUP2 EQU2 JMP2r
132
+	,&not-found JNZ
170 133
 
171
-@traverse-tree ( tree-ptr* search-key* max-key-len --
172
-		binary-ptr* 00 if key matched
173
-		OR incoming-ptr* 01 if key not found )
174
-	.tree/max-key-len POK .tree/search-key POK2
134
+	( tree-offset* token-routine-ptr* / end* )
135
+	STH2r ;asma/token STA2
136
+	SWP2 POP2 LDA2
137
+	JMP2 ( tail call )
175 138
 
176
-	&loop
177
-	DUP2 LDA2 #0000 NEQ2 ,&valid-node JNZ
178
-	#01 JMP2r
139
+	&not-found ( tree-offset* dummy* / end* )
140
+	POP2 POP2r
141
+	;&first-char-dispatch ADD2 LDA2
142
+	JMP2 ( tail call )
179 143
 
180
-	&valid-node
181
-	LDA2 DUP2 STH2 #0004 ADD2 ,strcmp-tree JSR
182
-	DUP ,&nomatch JNZ
183
-	POP2r JMP2r
144
+	&first-char-trees
145
+		:asma-first-char-normal/_entry
146
+		:asma-first-char-comment/_entry
147
+		:asma-first-char-macro/_entry
184 148
 
185
-	&nomatch
186
-	#07 SFT #02 MUL #00 SWP
187
-	STH2r ADD2
188
-	,&loop JMP
149
+	&first-char-dispatch
150
+		:asma-normal-body
151
+		:asma-ignore
152
+		:asma-macro-body
189 153
 
190
-@strcmp-tree ( node-key* -- order if strings differ
191
-                         OR after-node-key* 00 if strings match )
192
-	.tree/search-key PEK2 STH2
193
-	.tree/max-key-len PEK
154
+@asma-parse-hex-digit ( charcode -- 00-0f if valid hex
155
+                                 OR 10-ff otherwise )
156
+	DUP #3a LTH ,&digit JNZ
157
+	DUP #60 GTH ,&letter JNZ
158
+	JMP2r
194 159
 
195
-	&loop ( node-key* key-len in wst, search-key* in rst )
196
-	DUP ,&keep-going JNZ
160
+	&digit
161
+	#30 SUB
162
+	JMP2r
197 163
 
198
-	( exhausted key-len, match found )
199
-	POP2r
164
+	&letter
165
+	#57 SUB
200 166
 	JMP2r
201 167
 
202
-	&keep-going
203
-	#01 OVR2 LDA DUP2r LDAr STHr
204
-	DUP2 ORA ,&not-end JNZ
168
+@asma-parse-hex-string ( -- value* 06 if valid hex and length > 2
169
+                         OR value* 03 if valid hex and length <= 2
170
+                         OR 00 otherwise )
171
+	;asma/token LDA2 DUP2 ,asma-strlen JSR #02 GTH ROT ROT
172
+	LIT2r 0000
205 173
 
206
-	( end of C strings, match found )
207
-	POP2r POP ROT POP SWP ADD2 #00
174
+	&loop
175
+	DUP2 LDA
176
+	DUP ,&not-end JNZ
177
+	POP POP2
178
+	STH2r ROT #01 ADD #03 MUL
208 179
 	JMP2r
209 180
 
210 181
 	&not-end
211
-	SUB DUP ,&nomatch JNZ
212
-	POP SUB
213
-	LIT2r [ 0001 ] ADD2r STH
214
-	LIT2  [ 0001 ] ADD2  STHr
182
+	,asma-parse-hex-digit JSR
183
+	DUP #f0 AND ,&fail JNZ
184
+	LIT2r 0010 MUL2r
185
+	#00 STH STH ADD2r
186
+	#0001 ADD2
215 187
 	,&loop JMP
216 188
 
217
-	&nomatch
218
-	STH POP2 POP2 STHr POP2r
219
-	JMP2r
220
-
221
-@highest-bit ( n -- 00 if n is 00
222
-                 OR 01 if n is 01
223
-                 OR 02 if n is 02..03
224
-                 OR 03 if n is 04..07
225
-                 OR 04 if n is 08..0f
226
-                 ..
227
-                 OR 08 if n is 80..ff )
228
-	DUP #00 NEQ JMP JMP2r
229
-	DUP #01 SFT ORA
230
-	DUP #02 SFT ORA
231
-	DUP #04 SFT ORA
232
-	#1d MUL #05 SFT #00 SWP ;&lookup ADD2 LDA
189
+	&fail
190
+	POP POP2 POP2r
191
+	DUP EOR
233 192
 	JMP2r
234 193
 
235
-	&lookup
236
-	[ 01 06 02 07 05 04 03 08 ]
237
-
238
-@memcpy ( src-ptr* dest-ptr* length* -- after-dest-ptr* )
239
-	SWP2 STH2
194
+@asma-strlen ( string-ptr* -- length )
195
+	LITr 00
240 196
 
241 197
 	&loop
242
-	DUP2 ORA ,&keep-going JNZ
243
-	POP2 POP2 STH2r
198
+	DUP2 LDA
199
+	,&not-end JNZ
200
+	POP2 STHr
244 201
 	JMP2r
245 202
 
246
-	&keep-going
247
-	#0001 SUB2
248
-	SWP2 DUP2 LDA DUP2r STH2r STA
249
-	#0001 ADD2 SWP2
250
-	LIT2r [ 0001 ] ADD2r
251
-	,&loop JMP
252
-
253
-@strcpy ( src-ptr* dest-ptr* -- after-dest-ptr* )
254
-	OVR2 ,strlen JSR #0001 ADD2 ,memcpy JMP
255
-
256
-@strlen ( string-ptr* -- length* )
257
-	DUP2 #0001 SUB2
258
-	&loop
203
+	&not-end
204
+	LITr 01 ADDr
259 205
 	#0001 ADD2
260
-	DUP2 LDA ,&loop JNZ
261
-	SWP2 SUB2
262
-	JMP2r
263
-
264
-@append-heap ( string-ptr* -- after-string-ptr* )
265
-	.assembler/heap PEK2 ;strcpy JSR2
266
-	DUP2 .assembler/heap POK2
267
-	JMP2r
206
+	,&loop JMP
268 207
 
269
-@append-tree ( string-ptr* incoming-ptr* -- binary-data* )
270
-	.assembler/heap PEK2 SWP2 STA2
271
-	;&zero-pointers .assembler/heap PEK2 #0004 ,memcpy JSR .assembler/heap POK2
272
-	,append-heap JSR
273
-	JMP2r
208
+%asma-SHORT-FLAG { #20 }
209
+%asma-RETURN-FLAG { #40 }
274 210
 
275
-	&zero-pointers [ 0000 0000 ]
211
+@asma-parse-opcode ( -- byte 00 if valid opcode
212
+                     OR 01 otherwise )
213
+	;asma/token LDA2
214
+	DUP2 ,asma-strlen JSR #03 LTH ,&too-short JNZ
276 215
 
277
-@add-label ( label-flags string-ptr* tree-ptr* -- )
278
-	OVR2 #ff ;traverse-tree JSR2
279
-	,&new-label JNZ
216
+	( truncate to three chars long )
217
+	#0003 ADD2 ( end* / )
218
+	DUP2 STH2 DUP2r LDAr ( end* / end* char )
219
+	DUP2 STH2 ( end* / end* char end* )
220
+	LITr 00 STH2 ( / end* char end* 00 end* )
221
+	STAr ( / end* char end* )
280 222
 
281
-	( label already exists, check the flags and addr value )
282
-	SWP2 POP2
283
-	DUP2 #0001 ADD2 LDA2 .assembler/addr PEK2 EQU2 ,&addr-okay JNZ
284
-	( FIXME address is different to previous run, or label defined twice )
285
-	&addr-okay
286
-	LDA EQU ,&type-okay JNZ
287
-	( FIXME node type is different to before )
288
-	&type-okay
289
-	JMP2r
290
-
291
-	&new-label
292
-	,append-tree JSR
293
-	(
294
-	~assembler.heap SWP2 STR2
295
-	,$zero-pointers ~assembler.heap #0004 ^memcpy JSR =assembler.heap
296
-	~assembler.heap ,strcpy JSR2
297
-	)
298
-	
299
-	DUP2 STH2 STA STH2r
300
-	DUP2 #0001 ADD2 .assembler/addr PEK2 SWP2 STA2
301
-	#0003 ADD2 .assembler/heap POK2
302
-	JMP2r
303
-
304
-@lookup-label ( string-ptr* -- address* node-type if found
305
-                            OR false-address* 00 if not found )
306
-	DUP2
307
-	&loop
308
-	DUP2 #0001 ADD2 SWP2 LDA
309
-	DUP #2e EQU ,&dotted JNZ
310
-	,&loop JNZ
311
-	DUP2 EOR2 ( faster than POP2 #0000 )
312
-	.assembler/field POK2
313
-
314
-	&main
315
-	DUP2 ;label-tree SWP2 #ff ;traverse-tree JSR2
316
-	,&not-found JNZ
317
-
318
-	SWP2 POP2
319
-	.assembler/field PEK2 #0000 EQU2 ,&end JNZ
320
-	DUP2 LDA #80 LTH ,&not-found JNZ
321
-	#0003 ADD2 .assembler/field PEK2 #ff ;traverse-tree JSR2
223
+	;asma-trees/opcodes ;asma-traverse-tree JSR2
224
+	STAr
322 225
 	,&not-found JNZ
323 226
 
324
-	&end
325
-	DUP2 #0001 ADD2 LDA2 SWP2 LDA
326
-	JMP2r
327
-
328
-	&not-found
329
-	POP2
330
-	( FIXME complain about missing label )
331
-	POP2
332
-	( false-address is out of reach for JMP )
333
-	.assembler/addr PEK2 #8765 ADD2
334
-	#00
335
-	JMP2r
336
-
337
-	&dotted
338
-	DUP OVR2 .assembler/field POK2
339
-	EOR ROT ROT #0001 SUB2 STA
340
-	,&main JMP
341
-
342
-@write-byte ( byte -- )
343
-	( FIXME )  .Console/byte DEO
344
-	.assembler/addr PEK2 #0001 ADD2 .assembler/addr POK2
345
-	JMP2r
346
-
347
-@write-short ( short -- )
348
-	( FIXME )  .Console/short DEO2
349
-	.assembler/addr PEK2 #0002 ADD2 .assembler/addr POK2
350
-	JMP2r
351
-
352
-@label-tree :l-root
353
-@macro-tree [ 0000 ]
354
-
355
-@opcodes
356
-	(
357
-		The code for this section is automatically generated, and needs to be
358
-		regenerated when the opcode list in src/assembler.c is updated.
359
-
360
-		After editing src/assembler.c, run "lua etc/assembler-trees.lua"
361
-		and this file will be edited automatically.
362
-
363
-		This is the first example of a binary tree in this code, so let's
364
-		explore them in general. The format of a tree node in memory is:
365
-
366
-		left-node* right-node* node-key-cstring binary-data
367
-
368
-		and the general algorithm is to compare the key you're looking for
369
-		against node-key-cstring, and move to the node pointed to by left-node*
370
-		or right-node* if the keys don't match. If your key sorts earlier than
371
-		use left-node*, otherwise go to right-node*. When you find a node that
372
-		matches your key, traverse-bintree gives you a pointer to the
373
-		binary-data straight after the node-key-cstring. This data can contain
374
-		anything you want: fixed length fields, executable code... in this case
375
-		of this opcode tree, we store nothing. traverse-bintree is passed the
376
-		maximum length of node-key-cstring, not including the zero, so the zero
377
-		can be omitted if the string is at that maximum length.
378
-
379
-		If the key isn't present in the tree, you'll eventually get to a node
380
-		where the left-node* or right-node* pointer you'll need to follow is
381
-		null (0000). traverse-bintree will give you the location of that
382
-		pointer, so if you want to insert another node, you can write it to the
383
-		heap and overwrite the pointer with the new node's location. This
384
-		approach works even if the tree is completely empty and the pointer
385
-		you've provided to the root node is null, since that pointer gets
386
-		updated to point to the first node without needing any special logic.
387
-
388
-		The ordering of nodes in memory is totally arbitrary, so for pre-
389
-		prepared trees like this one we can have our own meaning for the order
390
-		of the nodes. By ordering the opcodes by their byte value, we can find
391
-		the byte by subtracting $asm from the binary-data pointer and dividing
392
-		by seven (the size of each node). By multiplying the byte value by seven
393
-		and adding to $disasm, we get the opcode name when disassembling too.
394
-	)
395
-	
396
-	&tree   :&op-lth ( opcode tree )
397
-	&start
398
-	&op-brk :&op-add :&op-dup &disasm [ "BRK ] &asm
399
-	&op-nop :&op-mul :&op-ovr         [ "NOP ]
400
-	&op-lit [ 0000 ] [ 0000 ]         [ "LIT ]
401
-	&op-pop [ 0000 ] [ 0000 ]         [ "POP ]
402
-	&op-dup :&op-div :&op-eor         [ "DUP ]
403
-	&op-swp [ 0000 ] [ 0000 ]         [ "SWP ]
404
-	&op-ovr :&op-ora :&op-pek         [ "OVR ]
405
-	&op-rot :&op-pop :&op-sft         [ "ROT ]
406
-	&op-equ :&op-brk :&op-jnz         [ "EQU ]
407
-	&op-neq [ 0000 ] [ 0000 ]         [ "NEQ ]
408
-	&op-gth [ 0000 ] [ 0000 ]         [ "GTH ]
409
-	&op-lth :&op-equ :&op-pok         [ "LTH ]
410
-	&op-gts :&op-gth :&op-jmp         [ "GTS ]
411
-	&op-lts [ 0000 ] [ 0000 ]         [ "LTS ]
412
-	        [ 0000 ] [ 0000 ]         [ "??? ]
413
-	        [ 0000 ] [ 0000 ]         [ "??? ]
414
-	&op-pek [ 0000 ] [ 0000 ]         [ "PEK ]
415
-	&op-pok :&op-nop :&op-sth         [ "POK ]
416
-	&op-ldr :&op-jsr :&op-lit         [ "LDR ]
417
-	&op-str [ 0000 ] [ 0000 ]         [ "STR ]
418
-	&op-jmp [ 0000 ] [ 0000 ]         [ "JMP ]
419
-	&op-jnz :&op-gts :&op-ldr         [ "JNZ ]
420
-	&op-jsr [ 0000 ] [ 0000 ]         [ "JSR ]
421
-	&op-sth :&op-rot :&op-sub         [ "STH ]
422
-	&op-add [ 0000 ] :&op-and         [ ADD ]
423
-	&op-sub :&op-str :&op-swp         [ "SUB ]
424
-	&op-mul :&op-lts :&op-neq         [ "MUL ]
425
-	&op-div [ 0000 ] [ 0000 ]         [ "DIV ]
426
-	&op-and [ 0000 ] [ 0000 ]         [ "AND ]
427
-	&op-ora [ 0000 ] [ 0000 ]         [ "ORA ]
428
-	&op-eor [ 0000 ] [ 0000 ]         [ "EOR ]
429
-	&op-sft [ 0000 ] [ 0000 ]         [ "SFT ]
430
-
431
-@state-machine-pointers
432
-( normal mode 00 )
433
-:normal-root   :normal-main
434
-( macro definition 01 )
435
-:macro-root    :macro-main
436
-( macro definition, contents ignored 02 )
437
-:macro-root    :ignore
438
-( variable definition, expect field size 04 )
439
-:variable-nul  :variable-size
440
-( variable definition, expect field name 08 )
441
-:variable-root :variable-name
442
-( reserved for future use 10 )
443
-[ 0000 ]       :ignore
444
-( literal data 20 )
445
-:normal-5d     :data-main
446
-( reserved for future use 40 )
447
-[ 0000 ]       :ignore
448
-( comment 80 )
449
-:normal-29     :ignore
450
-
451
-(
452
-	Next up, we have the tree of code corresponding to each token's
453
-	first character. Here we do have a binary payload, which is
454
-	the code to run when the assembler considers the token.
455
-
456
-	Some special assembler modes have their own trees. Since comments
457
-	have a very simple tree that only understands the end of comments,
458
-	we reuse the terminal branch of the main tree as the root of
459
-	the comment tree.
460
-)
461
-
462
-
463
-(
464
-	Left and right parentheses start and end comment sections. They use the
465
-	highest bit in assembler state, so they receive highest priority: it
466
-	doesn't matter what other bits are set, a comment's a comment.
467
-)
468
-
469
-
470
-@normal-28  [ 0000 ]    :normal-29  [ 28 ]
471
-	.assembler/state PEK #80 ORA .assembler/state POK
472
-	JMP2r
473
-
474
-@normal-29  [ 0000 ]    [ 0000 ]    [ 29 ]
475
-	.assembler/state PEK #7f AND .assembler/state POK
476
-	JMP2r
477
-
478
-(
479
-	Ampersands introduce global labels, and define the scope for any
480
-	local labels that follow.
481
-)
482
-
483
-
484
-@normal-@   [ 0000 ]    [ 0000 ]    [ 40 ]
485
-	#00 .assembler/token PEK2 ;label-tree ;add-label JSR2
486
-
487
-	&scope
488
-	.assembler/token PEK2 ;assembler/scope ;strcpy JSR2
489
-	DUP2 ;assembler/scope SUB2 .assembler/scope-len POK POP
490
-	#0001 SUB2 #2d SWP POK POP
491
-	JMP2r
492
-
493
-(
494
-	Dollar signs introduce local labels, which use the scope defined above.
495
-)
496
-
497
-
498
-@normal-24  :normal-"   :normal-,   [ 24 ]
499
-	.assembler/token PEK2
500
-	;assembler/scope .assembler/scope-len PEK ADD
501
-	;strcpy JSR2 POP2
502
-
503
-	#00 ;assembler/scope ;label-tree ;add-label JMP2 ( tail call )
504
-
505
-(
506
-	Hash signs followed by two or four hex digits write a literal.
507
-)
508
-
509
-
510
-@normal-#   [ 0000 ]    [ 0000 ]    [ 23 ]
511
-	.assembler/token PEK2 ;parse-hex-string JSR2
512
-	DUP ,&valid JNZ
513
-	( FIXME complain about invalid hex literal )
514
-	POP
227
+	;asma-opcodes/_disasm SUB2 #0003 SFT2 ( 00 byte / end* )
228
+	&loop
229
+	DUP2r LDAr STHr LIT2r 0001 ADD2r ( 00 byte char / end* )
230
+	DUP ,&not-end JNZ
231
+	POP POP2r
232
+	SWP
515 233
 	JMP2r
516
-	
517
-	&valid
518
-	DUP #01 SUB SHORT_FLAG MUL ( short flag for opcode )
519
-	;opcodes/op-lit ;opcodes/start SUB2 #07 DIV
520
-	ADD ADD ;write-byte JSR2
521 234
 
522
-	&value
523
-	#02 EQU ,&short JNZ
524
-	;write-byte JMP2 ( tail call )
525
-
526
-	&short
527
-	;write-short JMP2 ( tail call )
528
-
529
-(
530
-	Left and right square brackets start and end literal data sections.
531
-)
235
+	&not-end
236
+	DUP LIT '2 NEQ ,&not-two JNZ
237
+	POP asma-SHORT-FLAG ORA ,&loop JMP
532 238
 
239
+	&not-two
240
+	LIT 'r NEQ ,&not-return JNZ
241
+	asma-RETURN-FLAG ORA ,&loop JMP
533 242
 
534
-@normal-5b  :normal-@   :normal-5d  [ 5b ]
535
-	.assembler/state PEK #20 ORA .assembler/state POK
243
+	&not-return ( 00 byte / end* )
244
+	&not-found ( incoming-ptr* / end* )
245
+	POP2r
246
+	&too-short ( token* / )
247
+	POP2 #01
536 248
 	JMP2r
537 249
 
538
-@normal-5d  [ 0000 ]    [ 0000 ]    [ 5d ]
539
-	.assembler/state PEK #df AND .assembler/state POK
250
+@asma-write-byte ( byte -- )
251
+	#3e .Console/char DEO
252
+	#20 .Console/char DEO
253
+	.Console/byte DEO ( FIXME actually write! )
254
+	#0a .Console/char DEO
255
+	;asma/addr LDA2 #0001 ADD2 ;asma/addr STA2
540 256
 	JMP2r
541 257
 
542
-@data-]    :normal-28  [ 0000 ]    [ 5d ]
543
-	.assembler/state PEK #df AND .assembler/state POK
544
-	JMP2r
258
+@asma-write-short ( short -- )
259
+	SWP
260
+	,asma-write-byte JSR
261
+	,asma-write-byte JMP ( tail call )
545 262
 
546
-@data-root
547
-@data-nul  [ 0000 ]    :data-]    [ 00 ]
263
+@asma-append-heap-byte ( dummy byte -- dummy )
264
+	;asma/heap LDA2
265
+	OVR2 OVR2 STA POP
266
+	#0001 ADD2 ;asma/heap STA2
267
+	POP
548 268
 	JMP2r
549 269
 
550
-@data-main
551
-	.assembler/token PEK2 ;parse-hex-string JSR2
552
-	DUP ,normal-#/value JNZ
553
-	POP
270
+@asma-append-heap-short ( dummy short* -- dummy )
271
+	SWP
272
+	,asma-append-heap-byte JSR
273
+	,asma-append-heap-byte JMP ( tail call )
554 274
 
555
-	.assembler/token PEK2
556
-	&loop
275
+@asma-append-heap-string ( string* -- )
557 276
 	DUP2 LDA
558
-	DUP ,&keep-going JNZ
559
-	POP POP2 JMP2r
277
+	DUP ,asma-append-heap-byte JSR
278
+	,&keep-going JNZ
279
+	POP2 JMP2r
560 280
 
561 281
 	&keep-going
562
-	;write-byte JSR2
563 282
 	#0001 ADD2
283
+	,asma-append-heap-string JMP
284
+
285
+@asma-traverse-tree ( incoming-ptr* -- binary-ptr* 00 if key found
286
+                                    OR node-incoming-ptr* 01 if key not found )
287
+	( ;&help-str .Console/string DEO2
288
+	DUP2 .Console/short DEO2
289
+	#20 .Console/char DEO
290
+	;asma/token LDA2 .Console/string DEO2
291
+	#20 .Console/char DEO
292
+	;asma/orig-token LDA2 .Console/string DEO2
293
+	#0a .Console/char DEO )
294
+
295
+	&loop ( incoming-ptr* )
296
+	DUP2 LDA2 ORA ,&valid-node JNZ
297
+	#01 JMP2r
298
+
299
+	&valid-node
300
+	LDA2 DUP2 STH2
301
+	#0004 ADD2 ,asma-strcmp-tree JSR
302
+	DUP ,&nomatch JNZ
303
+	POP2r JMP2r
304
+
305
+	&nomatch
306
+	#06 SFT #02 AND #00 SWP
307
+	STH2r ADD2
564 308
 	,&loop JMP
565 309
 
566
-(
567
-	A pipe moves the current address to the hex value given.
568
-)
310
+	( &help-str "Looking 20 "up 20 00 )
311
+
312
+@asma-strcmp-tree ( node-key* -- order if strings differ
313
+                              OR after-node-key* 00 if strings match )
314
+	;asma/token LDA2 STH2
569 315
 
316
+	&loop ( node-key* / token* )
317
+	DUP2 #0001 ADD2 SWP2 LDA DUP2r LDAr STHr
318
+	DUP2 ORA ,&not-end JNZ
570 319
 
571
-@normal-|   :normal-{   :normal-}   [ 7c ]
572
-	.assembler/token PEK2 ;parse-hex-string JSR2
573
-	DUP #02 EQU ,&valid JNZ
574
-	#00 EQU JMP POP
575
-	( FIXME complain about invalid hex literal )
320
+	( end of C strings, match found )
321
+	POP2r POP
576 322
 	JMP2r
577 323
 
578
-	&valid
324
+	&not-end
325
+	SUB
326
+	DUP ,&nomatch JNZ
579 327
 	POP
580
-	DUP2 .assembler/addr PEK2 LTH2 ,&backwards JNZ
581
-	( FIXME add zeroes when writing )
582
-	.assembler/addr POK2
583
-	JMP2r
328
+	LIT2r 0001 ADD2r
329
+	,&loop JMP
584 330
 
585
-	&backwards
586
-	( FIXME complain about going backwards )
587
-	POP2
331
+	&nomatch
332
+	POP2r ROT ROT POP2
588 333
 	JMP2r
589 334
 
590
-(
591
-	Commas and dots write the label address - the comma precedes this
592
-	with a LIT2 opcode.
593
-)
335
+( actions based on first character )
594 336
 
337
+%asma-STATE-SET { ;asma/state LDA ORA ;asma/state STA }
338
+%asma-STATE-CLEAR { #ff EOR ;asma/state LDA AND ;asma/state STA }
595 339
 
596
-@normal-,   :normal-%   :normal-dot [ 2c ]
597
-	;opcodes/op-lit ;opcodes/start SUB2 #07 DIV SHORT_FLAG ADD ;write-byte JSR2 POP
598
-	,normal-dot/main JMP
340
+@asma-comment-start
341
+	#02 asma-STATE-SET
342
+@asma-ignore
343
+	JMP2r
599 344
 
600
-@normal-dot [ 0000 ]    :normal-;   [ 2e ]
601
-	&main
602
-	.assembler/token PEK2 ;lookup-label JSR2
603
-	POP ( don't care about node type )
604
-	;write-short JMP2 ( tail call )
345
+@asma-comment-end
346
+	#02 asma-STATE-CLEAR
347
+	JMP2r
605 348
 
606
-(
607
-	Caret writes LIT, followed by the label address as an offset.
608
-)
349
+@asma-macro-define
350
+	;asma/pass LDA ,&ignore-macro JNZ
609 351
 
352
+	;asma-trees/macros ;asma-traverse-tree JSR2 ,&not-exist JNZ
353
+	POP2
354
+	;asma-msg-macro ;asma/error STA2
355
+	JMP2r
610 356
 
611
-@normal-^   :normal-5b  :normal-|   [ 5e ]
612
-	;opcodes/op-lit ;opcodes/start SUB2 #07 DIV ;write-byte JSR2 POP
613
-	.assembler/token PEK2 ;lookup-label JSR2
614
-	POP ( don't care about node type )
615
-	.assembler/addr PEK2 SUB2
616
-	DUP2 #ff79 GTH2 ,&okay JNZ
617
-	DUP2 #0080 LTH2 ,&okay JNZ
357
+	&not-exist
358
+	( define macro by creating new node )
359
+	;asma/heap LDA2 SWP2 STA2
360
+	#0000 ;asma-append-heap-short JSR2 ( less-than pointer )
361
+	#0000 ;asma-append-heap-short JSR2 ( greater-than pointer )
362
+	;asma/token LDA2 ;asma-append-heap-string JSR2 ( key )
363
+	#04 asma-STATE-SET
364
+	JMP2r
618 365
 
619
-	( FIXME complain about jump being too far )
366
+	&ignore-macro
367
+	#0c asma-STATE-SET
368
+	JMP2r
620 369
 
621
-	&okay
622
-	;write-byte JSR2 POP
370
+@asma-macro-body
371
+	;asma/token LDA2 ;asma-append-heap-string JSR2
623 372
 	JMP2r
624 373
 
625
-(
626
-	Tilde and equals are the load and store helpers respectively.
627
-	If the target is in the zero page, use LDR/PEK or STR/POK opcodes,
628
-	otherwise use LDR2/PEK2 or STR2/POK2 opcodes.
629
-)
374
+@asma-macro-end
375
+	#00 ;asma-append-heap-byte JSR2
376
+	#0c asma-STATE-CLEAR
377
+	JMP2r
630 378
 
631
-@normal-~   [ 0000 ]    [ 0000 ]    [ 7e ]
632
-	LIT2r :opcodes/op-ldr LIT2r :opcodes/op-pek
633
-	,normal-=/main JMP
379
+@asma-label-define
380
+	#0000 ;asma/scope-addr STA2
381
+	;asma-trees/labels ,asma-label-helper JSR
382
+	,&already-existed JNZ
634 383
 
635
-@normal-root
636
-@normal-=   :normal-24  :normal-^   [ 3d ]
637
-	LIT2r :opcodes/op-str LIT2r :opcodes/op-pok
638
-	&main
639
-	.assembler/token PEK2 ;lookup-label JSR2
640
-	DUP #03 AND ,&valid JNZ
384
+	#0000 ;asma-append-heap-short JSR2 ( data2: subtree incoming ptr )
641 385
 
642
-	( FIXME complain about helper not being usable )
643
-	POP2 JMP2r
386
+	&already-existed
387
+	;asma/addr LDA2 ;asma/scope-addr STA2
388
+	#0002 ADD2 ;asma-trees/scope STA2
389
+	JMP2r
644 390
 
645
-	&valid
646
-	#02 AND ,&two-byte JNZ
647
-	SWP2r
648
-	&two-byte
649
-	POP2r
650
-	LIT2r :opcodes/start SUB2r LITr [ 07 ] DIVr
651
-	OVR #00 EQU ,&byte-mode JNZ
391
+@asma-sublabel-define
392
+	;asma-trees/scope LDA2 ,asma-label-helper JSR
393
+	POP POP2
394
+	JMP2r
652 395
 
653
-	;write-short SHORT_FLAG ,&end JMP
396
+@asma-label-helper ( incoming-ptr* -- binary-ptr* 00 if label existed already
397
+                                   OR binary-ptr* 01 if label was created )
398
+	;asma-traverse-tree JSR2
399
+	,&new-label JNZ
654 400
 
655
-	&byte-mode
656
-	SWP POP
657
-	;write-byte #00
401
+	( label already exists )
402
+	( FIXME check label address )
403
+	#01 JMP2r
658 404
 
659
-	&end
660
-	;opcodes/op-lit ;opcodes/start SUB2 #07 DIV ADD ADD ;write-byte JSR2
661
-	JSR2
662
-	STHr ;write-byte JSR2
663
-	POPr
664
-	JMP2r
405
+	&new-label ( incoming-ptr* )
406
+	( define label by creating new node )
407
+	;asma/heap LDA2 SWP2 STA2
408
+	#0000 ;asma-append-heap-short JSR2 ( less-than pointer )
409
+	#0000 ;asma-append-heap-short JSR2 ( greater-than pointer )
410
+	;asma/token LDA2 ;asma-append-heap-string JSR2 ( key )
665 411
 
666
-(
667
-	Semicolons introduce variables. The variable name is added to the label
668
-	tree as usual, but all of the subfields are collected into their own tree
669
-	pointed to in the variable name's binary data.
670
-)
412
+	;asma/heap LDA2
671 413
 
672
-@normal-;   [ 0000 ]    [ 0000 ]    [ 3b ]
673
-	#80 .assembler/token PEK2 ;label-tree ;add-label JSR2
674
-	.assembler/heap PEK2 #0000 OVR2 STA2
675
-	DUP2 #0003 SUB2 .assembler/var_size POK2
676
-	DUP2 .assembler/subtree POK2
677
-	#0002 ADD2 .assembler/heap POK2
414
+	;asma/addr LDA2 ;asma/scope-addr LDA2 SUB2
415
+	;asma-append-heap-short JSR2 ( data1: address )
416
+	#00 JMP2r
678 417
 
679
-	.assembler/state PEK #0c ORA .assembler/state POK
680
-	JMP2r
418
+@asma-pad-absolute
419
+	#0000 ,asma-pad-helper JMP
681 420
 
682
-@variable-root
683
-@variable-{ :variable-nul :variable-} [ 7b ]
684
-	JMP2r
421
+@asma-pad-relative
422
+	;asma/addr LDA2
423
+	( fall through )
685 424
 
686
-@variable-nul [ 0000 ]    :normal-28  [ 00 ]
687
-	JMP2r
425
+@asma-pad-helper ( offset* -- )
426
+	;asma-parse-hex-string JSR2
427
+	,&valid JNZ
688 428
 
689
-@variable-} [ 0000 ]    [ 0000 ]    [ 7d ]
690
-	.assembler/state PEK #f3 AND .assembler/state POK
429
+	;asma-msg-hex ;asma/error POK2
691 430
 	JMP2r
692 431
 
693
-@variable-name
694
-	#00 .assembler/token PEK2 .assembler/subtree PEK2 ;add-label JSR2
695
-	.assembler/heap PEK2 #0003 SUB2 .assembler/field_size POK2
696
-	.assembler/state PEK #f7 AND .assembler/state POK
432
+	&valid
433
+	( FIXME complain if rewind after writing nonzeroes )
434
+	ADD2 ;asma/addr STA2
697 435
 	JMP2r
698 436
 
699
-@variable-size
700
-	.assembler/token PEK2 ;parse-hex-length JSR2
701
-	,&valid JNZ
702
-	( FIXME complain about invalid size )
703
-	JMP2r
437
+@asma-raw-char
438
+	;asma/token LDA2 LDA
439
+	;asma-write-byte JMP2 ( tail call )
704 440
 
705
-	&valid
706
-	&no-var-size
707
-	DUP #02 GTH ,&end JNZ
708
-	DUP .assembler/field_size PEK2 STA
709
-	.assembler/var_size PEK2 #0000 EQU2 ,&end JNZ
710
-	DUP #80 EOR .assembler/var_size PEK2 STA
711
-	,&end JMP
441
+@asma-raw-word
442
+	;asma/token LDA2
712 443
 
713 444
 	&loop
714
-	#00 ;write-byte JSR2
715
-	#01 SUB
716
-	&end
717
-	DUP ,&loop JNZ
718
-	POP
719
-	.assembler/state PEK #0c ORA .assembler/state POK
720
-	#0000 .assembler/var_size POK2
445
+	DUP2 LDA
446
+	DUP ,&not-end JNZ
447
+
448
+	POP POP2
721 449
 	JMP2r
722 450
 
723
-(
724
-	Percent signs introduce macros. The macro name is added to the macro tree,
725
-	and all the arguments are collected into a list that follows the label's
726
-	binary data.
727
-)
451
+	&not-end
452
+	;asma-write-byte JSR2
453
+	#0001 ADD2
454
+	,&loop JMP
455
+
456
+@asma-literal-abs-addr
457
+	LIT LIT2 ;asma-write-byte JSR2
458
+	( fall through )
728 459
 
729
-@normal-%   [ 0000 ]    :normal-28  [ 25 ]
730
-	;macro-tree .assembler/token PEK2 #ff ;traverse-tree JSR2
731
-	,&new-macro JNZ
460
+@asma-abs-addr
461
+	,asma-addr-helper JSR
462
+	;asma-write-short JMP2 ( tail call )
732 463
 
733
-	( macro already exists, we assume defined in a previous pass
734
-	  we totally ignore the contents )
735
-	POP2
736
-	.assembler/state PEK #02 ORA .assembler/state POK
737
-	JMP2r
464
+@asma-literal-zero-addr
465
+	LIT LIT ;asma-write-byte JSR2
466
+	,asma-addr-helper JSR
467
+	;asma-write-byte JSR2
738 468
 
739
-	&new-macro
740
-	.assembler/token PEK2 SWP2 ;append-tree JSR2
741
-	POP2
742
-	.assembler/state PEK #01 ORA .assembler/state POK
469
+	,&not-zero-page JNZ
743 470
 	JMP2r
744 471
 
745
-@macro-root
746
-@macro-{   :macro-nul :macro-}   [ 7b ]
472
+	&not-zero-page
473
+	;asma-msg-zero-page ;asma/error STA2
747 474
 	JMP2r
748 475
 
749
-@macro-}   [ 0000 ]    [ 0000 ]    [ 7d ]
750
-	.assembler/heap PEK2 DUP2 #00 ROT ROT STA
751
-	#0001 ADD2 .assembler/heap POK2
752
-	.assembler/state PEK #fc AND .assembler/state POK
753
-	JMP2r
476
+@asma-literal-rel-addr
477
+	LIT LIT ;asma-write-byte JSR2
478
+	,asma-addr-helper JSR ;asma/addr LDA2 SUB2 #0002 SUB2
754 479
 
755
-@macro-nul [ 0000 ]    :normal-28  [ 00 ]
756
-	JMP2r
480
+	DUP2 #0080 LTH2 STH
481
+	DUP2 #ff7f GTH2 STHr ORA ,&in-bounds JNZ
757 482
 
758
-@macro-main
759
-	.assembler/token PEK2 ;append-heap JSR2
760 483
 	POP2
484
+	;asma-msg-relative ;asma/error STA2
761 485
 	JMP2r
762 486
 
763
-
764
-@normal-"   :normal-nul :normal-#   [ 22 ]
765
-	( FIXME NYI )
487
+	&in-bounds
488
+	;asma-write-byte JSR2
489
+	POP
766 490
 	JMP2r
767 491
 
768
-@normal-{   [ 0000 ]    [ 0000 ]    [ 7b ]
769
-	( these are spurious, but ignore them anyway )
770
-	JMP2r
492
+@asma-addr-helper ( -- addr* )
493
+	;asma/token LDA2 DUP2 LDA #26 NEQ ,&not-local JNZ
494
+	#0001 ADD2 ;asma/token STA2
495
+	;asma/scope-addr LDA2 ;asma-trees/scope LDA2
496
+	,&final-lookup JMP
497
+
498
+	&not-local ( token* )
499
+	DUP2 LDA
500
+	DUP ,&not-end JNZ
501
+	POP POP2
502
+	#0000 ;asma-trees/labels
503
+	,&final-lookup JMP
504
+
505
+	&not-end ( token* char )
506
+	#2f EQU ,&found-slash JNZ
507
+	#0001 ADD2
508
+	,&not-local JMP
509
+
510
+	&found-slash ( token* )
511
+	DUP2 #00 ROT ROT STA
512
+	;asma-trees/labels ;asma-traverse-tree JSR2 STH
513
+	SWP2 DUP2 #2f ROT ROT STA
514
+	STHr ,&not-found JNZ
515
+	( token* binary-ptr* )
516
+	#0001 ADD2 ;asma/token STA2
517
+	DUP2 LDA2 SWP2 #0002 ADD2
771 518
 
772
-@normal-}   [ 0000 ]    :normal-~   [ 7d ]
773
-	( these are spurious, but ignore them anyway )
519
+	&final-lookup ( addr-offset* incoming-ptr* )
520
+	;asma-traverse-tree JSR2 ,&not-found JNZ
521
+	LDA2 ADD2
774 522
 	JMP2r
775 523
 
776
-@normal-nul [ 0000 ]    [ 0000 ]    [ 00 ]
777
-@ignore
524
+	&not-found ( dummy* dummy* )
525
+
526
+	;asma/pass LDA #00 EQU ,&ignore-error JNZ
527
+	;asma-msg-label ;asma/error STA2
528
+	&ignore-error
529
+
530
+	POP2 POP2
531
+	;asma/addr LDA2
778 532
 	JMP2r
779 533
 
780
-@normal-main
781
-	.assembler/token PEK2
782
-	;opcodes/tree OVR2 #03 ;traverse-tree JSR2
783
-	,&not-opcode JNZ
534
+@asma-literal-hex
535
+	;asma-parse-hex-string JSR2 JMP
536
+	( hex invalid ) ,&invalid JMP
537
+	( hex byte    ) ,asma-byte-helper JMP
538
+	( hex short   ) ,asma-short-helper JMP
784 539
 
785
-	;opcodes/asm SUB2 #0007 DIV2
786
-	SWP2 #0003 ADD2
787
-	&flags
788
-	DUP2 LDA
789
-	DUP #00 EQU ,&end-flags JNZ
790
-	DUP #32 NEQ ,&not-two JNZ
791
-	POP SWP2 SHORT_FLAG ORA SWP2 #0001 ADD2 ,&flags JMP
792
-	&not-two
793
-	DUP #72 NEQ ,&not-r JNZ
794
-	POP SWP2 RETURN_FLAG ORA SWP2 #0001 ADD2 ,&flags JMP
795
-	&not-r
796
-	POP POP2 .assembler/token PEK2 SWP2
797
-	,&not-opcode JMP
540
+	&invalid
541
+	POP2
798 542
 
799
-	&end-flags
800
-	POP POP2
801
-	;write-byte JSR2
543
+	;asma-msg-hex ;asma/error STA2
544
+	JMP2r
545
+
546
+@asma-byte-helper ( dummy value -- )
547
+	LIT LIT ;asma-write-byte JSR2
548
+	&raw
549
+	;asma-write-byte JSR2
802 550
 	POP
803 551
 	JMP2r
804 552
 
553
+@asma-short-helper ( value* -- )
554
+	LIT LIT2 ;asma-write-byte JSR2
555
+	&raw
556
+	;asma-write-short JMP2 ( tail call )
557
+
558
+@asma-normal-body
559
+	;asma-parse-opcode JSR2 ,&not-opcode JNZ
560
+	;asma-write-byte JMP2 ( tail call )
561
+
805 562
 	&not-opcode
563
+	;asma-parse-hex-string JSR2 JMP
564
+	( hex invalid ) ,&not-hex JMP
565
+	( hex byte    ) ,asma-byte-helper/raw JMP
566
+	( hex short   ) ,asma-short-helper/raw JMP
567
+
568
+	&not-hex
569
+	;asma-trees/macros ;asma-traverse-tree JSR2 ,&not-macro JNZ
570
+
571
+	&macro-loop
572
+	DUP2 LDA ,&keep-going JNZ
573
+	&error
806 574
 	POP2
807
-	;macro-tree SWP2 #ff ;traverse-tree JSR2
808
-	,&not-macro JNZ
809
-	;assemble-macro JMP2 ( tail call )
575
+	JMP2r
576
+
577
+	&keep-going
578
+	DUP2 DUP2 ;asma-strlen JSR2 #00 SWP #0001 ADD2 ADD2
579
+	SWP2 ;asma-assemble-token JSR2 asma-IF-ERROR ,&error JNZ
580
+	,&macro-loop JMP
810 581
 
811 582
 	&not-macro
812
-	( FIXME complain about bad opcode / nonexistent macro )
813 583
 	POP2
814
-	JMP2r
815 584
 
816
-(
817
-	Here's the big set of trees relating to labels. Starting from l-root, all
818
-	the devices are stored here, perhaps some helper functions in the future,
819
-	too.
820
-
821
-	left-node* right-node* node-key-cstring binary-data
822
-
823
-	The node-keys are terminated with NUL since, unlike the opcodes and first
824
-	characters, the keys are variable length.
825
-
826
-	The binary-data is either three or five bytes long:
827
-		flags value* [ subtree-pointer* ]
828
-
829
-	The flags byte is divided up into bits:
830
-
831
-	bit 0-1: 00 means store / load helpers cannot be used,
832
-	         01 means the helpers use POK / PEK,
833
-	         02 means the helpers use STR / LDR,
834
-	         03 is invalid;
835
-	bits 2-6 are reserved; and
836
-	bit 7: 80 means there is a subtree.
837
-
838
-	If there is a subtree, it is searched when the reference contains a dot.
839
-)
840
-
841
-
842
-@l-Audio           [ 0000 ]          [ 0000 ]         [ "Audio 00 ]      [ 80 ] :Audio :l-Audio-root
843
-@l-Audio-delay     [ 0000 ]          [ 0000 ]         [ "delay 00 ]      [ 02 ] :Audio/delay
844
-@l-Audio-envelope :l-Audio-delay    :l-Audio-finish   [ "envelope 00 ]   [ 02 ] :Audio/envelope
845
-@l-Audio-finish    [ 0000 ]          [ 0000 ]         [ "finish 00 ]     [ 01 ] :Audio/finish
846
-@l-Audio-root
847
-@l-Audio-pitch    :l-Audio-envelope :l-Audio-value    [ "pitch 00 ]      [ 01 ] :Audio/pitch
848
-@l-Audio-play      [ 0000 ]          [ 0000 ]         [ "play 00 ]       [ 01 ] :Audio/play
849
-@l-Audio-value    :l-Audio-play     :l-Audio-volume   [ "value 00 ]      [ 02 ] :Audio/value
850
-@l-Audio-volume    [ 0000 ]         :l-Audio-wave     [ "volume 00 ]     [ 01 ] :Audio/volume
851
-@l-Audio-wave      [ 0000 ]          [ 0000 ]         [ "wave 00 ]       [ 02 ] :Audio/wave
852
-@l-Console        :l-Audio          :l-Controller     [ "Console 00 ]    [ 80 ] :Console :l-Console-root
853
-@l-Console-byte    [ 0000 ]         :l-Console-char   [ "byte 00 ]       [ 01 ] :Console/byte
854
-@l-Console-char    [ 0000 ]          [ 0000 ]         [ "char 00 ]       [ 01 ] :Console/char
855
-@l-Console-root
856
-@l-Console-short  :l-Console-byte   :l-Console-string [ "short 00 ]      [ 02 ] :Console/short
857
-@l-Console-string  [ 0000 ]         :l-Console-vector [ "string 00 ]     [ 02 ] :Console/string
858
-@l-Console-vector  [ 0000 ]          [ 0000 ]         [ "vector 00 ]     [ 02 ] :Console/vector
859
-@l-Controller      [ 0000 ]          [ 0000 ]         [ "Controller 00 ] [ 80 ] :Controller :l-Controller-root
860
-@l-Controller-button  [ 0000 ]          [ 0000 ]         [ "button 00 ]     [ 01 ] :Controller/button
861
-@l-Controller-root
862
-@l-Controller-key :l-Controller-button :l-Controller-vector [ "key 00 ]        [ 01 ] :Controller/key
863
-@l-Controller-vector  [ 0000 ]          [ 0000 ]         [ "vector 00 ]     [ 02 ] :Controller/vector
864
-@l-root
865
-@l-DateTime       :l-Console        :l-Mouse          [ "DateTime 00 ]   [ 80 ] :DateTime :l-DateTime-root
866
-@l-DateTime-day    [ 0000 ]          [ 0000 ]         [ "day 00 ]        [ 01 ] :DateTime/day
867
-@l-DateTime-dotw  :l-DateTime-day   :l-DateTime-doty  [ "dotw 00 ]       [ 01 ] :DateTime/dotw
868
-@l-DateTime-doty   [ 0000 ]         :l-DateTime-hour  [ "doty 00 ]       [ 02 ] :DateTime/doty
869
-@l-DateTime-hour   [ 0000 ]          [ 0000 ]         [ "hour 00 ]       [ 01 ] :DateTime/hour
870
-@l-DateTime-root
871
-@l-DateTime-isdst :l-DateTime-dotw  :l-DateTime-refresh [ "isdst 00 ]      [ 01 ] :DateTime/isdst
872
-@l-DateTime-minute  [ 0000 ]         :l-DateTime-month [ "minute 00 ]     [ 01 ] :DateTime/minute
873
-@l-DateTime-month  [ 0000 ]          [ 0000 ]         [ "month 00 ]      [ 01 ] :DateTime/month
874
-@l-DateTime-refresh :l-DateTime-minute :l-DateTime-second [ "refresh 00 ]    [ 01 ] :DateTime/refresh
875
-@l-DateTime-second  [ 0000 ]         :l-DateTime-year  [ "second 00 ]     [ 01 ] :DateTime/second
876
-@l-DateTime-year   [ 0000 ]          [ 0000 ]         [ "year 00 ]       [ 02 ] :DateTime/year
877
-@l-File            [ 0000 ]          [ 0000 ]         [ "File 00 ]       [ 80 ] :File :l-File-root
878
-@l-File-length     [ 0000 ]          [ 0000 ]         [ "length 00 ]     [ 02 ] :File/length
879
-@l-File-load      :l-File-length    :l-File-name      [ "load 00 ]       [ 02 ] :File/load
880
-@l-File-name       [ 0000 ]          [ 0000 ]         [ "name 00 ]       [ 02 ] :File/name
881
-@l-File-root
882
-@l-File-offset    :l-File-load      :l-File-success   [ "offset 00 ]     [ 02 ] :File/offset
883
-@l-File-save       [ 0000 ]          [ 0000 ]         [ "save 00 ]       [ 02 ] :File/save
884
-@l-File-success   :l-File-save      :l-File-vector    [ "success 00 ]    [ 02 ] :File/success
885
-@l-File-vector     [ 0000 ]          [ 0000 ]         [ "vector 00 ]     [ 02 ] :File/vector
886
-@l-Mouse          :l-File           :l-Screen         [ "Mouse 00 ]      [ 80 ] :Mouse :l-Mouse-root
887
-@l-Mouse-chord     [ 0000 ]         :l-Mouse-state    [ "chord 00 ]      [ 01 ] :Mouse/chord
888
-@l-Mouse-state     [ 0000 ]          [ 0000 ]         [ "state 00 ]      [ 01 ] :Mouse/state
889
-@l-Mouse-root
890
-@l-Mouse-vector   :l-Mouse-chord    :l-Mouse-x        [ "vector 00 ]     [ 02 ] :Mouse/vector
891
-@l-Mouse-x         [ 0000 ]         :l-Mouse-y        [ "x 00 ]          [ 02 ] :Mouse/x
892
-@l-Mouse-y         [ 0000 ]          [ 0000 ]         [ "y 00 ]          [ 02 ] :Mouse/y
893
-@l-Screen          [ 0000 ]         :l-System         [ "Screen 00 ]     [ 80 ] :Screen :l-Screen-root
894
-@l-Screen-addr     [ 0000 ]          [ 0000 ]         [ "addr 00 ]       [ 02 ] :Screen/addr
895
-@l-Screen-color   :l-Screen-addr    :l-Screen-height  [ "color 00 ]      [ 01 ] :Screen/color
896
-@l-Screen-height   [ 0000 ]          [ 0000 ]         [ "height 00 ]     [ 02 ] :Screen/height
897
-@l-Screen-root
898
-@l-Screen-vector  :l-Screen-color   :l-Screen-x       [ "vector 00 ]     [ 02 ] :Screen/vector
899
-@l-Screen-width    [ 0000 ]          [ 0000 ]         [ "width 00 ]      [ 02 ] :Screen/width
900
-@l-Screen-x       :l-Screen-width   :l-Screen-y       [ "x 00 ]          [ 02 ] :Screen/x
901
-@l-Screen-y        [ 0000 ]          [ 0000 ]         [ "y 00 ]          [ 02 ] :Screen/y
902
-@l-System          [ 0000 ]          [ 0000 ]         [ "System 00 ]     [ 80 ] :System :l-System-root
903
-@l-System-b        [ 0000 ]          [ 0000 ]         [ b 00 ]          [ 02 ] :System/b
904
-@l-System-root
905
-@l-System-g       :l-System-b       :l-System-r       [ "g 00 ]          [ 02 ] :System/g
906
-@l-System-r        [ 0000 ]         :l-System-vector  [ "r 00 ]          [ 02 ] :System/r
907
-@l-System-vector   [ 0000 ]          [ 0000 ]         [ "vector 00 ]     [ 02 ] :System/vector
908
-
909
-@assembler-heap-start
585
+	;asma-msg-label ;asma/error STA2
586
+	JMP2r
587
+
588
+( messages )
589
+
590
+@asma-msg-hex       "Invalid 20 "hexadecimal 00
591
+@asma-msg-zero-page "Address 20 "not 20 "in 20 "zero 20 "page 00
592
+@asma-msg-relative  "Address 20 "outside 20 "range 00
593
+@asma-msg-label     "Label 20 "not 20 "found 00
594
+@asma-msg-macro     "Macro 20 "already 20 "exists 00
595
+
596
+( trees )
597
+
598
+( --- 8< ------- 8< --- cut here --- 8< ------- 8< --- )
599
+(          automatically generated code below          )
600
+(          see etc/asma.moon for instructions          )
601
+
602
+(	label       less than  greater than key            data )
603
+
604
+@asma-first-char-comment
605
+	&_entry      $2         $2          ') 00          :asma-comment-end
606
+
607
+@asma-first-char-macro
608
+	&28          $2         $2          '( 00          :asma-comment-start
609
+	&29         :&28        $2          ') 00          :asma-comment-end
610
+	&_entry     :&29       :&7d         '{ 00          :asma-ignore
611
+	&7d          $2         $2          '} 00          :asma-macro-end
612
+
613
+@asma-first-char-normal
614
+	&22          $2         $2          '" 00          :asma-raw-word
615
+	&23         :&22        $2          '# 00          :asma-literal-hex
616
+	&24         :&23       :&25         '$ 00          :asma-pad-relative
617
+	&25          $2         $2          '% 00          :asma-macro-define
618
+	&26         :&24       :&29         26 00 ( & )    :asma-sublabel-define
619
+	&27          $2         $2          '' 00          :asma-raw-char
620
+	&28         :&27        $2          '( 00          :asma-comment-start
621
+	&29         :&28       :&2c         ') 00          :asma-comment-end
622
+	&2c          $2         $2          ', 00          :asma-literal-rel-addr
623
+	&_entry     :&26       :&5d         '. 00          :asma-literal-zero-addr
624
+	&3a          $2         $2          ': 00          :asma-abs-addr
625
+	&3b         :&3a        $2          '; 00          :asma-literal-abs-addr
626
+	&40         :&3b       :&5b         '@ 00          :asma-label-define
627
+	&5b          $2         $2          '[ 00          :asma-ignore
628
+	&5d         :&40       :&7c         '] 00          :asma-ignore
629
+	&7b          $2         $2          '{ 00          :asma-ignore
630
+	&7c         :&7b       :&7d         '| 00          :asma-pad-absolute
631
+	&7d          $2         $2          '} 00          :asma-ignore
632
+
633
+@asma-labels
634
+	&Audio0      $2         $2          "Audio0 00     0030 :asma-ldev-Audio/_entry
635
+	&Audio1     :&Audio0   :&Audio2     "Audio1 00     0040 :asma-ldev-Audio/_entry
636
+	&Audio2      $2         $2          "Audio2 00     0050 :asma-ldev-Audio/_entry
637
+	&Audio3     :&Audio1   :&Controller "Audio3 00     0060 :asma-ldev-Audio/_entry
638
+	&Console     $2         $2          "Console 00    0010 :asma-ldev-Console/_entry
639
+	&Controller :&Console   $2          "Controller 00 0080 :asma-ldev-Controller/_entry
640
+	&_entry     :&Audio3   :&Mouse      "DateTime 00   00b0 :asma-ldev-DateTime/_entry
641
+	&File        $2         $2          "File 00       00a0 :asma-ldev-File/_entry
642
+	&Midi       :&File      $2          "Midi 00       0070 :asma-ldev-Midi/_entry
643
+	&Mouse      :&Midi     :&System     "Mouse 00      0090 :asma-ldev-Mouse/_entry
644
+	&Screen      $2         $2          "Screen 00     0020 :asma-ldev-Screen/_entry
645
+	&System     :&Screen    $2          "System 00     0000 :asma-ldev-System/_entry
646
+
647
+@asma-ldev-Audio
648
+	&addr        $2         $2          "addr 00       000c
649
+	&adsr       :&addr      $2          "adsr 00       0008
650
+	&length     :&adsr     :&output     "length 00     000a
651
+	&output      $2         $2          "output 00     0004
652
+	&_entry     :&length   :&vector     "pitch 00      000f
653
+	&position    $2         $2          "position 00   0002
654
+	&vector     :&position :&volume     "vector 00     0000
655
+	&volume      $2         $2          "volume 00     000e
656
+
657
+@asma-ldev-Console
658
+	&byte        $2         $2          "byte 00       0009
659
+	&char       :&byte      $2          "char 00       0008
660
+	&_entry     :&char     :&string     "short 00      000a
661
+	&string      $2         $2          "string 00     000c
662
+
663
+@asma-ldev-Controller
664
+	&button      $2         $2          "button 00     0002
665
+	&_entry     :&button   :&vector     "key 00        0003
666
+	&vector      $2         $2          "vector 00     0000
667
+
668
+@asma-ldev-DateTime
669
+	&day         $2         $2          "day 00        0003
670
+	&dotw       :&day       $2          "dotw 00       0007
671
+	&doty       :&dotw     :&hour       "doty 00       0008
672
+	&hour        $2         $2          "hour 00       0004
673
+	&_entry     :&doty     :&second     "isdst 00      000a
674
+	&minute      $2         $2          "minute 00     0005
675
+	&month      :&minute    $2          "month 00      0002
676
+	&second     :&month    :&year       "second 00     0006
677
+	&year        $2         $2          "year 00       0000
678
+
679
+@asma-ldev-File
680
+	&length      $2         $2          "length 00     000a
681
+	&load       :&length   :&name       "load 00       000c
682
+	&name        $2         $2          "name 00       0008
683
+	&_entry     :&load     :&success    "offset 00     0004
684
+	&save        $2         $2          "save 00       000e
685
+	&success    :&save     :&vector     "success 00    0002
686
+	&vector      $2         $2          "vector 00     0000
687
+
688
+@asma-ldev-Midi
689
+	&channel     $2         $2          "channel 00    0002
690
+	&note       :&channel   $2          "note 00       0003
691
+	&_entry     :&note     :&velocity   "vector 00     0000
692
+	&velocity    $2         $2          "velocity 00   0004
693
+
694
+@asma-ldev-Mouse
695
+	&chord       $2         $2          "chord 00      0007
696
+	&state      :&chord     $2          "state 00      0006
697
+	&_entry     :&state    :&y          "vector 00     0000
698
+	&x           $2         $2          "x 00          0002
699
+	&y          :&x         $2          "y 00          0004
700
+
701
+@asma-ldev-Screen
702
+	&addr        $2         $2          "addr 00       000c
703
+	&color      :&addr     :&height     "color 00      000e
704
+	&height      $2         $2          "height 00     0004
705
+	&_entry     :&color    :&x          "vector 00     0000
706
+	&width       $2         $2          "width 00      0002
707
+	&x          :&width    :&y          "x 00          0008
708
+	&y           $2         $2          "y 00          000a
709
+
710
+@asma-ldev-System
711
+	&b           $2         $2          "b 00          000c
712
+	&g          :&b        :&r          "g 00          000a
713
+	&r           $2         $2          "r 00          0008
714
+	&_entry     :&g        :&wst        "rst 00        0003
715
+	&vector      $2         $2          "vector 00     0000
716
+	&wst        :&vector    $2          "wst 00        0002
717
+
718
+@asma-opcodes
719
+	&BRK        :&AND      :&DEI &_disasm "BRK 00
720
+	&LIT         $2         $2          "LIT 00
721
+	&NOP         $2         $2          "NOP 00
722
+	&POP        :&ORA      :&STH        "POP 00
723
+	&DUP        :&DIV      :&EOR        "DUP 00
724
+	&SWP         $2         $2          "SWP 00
725
+	&OVR         $2         $2          "OVR 00
726
+	&ROT         $2         $2          "ROT 00
727
+	&EQU        :&DEO      :&JSR        "EQU 00
728
+	&NEQ        :&MUL      :&NOP        "NEQ 00
729
+	&GTH         $2         $2          "GTH 00
730
+	&_entry     :&EQU      :&POP        "LTH 00
731
+	&JMP        :&GTH      :&JNZ        "JMP 00
732
+	&JNZ         $2         $2          "JNZ 00
733
+	&JSR        :&JMP      :&LDR        "JSR 00
734
+	&STH        :&SFT      :&SUB        "STH 00
735
+	&PEK        :&OVR      :&POK        "PEK 00
736
+	&POK         $2         $2          "POK 00
737
+	&LDR        :&LDA      :&LIT        "LDR 00
738
+	&STR         $2         $2          "STR 00
739
+	&LDA         $2         $2          "LDA 00
740
+	&STA         $2         $2          "STA 00
741
+	&DEI         $2         $2          "DEI 00
742
+	&DEO        :&BRK      :&DUP        "DEO 00
743
+	&ADD         $2         $2          "ADD 00
744
+	&SUB        :&STR      :&SWP        "SUB 00
745
+	&MUL         $2         $2          "MUL 00
746
+	&DIV         $2         $2          "DIV 00
747
+	&AND        :&ADD       $2          "AND 00
748
+	&ORA        :&NEQ      :&PEK        "ORA 00
749
+	&EOR         $2         $2          "EOR 00
750
+	&SFT        :&ROT      :&STA        "SFT 00
751
+
752
+@asma-heap
910 753