Skip to content

Commit ec441c3

Browse files
authored
Merge pull request #558 from boriel/feature/asm_temporary_labels
Feature/asm temporary labels
2 parents c51af69 + 3996372 commit ec441c3

109 files changed

Lines changed: 974 additions & 821 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/arch/zx48k/library-asm/copy_attr.asm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ TABLE:
6767

6868
__REFRESH_TMP:
6969
ld a, (hl)
70-
and 10101010b
70+
and 0b10101010
7171
ld c, a
7272
rra
7373
or c

src/arch/zxnext/library-asm/copy_attr.asm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ TABLE:
6767

6868
__REFRESH_TMP:
6969
ld a, (hl)
70-
and 10101010b
70+
and 0b10101010
7171
ld c, a
7272
rra
7373
or c

src/outfmt/codeemitter.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,22 @@
1111
# The code emission interface.
1212
# --------------------------------------------
1313

14+
from abc import ABC, abstractmethod
1415

15-
class CodeEmitter(object):
16+
17+
class CodeEmitter(ABC):
1618
""" The base code emission interface.
1719
"""
18-
pass
20+
21+
@abstractmethod
22+
def emit(
23+
self,
24+
output_filename: str,
25+
program_name: str,
26+
loader_bytes: bytearray,
27+
entry_point,
28+
program_bytes,
29+
aux_bin_blocks,
30+
aux_headless_bin_blocks
31+
):
32+
pass

src/parsetab/tabs.dbm.bak

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
'zxbpp', (0, 76970)
2-
'asmparse', (77312, 271961)
3-
'zxnext_asmparse', (349696, 302573)
4-
'zxbparser', (652288, 703160)
2+
'asmparse', (77312, 272467)
3+
'zxnext_asmparse', (350208, 303081)
4+
'zxbparser', (653312, 703160)

src/parsetab/tabs.dbm.dat

1 KB
Binary file not shown.

src/parsetab/tabs.dbm.dir

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
'zxbpp', (0, 76970)
2-
'asmparse', (77312, 271961)
3-
'zxnext_asmparse', (349696, 302573)
4-
'zxbparser', (652288, 703160)
2+
'asmparse', (77312, 272467)
3+
'zxnext_asmparse', (350208, 303081)
4+
'zxbparser', (653312, 703160)

src/zxbasm/asm.py

Lines changed: 87 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,151 +1,120 @@
1-
#!/usr/bin/env python
2-
# -*- coding: utf-8 -*-
3-
# vim: ts=4:et:sw=4
1+
from typing import Any, NamedTuple
42

5-
from src.zxbasm.z80 import Z80SET
6-
from src.api.errors import Error
7-
import re
8-
9-
# Reg. Exp. for counting N args in an asm mnemonic
10-
ARGre = re.compile(r'\bN+\b')
11-
12-
Z80_8REGS = ('A', 'B', 'C', 'D', 'E', 'H', 'L',
13-
'IXh', 'IYh', 'IXl', 'IYl', 'I', 'R')
14-
15-
Z80_16REGS = {'AF': ('A', 'F'), 'BC': ('B', 'C'), 'DE': ('D', 'E'),
16-
'HL': ('H', 'L'), 'SP': (),
17-
'IX': ('IXh', 'IXl'), 'IY': ('IYh', 'IYl')
18-
}
19-
20-
21-
def num2bytes(x, bytes_):
22-
""" Returns x converted to a little-endian t-uple of bytes.
23-
E.g. num2bytes(255, 4) = (255, 0, 0, 0)
24-
"""
25-
if not isinstance(x, int): # If it is another "thing", just return ZEROs
26-
return tuple([0] * bytes_)
3+
from src.api import errmsg
4+
from src.api import global_ as gl
275

28-
x = x & ((2 << (bytes_ * 8)) - 1) # mask the initial value
29-
result = ()
30-
31-
for i in range(bytes_):
32-
result += (x & 0xFF,)
33-
x >>= 8
34-
35-
return result
6+
from src.api.errors import Error
7+
from src.zxbasm.expr import Expr
8+
from src.zxbasm.asm_instruction import AsmInstruction
369

3710

38-
class InvalidMnemonicError(Error):
39-
""" Exception raised when an invalid Mnemonic has been emitted.
11+
class Container(NamedTuple):
12+
""" Single class container
4013
"""
14+
item: Any
15+
lineno: int
4116

42-
def __init__(self, mnemo):
43-
self.msg = "Invalid mnemonic '%s'" % mnemo
44-
self.mnemo = mnemo
4517

18+
class Asm(AsmInstruction):
19+
""" Class extension to AsmInstruction with a short name :-P
20+
and will trap some exceptions and convert them to error msgs.
4621
47-
class InvalidArgError(Error):
48-
""" Exception raised when an invalid argument has been emitted.
22+
It will also record source line
4923
"""
5024

51-
def __init__(self, arg):
52-
self.msg = "Invalid argument '%s'. It must be an integer." % str(arg)
53-
self.mnemo = arg
25+
def __init__(self, lineno, asm, arg=None):
26+
self.lineno = lineno
5427

28+
if asm not in ('DEFB', 'DEFS', 'DEFW'):
29+
try:
30+
super().__init__(asm, arg)
31+
except Error as v:
32+
errmsg.error(lineno, v.msg)
33+
return
5534

56-
class InternalMismatchSizeError(Error):
57-
""" Exception raised when an invalid instruction length has been emitted.
58-
"""
59-
60-
def __init__(self, current_size, asm):
61-
a = '' if current_size == 1 else 's'
62-
b = '' if asm.size == 1 else 's'
35+
self.pending = len([x for x in self.arg if isinstance(x, Expr) and x.try_eval() is None]) > 0
6336

64-
self.msg = ("Invalid instruction [%s] size (%i byte%s). "
65-
"It should be %i byte%s." % (asm.asm, current_size, a,
66-
asm.size, b))
67-
self.current_size = current_size
68-
self.asm = asm
37+
if not self.pending:
38+
self.arg = self.argval()
39+
else:
40+
self.asm = asm
41+
self.pending = True
6942

43+
if isinstance(arg, str):
44+
self.arg = tuple([Expr(Container(ord(x), lineno)) for x in arg])
45+
else:
46+
self.arg = arg
7047

71-
class AsmInstruction:
72-
""" Derives from Opcode. This one checks for opcode validity.
73-
"""
74-
def __init__(self, asm, arg=None):
75-
""" Parses the given asm instruction and validates
76-
it against the Z80SET table. Raises InvalidMnemonicError
77-
if not valid.
48+
self.arg_num = len(self.arg)
7849

79-
It uses the Z80SET global dictionary. Args is an optional
80-
argument (it can be a Label object or a value)
50+
def bytes(self) -> bytearray:
51+
""" Returns opcodes
8152
"""
82-
if isinstance(arg, list):
83-
arg = tuple(arg)
53+
if self.asm not in ('DEFB', 'DEFS', 'DEFW'):
54+
if self.pending:
55+
tmp = self.arg # Saves current arg temporarily
56+
self.arg = (0, ) * self.arg_num
57+
result = super(Asm, self).bytes()
58+
self.arg = tmp # And recovers it
8459

85-
if arg is None:
86-
arg = ()
60+
return result
8761

88-
if arg is not None and not isinstance(arg, tuple):
89-
arg = (arg,)
62+
return super(Asm, self).bytes()
9063

91-
asm = asm.split(';', 1) # Try to get comments out, if any
92-
if len(asm) > 1:
93-
self.comments = ';' + asm[1]
94-
else:
95-
self.comments = ''
64+
if self.asm == 'DEFB':
65+
if self.pending:
66+
return bytearray((0, ) * self.arg_num)
9667

97-
asm = asm[0]
68+
return bytearray(x & 0xFF for x in self.argval())
9869

99-
self.mnemo = asm.upper()
100-
if self.mnemo not in Z80SET.keys():
101-
raise InvalidMnemonicError(asm)
70+
if self.asm == 'DEFS':
71+
if self.pending:
72+
N = self.arg[0]
73+
if isinstance(N, Expr):
74+
N = N.eval()
75+
return (0, ) * N
10276

103-
Z80 = Z80SET[self.mnemo]
77+
args = self.argval()
78+
arg0 = args[0]
79+
arg1 = args[1]
80+
assert isinstance(arg0, int)
81+
assert isinstance(arg1, int)
10482

105-
self.asm = asm
106-
self.size = Z80.size
107-
self.T = Z80.T
108-
self.opcode = Z80.opcode
109-
self.argbytes = tuple([len(x) for x in ARGre.findall(asm)])
110-
self.arg = arg
111-
self.arg_num = len(ARGre.findall(asm))
83+
if arg1 > 255:
84+
errmsg.warning_value_will_be_truncated(self.lineno)
85+
num = arg1 & 0xFF
86+
return bytearray((num, ) * arg0)
11287

113-
def argval(self):
114-
""" Returns the value of the arg (if any) or None.
115-
If the arg. is not an integer, an error be triggered.
116-
"""
117-
if self.arg is None or any(x is None for x in self.arg):
118-
return None
88+
if self.pending: # DEFW
89+
return bytearray((0, ) * 2 * self.arg_num)
11990

120-
for x in self.arg:
121-
if not isinstance(x, int):
122-
raise InvalidArgError(self.arg)
91+
result = bytearray()
92+
for i in self.argval():
93+
x = i & 0xFFFF
94+
result.extend([x & 0xFF, x >> 8])
12395

124-
return self.arg
96+
return bytearray(result)
12597

126-
def bytes(self) -> bytearray:
127-
""" Returns a t-uple with instruction bytes (integers)
98+
def argval(self):
99+
""" Solve args values or raise errors if not
100+
defined yet
128101
"""
129-
result = []
130-
op = self.opcode.split(' ')
131-
argi = 0
132-
133-
while op:
134-
q = op.pop(0)
102+
if gl.has_errors:
103+
return [None]
135104

136-
if q == 'XX':
137-
for k in range(self.argbytes[argi] - 1):
138-
op.pop(0)
105+
if self.asm in ('DEFB', 'DEFS', 'DEFW'):
106+
result = tuple([x.eval() if isinstance(x, Expr) else x for x in self.arg])
107+
if self.asm == 'DEFB' and any(x > 255 for x in result):
108+
errmsg.warning_value_will_be_truncated(self.lineno)
109+
return result
139110

140-
result.extend(num2bytes(self.argval()[argi], self.argbytes[argi]))
141-
argi += 1
142-
else:
143-
result.append(int(q, 16)) # Add opcode
144-
145-
if len(result) != self.size:
146-
raise InternalMismatchSizeError(len(result), self)
111+
self.arg = tuple([x if not isinstance(x, Expr) else x.eval() for x in self.arg])
112+
if gl.has_errors:
113+
return [None]
147114

148-
return bytearray(result)
115+
if self.asm.split(' ')[0] in ('JR', 'DJNZ'): # A relative jump?
116+
if self.arg[0] < -128 or self.arg[0] > 127:
117+
errmsg.error(self.lineno, 'Relative jump out of range')
118+
return [None]
149119

150-
def __str__(self):
151-
return self.asm
120+
return super(Asm, self).argval()

0 commit comments

Comments
 (0)