New command-line system.

This is a full optparse-based parser for all the options we want
to have in Ophis 2.0, but the pass-disablers aren't working yet.

This also doesn't handle positional arguments the way we hope
to eventually; that will come later.

optparse is deprecated in 2.7, but its replacement isn't available
in any previous version of Python, so we avoid it so as to not
gratuitously break compatibility on older machines.

It would be nice to at least stay usable on stock Leopard Macs (2.5).
This commit is contained in:
Michael C. Martin 2012-05-30 22:18:45 -07:00
parent eae4ea7dcd
commit e47073bc1d
6 changed files with 90 additions and 81 deletions

View File

@ -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:])

View File

@ -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()

View File

@ -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:

View File

@ -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:])

View File

@ -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)

View File

@ -1,4 +1,5 @@
#!/usr/local/bin/python
import sys
import Ophis.Main
Ophis.Main.run_ophis()
Ophis.Main.run_ophis(sys.argv[1:])