def main(args=None): # Initializes asm parser state api.config.init() asmparse.init() zxbpp.init() # Create option parser o_parser = argparse.ArgumentParser(prog='zxbasm') o_parser.add_argument('PROGRAM', type=str, help='ASM program file') o_parser.add_argument("-d", "--debug", action="count", default=OPTIONS.Debug.value, help="Enable verbosity/debugging output") o_parser.add_argument("-O", "--optimize", type=int, dest="optimization_level", help="Sets optimization level. 0 = None", default=OPTIONS.optimization.value) o_parser.add_argument( "-o", "--output", type=str, dest="output_file", help="Sets output file. Default is input filename with .bin extension", default=None) o_parser.add_argument("-T", "--tzx", action="store_true", dest="tzx", default=False, help="Sets output format to tzx (default is .bin)") o_parser.add_argument("-t", "--tap", action="store_true", dest="tap", default=False, help="Sets output format to tzx (default is .bin)") o_parser.add_argument( "-B", "--BASIC", action="store_true", dest="basic", default=False, help= "Creates a BASIC loader which load the rest of the CODE. Requires -T ot -t" ) o_parser.add_argument( "-a", "--autorun", action="store_true", default=False, help="Sets the program to auto run once loaded (implies --BASIC)") o_parser.add_argument( "-e", "--errmsg", type=str, dest="stderr", default=OPTIONS.StdErrFileName.value, help="Error messages file (standard error console by default") o_parser.add_argument("-M", "--mmap", type=str, dest="memory_map", default=None, help="Generate label memory map") o_parser.add_argument( "-b", "--bracket", action="store_true", default=False, help="Allows brackets only for memory access and indirections") o_parser.add_argument("--version", action="version", version="%(prog)s " + VERSION) options = o_parser.parse_args(args) if not os.path.exists(options.PROGRAM): o_parser.error("No such file or directory: '%s'" % options.PROGRAM) sys.exit(2) OPTIONS.Debug.value = int(options.debug) OPTIONS.inputFileName.value = options.PROGRAM OPTIONS.outputFileName.value = options.output_file OPTIONS.optimization.value = options.optimization_level OPTIONS.use_loader.value = options.autorun or options.basic OPTIONS.autorun.value = options.autorun OPTIONS.StdErrFileName.value = options.stderr OPTIONS.memory_map.value = options.memory_map OPTIONS.bracket.value = options.bracket if options.tzx: OPTIONS.output_file_type.value = 'tzx' elif options.tap: OPTIONS.output_file_type.value = 'tap' if not OPTIONS.outputFileName.value: OPTIONS.outputFileName.value = os.path.splitext( os.path.basename(OPTIONS.inputFileName.value) )[0] + os.path.extsep + OPTIONS.output_file_type.value if OPTIONS.StdErrFileName.value: OPTIONS.stderr.value = open(OPTIONS.StdErrFileName.value, 'wt') if int(options.tzx) + int(options.tap) > 1: o_parser.error("Options --tap, --tzx and --asm are mutually exclusive") return 3 if OPTIONS.use_loader.value and not options.tzx and not options.tap: o_parser.error( 'Option --BASIC and --autorun requires --tzx or tap format') return 4 # Configure the preprocessor to use the asm-preprocessor-lexer zxbpp.setMode('asm') # Now filter them against the preprocessor zxbpp.main([OPTIONS.inputFileName.value]) # Now output the result asm_output = zxbpp.OUTPUT asmparse.assemble(asm_output) if global_.has_errors: return 1 if not asmparse.MEMORY.memory_bytes: # empty seq. asmparse.warning(0, "Nothing to assemble. Exiting...") return 0 current_org = max(asmparse.MEMORY.memory_bytes.keys() or [0]) + 1 for label, line in asmparse.INITS: expr_label = Expr.makenode( Container(asmparse.MEMORY.get_label(label, line), line)) asmparse.MEMORY.add_instruction(Asm(0, 'CALL NN', expr_label)) if len(asmparse.INITS) > 0: if asmparse.AUTORUN_ADDR is not None: asmparse.MEMORY.add_instruction( Asm(0, 'JP NN', asmparse.AUTORUN_ADDR)) else: asmparse.MEMORY.add_instruction( Asm(0, 'JP NN', min(asmparse.MEMORY.orgs.keys())) ) # To the beginning of binary. Ehem... asmparse.AUTORUN_ADDR = current_org if OPTIONS.memory_map.value: with open(OPTIONS.memory_map.value, 'wt') as f: f.write(asmparse.MEMORY.memory_map) asmparse.generate_binary(OPTIONS.outputFileName.value, OPTIONS.output_file_type.value) return global_.has_errors
def main(args=None): """ Entry point when executed from command line. You can use zxb.py as a module with import, and this function won't be executed. """ api.config.init() zxbpp.init() zxbparser.init() arch.zx48k.backend.init() arch.zx48k.Translator.reset() asmparse.init() # ------------------------------------------------------------ # Command line parsing # ------------------------------------------------------------ parser = argparse.ArgumentParser(prog='zxb') parser.add_argument('PROGRAM', type=str, help='BASIC program file') parser.add_argument('-d', '--debug', dest='debug', default=OPTIONS.Debug.value, action='count', help='Enable verbosity/debugging output. Additional -d increase verbosity/debug level') parser.add_argument('-O', '--optimize', type=int, default=OPTIONS.optimization.value, help='Sets optimization level. ' '0 = None (default level is {0})'.format(OPTIONS.optimization.value)) parser.add_argument('-o', '--output', type=str, dest='output_file', default=None, help='Sets output file. Default is input filename with .bin extension') parser.add_argument('-T', '--tzx', action='store_true', help="Sets output format to tzx (default is .bin)") parser.add_argument('-t', '--tap', action='store_true', help="Sets output format to tap (default is .bin)") parser.add_argument('-B', '--BASIC', action='store_true', dest='basic', help="Creates a BASIC loader which loads the rest of the CODE. Requires -T ot -t") parser.add_argument('-a', '--autorun', action='store_true', help="Sets the program to be run once loaded") parser.add_argument('-A', '--asm', action='store_true', help="Sets output format to asm") parser.add_argument('-S', '--org', type=str, default=str(OPTIONS.org.value), help="Start of machine code. By default %i" % OPTIONS.org.value) parser.add_argument('-e', '--errmsg', type=str, dest='stderr', default=OPTIONS.StdErrFileName.value, help='Error messages file (standard error console by default)') parser.add_argument('--array-base', type=int, default=OPTIONS.array_base.value, help='Default lower index for arrays ({0} by default)'.format(OPTIONS.array_base.value)) parser.add_argument('--string-base', type=int, default=OPTIONS.string_base.value, help='Default lower index for strings ({0} by default)'.format(OPTIONS.array_base.value)) parser.add_argument('-Z', '--sinclair', action='store_true', help='Enable by default some more original ZX Spectrum Sinclair BASIC features: ATTR, SCREEN$, ' 'POINT') parser.add_argument('-H', '--heap-size', type=int, default=OPTIONS.heap_size.value, help='Sets heap size in bytes (default {0} bytes)'.format(OPTIONS.heap_size.value)) parser.add_argument('--debug-memory', action='store_true', help='Enables out-of-memory debug') parser.add_argument('--debug-array', action='store_true', help='Enables array boundary checking') parser.add_argument('--strict-bool', action='store_true', help='Enforce boolean values to be 0 or 1') parser.add_argument('--enable-break', action='store_true', help='Enables program execution BREAK detection') parser.add_argument('-E', '--emit-backend', action='store_true', help='Emits backend code instead of ASM or binary') parser.add_argument('--explicit', action='store_true', help='Requires all variables and functions to be declared before used') parser.add_argument('-D', '--define', type=str, dest='defines', action='append', help='Defines de given macro. Eg. -D MYDEBUG or -D NAME=Value') parser.add_argument('-M', '--mmap', type=str, dest='memory_map', default=None, help='Generate label memory map') parser.add_argument('-i', '--ignore-case', action='store_true', help='Ignore case. Makes variable names are case insensitive') parser.add_argument('-I', '--include-path', type=str, default='', help='Add colon separated list of directories to add to include path. e.g. -I dir1:dir2') parser.add_argument('--strict', action='store_true', help='Enables strict mode. Force explicit type declaration') parser.add_argument('--headerless', action='store_true', help='Header-less mode: omit asm prologue and epilogue') parser.add_argument('--version', action='version', version='%(prog)s {0}'.format(VERSION)) parser.add_argument('--parse-only', action='store_true', help='Only parses to check for syntax and semantic errors') parser.add_argument('--append-binary', default=[], action='append', help='Appends binary to tape file (only works with -t or -T)') parser.add_argument('--append-headless-binary', default=[], action='append', help='Appends binary to tape file (only works with -t or -T)') options = parser.parse_args(args=args) # ------------------------------------------------------------ # Setting of internal parameters according to command line # ------------------------------------------------------------ OPTIONS.Debug.value = options.debug OPTIONS.optimization.value = options.optimize OPTIONS.outputFileName.value = options.output_file OPTIONS.StdErrFileName.value = options.stderr OPTIONS.array_base.value = options.array_base OPTIONS.string_base.value = options.string_base OPTIONS.Sinclair.value = options.sinclair OPTIONS.heap_size.value = options.heap_size OPTIONS.memoryCheck.value = options.debug_memory OPTIONS.strictBool.value = options.strict_bool or OPTIONS.Sinclair.value OPTIONS.arrayCheck.value = options.debug_array OPTIONS.emitBackend.value = options.emit_backend OPTIONS.enableBreak.value = options.enable_break OPTIONS.explicit.value = options.explicit OPTIONS.memory_map.value = options.memory_map OPTIONS.strict.value = options.strict OPTIONS.headerless.value = options.headerless OPTIONS.org.value = api.utils.parse_int(options.org) if OPTIONS.org.value is None: parser.error("Invalid --org option '{}'".format(options.org)) if options.defines: for i in options.defines: name, val = tuple(i.split('=', 1)) OPTIONS.__DEFINES.value[name] = val zxbpp.ID_TABLE.define(name, lineno=0) if OPTIONS.Sinclair.value: OPTIONS.array_base.value = 1 OPTIONS.string_base.value = 1 OPTIONS.strictBool.value = True OPTIONS.case_insensitive.value = True if options.ignore_case: OPTIONS.case_insensitive.value = True debug.ENABLED = OPTIONS.Debug.value if int(options.tzx) + int(options.tap) + int(options.asm) + int(options.emit_backend) + \ int(options.parse_only) > 1: parser.error("Options --tap, --tzx, --emit-backend, --parse-only and --asm are mutually exclusive") return 3 if options.basic and not options.tzx and not options.tap: parser.error('Option --BASIC and --autorun requires --tzx or tap format') return 4 if options.append_binary and not options.tzx and not options.tap: parser.error('Option --append-binary needs either --tap or --tzx') return 5 OPTIONS.use_loader.value = options.basic OPTIONS.autorun.value = options.autorun if options.tzx: OPTIONS.output_file_type.value = 'tzx' elif options.tap: OPTIONS.output_file_type.value = 'tap' elif options.asm: OPTIONS.output_file_type.value = 'asm' elif options.emit_backend: OPTIONS.output_file_type.value = 'ic' args = [options.PROGRAM] if not os.path.exists(options.PROGRAM): parser.error("No such file or directory: '%s'" % args[0]) return 2 if OPTIONS.memoryCheck.value: OPTIONS.__DEFINES.value['__MEMORY_CHECK__'] = '' zxbpp.ID_TABLE.define('__MEMORY_CHECK__', lineno=0) if OPTIONS.arrayCheck.value: OPTIONS.__DEFINES.value['__CHECK_ARRAY_BOUNDARY__'] = '' zxbpp.ID_TABLE.define('__CHECK_ARRAY_BOUNDARY__', lineno=0) OPTIONS.include_path.value = options.include_path OPTIONS.inputFileName.value = zxbparser.FILENAME = \ os.path.basename(args[0]) if not OPTIONS.outputFileName.value: OPTIONS.outputFileName.value = \ os.path.splitext(os.path.basename(OPTIONS.inputFileName.value))[0] + os.path.extsep + \ OPTIONS.output_file_type.value if OPTIONS.StdErrFileName.value: OPTIONS.stderr.value = open_file(OPTIONS.StdErrFileName.value, 'wt', 'utf-8') zxbpp.setMode('basic') zxbpp.main(args) if gl.has_errors: debug.__DEBUG__("exiting due to errors.") return 1 # Exit with errors input_ = zxbpp.OUTPUT zxbparser.parser.parse(input_, lexer=zxblex.lexer, tracking=True, debug=(OPTIONS.Debug.value > 2)) if gl.has_errors: debug.__DEBUG__("exiting due to errors.") return 1 # Exit with errors # Optimizations optimizer = api.optimize.OptimizerVisitor() optimizer.visit(zxbparser.ast) # Emits intermediate code translator = arch.zx48k.Translator() translator.visit(zxbparser.ast) if gl.DATA_IS_USED: gl.FUNCTIONS.extend(gl.DATA_FUNCTIONS) # This will fill MEMORY with pending functions func_visitor = arch.zx48k.FunctionTranslator(gl.FUNCTIONS) func_visitor.start() # Emits data lines translator.emit_data_blocks() # Emits default constant strings translator.emit_strings() # Emits jump tables translator.emit_jump_tables() if OPTIONS.emitBackend.value: with open_file(OPTIONS.outputFileName.value, 'wt', 'utf-8') as output_file: for quad in translator.dumpMemory(backend.MEMORY): output_file.write(str(quad) + '\n') backend.MEMORY[:] = [] # Empties memory # This will fill MEMORY with global declared variables translator = arch.zx48k.VarTranslator() translator.visit(zxbparser.data_ast) for quad in translator.dumpMemory(backend.MEMORY): output_file.write(str(quad) + '\n') return 0 # Exit success # Join all lines into a single string and ensures an INTRO at end of file asm_output = backend.emit(backend.MEMORY) asm_output = optimize(asm_output) + '\n' asm_output = asm_output.split('\n') for i in range(len(asm_output)): tmp = backend.ASMS.get(asm_output[i], None) if tmp is not None: asm_output[i] = '\n'.join(tmp) asm_output = '\n'.join(asm_output) # Now filter them against the preprocessor again zxbpp.setMode('asm') zxbpp.OUTPUT = '' zxbpp.filter_(asm_output, args[0]) # Now output the result asm_output = zxbpp.OUTPUT.split('\n') get_inits(asm_output) # Find out remaining inits backend.MEMORY[:] = [] # This will fill MEMORY with global declared variables translator = arch.zx48k.VarTranslator() translator.visit(zxbparser.data_ast) if gl.has_errors: debug.__DEBUG__("exiting due to errors.") return 1 # Exit with errors tmp = [x for x in backend.emit(backend.MEMORY) if x.strip()[0] != '#'] asm_output += tmp asm_output = backend.emit_start() + asm_output asm_output += backend.emit_end(asm_output) if options.asm: # Only output assembler file with open_file(OPTIONS.outputFileName.value, 'wt', 'utf-8') as output_file: output(asm_output, output_file) elif not options.parse_only: fout = StringIO() output(asm_output, fout) asmparse.assemble(fout.getvalue()) fout.close() asmparse.generate_binary(OPTIONS.outputFileName.value, OPTIONS.output_file_type.value, binary_files=options.append_binary, headless_binary_files=options.append_headless_binary) if gl.has_errors: return 5 # Error in assembly if OPTIONS.memory_map.value: with open_file(OPTIONS.memory_map.value, 'wt', 'utf-8') as f: f.write(asmparse.MEMORY.memory_map) return gl.has_errors # Exit success
def main(argv): ''' Entry point when executed from command line. You can use zxb.py as a module with import, and this function won't be executed. ''' global FLAG_use_BASIC, FLAG_autorun global FILE_input, FILE_output, FILE_output_ext, OPTIONS_asm OPTIONS.add_option_if_not_defined('memoryCheck', bool, False) OPTIONS.add_option_if_not_defined('strictBool', bool, False) OPTIONS.add_option_if_not_defined('arrayCheck', bool, False) OPTIONS.add_option_if_not_defined('array_base', int, 0) OPTIONS.add_option_if_not_defined('string_base', int, 0) OPTIONS.add_option_if_not_defined('enableBreak', bool, False) OPTIONS.add_option_if_not_defined('emmitBackend', bool, False) OPTIONS.add_option_if_not_defined('arch', str, 'zx48k') OPTIONS.add_option_if_not_defined('__DEFINES', dict, {}) OPTIONS.add_option_if_not_defined('explicit', bool, False) # ------------------------------------------------------------ # Command line parsing # ------------------------------------------------------------ parser = OptionParser(usage='Usage: %prog <input file> [options]', version='%prog ' + VERSION) parser.add_option( "-d", "--debug", action="count", dest="debug", default=OPTIONS.Debug.value, help= "Enable verbosity/debugging output. Additional -d increase verbosity/debug level." ) parser.add_option("-O", "--optimize", type="int", dest="optimization_level", help="Sets optimization level. 0 = None", default=DEFAULT_OPTIMIZATION_LEVEL) parser.add_option( "-o", "--output", type="string", dest="output_file", help="Sets output file. Default is input filename with .bin extension", default=None) parser.add_option("-T", "--tzx", action="store_true", dest="tzx", default=False, help="Sets output format to tzx (default is .bin)") parser.add_option("-t", "--tap", action="store_true", dest="tap", default=False, help="Sets output format to tap (default is .bin)") parser.add_option( "-B", "--BASIC", action="store_true", dest="basic", default=False, help= "Creates a BASIC loader which load the rest of the CODE. Requires -T ot -t" ) parser.add_option("-a", "--autorun", action="store_true", dest="autorun", default=False, help="Sets the program to be run once loaded") parser.add_option("-A", "--asm", action="store_true", dest="asm", default=False, help="Sets output format to asm") parser.add_option("-S", "--org", type="int", dest="org", help="Start of machine code. By default %i" % OPTIONS.org.value, default=OPTIONS.org.value) parser.add_option( "-e", "--errmsg", type="string", dest="stderr", default=OPTIONS.StdErrFileName.value, help="Error messages file (standard error console by default)") parser.add_option("--array-base", type="int", dest="array_base", default=OPTIONS.array_base.value, help="Default lower index for arrays (0 by default)") parser.add_option("--string-base", type="int", dest="string_base", default=OPTIONS.string_base.value, help="Default lower index for strings (0 by default)") parser.add_option( "-Z", "--sinclair", action="store_true", dest="sinclair", default=False, help= "Enable by default some more original ZX Spectrum Sinclair BASIC features: ATTR, SCREEN$, POINT" ) parser.add_option("-H", "--heap-size", type="int", dest="heap_size", default=OPTIONS.heap_size.value, help="Sets heap size in bytes (default %i bytes)" % OPTIONS.heap_size.value) parser.add_option("--debug-memory", action="store_true", dest="debug_memory", default=False, help="Enables out-of-memory debug") parser.add_option("--debug-array", action="store_true", dest="debug_array", default=False, help="Enables array boundary checking") parser.add_option("--strict-bool", action="store_true", dest="strict_bool", default=False, help="Enforce boolean values to be 0 or 1") parser.add_option("--enable-break", action="store_true", dest="enable_break", default=False, help="Enables program execution BREAK detection") parser.add_option("-E", "--emmit-backend", action="store_true", dest="emmit_backend", default=False, help="Emmits backend code instead of ASM or binary") parser.add_option( "--explicit", action="store_true", dest="explicit", default=False, help="Requires all variables and functions to be declared before used") parser.add_option( "-D", "--define", type="str", dest="defines", action="append", help="Defines de given macro. Eg. -D MYDEBUG or -D NAME=Value") (options, args) = parser.parse_args() if len(args) != 1: parser.error("missing input file. (Try -h)") return 3 # ------------------------------------------------------------ # Setting of internal parameters according to command line # ------------------------------------------------------------ OPTIONS.Debug.value = options.debug asmparse.FLAG_optimize = OPTIONS.optimization.value = options.optimization_level asmparse.FILE_output = OPTIONS.outputFileName.value = FILE_output = options.output_file asmparse.FILE_stderr = OPTIONS.StdErrFileName.value = options.stderr OPTIONS.array_base.value = options.array_base OPTIONS.string_base.value = options.string_base OPTIONS.Sinclair.value = options.sinclair OPTIONS.org.value = options.org OPTIONS.heap_size.value = options.heap_size OPTIONS.memoryCheck.value = options.debug_memory OPTIONS.strictBool.value = options.strict_bool or OPTIONS.Sinclair.value OPTIONS.arrayCheck.value = options.debug_array OPTIONS.emmitBackend.value = options.emmit_backend OPTIONS.enableBreak.value = options.enable_break OPTIONS.explicit.value = options.explicit if options.defines: for i in options.defines: name, val = tuple(i.split('=', 1)) OPTIONS.__DEFINES.value[name] = val zxbpp.ID_TABLE.define(name, lineno=0) if OPTIONS.Sinclair.value: OPTIONS.array_base.value = 1 OPTIONS.string_base.value = 1 OPTIONS.strictBool.value = True debug.ENABLED = OPTIONS.Debug.value if int(options.tzx) + int(options.tap) + int(options.asm) + int( options.emmit_backend) > 1: parser.error( "Options --tap, --tzx, --emmit-backend and --asm are excluyent") return 3 asmparse.FLAG_use_BASIC = options.basic backend.FLAG_autostart = asmparse.FLAG_autorun = options.autorun if asmparse.FLAG_use_BASIC and not options.tzx and not options.tap: parser.error( 'Option --BASIC and --autorun requires --tzx or tap format') return 4 if options.tzx: FILE_output_ext = 'tzx' elif options.tap: FILE_output_ext = 'tap' elif options.asm: FILE_output_ext = 'asm' elif options.emmit_backend: FILE_output_ext = 'ic' if not os.path.exists(args[0]): parser.error("No such file or directory: '%s'" % args[0]) return 2 if OPTIONS.memoryCheck.value: OPTIONS.__DEFINES.value['__MEMORY_CHECK__'] = '' zxbpp.ID_TABLE.define('__MEMORY_CHECK__', lineno=0) if OPTIONS.arrayCheck.value: OPTIONS.__DEFINES.value['__CHECK_ARRAY_BOUNDARY__'] = '' zxbpp.ID_TABLE.define('__CHECK_ARRAY_BOUNDARY__', lineno=0) zxbpp.main(args) asmparse.FILE_output_ext = FILE_output_ext input = zxbpp.OUTPUT asmparse.FILE_input = FILE_input = zxbparser.FILENAME = os.path.basename( args[0]) if FILE_output is None: OPTIONS.outputFileName.value = FILE_output = os.path.splitext( os.path.basename(FILE_input))[0] + '.' + FILE_output_ext asmparse.FILE_output = FILE_output if OPTIONS.StdErrFileName.value is not None: FILE_stderr = asmparse.FILE_stderr = OPTIONS.StdErrFileName.value OPTIONS.stderr.value = open(FILE_stderr, 'wt') zxbparser.parser.parse(input, lexer=zxblex.lexer, tracking=True, debug=(OPTIONS.Debug.value > 2)) if gl.has_errors: return 1 # Exit with errors zxbtrad.traverse(zxbparser.ast) # This will fill MEMORY with code zxbtrad.traverse( zxbtrad.FUNCTIONS) # This will fill MEMORY with pending functions zxbtrad.emmit_strings() if OPTIONS.emmitBackend.value: output_file = open(FILE_output, 'wt') for quad in zxbtrad.dumpMemory(MEMORY): output_file.write(str(quad) + '\n') MEMORY[:] = [] # Empties memory zxbtrad.traverse( zxbparser.data_ast ) # This will fill MEMORY with global declared variables for quad in zxbtrad.dumpMemory(MEMORY): output_file.write(str(quad) + '\n') output_file.close() return 0 # Join all lines into a single string and ensures an INTRO at end of file asm_output = backend.emmit(MEMORY) from optimizer import optimize asm_output = optimize(asm_output) + '\n' # Now put user asm blocks back from backend import ASMS asm_output = asm_output.split('\n') for i in range(len(asm_output)): tmp = ASMS.get(asm_output[i], None) if tmp is not None: asm_output[i] = '\n'.join(tmp) asm_output = '\n'.join(asm_output) # Now filter them against the preprocessor again zxbpp.setMode('asm') zxbpp.OUTPUT = '' zxbpp.filter(asm_output, args[0]) # Now output the result asm_output = zxbpp.OUTPUT.split('\n') get_inits(asm_output) # Find out remaining inits MEMORY[:] = [] zxbtrad.traverse(zxbparser.data_ast ) # This will fill MEMORY with global declared variables tmp = [x for x in backend.emmit(MEMORY) if x.strip()[0] != '#'] asm_output += tmp asm_output = backend.emmit_start() + asm_output asm_output += backend.emmit_end(asm_output) if options.asm: # Only output assembler file output_file = open(FILE_output, 'wt') output(asm_output, output_file) output_file.close() else: from StringIO import StringIO fout = StringIO() output(asm_output, fout) asmparse.assemble(fout.getvalue()) fout.close() asmparse.generate_binary(FILE_output, FILE_output_ext) return 0 # Exit success
OPTIONS.stderr.value = open(asmparse.FILE_stderr, 'wt') if int(options.tzx) + int(options.tap) > 1: o_parser.error("Options --tap, --tzx and --asm are mutually excluyent") sys.exit(3) if asmparse.FLAG_use_BASIC and not options.tzx and not options.tap: o_parser.error('Option --BASIC and --autorun requires --tzx or tap format') sys.exit(4) # Configure the preprocessor to use the asm-preprocessor-lexer zxbpp.setMode('asm') # Now filter them against the preprocessor zxbpp.main([asmparse.FILE_input]) # Now output the result asm_output = zxbpp.OUTPUT asmparse.assemble(asm_output) current_org = max(asmparse.MEMORY.memory_bytes.keys()) + 1 for label, line in asmparse.INITS: expr_label = Expr.makenode(Container(asmparse.MEMORY.get_label(label, line), line)) asmparse.MEMORY.add_instruction(Asm(0, 'CALL NN', expr_label)) if len(asmparse.INITS) > 0: if asmparse.AUTORUN_ADDR is not None: asmparse.MEMORY.add_instruction(Asm(0, 'JP NN', asmparse.AUTORUN_ADDR)) else:
def main(argv): ''' Entry point when executed from command line. You can use zxb.py as a module with import, and this function won't be executed. ''' global FLAG_use_BASIC, FLAG_autorun global FILE_input, FILE_output, FILE_output_ext, OPTIONS_asm OPTIONS.add_option_if_not_defined('memoryCheck', bool, False) OPTIONS.add_option_if_not_defined('strictBool', bool, False) OPTIONS.add_option_if_not_defined('arrayCheck', bool, False) OPTIONS.add_option_if_not_defined('array_base', int, 0) OPTIONS.add_option_if_not_defined('string_base', int, 0) OPTIONS.add_option_if_not_defined('enableBreak', bool, False) OPTIONS.add_option_if_not_defined('emmitBackend', bool, False) OPTIONS.add_option_if_not_defined('arch', str, 'zx48k') OPTIONS.add_option_if_not_defined('__DEFINES', dict, {}) OPTIONS.add_option_if_not_defined('explicit', bool, False) # ------------------------------------------------------------ # Command line parsing # ------------------------------------------------------------ parser = OptionParser(usage='Usage: %prog <input file> [options]', version = '%prog ' + VERSION) parser.add_option("-d", "--debug", action="count", dest="debug", default=OPTIONS.Debug.value, help="Enable verbosity/debugging output. Additional -d increase verbosity/debug level.") parser.add_option("-O", "--optimize", type="int", dest="optimization_level", help="Sets optimization level. 0 = None", default=DEFAULT_OPTIMIZATION_LEVEL) parser.add_option("-o", "--output", type="string", dest="output_file", help="Sets output file. Default is input filename with .bin extension", default=None) parser.add_option("-T", "--tzx", action="store_true", dest="tzx", default=False, help="Sets output format to tzx (default is .bin)") parser.add_option("-t", "--tap", action="store_true", dest="tap", default=False, help="Sets output format to tap (default is .bin)") parser.add_option("-B", "--BASIC", action="store_true", dest="basic", default=False, help="Creates a BASIC loader which load the rest of the CODE. Requires -T ot -t") parser.add_option("-a", "--autorun", action="store_true", dest="autorun", default=False, help="Sets the program to be run once loaded") parser.add_option("-A", "--asm", action="store_true", dest="asm", default=False, help="Sets output format to asm") parser.add_option("-S", "--org", type="int", dest="org", help="Start of machine code. By default %i" % OPTIONS.org.value, default=OPTIONS.org.value) parser.add_option("-e", "--errmsg", type="string", dest="stderr", default=OPTIONS.StdErrFileName.value, help="Error messages file (standard error console by default)") parser.add_option("--array-base", type="int", dest="array_base", default=OPTIONS.array_base.value, help="Default lower index for arrays (0 by default)") parser.add_option("--string-base", type="int", dest="string_base", default=OPTIONS.string_base.value, help="Default lower index for strings (0 by default)") parser.add_option("-Z", "--sinclair", action="store_true", dest="sinclair", default=False, help="Enable by default some more original ZX Spectrum Sinclair BASIC features: ATTR, SCREEN$, POINT") parser.add_option("-H", "--heap-size", type="int", dest="heap_size", default=OPTIONS.heap_size.value, help="Sets heap size in bytes (default %i bytes)" % OPTIONS.heap_size.value) parser.add_option("--debug-memory", action="store_true", dest="debug_memory", default=False, help="Enables out-of-memory debug") parser.add_option("--debug-array", action="store_true", dest="debug_array", default=False, help="Enables array boundary checking") parser.add_option("--strict-bool", action="store_true", dest="strict_bool", default=False, help="Enforce boolean values to be 0 or 1") parser.add_option("--enable-break", action="store_true", dest="enable_break", default=False, help="Enables program execution BREAK detection") parser.add_option("-E", "--emmit-backend", action="store_true", dest="emmit_backend", default=False, help="Emmits backend code instead of ASM or binary") parser.add_option("--explicit", action="store_true", dest="explicit", default=False, help="Requires all variables and functions to be declared before used") parser.add_option("-D", "--define", type="str", dest="defines", action="append", help="Defines de given macro. Eg. -D MYDEBUG or -D NAME=Value") (options, args) = parser.parse_args() if len(args) != 1: parser.error("missing input file. (Try -h)") return 3 # ------------------------------------------------------------ # Setting of internal parameters according to command line # ------------------------------------------------------------ OPTIONS.Debug.value = options.debug asmparse.FLAG_optimize = OPTIONS.optimization.value = options.optimization_level asmparse.FILE_output = OPTIONS.outputFileName.value = FILE_output = options.output_file asmparse.FILE_stderr = OPTIONS.StdErrFileName.value = options.stderr OPTIONS.array_base.value = options.array_base OPTIONS.string_base.value = options.string_base OPTIONS.Sinclair.value = options.sinclair OPTIONS.org.value = options.org OPTIONS.heap_size.value = options.heap_size OPTIONS.memoryCheck.value = options.debug_memory OPTIONS.strictBool.value = options.strict_bool or OPTIONS.Sinclair.value OPTIONS.arrayCheck.value = options.debug_array OPTIONS.emmitBackend.value = options.emmit_backend OPTIONS.enableBreak.value = options.enable_break OPTIONS.explicit.value = options.explicit if options.defines: for i in options.defines: name, val = tuple(i.split('=', 1)) OPTIONS.__DEFINES.value[name] = val zxbpp.ID_TABLE.define(name, lineno = 0) if OPTIONS.Sinclair.value: OPTIONS.array_base.value = 1 OPTIONS.string_base.value = 1 OPTIONS.strictBool.value = True debug.ENABLED = OPTIONS.Debug.value if int(options.tzx) + int(options.tap) + int(options.asm) + int(options.emmit_backend) > 1: parser.error("Options --tap, --tzx, --emmit-backend and --asm are excluyent") return 3 asmparse.FLAG_use_BASIC = options.basic backend.FLAG_autostart = asmparse.FLAG_autorun = options.autorun if asmparse.FLAG_use_BASIC and not options.tzx and not options.tap: parser.error('Option --BASIC and --autorun requires --tzx or tap format') return 4 if options.tzx: FILE_output_ext = 'tzx' elif options.tap: FILE_output_ext = 'tap' elif options.asm: FILE_output_ext = 'asm' elif options.emmit_backend: FILE_output_ext = 'ic' if not os.path.exists(args[0]): parser.error("No such file or directory: '%s'" % args[0]) return 2 if OPTIONS.memoryCheck.value: OPTIONS.__DEFINES.value['__MEMORY_CHECK__'] = '' zxbpp.ID_TABLE.define('__MEMORY_CHECK__', lineno = 0) if OPTIONS.arrayCheck.value: OPTIONS.__DEFINES.value['__CHECK_ARRAY_BOUNDARY__'] = '' zxbpp.ID_TABLE.define('__CHECK_ARRAY_BOUNDARY__', lineno = 0) zxbpp.main(args) asmparse.FILE_output_ext = FILE_output_ext input = zxbpp.OUTPUT asmparse.FILE_input = FILE_input = zxbparser.FILENAME = os.path.basename(args[0]) if FILE_output is None: OPTIONS.outputFileName.value = FILE_output = os.path.splitext(os.path.basename(FILE_input))[0] + '.' + FILE_output_ext asmparse.FILE_output = FILE_output if OPTIONS.StdErrFileName.value is not None: FILE_stderr = asmparse.FILE_stderr = OPTIONS.StdErrFileName.value OPTIONS.stderr.value = open(FILE_stderr, 'wt') zxbparser.parser.parse(input, lexer = zxblex.lexer, tracking = True, debug = (OPTIONS.Debug.value > 2)) if gl.has_errors: return 1 # Exit with errors zxbtrad.traverse(zxbparser.ast) # This will fill MEMORY with code zxbtrad.traverse(zxbtrad.FUNCTIONS) # This will fill MEMORY with pending functions zxbtrad.emmit_strings() if OPTIONS.emmitBackend.value: output_file = open(FILE_output, 'wt') for quad in zxbtrad.dumpMemory(MEMORY): output_file.write(str(quad) + '\n') MEMORY[:] = [] # Empties memory zxbtrad.traverse(zxbparser.data_ast) # This will fill MEMORY with global declared variables for quad in zxbtrad.dumpMemory(MEMORY): output_file.write(str(quad) + '\n') output_file.close() return 0 # Join all lines into a single string and ensures an INTRO at end of file asm_output = backend.emmit(MEMORY) from optimizer import optimize asm_output = optimize(asm_output) + '\n' # Now put user asm blocks back from backend import ASMS asm_output = asm_output.split('\n') for i in range(len(asm_output)): tmp = ASMS.get(asm_output[i], None) if tmp is not None: asm_output[i] = '\n'.join(tmp) asm_output = '\n'.join(asm_output) # Now filter them against the preprocessor again zxbpp.setMode('asm') zxbpp.OUTPUT = '' zxbpp.filter(asm_output, args[0]) # Now output the result asm_output = zxbpp.OUTPUT.split('\n') get_inits(asm_output) # Find out remaining inits MEMORY[:] = [] zxbtrad.traverse(zxbparser.data_ast) # This will fill MEMORY with global declared variables tmp = [x for x in backend.emmit(MEMORY) if x.strip()[0] != '#'] asm_output += tmp asm_output = backend.emmit_start() + asm_output asm_output += backend.emmit_end(asm_output) if options.asm: # Only output assembler file output_file = open(FILE_output, 'wt') output(asm_output, output_file) output_file.close() else: from StringIO import StringIO fout = StringIO() output(asm_output, fout) asmparse.assemble(fout.getvalue()) fout.close() asmparse.generate_binary(FILE_output, FILE_output_ext) return 0 # Exit success
if asmparse.FILE_stderr not in (None, ''): OPTIONS.stderr.value = open(asmparse.FILE_stderr, 'wt') if int(options.tzx) + int(options.tap) > 1: o_parser.error("Options --tap, --tzx and --asm are mutually excluyent") sys.exit(3) if asmparse.FLAG_use_BASIC and not options.tzx and not options.tap: o_parser.error('Option --BASIC and --autorun requires --tzx or tap format') sys.exit(4) # Configure the preprocessor to use the asm-preprocessor-lexer zxbpp.setMode('asm') # Now filter them against the preprocessor zxbpp.main([asmparse.FILE_input]) # Now output the result asm_output = zxbpp.OUTPUT asmparse.assemble(asm_output) current_org = max(asmparse.MEMORY.memory_bytes.keys()) + 1 for label, line in asmparse.INITS: expr_label = Expr.makenode( Container(asmparse.MEMORY.get_label(label, line), line)) asmparse.MEMORY.add_instruction(Asm(0, 'CALL NN', expr_label)) if len(asmparse.INITS) > 0: if asmparse.AUTORUN_ADDR is not None: asmparse.MEMORY.add_instruction(Asm(0, 'JP NN', asmparse.AUTORUN_ADDR))