Example #1
0
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
Example #2
0
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
Example #3
0
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
Example #4
0
    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:
Example #5
0
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
Example #6
0
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))