From b602cc9bd649e9b8283643acaf3946a186dfad69 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Wed, 28 Aug 2013 16:48:29 -0500 Subject: [PATCH 1/3] don't directly reference two macro classes Ideally the macro classes will be removed from the preprocessor core soon, there's no reason they should be infecting these functions. --- preprocessor.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/preprocessor.py b/preprocessor.py index c4b843e1b..7a9ee756e 100644 --- a/preprocessor.py +++ b/preprocessor.py @@ -425,6 +425,18 @@ def macro_test(asm): else: return (None, None) +def is_based_on(something, base): + """ + Checks whether or not 'something' is a class that is a subclass of a class + by name. This is a terrible hack but it removes a direct dependency on + existing macros. + + Used by macro_translator. + """ + options = [str(klass.__name__) for klass in something.__bases__] + options += [something.__name__] + return (base in options) + def macro_translator(macro, token, line): """ Converts a line with a macro into a rgbasm-compatible line. @@ -540,14 +552,14 @@ def macro_translator(macro, token, line): output += ("; " + description + "\n") - if size == 3 and issubclass(param_klass, PointerLabelBeforeBank): + if size == 3 and is_based_on(param_klass, "PointerLabelBeforeBank"): # write the bank first output += ("db " + param + "\n") # write the pointer second output += ("dw " + params[index+1].strip() + "\n") index += 2 correction += 1 - elif size == 3 and issubclass(param_klass, PointerLabelAfterBank): + elif size == 3 and is_based_on(param_klass, "PointerLabelAfterBank"): # write the pointer first output += ("dw " + param + "\n") # write the bank second From 16bfc0112428cd9f872e06b2ce6a2fe553b8eb11 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Wed, 28 Aug 2013 17:18:29 -0500 Subject: [PATCH 2/3] use generic skippable macros in preprocessor This removes TextEndingCommand from the preprocessor. Instead, there is a generic concept of a skippable type of macro like "db". This adds SkippableMacro to the preprocessor. --- preprocessor.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/preprocessor.py b/preprocessor.py index 7a9ee756e..150faee11 100644 --- a/preprocessor.py +++ b/preprocessor.py @@ -13,7 +13,6 @@ from extras.pokemontools.crystal import ( PointerLabelBeforeBank, PointerLabelAfterBank, ItemFragment, - TextEndingCommand, text_command_classes, movement_command_classes, music_classes, @@ -42,6 +41,13 @@ show_original_lines = False # helpful for debugging macros do_macro_sanity_check = False +class SkippableMacro(object): + macro_name = "db" + +skippable_macros = [SkippableMacro] + +macros += skippable_macros + chars = { "ガ": 0x05, "ギ": 0x06, @@ -437,7 +443,7 @@ def is_based_on(something, base): options += [something.__name__] return (base in options) -def macro_translator(macro, token, line): +def macro_translator(macro, token, line, skippable_macros): """ Converts a line with a macro into a rgbasm-compatible line. """ @@ -476,10 +482,10 @@ def macro_translator(macro, token, line): if show_original_lines: sys.stdout.write("; original_line: " + original_line) - # "db" is a macro because of TextEndingCommand + # "db" is a macro because of SkippableMacro # rgbasm can handle "db" so no preprocessing is required # (don't check its param count) - if macro.macro_name == "db" and macro in [TextEndingCommand, ItemFragment]: + if macro.macro_name == "db" and macro in skippable_macros: sys.stdout.write(original_line) return @@ -582,7 +588,7 @@ def macro_translator(macro, token, line): sys.stdout.write(output) -def read_line(l): +def read_line(l, skippable_macros): """Preprocesses a given line of asm.""" # strip comments from asm @@ -610,14 +616,18 @@ def read_line(l): else: macro, token = macro_test(asm) if macro: - macro_translator(macro, token, asm) + macro_translator(macro, token, asm, skippable_macros) else: sys.stdout.write(asm) if comment: sys.stdout.write(comment) -def preprocess(lines=None): +def preprocess(skippable_macros=None, lines=None): """Main entry point for the preprocessor.""" + if skippable_macros == None: + # Note that this is bad because the macro table doesn't include the + # skippable macros. + skippable_macros = [SkippableMacro] if not lines: # read each line from stdin @@ -627,8 +637,8 @@ def preprocess(lines=None): lines = lines.split("\n") for l in lines: - read_line(l) + read_line(l, skippable_macros) # only run against stdin when not included as a module if __name__ == "__main__": - preprocess() + preprocess(skippable_macros=skippable_macros) From e4d3ea72569b3c326c264be9dda31e237475bd55 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Wed, 28 Aug 2013 17:53:26 -0500 Subject: [PATCH 3/3] don't use globals in the preprocessor Macros are now passed around as lists and dicts. --- preprocessor.py | 33 +++++++++++++++++---------------- prequeue.py | 2 +- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/preprocessor.py b/preprocessor.py index 150faee11..54000a7a6 100644 --- a/preprocessor.py +++ b/preprocessor.py @@ -44,10 +44,6 @@ do_macro_sanity_check = False class SkippableMacro(object): macro_name = "db" -skippable_macros = [SkippableMacro] - -macros += skippable_macros - chars = { "ガ": 0x05, "ギ": 0x06, @@ -415,11 +411,10 @@ def quote_translator(asm): def extract_token(asm): return asm.split(" ")[0].strip() -def make_macro_table(): +def make_macro_table(macros): return dict(((macro.macro_name, macro) for macro in macros)) -macro_table = make_macro_table() -def macro_test(asm): +def macro_test(asm, macro_table): """ Returns a matching macro, or None/False. """ @@ -485,7 +480,7 @@ def macro_translator(macro, token, line, skippable_macros): # "db" is a macro because of SkippableMacro # rgbasm can handle "db" so no preprocessing is required # (don't check its param count) - if macro.macro_name == "db" and macro in skippable_macros: + if macro.__name__ in skippable_macros or (macro.macro_name == "db" and macro in skippable_macros): sys.stdout.write(original_line) return @@ -542,7 +537,10 @@ def macro_translator(macro, token, line, skippable_macros): index = 0 while index < len(params): - param_type = macro.param_types[index - correction] + try: + param_type = macro.param_types[index - correction] + except KeyError as exception: + raise Exception("line is: " + str(line) + " and macro is: " + str(macro)) description = param_type["name"] param_klass = param_type["class"] byte_type = param_klass.byte_type # db or dw @@ -588,7 +586,7 @@ def macro_translator(macro, token, line, skippable_macros): sys.stdout.write(output) -def read_line(l, skippable_macros): +def read_line(l, skippable_macros, macro_table): """Preprocesses a given line of asm.""" # strip comments from asm @@ -614,7 +612,7 @@ def read_line(l, skippable_macros): # check against other preprocessor features else: - macro, token = macro_test(asm) + macro, token = macro_test(asm, macro_table) if macro: macro_translator(macro, token, asm, skippable_macros) else: @@ -622,13 +620,16 @@ def read_line(l, skippable_macros): if comment: sys.stdout.write(comment) -def preprocess(skippable_macros=None, lines=None): +def preprocess(macros, skippable_macros=None, lines=None): """Main entry point for the preprocessor.""" if skippable_macros == None: - # Note that this is bad because the macro table doesn't include the - # skippable macros. skippable_macros = [SkippableMacro] + macro_table = make_macro_table(list(set(macros + skippable_macros))) + + # HACK for pokecrystal. Must be after make_macro_table call. + skippable_macros += ["TextEndingCommand"] + if not lines: # read each line from stdin lines = (sys.stdin.readlines()) @@ -637,8 +638,8 @@ def preprocess(skippable_macros=None, lines=None): lines = lines.split("\n") for l in lines: - read_line(l, skippable_macros) + read_line(l, skippable_macros, macro_table) # only run against stdin when not included as a module if __name__ == "__main__": - preprocess(skippable_macros=skippable_macros) + preprocess(macros) diff --git a/prequeue.py b/prequeue.py index c90d133ea..c9a9a8bcc 100644 --- a/prequeue.py +++ b/prequeue.py @@ -13,4 +13,4 @@ if __name__ == '__main__': dest = os.path.splitext(source)[0] + '.tx' sys.stdin = open(source, 'r') sys.stdout = open(dest, 'w') - preprocessor.preprocess() + preprocessor.preprocess(preprocessor.macros)