shithub: pokecrystal

Download patch

ref: e2d31b6029b353965d97fbc684e679116422fba7
parent: 8f2221aa703b3ed0d98003a055c65ea794144b64
author: Bryan Bishop <[email protected]>
date: Thu Apr 26 10:14:46 EDT 2012

preprocessor support for macros

--- a/textpre.py
+++ b/textpre.py
@@ -3,6 +3,11 @@
 
 import sys
 
+from extras.crystal import *
+
+macros = command_classes + \
+         [Warp, XYTrigger, Signpost, PeopleEvent, DataByteWordMacro]
+
 chars = {
 "ガ": 0x05,
 "ギ": 0x06,
@@ -360,6 +365,138 @@
         even = not even
     return
 
+def extract_token(asm):
+    token = asm.split(" ")[0].replace("\t", "")
+    return token
+
+def macro_test(asm):
+    """ Returns a matching macro, or None/False.
+    """
+
+    # macros are determined by the first symbol on the line
+    token = extract_token(asm)
+
+    # check against all names
+    for macro in macros:
+        if macro.macro_name == token:
+            return macro, token
+
+    return None, None
+
+def macro_translator(macro, token, line):
+    """ Converts a line with a macro into a rgbasm-compatible line.
+    """
+    assert macro.macro_name == token, "macro/token mismatch"
+    
+    original_line = line
+
+    # remove trailing newline
+    if line[-1] == "\n":
+        line = line[:-1]
+    else:
+        original_line += "\n"
+
+    # remove first tab
+    has_tab = False
+    if line[0] == "\t":
+        has_tab = True
+        line = line[1:]
+
+    # remove duplicate whitespace (also trailing)
+    line = " ".join(line.split())
+
+    params = []
+
+    # check if the line has params
+    if " " in line:
+        # split the line into separate parameters
+        params = line.replace(token, "").split(",")
+
+        # check if there are no params (redundant)
+        if len(params) == 1 and params[0] == "":
+            raise Exception, "ERROR: macro has no params?"
+
+    # write out a comment showing the original line
+    sys.stdout.write("; original_line: " + original_line)
+
+    # certain macros don't need an initial byte written
+    # do: all scripting macros
+    # don't: signpost, warp_def, person_event, xy_trigger
+    if not macro.override_byte_check:
+        sys.stdout.write("db $%.2x\n" % (macro.id))
+
+    # --- long-winded sanity check goes here ---
+
+    # sanity check... this won't work because PointerLabelBeforeBank shows
+    # up as two params, so these two lengths will always be different.
+    #assert len(params) == len(macro.param_types), \
+    #       "mismatched number of parameters on this line: " + \
+    #       original_line
+
+    # v2 sanity check :) although it sorta sucks that this loop happens twice?
+    allowed_length = 0
+    for (index, param_type) in macro.param_types.items():
+        param_klass = param_type["class"]
+
+        if param_klass.byte_type == "db":
+            allowed_length += 1 # just one value
+        elif param_klass.byte_type == "dw":
+            if param_klass.size == 2:
+                allowed_length += 1 # just label
+            elif param_klass.size == 3:
+                allowed_length += 2 # bank and label
+            else:
+                raise Exception, "dunno what to do with a macro param with a size > 3"
+        else:
+            raise Exception, "dunno what to do with this non db/dw macro param: " + \
+                             str(param_klass) + " in line: " + original_line
+    
+    assert len(params) == allowed_length, \
+           "mismatched number of parameters on this line: " + \
+           original_line
+    # --- end of ridiculously long sanity check ---
+
+    index = 0
+    while index < len(macro.param_types):
+        param_type  = macro.param_types[index]
+        description = param_type["name"]
+        param_klass = param_type["class"]
+        byte_type   = param_klass.byte_type # db or dw
+        size        = param_klass.size
+        param       = params[index].strip()
+        
+        # param_klass.to_asm() won't work here because it doesn't
+        # include db/dw.
+
+        # some parameters are really multiple types of bytes
+        if (byte_type == "dw" and size != 2) or \
+           (byte_type == "db" and size != 1):
+
+            sys.stdout.write("; " + description + "\n")
+            
+            if   size == 3 and issubclass(param_klass, PointerLabelBeforeBank):
+                # write the bank first
+                sys.stdout.write("db " + params[index] + "\n")
+                # write the pointer second
+                sys.stdout.write("dw " + params[index+1] + "\n")
+                index += 2
+            elif size == 3 and issubclass(param_klass, PointerLabelAfterBank):
+                # write the pointer first
+                sys.stdout.write("dw " + params[index+1] + "\n")
+                # write the bank second
+                sys.stdout.write("db " + params[index] + "\n")
+                index += 2
+            else:
+                raise Exception, "dunno what to do with this macro " + \
+                "param (" + str(param_klass) + ") " + "on this line: " + \
+                original_line
+
+        # or just print out the byte
+        else:
+            sys.stdout.write(byte_type + " " + param + " ; " + description + "\n")
+
+            index += 1
+
 for l in sys.stdin:
     # strip and store any comment on this line
     if ";" in l:
@@ -371,8 +508,15 @@
     # convert text to bytes when a quote appears (not in a comment)
     if "\"" in asm:
         quote_translator(asm)
+
+    # check against other preprocessor features
     else:
-        sys.stdout.write(asm)
+        macro, token = macro_test(asm)
+
+        if macro:
+            macro_translator(macro, token, asm)
+        else:
+            sys.stdout.write(asm)
 
     # show line comment
     if comment != None: