diff --git a/bin/sixtypical b/bin/sixtypical index 3ca394d..9b2d2cd 100755 --- a/bin/sixtypical +++ b/bin/sixtypical @@ -20,7 +20,7 @@ import traceback from sixtypical.parser import Parser, ParsingContext from sixtypical.analyzer import Analyzer -from sixtypical.outputter import Outputter +from sixtypical.outputter import outputter_class_for from sixtypical.compiler import Compiler @@ -79,25 +79,23 @@ def process_input_files(filenames, options): if options.analyze_only: return - outputter = Outputter(options.output_format) - + start_addr = None if options.origin is not None: if options.origin.startswith('0x'): - outputter.set_start_addr(int(options.origin, 16)) + start_addr = int(options.origin, 16) else: - outputter.set_start_addr(int(options.origin, 10)) + start_addr = int(options.origin, 10) with open(options.output, 'wb') as fh: - # this is *awful* binding - emitter = outputter.write_prelude(fh) - compiler = Compiler(emitter) + outputter = outputter_class_for(options.output_format)(fh, start_addr=start_addr) + outputter.write_prelude() + compiler = Compiler(outputter.emitter) compiler.compile_program(program, compilation_roster=compilation_roster) - outputter.write_postlude(emitter) - + outputter.write_postlude() if options.debug: - pprint(emitter.accum) + pprint(outputter.emitter) else: - emitter.serialize_to(fh) + outputter.emitter.serialize_to(fh) if __name__ == '__main__': diff --git a/src/sixtypical/outputter.py b/src/sixtypical/outputter.py index b6cbbfc..b3828ef 100644 --- a/src/sixtypical/outputter.py +++ b/src/sixtypical/outputter.py @@ -4,49 +4,71 @@ from sixtypical.emitter import Emitter, Byte, Word class Outputter(object): - def __init__(self, output_format): - self.output_format = output_format - if output_format == 'raw': - self.start_addr = 0x0000 - self.prelude = [] - elif output_format == 'prg': - self.start_addr = 0xc000 - self.prelude = [] - elif output_format == 'c64-basic-prg': - self.start_addr = 0x0801 - self.prelude = [0x10, 0x08, 0xc9, 0x07, 0x9e, 0x32, - 0x30, 0x36, 0x31, 0x00, 0x00, 0x00] - elif output_format == 'vic20-basic-prg': - self.start_addr = 0x1001 - self.prelude = [0x0b, 0x10, 0xc9, 0x07, 0x9e, 0x34, - 0x31, 0x30, 0x39, 0x00, 0x00, 0x00] - elif output_format == 'atari2600-cart': - self.start_addr = 0xf000 - self.prelude = [0x78, 0xd8, 0xa2, 0xff, 0x9a, 0xa9, - 0x00, 0x95, 0x00, 0xca, 0xd0, 0xfb] - else: - raise NotImplementedError("Unknown output format: {}".format(output_format)) + def __init__(self, fh, start_addr=None): + self.start_addr = self.__class__.start_addr + if start_addr is not None: + self.start_addr = start_addr + self.prelude = self.__class__.prelude + self.fh = fh + self.emitter = Emitter(self.start_addr) - def set_start_addr(self, start_addr): - self.start_addr = start_addr + def write_header(self): + pass - def write_prelude(self, fh): + def write_prelude(self): + self.write_header() + for byte in self.prelude: + self.emitter.emit(Byte(byte)) + def write_postlude(self): + pass + + +class RawOutputter(Outputter): + start_addr = 0x0000 + prelude = [] + + +class PrgOutputter(Outputter): + start_addr = 0xc000 + prelude = [] + + def write_header(self): # If we are outputting a .PRG, we output the load address first. # We don't use the Emitter for this b/c not part of addr space. - if self.output_format in ('prg', 'c64-basic-prg', 'vic20-basic-prg'): - fh.write(bytearray(Word(self.start_addr).serialize(0))) + self.fh.write(bytearray(Word(self.start_addr).serialize(0))) - emitter = Emitter(self.start_addr) - for byte in self.prelude: - emitter.emit(Byte(byte)) - return emitter +class C64BasicPrgOutputter(PrgOutputter): + start_addr = 0x0801 + prelude = [0x10, 0x08, 0xc9, 0x07, 0x9e, 0x32, + 0x30, 0x36, 0x31, 0x00, 0x00, 0x00] - def write_postlude(self, emitter): + +class Vic20BasicPrgOutputter(PrgOutputter): + start_addr = 0x1001 + prelude = [0x0b, 0x10, 0xc9, 0x07, 0x9e, 0x34, + 0x31, 0x30, 0x39, 0x00, 0x00, 0x00] + + +class Atari2600CartOutputter(Outputter): + start_addr = 0xf000 + prelude = [0x78, 0xd8, 0xa2, 0xff, 0x9a, 0xa9, + 0x00, 0x95, 0x00, 0xca, 0xd0, 0xfb] + + def write_postlude(self): # If we are outputting a cartridge with boot and BRK address # at the end, pad to ROM size minus 4 bytes, and emit addresses. - if self.output_format == 'atari2600-cart': - emitter.pad_to_size(4096 - 4) - emitter.emit(Word(self.start_addr)) - emitter.emit(Word(self.start_addr)) + self.emitter.pad_to_size(4096 - 4) + self.emitter.emit(Word(self.start_addr)) + self.emitter.emit(Word(self.start_addr)) + + +def outputter_class_for(output_format): + return { + 'raw': RawOutputter, + 'prg': PrgOutputter, + 'c64-basic-prg': C64BasicPrgOutputter, + 'vic20-basic-prg': Vic20BasicPrgOutputter, + 'atari2600-cart': Atari2600CartOutputter, + }[output_format]