diff --git a/bin/ophis b/bin/ophis index 1299a49..c368123 100755 --- a/bin/ophis +++ b/bin/ophis @@ -7,4 +7,4 @@ path.insert(0, join(dirname(realpath(argv[0])), '..', 'src')) import Ophis.Main -Ophis.Main.run_ophis() +Ophis.Main.run_ophis(argv[1:]) diff --git a/src/Ophis/CmdLine.py b/src/Ophis/CmdLine.py index 201ff3e..d50f1be 100644 --- a/src/Ophis/CmdLine.py +++ b/src/Ophis/CmdLine.py @@ -1,17 +1,76 @@ -"""Command line options data. +"""Command line options data.""" - verbose: - 0: Only report errors - 1: Announce each file as it is read, and data count (default) - 2: As above, but also announce each pass. - 3: As above, but print the IR after each pass. - 4: As above, but print the labels after each pass. - - 6510 compatibility and deprecation are handled in Ophis.Main.""" +import optparse # Copyright 2002-2012 Michael C. Martin and additional contributors. # You may use, modify, and distribute this file under the MIT # license: See README for details. -verbose = 1; +enable_collapse = True +enable_branch_extend = True +enable_undoc_ops = False +enable_65c02_exts = False +warn_on_branch_extend = True + +print_summary = True +print_loaded_files = False +print_pass = False +print_ir = False +print_labels = False + +infile = None +outfile = None + +def parse_args(raw_args): + "Populate the module's globals based on the command-line options given." + global enable_collapse, enable_branch_extend, enable_undoc_ops, enable_65c02_exts + global warn_on_branch_extend + global print_summary, print_loaded_files, print_pass, print_ir, print_labels + global infile, outfile + + parser = optparse.OptionParser(usage= "Usage: %prog [options] srcfile outfile", version="Ophis 6502 cross-assembler, version 2.0") + + ingrp = optparse.OptionGroup(parser, "Input options") + ingrp.add_option("-u", "--undoc", action="store_true", default=False, help="Enable 6502 undocumented opcodes") + ingrp.add_option("-c", "--65c02", action="store_true", default=False, dest="c02", help="Enable 65c02 extended instruction set") + + outgrp = optparse.OptionGroup(parser, "Console output options") + outgrp.add_option("-v", "--verbose", action="store_const", const=2, help="Verbose mode", default=1) + outgrp.add_option("-q", "--quiet", action="store_const", help="Quiet mode", dest="verbose", const=0) + outgrp.add_option("-d", "--debug", action="count", dest="verbose", help=optparse.SUPPRESS_HELP) + outgrp.add_option("--no-warn", action="store_false", dest="warn", default=True, help="Do not print warnings") + + bingrp = optparse.OptionGroup(parser, "Binary output options") + bingrp.add_option("--no-collapse", action="store_false", dest="enable_collapse", default="True", help="Disable zero-page collapse pass") + bingrp.add_option("--no-branch-extend", action="store_false", dest="enable_branch_extend", default="True", help="Disable branch-extension pass") + + parser.add_option_group(ingrp) + parser.add_option_group(outgrp) + parser.add_option_group(bingrp) + + (options, args) = parser.parse_args(raw_args) + + if len(args) > 2: + parser.error("Too many files specified") + if len(args) == 1: + parser.error("No output file specified") + if len(args) == 0: + parser.error("No files specified") + if options.c02 and options.undoc: + parser.error("--undoc and --65c02 are mutually exclusive") + + infile = args[0] + outfile = args[1] + enable_collapse = options.enable_collapse + enable_branch_extend = options.enable_branch_extend + enable_undoc_ops = options.undoc + enable_65c02_exts = options.c02 + warn_on_branch_extend = options.warn + print_summary = options.verbose > 0 # no options set + print_loaded_files = options.verbose > 1 # v + print_pass = options.verbose > 2 # dd + print_ir = options.verbose > 3 # ddd + print_labels = options.verbose > 4 # dddd + + parser.destroy() diff --git a/src/Ophis/Frontend.py b/src/Ophis/Frontend.py index 8d2a7c4..4313c57 100644 --- a/src/Ophis/Frontend.py +++ b/src/Ophis/Frontend.py @@ -310,7 +310,7 @@ def parse_line(ppt, lexemelist): def parse_file(ppt, filename): "Loads an Ophis source file, and returns an IR list." Err.currentpoint = ppt - if Cmd.verbose > 0: + if Cmd.print_loaded_files: if filename != '-': print>>sys.stderr, "Loading "+filename else: diff --git a/src/Ophis/Main.py b/src/Ophis/Main.py index 6aa4158..c439f32 100644 --- a/src/Ophis/Main.py +++ b/src/Ophis/Main.py @@ -1,7 +1,7 @@ """Main controller routines for the Ophis assembler. When invoked as main, interprets its command line and goes from there. - Otherwise, use run_all to interpret a file set.""" + Otherwise, use run_ophis(cmdline-list) to use it inside a script.""" # Copyright 2002-2012 Michael C. Martin and additional contributors. # You may use, modify, and distribute this file under the MIT @@ -17,18 +17,6 @@ import Ophis.Environment import Ophis.CmdLine import Ophis.Opcodes - -def usage(): - "Prints a usage message and quits." - print>>sys.stderr, "Usage:" - print>>sys.stderr, "\tOphis [options] infile outfile" - print>>sys.stderr, "" - print>>sys.stderr, "Options:" - print>>sys.stderr, "\t-6510 Allow 6510 undocumented opcodes" - print>>sys.stderr, "\t-65c02 Enable 65c02 extensions" - print>>sys.stderr, "\t-v n Set verbosity to n (0-4, 1=default)" - sys.exit(1) - def run_all(infile, outfile): "Transforms the source infile to a binary outfile." Err.count = 0 @@ -69,56 +57,17 @@ def run_all(infile, outfile): else: Err.report() -def run_ophis(): - infile = None - outfile = None - - p65_compatibility_mode = 0 - chip_extension = None - - reading_arg = 0 - - for x in sys.argv[1:]: - if reading_arg: - try: - Ophis.CmdLine.verbose = int(x) - reading_arg = 0 - except ValueError: - print>>sys.stderr, "FATAL: Non-integer passed as argument to -v" - usage() - elif x[0] == '-' and x != '-': - if x == '-v': - reading_arg = 1 - elif x == '-6510': - chip_extension = Ophis.Opcodes.undocops - elif x == '-65c02': - chip_extension = Ophis.Opcodes.c02extensions - else: - print>>sys.stderr, "FATAL: Unknown option "+x - usage() - elif infile == None: - infile = x - elif outfile == None: - outfile = x - else: - print>>sys.stderr, "FATAL: Too many files specified" - usage() - - if infile is None: - print>>sys.stderr, "FATAL: No files specified" - usage() - - if outfile is None: - print>>sys.stderr, "FATAL: No output file specified" - usage() - +def run_ophis(args): + Ophis.CmdLine.parse_args(args) Ophis.Frontend.pragma_modules.append(Ophis.CorePragmas) - if chip_extension is not None: - Ophis.Opcodes.opcodes.update(chip_extension) + if Ophis.CmdLine.enable_undoc_ops: + Ophis.Opcodes.opcodes.update(Ophis.Opcodes.undocops) + elif Ophis.CmdLine.enable_65c02_exts: + Ophis.Opcodes.opcodes.update(Ophis.Opcodes.c02extensions) Ophis.CorePragmas.reset() - run_all(infile, outfile) + run_all(Ophis.CmdLine.infile, Ophis.CmdLine.outfile) if __name__ == '__main__': - run_ophis() + run_ophis(sys.argv[1:]) diff --git a/src/Ophis/Passes.py b/src/Ophis/Passes.py index a19d02c..8565e55 100644 --- a/src/Ophis/Passes.py +++ b/src/Ophis/Passes.py @@ -54,16 +54,16 @@ class Pass: """Prepares the environment and runs this pass, possibly printing debugging information.""" if Err.count == 0: - if Cmd.verbose > 1: print>>sys.stderr, "Running: "+self.name + if Cmd.print_pass: print>>sys.stderr, "Running: "+self.name env.reset() self.prePass() node.accept(self, env) self.postPass() env.reset() - if Cmd.verbose > 3: + if Cmd.print_labels: print>>sys.stderr, "Current labels:" print>>sys.stderr, env - if Cmd.verbose > 2: + if Cmd.print_ir: print>>sys.stderr, "Current IR:" print>>sys.stderr, node @@ -83,7 +83,7 @@ class FixPoint: p.go(node, env) if Err.count != 0: break if self.fixpoint(): break - if Cmd.verbose > 1: print>>sys.stderr, "Fixpoint failed, looping back" + if Cmd.print_pass: print>>sys.stderr, "Fixpoint failed, looping back" else: Err.log("Can't make %s converge! Maybe there's a recursive dependency somewhere?" % self.name) @@ -96,7 +96,7 @@ class DefineMacros(Pass): def postPass(self): if self.inDef: Err.log("Unmatched .macro") - elif Cmd.verbose > 2: + elif Cmd.print_ir: print>>sys.stderr, "Macro definitions:" Macro.dump() def visitMacroBegin(self, node, env): @@ -392,7 +392,7 @@ class ExtendBranches(PCTracker): # If BRA - BRanch Always - is out of range, it's a JMP. node.data = ('jmp', expr) node.nodetype = "Absolute" - if Cmd.verbose > 0: + if Cmd.warn_on_branch_extend: print>>sys.stderr, str(node.ppt) + ": WARNING: bra out of range, replacing with jmp" else: # Otherwise, we replace it with a 'macro' of sorts by hand: @@ -403,7 +403,7 @@ class ExtendBranches(PCTracker): IR.Node(node.ppt, "Absolute", 'jmp', expr)] node.nodetype='SEQUENCE' node.data = expansion - if Cmd.verbose > 0: + if Cmd.warn_on_branch_extend: print>>sys.stderr, str(node.ppt) + ": WARNING: "+opcode+" out of range, replacing with "+ExtendBranches.reversed[opcode] +"/jmp combo" self.expanded += 1 node.accept(self, env) @@ -435,7 +435,7 @@ class Assembler(Pass): self.filler = 0 def postPass(self): - if Cmd.verbose > 0 and Err.count == 0: + if Cmd.print_summary and Err.count == 0: print>>sys.stderr, "Assembly complete: %s bytes output (%s code, %s data, %s filler)" \ % (len(self.output), self.code, self.data, self.filler) diff --git a/src/scripts/ophis b/src/scripts/ophis index 5ddbf88..e54434a 100644 --- a/src/scripts/ophis +++ b/src/scripts/ophis @@ -1,4 +1,5 @@ #!/usr/local/bin/python +import sys import Ophis.Main -Ophis.Main.run_ophis() +Ophis.Main.run_ophis(sys.argv[1:])