diff --git a/CHANGES.txt b/CHANGES.txt
index 6cd74cb..ed23585 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,8 @@
0.14 *Next Release*
+ - Assembling now detects syntax errors, overflows, and bad labels
+ separately and shows specific error messages.
+
0.13 (2012-11-15)
- Fixed a bug where negative numbers could be entered
diff --git a/py65/monitor.py b/py65/monitor.py
index c6f843d..027775d 100644
--- a/py65/monitor.py
+++ b/py65/monitor.py
@@ -268,28 +268,30 @@ class Monitor(cmd.Cmd):
return self.help_EOF()
def do_assemble(self, args):
- split = args.split(None, 1)
- if len(split) != 2:
+ splitted = args.split(None, 1)
+ if len(splitted) != 2:
return self._interactive_assemble(args)
- start, statement = split
+ statement = splitted[1]
try:
- start = self._address_parser.number(start)
- except KeyError:
- self._output("Bad label: %s" % start)
- return
+ start = self._address_parser.number(splitted[0])
+ bytes = self._assembler.assemble(statement, start)
- bytes = self._assembler.assemble(statement, start)
- if bytes is None:
- self._output("Assemble failed: %s" % statement)
- else:
end = start + len(bytes)
self._mpu.memory[start:end] = bytes
self.do_disassemble((self.addrFmt+":"+self.addrFmt) % (start, end))
+ except KeyError:
+ self._output("Bad label: %s" % args)
+ except OverflowError:
+ self._output("Overflow error: %s" % args)
+ except SyntaxError:
+ self._output("Syntax error: %s" % statement)
def help_assemble(self):
- self._output("assemble
")
- self._output("Assemble a statement at the address.")
+ self._output("assemble \t"
+ "Assemble a statement at the address.")
+ self._output("assemble \t\t"
+ "Start interactive assembly at the address.")
def _interactive_assemble(self, args):
if args == '':
@@ -298,35 +300,38 @@ class Monitor(cmd.Cmd):
try:
start = self._address_parser.number(args)
except KeyError:
- self._output("Bad label: %s" % start)
+ self._output("Bad label: %s" % args)
return
- assembling = True
-
- while assembling:
+ while True:
prompt = "\r$" + ( self.addrFmt % start ) + " " + (" " * (1 + self.byteWidth/4) * 3)
line = console.line_input(prompt,
stdin=self.stdin, stdout=self.stdout)
- if not line:
+ if not line.strip():
self.stdout.write("\n")
return
# assemble into memory
- bytes = self._assembler.assemble(line, pc=start)
- if bytes is None:
- self.stdout.write("\r$" + (self.addrFmt % start) + " ???\n")
- continue
- end = start + len(bytes)
- self._mpu.memory[start:end] = bytes
+ try:
+ bytes = self._assembler.assemble(line, pc=start)
- # print disassembly
- bytes, disasm = self._disassembler.instruction_at(start)
- disassembly = self._format_disassembly(start, bytes, disasm)
- self.stdout.write("\r" + (' ' * (len(prompt+line) + 5) ) + "\r")
- self.stdout.write(disassembly + "\n")
+ end = start + len(bytes)
+ self._mpu.memory[start:end] = bytes
- start += bytes
+ # print disassembly
+ bytes, disasm = self._disassembler.instruction_at(start)
+ disassembly = self._format_disassembly(start, bytes, disasm)
+ self.stdout.write("\r" + (' ' * (len(prompt+line) + 5) ) + "\r")
+ self.stdout.write(disassembly + "\n")
+
+ start += bytes
+ except KeyError:
+ self.stdout.write("\r$" + (self.addrFmt % start) + " ?Label\n")
+ except OverflowError:
+ self.stdout.write("\r$" + (self.addrFmt % start) + " ?Overflow\n")
+ except SyntaxError:
+ self.stdout.write("\r$" + (self.addrFmt % start) + " ?Syntax\n")
def do_disassemble(self, args):
split = shlex.split(args)
diff --git a/py65/tests/test_monitor.py b/py65/tests/test_monitor.py
index 9900c58..5e6d0b5 100644
--- a/py65/tests/test_monitor.py
+++ b/py65/tests/test_monitor.py
@@ -114,15 +114,23 @@ class MonitorTests(unittest.TestCase):
mon.do_assemble('nonexistant rts')
out = stdout.getvalue()
- self.assertEqual("Bad label: nonexistant\n", out)
+ self.assertEqual("Bad label: nonexistant rts\n", out)
- def test_do_assemble_shows_bad_statement_error(self):
+ def test_do_assemble_shows_bad_syntax_error(self):
stdout = StringIO()
mon = Monitor(stdout=stdout)
mon.do_assemble('c000 foo')
out = stdout.getvalue()
- self.assertEqual("Assemble failed: foo\n", out)
+ self.assertEqual("Syntax error: foo\n", out)
+
+ def test_do_assemble_shows_overflow_error(self):
+ stdout = StringIO()
+ mon = Monitor(stdout=stdout)
+ mon.do_assemble('c000 lda #$fff')
+
+ out = stdout.getvalue()
+ self.assertEqual("Overflow error: c000 lda #$fff\n", out)
def test_do_assemble_passes_addr_for_relative_branch_calc(self):
stdout = StringIO()
@@ -138,7 +146,7 @@ class MonitorTests(unittest.TestCase):
mon.do_assemble("-1 lda #$ab")
out = stdout.getvalue()
- self.assertEqual("$0000 a9 ab LDA #$ab\n", out)
+ self.assertEqual("Overflow error: -1 lda #$ab\n", out)
def test_help_assemble(self):
stdout = StringIO()
diff --git a/py65/tests/utils/test_addressing.py b/py65/tests/utils/test_addressing.py
index e2c171e..40164f8 100644
--- a/py65/tests/utils/test_addressing.py
+++ b/py65/tests/utils/test_addressing.py
@@ -108,18 +108,18 @@ class AddressParserTests(unittest.TestCase):
def test_number_constrains_address_at_zero_or_above(self):
parser = AddressParser()
- self.assertEqual(0x0000, parser.number('-1'))
+ self.assertRaises(OverflowError, parser.number, '-1')
def test_number_constrains_address_at_maxwidth_16(self):
parser = AddressParser()
parser.labels = {'foo': 0xFFFF}
- self.assertEqual(0xFFFF, parser.number('foo+5'))
+ self.assertRaises(OverflowError, parser.number, 'foo+5')
def test_number_constrains_address_at_maxwidth_24(self):
parser = AddressParser()
parser.maxwidth = 24
parser.labels = {'foo': 0xFFFFFF}
- self.assertEqual(0xFFFFFF, parser.number('foo+5'))
+ self.assertRaises(OverflowError, parser.number, 'foo+5')
def test_label_for_returns_label(self):
parser = AddressParser(labels={'chrout':0xFFD2})
diff --git a/py65/utils/addressing.py b/py65/utils/addressing.py
index 4798a60..6e9fbab 100644
--- a/py65/utils/addressing.py
+++ b/py65/utils/addressing.py
@@ -93,7 +93,7 @@ class AddressParser(object):
return (start, end)
def _constrain(self, address):
- """Constrains a number to be within the address range"""
- address = max(address, 0)
- address = min(address, self._maxaddr)
+ '''Raises OverflowError if the address is illegal'''
+ if address < 0 or address > self._maxaddr:
+ raise OverflowError(address)
return address