2015-10-16 08:30:24 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
"""Usage: sixtypical [OPTIONS] FILES
|
|
|
|
|
2018-02-05 13:17:23 +00:00
|
|
|
Analyzes and compiles a Sixtypical program.
|
2015-10-16 08:30:24 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
from os.path import realpath, dirname, join
|
|
|
|
import sys
|
|
|
|
|
|
|
|
sys.path.insert(0, join(dirname(realpath(sys.argv[0])), '..', 'src'))
|
|
|
|
|
|
|
|
# ----------------------------------------------------------------- #
|
|
|
|
|
|
|
|
import codecs
|
|
|
|
from optparse import OptionParser
|
2015-10-22 14:45:16 +00:00
|
|
|
from pprint import pprint
|
2015-10-16 08:30:24 +00:00
|
|
|
import sys
|
|
|
|
import traceback
|
|
|
|
|
|
|
|
from sixtypical.parser import Parser
|
2015-10-21 14:45:14 +00:00
|
|
|
from sixtypical.analyzer import Analyzer
|
2015-10-17 11:28:39 +00:00
|
|
|
from sixtypical.emitter import Emitter, Byte, Word
|
2015-10-17 14:06:50 +00:00
|
|
|
from sixtypical.compiler import Compiler
|
2015-10-16 08:30:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
optparser = OptionParser(__doc__.strip())
|
|
|
|
|
2018-02-06 16:14:44 +00:00
|
|
|
optparser.add_option("--analyze-only",
|
2015-10-17 14:23:00 +00:00
|
|
|
action="store_true",
|
2018-02-06 16:14:44 +00:00
|
|
|
help="Only parse and analyze the program; do not compile it.")
|
2015-10-17 14:23:00 +00:00
|
|
|
optparser.add_option("--basic-prelude",
|
|
|
|
action="store_true",
|
2018-02-06 16:14:44 +00:00
|
|
|
help="Insert a Commodore BASIC 2.0 snippet before the program "
|
|
|
|
"so that it can be LOADed and RUN on Commodore platforms.")
|
2015-10-17 10:08:25 +00:00
|
|
|
optparser.add_option("--debug",
|
2015-10-17 14:23:00 +00:00
|
|
|
action="store_true",
|
2018-02-06 16:14:44 +00:00
|
|
|
help="Display debugging information when analyzing and compiling.")
|
|
|
|
optparser.add_option("--parse-only",
|
|
|
|
action="store_true",
|
|
|
|
help="Only parse the program; do not analyze or compile it.")
|
2015-10-16 08:30:24 +00:00
|
|
|
optparser.add_option("--traceback",
|
2015-10-17 14:23:00 +00:00
|
|
|
action="store_true",
|
2018-02-06 16:14:44 +00:00
|
|
|
help="When an error occurs, display a full Python traceback.")
|
2015-10-16 08:30:24 +00:00
|
|
|
|
|
|
|
(options, args) = optparser.parse_args(sys.argv[1:])
|
|
|
|
|
|
|
|
for filename in args:
|
|
|
|
text = open(filename).read()
|
2018-02-06 16:14:44 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
parser = Parser(text)
|
|
|
|
program = parser.program()
|
|
|
|
except Exception as e:
|
|
|
|
if options.traceback:
|
|
|
|
raise
|
|
|
|
else:
|
|
|
|
traceback.print_exception(e.__class__, e, None)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
if options.parse_only:
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
try:
|
|
|
|
analyzer = Analyzer(debug=options.debug)
|
|
|
|
analyzer.analyze_program(program)
|
|
|
|
except Exception as e:
|
|
|
|
if options.traceback:
|
|
|
|
raise
|
2015-10-17 10:08:25 +00:00
|
|
|
else:
|
2018-02-06 16:14:44 +00:00
|
|
|
traceback.print_exception(e.__class__, e, None)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
if options.analyze_only:
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
fh = sys.stdout
|
|
|
|
start_addr = 0xc000
|
|
|
|
prelude = []
|
|
|
|
if options.basic_prelude:
|
|
|
|
start_addr = 0x0801
|
|
|
|
prelude = [0x10, 0x08, 0xc9, 0x07, 0x9e, 0x32,
|
|
|
|
0x30, 0x36, 0x31, 0x00, 0x00, 0x00]
|
|
|
|
|
|
|
|
# we are outputting a .PRG, so we output the load address first
|
|
|
|
# we don't use the Emitter for this b/c not part of addr space
|
|
|
|
if not options.debug:
|
|
|
|
fh.write(Word(start_addr).serialize(0))
|
|
|
|
|
|
|
|
emitter = Emitter(start_addr)
|
|
|
|
for byte in prelude:
|
|
|
|
emitter.emit(Byte(byte))
|
|
|
|
compiler = Compiler(emitter)
|
|
|
|
compiler.compile_program(program)
|
|
|
|
if options.debug:
|
|
|
|
pprint(emitter.accum)
|
|
|
|
else:
|
|
|
|
emitter.serialize(fh)
|