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