import sys import os import re import zxbpplex import zxbasmpplex import ply.yacc as yacc from zxbpplex import tokens from common import OPTIONS from output import msg, warning, error, CURRENT_FILE from prepro import DefinesTable, ID, MacroCall, Arg, ArgList from prepro.exceptions import PreprocError OPTIONS.add_option_if_not_defined('Sinclair', bool, False) OUTPUT = '' INCLUDED = {} # Already included files (with lines) SPACES = re.compile(r'[ \t]+') # Set to BASIC or ASM depending on the Lexer context # e.g. for .ASM files should be set to zxbppasmlex.Lexer() # Use setMode('ASM' or 'BASIC') to change this FLAG LEXER = zxbpplex.Lexer() # CURRENT working directory for this cpp precedence = ( ('left', 'DUMMY'), ('left', 'EQ', 'NE', 'LT', 'LE', 'GT', 'GE'),
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
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
import sys, os import re from optparse import OptionParser import asmparse from asmparse import Asm, Expr, Container import zxbpp from common import OPTIONS # Release version VERSION = '1.4' # Create default options OPTIONS.add_option_if_not_defined('optimization', int, 0) # Create option parser o_parser = OptionParser(usage='Usage: %prog <input file> [options]', version = '%prog ' + VERSION) o_parser.add_option("-d", "--debug", action="store_true", dest="debug", default=OPTIONS.Debug.value, help="Enable verbosity/debugging output") o_parser.add_option("-O", "--optimize", type="int", dest="optimization_level", help="Sets optimization level. 0 = None", default=asmparse.FLAG_optimize) o_parser.add_option("-o", "--output", type="string", dest="output_file", help="Sets output file. Default is input filename with .bin extension", default=None)
import sys, os import re from optparse import OptionParser import asmparse from asmparse import Asm, Expr, Container import zxbpp from common import OPTIONS # Release version VERSION = '1.4' # Create default options OPTIONS.add_option_if_not_defined('optimization', int, 0) # Create option parser o_parser = OptionParser(usage='Usage: %prog <input file> [options]', version='%prog ' + VERSION) o_parser.add_option("-d", "--debug", action="store_true", dest="debug", default=OPTIONS.Debug.value, help="Enable verbosity/debugging output") o_parser.add_option("-O", "--optimize", type="int",