2012-03-04 23:05:36 -08:00
|
|
|
|
#!/usr/bin/python
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
import sys
|
|
|
|
|
|
2013-08-03 14:25:14 -07:00
|
|
|
|
from extras.pokemontools.crystal import (
|
2013-01-10 13:07:36 -08:00
|
|
|
|
command_classes,
|
|
|
|
|
Warp,
|
|
|
|
|
XYTrigger,
|
|
|
|
|
Signpost,
|
|
|
|
|
PeopleEvent,
|
|
|
|
|
DataByteWordMacro,
|
|
|
|
|
text_command_classes,
|
|
|
|
|
movement_command_classes,
|
2013-01-27 15:45:23 -08:00
|
|
|
|
music_classes,
|
2013-03-29 15:54:13 -07:00
|
|
|
|
effect_classes,
|
2013-01-10 13:07:36 -08:00
|
|
|
|
)
|
2012-04-26 12:14:46 -07:00
|
|
|
|
|
2013-08-31 08:13:17 -07:00
|
|
|
|
def load_pokecrystal_macros():
|
|
|
|
|
"""
|
|
|
|
|
Construct a list of macros that are needed for pokecrystal preprocessing.
|
|
|
|
|
"""
|
|
|
|
|
ourmacros = []
|
|
|
|
|
|
|
|
|
|
even_more_macros = [
|
|
|
|
|
Warp,
|
|
|
|
|
XYTrigger,
|
|
|
|
|
Signpost,
|
|
|
|
|
PeopleEvent,
|
|
|
|
|
DataByteWordMacro,
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
ourmacros += command_classes
|
|
|
|
|
ourmacros += even_more_macros
|
|
|
|
|
ourmacros += [each[1] for each in text_command_classes]
|
|
|
|
|
ourmacros += movement_command_classes
|
|
|
|
|
ourmacros += music_classes
|
|
|
|
|
ourmacros += effect_classes
|
2013-01-27 15:45:23 -08:00
|
|
|
|
|
2013-08-31 08:13:17 -07:00
|
|
|
|
return ourmacros
|
2012-04-26 12:14:46 -07:00
|
|
|
|
|
2012-03-04 23:16:56 -08:00
|
|
|
|
chars = {
|
|
|
|
|
"ガ": 0x05,
|
|
|
|
|
"ギ": 0x06,
|
|
|
|
|
"グ": 0x07,
|
|
|
|
|
"ゲ": 0x08,
|
|
|
|
|
"ゴ": 0x09,
|
|
|
|
|
"ザ": 0x0A,
|
|
|
|
|
"ジ": 0x0B,
|
|
|
|
|
"ズ": 0x0C,
|
|
|
|
|
"ゼ": 0x0D,
|
|
|
|
|
"ゾ": 0x0E,
|
|
|
|
|
"ダ": 0x0F,
|
|
|
|
|
"ヂ": 0x10,
|
|
|
|
|
"ヅ": 0x11,
|
|
|
|
|
"デ": 0x12,
|
|
|
|
|
"ド": 0x13,
|
|
|
|
|
"バ": 0x19,
|
|
|
|
|
"ビ": 0x1A,
|
|
|
|
|
"ブ": 0x1B,
|
|
|
|
|
"ボ": 0x1C,
|
|
|
|
|
"が": 0x26,
|
|
|
|
|
"ぎ": 0x27,
|
|
|
|
|
"ぐ": 0x28,
|
|
|
|
|
"げ": 0x29,
|
|
|
|
|
"ご": 0x2A,
|
|
|
|
|
"ざ": 0x2B,
|
|
|
|
|
"じ": 0x2C,
|
|
|
|
|
"ず": 0x2D,
|
|
|
|
|
"ぜ": 0x2E,
|
|
|
|
|
"ぞ": 0x2F,
|
|
|
|
|
"だ": 0x30,
|
|
|
|
|
"ぢ": 0x31,
|
|
|
|
|
"づ": 0x32,
|
|
|
|
|
"で": 0x33,
|
|
|
|
|
"ど": 0x34,
|
|
|
|
|
"ば": 0x3A,
|
|
|
|
|
"び": 0x3B,
|
|
|
|
|
"ぶ": 0x3C,
|
|
|
|
|
"べ": 0x3D,
|
|
|
|
|
"ぼ": 0x3E,
|
|
|
|
|
"パ": 0x40,
|
|
|
|
|
"ピ": 0x41,
|
|
|
|
|
"プ": 0x42,
|
|
|
|
|
"ポ": 0x43,
|
|
|
|
|
"ぱ": 0x44,
|
|
|
|
|
"ぴ": 0x45,
|
|
|
|
|
"ぷ": 0x46,
|
|
|
|
|
"ぺ": 0x47,
|
|
|
|
|
"ぽ": 0x48,
|
|
|
|
|
"ア": 0x80,
|
|
|
|
|
"イ": 0x81,
|
|
|
|
|
"ウ": 0x82,
|
|
|
|
|
"エ": 0x83,
|
|
|
|
|
"ォ": 0x84,
|
|
|
|
|
"カ": 0x85,
|
|
|
|
|
"キ": 0x86,
|
|
|
|
|
"ク": 0x87,
|
|
|
|
|
"ケ": 0x88,
|
|
|
|
|
"コ": 0x89,
|
|
|
|
|
"サ": 0x8A,
|
|
|
|
|
"シ": 0x8B,
|
|
|
|
|
"ス": 0x8C,
|
|
|
|
|
"セ": 0x8D,
|
|
|
|
|
"ソ": 0x8E,
|
|
|
|
|
"タ": 0x8F,
|
|
|
|
|
"チ": 0x90,
|
|
|
|
|
"ツ": 0x91,
|
|
|
|
|
"テ": 0x92,
|
|
|
|
|
"ト": 0x93,
|
|
|
|
|
"ナ": 0x94,
|
|
|
|
|
"ニ": 0x95,
|
|
|
|
|
"ヌ": 0x96,
|
|
|
|
|
"ネ": 0x97,
|
|
|
|
|
"ノ": 0x98,
|
|
|
|
|
"ハ": 0x99,
|
|
|
|
|
"ヒ": 0x9A,
|
|
|
|
|
"フ": 0x9B,
|
|
|
|
|
"ホ": 0x9C,
|
|
|
|
|
"マ": 0x9D,
|
|
|
|
|
"ミ": 0x9E,
|
|
|
|
|
"ム": 0x9F,
|
|
|
|
|
"メ": 0xA0,
|
|
|
|
|
"モ": 0xA1,
|
|
|
|
|
"ヤ": 0xA2,
|
|
|
|
|
"ユ": 0xA3,
|
|
|
|
|
"ヨ": 0xA4,
|
|
|
|
|
"ラ": 0xA5,
|
|
|
|
|
"ル": 0xA6,
|
|
|
|
|
"レ": 0xA7,
|
|
|
|
|
"ロ": 0xA8,
|
|
|
|
|
"ワ": 0xA9,
|
|
|
|
|
"ヲ": 0xAA,
|
|
|
|
|
"ン": 0xAB,
|
|
|
|
|
"ッ": 0xAC,
|
|
|
|
|
"ャ": 0xAD,
|
|
|
|
|
"ュ": 0xAE,
|
|
|
|
|
"ョ": 0xAF,
|
|
|
|
|
"ィ": 0xB0,
|
|
|
|
|
"あ": 0xB1,
|
|
|
|
|
"い": 0xB2,
|
|
|
|
|
"う": 0xB3,
|
|
|
|
|
"え": 0xB4,
|
|
|
|
|
"お": 0xB5,
|
|
|
|
|
"か": 0xB6,
|
|
|
|
|
"き": 0xB7,
|
|
|
|
|
"く": 0xB8,
|
|
|
|
|
"け": 0xB9,
|
|
|
|
|
"こ": 0xBA,
|
|
|
|
|
"さ": 0xBB,
|
|
|
|
|
"し": 0xBC,
|
|
|
|
|
"す": 0xBD,
|
|
|
|
|
"せ": 0xBE,
|
|
|
|
|
"そ": 0xBF,
|
|
|
|
|
"た": 0xC0,
|
|
|
|
|
"ち": 0xC1,
|
|
|
|
|
"つ": 0xC2,
|
|
|
|
|
"て": 0xC3,
|
|
|
|
|
"と": 0xC4,
|
|
|
|
|
"な": 0xC5,
|
|
|
|
|
"に": 0xC6,
|
|
|
|
|
"ぬ": 0xC7,
|
|
|
|
|
"ね": 0xC8,
|
|
|
|
|
"の": 0xC9,
|
|
|
|
|
"は": 0xCA,
|
|
|
|
|
"ひ": 0xCB,
|
|
|
|
|
"ふ": 0xCC,
|
|
|
|
|
"へ": 0xCD,
|
|
|
|
|
"ほ": 0xCE,
|
|
|
|
|
"ま": 0xCF,
|
|
|
|
|
"み": 0xD0,
|
|
|
|
|
"む": 0xD1,
|
|
|
|
|
"め": 0xD2,
|
|
|
|
|
"も": 0xD3,
|
|
|
|
|
"や": 0xD4,
|
|
|
|
|
"ゆ": 0xD5,
|
|
|
|
|
"よ": 0xD6,
|
|
|
|
|
"ら": 0xD7,
|
|
|
|
|
"り": 0xD8,
|
|
|
|
|
"る": 0xD9,
|
|
|
|
|
"れ": 0xDA,
|
|
|
|
|
"ろ": 0xDB,
|
|
|
|
|
"わ": 0xDC,
|
|
|
|
|
"を": 0xDD,
|
|
|
|
|
"ん": 0xDE,
|
|
|
|
|
"っ": 0xDF,
|
|
|
|
|
"ゃ": 0xE0,
|
|
|
|
|
"ゅ": 0xE1,
|
|
|
|
|
"ょ": 0xE2,
|
|
|
|
|
"ー": 0xE3,
|
2013-07-31 15:02:08 -07:00
|
|
|
|
"ァ": 0xE9,
|
2012-03-04 23:05:36 -08:00
|
|
|
|
|
2012-03-04 23:16:56 -08:00
|
|
|
|
"@": 0x50,
|
|
|
|
|
"#": 0x54,
|
|
|
|
|
"…": 0x75,
|
2012-03-04 23:05:36 -08:00
|
|
|
|
|
2012-03-04 23:16:56 -08:00
|
|
|
|
"┌": 0x79,
|
|
|
|
|
"─": 0x7A,
|
|
|
|
|
"┐": 0x7B,
|
|
|
|
|
"│": 0x7C,
|
|
|
|
|
"└": 0x7D,
|
|
|
|
|
"┘": 0x7E,
|
2012-03-04 23:05:36 -08:00
|
|
|
|
|
2012-03-04 23:16:56 -08:00
|
|
|
|
"№": 0x74,
|
2012-03-04 23:05:36 -08:00
|
|
|
|
|
2012-03-04 23:16:56 -08:00
|
|
|
|
" ": 0x7F,
|
|
|
|
|
"A": 0x80,
|
|
|
|
|
"B": 0x81,
|
|
|
|
|
"C": 0x82,
|
|
|
|
|
"D": 0x83,
|
|
|
|
|
"E": 0x84,
|
|
|
|
|
"F": 0x85,
|
|
|
|
|
"G": 0x86,
|
|
|
|
|
"H": 0x87,
|
|
|
|
|
"I": 0x88,
|
|
|
|
|
"J": 0x89,
|
|
|
|
|
"K": 0x8A,
|
|
|
|
|
"L": 0x8B,
|
|
|
|
|
"M": 0x8C,
|
|
|
|
|
"N": 0x8D,
|
|
|
|
|
"O": 0x8E,
|
|
|
|
|
"P": 0x8F,
|
|
|
|
|
"Q": 0x90,
|
|
|
|
|
"R": 0x91,
|
|
|
|
|
"S": 0x92,
|
|
|
|
|
"T": 0x93,
|
|
|
|
|
"U": 0x94,
|
|
|
|
|
"V": 0x95,
|
|
|
|
|
"W": 0x96,
|
|
|
|
|
"X": 0x97,
|
|
|
|
|
"Y": 0x98,
|
|
|
|
|
"Z": 0x99,
|
|
|
|
|
"(": 0x9A,
|
|
|
|
|
")": 0x9B,
|
|
|
|
|
":": 0x9C,
|
|
|
|
|
";": 0x9D,
|
|
|
|
|
"[": 0x9E,
|
|
|
|
|
"]": 0x9F,
|
|
|
|
|
"a": 0xA0,
|
|
|
|
|
"b": 0xA1,
|
|
|
|
|
"c": 0xA2,
|
|
|
|
|
"d": 0xA3,
|
|
|
|
|
"e": 0xA4,
|
|
|
|
|
"f": 0xA5,
|
|
|
|
|
"g": 0xA6,
|
|
|
|
|
"h": 0xA7,
|
|
|
|
|
"i": 0xA8,
|
|
|
|
|
"j": 0xA9,
|
|
|
|
|
"k": 0xAA,
|
|
|
|
|
"l": 0xAB,
|
|
|
|
|
"m": 0xAC,
|
|
|
|
|
"n": 0xAD,
|
|
|
|
|
"o": 0xAE,
|
|
|
|
|
"p": 0xAF,
|
|
|
|
|
"q": 0xB0,
|
|
|
|
|
"r": 0xB1,
|
|
|
|
|
"s": 0xB2,
|
|
|
|
|
"t": 0xB3,
|
|
|
|
|
"u": 0xB4,
|
|
|
|
|
"v": 0xB5,
|
|
|
|
|
"w": 0xB6,
|
|
|
|
|
"x": 0xB7,
|
|
|
|
|
"y": 0xB8,
|
|
|
|
|
"z": 0xB9,
|
|
|
|
|
"Ä": 0xC0,
|
|
|
|
|
"Ö": 0xC1,
|
|
|
|
|
"Ü": 0xC2,
|
|
|
|
|
"ä": 0xC3,
|
|
|
|
|
"ö": 0xC4,
|
|
|
|
|
"ü": 0xC5,
|
|
|
|
|
"'d": 0xD0,
|
|
|
|
|
"'l": 0xD1,
|
|
|
|
|
"'m": 0xD2,
|
|
|
|
|
"'r": 0xD3,
|
|
|
|
|
"'s": 0xD4,
|
|
|
|
|
"'t": 0xD5,
|
|
|
|
|
"'v": 0xD6,
|
|
|
|
|
"'": 0xE0,
|
|
|
|
|
"-": 0xE3,
|
|
|
|
|
"?": 0xE6,
|
|
|
|
|
"!": 0xE7,
|
|
|
|
|
".": 0xE8,
|
|
|
|
|
"&": 0xE9,
|
|
|
|
|
"é": 0xEA,
|
|
|
|
|
"→": 0xEB,
|
2013-06-30 23:48:08 -07:00
|
|
|
|
"▷": 0xEC,
|
2012-07-07 18:51:02 -07:00
|
|
|
|
"▶": 0xED,
|
2013-05-01 20:18:38 -07:00
|
|
|
|
"▼": 0xEE,
|
2012-03-04 23:16:56 -08:00
|
|
|
|
"♂": 0xEF,
|
|
|
|
|
"¥": 0xF0,
|
|
|
|
|
"×": 0xF1,
|
|
|
|
|
"/": 0xF3,
|
|
|
|
|
",": 0xF4,
|
|
|
|
|
"♀": 0xF5,
|
|
|
|
|
"0": 0xF6,
|
|
|
|
|
"1": 0xF7,
|
|
|
|
|
"2": 0xF8,
|
|
|
|
|
"3": 0xF9,
|
|
|
|
|
"4": 0xFA,
|
|
|
|
|
"5": 0xFB,
|
|
|
|
|
"6": 0xFC,
|
|
|
|
|
"7": 0xFD,
|
|
|
|
|
"8": 0xFE,
|
|
|
|
|
"9": 0xFF
|
|
|
|
|
}
|
2012-03-04 23:05:36 -08:00
|
|
|
|
|
2013-08-31 07:45:12 -07:00
|
|
|
|
class PreprocessorException(Exception):
|
|
|
|
|
"""
|
|
|
|
|
There was a problem in the preprocessor.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
class MacroException(PreprocessorException):
|
|
|
|
|
"""
|
|
|
|
|
There was a problem with a macro.
|
|
|
|
|
"""
|
|
|
|
|
|
2012-04-26 09:19:34 -07:00
|
|
|
|
def separate_comment(l):
|
2013-03-21 13:15:42 -07:00
|
|
|
|
"""
|
|
|
|
|
Separates asm and comments on a single line.
|
2012-04-26 09:19:34 -07:00
|
|
|
|
"""
|
|
|
|
|
in_quotes = False
|
2013-06-20 21:58:35 -07:00
|
|
|
|
for i in xrange(len(l)):
|
|
|
|
|
if not in_quotes:
|
|
|
|
|
if l[i] == ";":
|
|
|
|
|
break
|
|
|
|
|
if l[i] == "\"":
|
|
|
|
|
in_quotes = not in_quotes
|
2013-06-25 18:24:09 -07:00
|
|
|
|
return l[:i], l[i:] or None
|
2012-03-04 23:05:36 -08:00
|
|
|
|
|
2012-04-26 09:19:34 -07:00
|
|
|
|
def quote_translator(asm):
|
2013-03-21 13:15:42 -07:00
|
|
|
|
"""
|
|
|
|
|
Writes asm with quoted text translated into bytes.
|
2012-04-26 09:19:34 -07:00
|
|
|
|
"""
|
2012-03-04 23:05:36 -08:00
|
|
|
|
|
|
|
|
|
# split by quotes
|
2013-06-20 21:58:35 -07:00
|
|
|
|
asms = asm.split('"')
|
2012-03-04 23:05:36 -08:00
|
|
|
|
|
|
|
|
|
# skip asm that actually does use ASCII in quotes
|
2013-06-20 21:58:35 -07:00
|
|
|
|
if "SECTION" in asms[0]\
|
|
|
|
|
or "INCBIN" in asms[0]\
|
|
|
|
|
or "INCLUDE" in asms[0]:
|
|
|
|
|
return asm
|
2012-03-04 23:05:36 -08:00
|
|
|
|
|
2013-05-10 23:32:07 -07:00
|
|
|
|
print_macro = False
|
|
|
|
|
if asms[0].strip() == 'print':
|
|
|
|
|
asms[0] = asms[0].replace('print','db 0,')
|
|
|
|
|
print_macro = True
|
|
|
|
|
|
2013-06-20 21:58:35 -07:00
|
|
|
|
output = ''
|
2012-03-04 23:05:36 -08:00
|
|
|
|
even = False
|
|
|
|
|
for token in asms:
|
|
|
|
|
if even:
|
2013-05-10 23:32:07 -07:00
|
|
|
|
characters = []
|
2012-03-04 23:05:36 -08:00
|
|
|
|
# token is a string to convert to byte values
|
|
|
|
|
while len(token):
|
|
|
|
|
# read a single UTF-8 codepoint
|
|
|
|
|
char = token[0]
|
2013-06-20 21:58:35 -07:00
|
|
|
|
if ord(char) < 0xc0:
|
|
|
|
|
token = token[1:]
|
|
|
|
|
# certain apostrophe-letter pairs are considered a single character
|
|
|
|
|
if char == "'" and token:
|
|
|
|
|
if token[0] in 'dlmrstv':
|
|
|
|
|
char += token[0]
|
|
|
|
|
token = token[1:]
|
|
|
|
|
elif ord(char) < 0xe0:
|
2012-03-04 23:05:36 -08:00
|
|
|
|
char = char + token[1:2]
|
|
|
|
|
token = token[2:]
|
2013-06-20 21:58:35 -07:00
|
|
|
|
elif ord(char) < 0xf0:
|
|
|
|
|
char = char + token[1:3]
|
|
|
|
|
token = token[3:]
|
|
|
|
|
elif ord(char) < 0xf8:
|
|
|
|
|
char = char + token[1:4]
|
|
|
|
|
token = token[4:]
|
|
|
|
|
elif ord(char) < 0xfc:
|
|
|
|
|
char = char + token[1:5]
|
|
|
|
|
token = token[5:]
|
2012-03-04 23:05:36 -08:00
|
|
|
|
else:
|
2013-06-20 21:58:35 -07:00
|
|
|
|
char = char + token[1:6]
|
|
|
|
|
token = token[6:]
|
2013-05-10 23:32:07 -07:00
|
|
|
|
characters += [char]
|
|
|
|
|
|
|
|
|
|
if print_macro:
|
|
|
|
|
line = 0
|
|
|
|
|
while len(characters):
|
|
|
|
|
last_char = 1
|
|
|
|
|
if len(characters) > 18 and characters[-1] != '@':
|
|
|
|
|
for i, char in enumerate(characters):
|
|
|
|
|
last_char = i + 1
|
|
|
|
|
if ' ' not in characters[i+1:18]: break
|
|
|
|
|
output += ", ".join("${0:02X}".format(chars[char]) for char in characters[:last_char-1])
|
|
|
|
|
if characters[last_char-1] != " ":
|
|
|
|
|
output += ", ${0:02X}".format(characters[last_char-1])
|
|
|
|
|
if not line & 1:
|
|
|
|
|
line_ending = 0x4f
|
|
|
|
|
else:
|
|
|
|
|
line_ending = 0x51
|
|
|
|
|
output += ", ${0:02X}".format(line_ending)
|
|
|
|
|
line += 1
|
|
|
|
|
else:
|
|
|
|
|
output += ", ".join(["${0:02X}".format(chars[char]) for char in characters[:last_char]])
|
|
|
|
|
characters = characters[last_char:]
|
|
|
|
|
if len(characters): output += ", "
|
|
|
|
|
# end text
|
|
|
|
|
line_ending = 0x57
|
|
|
|
|
output += ", ${0:02X}".format(line_ending)
|
|
|
|
|
|
|
|
|
|
output += ", ".join(["${0:02X}".format(chars[char]) for char in characters])
|
2012-03-04 23:05:36 -08:00
|
|
|
|
|
|
|
|
|
else:
|
2013-06-20 21:58:35 -07:00
|
|
|
|
output += token
|
2012-04-26 09:19:34 -07:00
|
|
|
|
|
2012-03-04 23:05:36 -08:00
|
|
|
|
even = not even
|
2013-01-10 14:30:49 -08:00
|
|
|
|
|
2013-06-20 21:58:35 -07:00
|
|
|
|
return output
|
2012-04-26 09:19:34 -07:00
|
|
|
|
|
2012-04-26 12:14:46 -07:00
|
|
|
|
def extract_token(asm):
|
2013-06-20 21:58:35 -07:00
|
|
|
|
return asm.split(" ")[0].strip()
|
2012-04-26 12:14:46 -07:00
|
|
|
|
|
2013-08-28 15:53:26 -07:00
|
|
|
|
def make_macro_table(macros):
|
2013-06-20 21:58:35 -07:00
|
|
|
|
return dict(((macro.macro_name, macro) for macro in macros))
|
2013-01-10 13:15:59 -08:00
|
|
|
|
|
2013-08-28 15:53:26 -07:00
|
|
|
|
def macro_test(asm, macro_table):
|
2013-03-21 13:15:42 -07:00
|
|
|
|
"""
|
|
|
|
|
Returns a matching macro, or None/False.
|
2012-04-26 12:14:46 -07:00
|
|
|
|
"""
|
|
|
|
|
# macros are determined by the first symbol on the line
|
|
|
|
|
token = extract_token(asm)
|
2013-08-30 16:26:07 -07:00
|
|
|
|
|
|
|
|
|
# skip db and dw since rgbasm handles those and they aren't macros
|
2013-08-31 09:57:01 -07:00
|
|
|
|
if token is not None and token not in ["db", "dw"] and token in macro_table:
|
|
|
|
|
return (macro_table[token], token)
|
|
|
|
|
else:
|
|
|
|
|
return (None, None)
|
2012-04-26 12:14:46 -07:00
|
|
|
|
|
2013-08-28 14:48:29 -07:00
|
|
|
|
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)
|
|
|
|
|
|
2013-08-31 08:39:49 -07:00
|
|
|
|
def check_macro_sanity(params, macro, original_line):
|
|
|
|
|
"""
|
|
|
|
|
Checks whether or not the correct number of arguments are being passed to a
|
|
|
|
|
certain macro. There are a number of possibilities based on the types of
|
|
|
|
|
parameters that define the macro.
|
|
|
|
|
|
|
|
|
|
@param params: a list of parameters given to the macro
|
|
|
|
|
@param macro: macro klass
|
|
|
|
|
@param original_line: the line being preprocessed
|
|
|
|
|
"""
|
|
|
|
|
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 MacroException(
|
|
|
|
|
"dunno what to do with a macro param with a size > 3 (size={size})"
|
|
|
|
|
.format(size=param_klass.size)
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
raise MacroException(
|
|
|
|
|
"dunno what to do with this non db/dw macro param: {klass} in line {line}"
|
|
|
|
|
.format(klass=param_klass, line=original_line)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# sometimes the allowed length can vary
|
|
|
|
|
if hasattr(macro, "allowed_lengths"):
|
|
|
|
|
allowed_lengths = macro.allowed_lengths + [allowed_length]
|
|
|
|
|
else:
|
|
|
|
|
allowed_lengths = [allowed_length]
|
|
|
|
|
|
|
|
|
|
# used twice, so precompute once
|
|
|
|
|
params_len = len(params)
|
|
|
|
|
|
|
|
|
|
if params_len not in allowed_lengths:
|
|
|
|
|
raise PreprocessorException(
|
|
|
|
|
"mismatched number of parameters ({count}, instead of any of {allowed}) on this line: {line}"
|
|
|
|
|
.format(
|
|
|
|
|
count=params_len,
|
|
|
|
|
allowed=allowed_lengths,
|
|
|
|
|
line=original_line,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
2013-08-31 07:37:55 -07:00
|
|
|
|
def macro_translator(macro, token, line, show_original_lines=False, do_macro_sanity_check=False):
|
2013-03-21 13:15:42 -07:00
|
|
|
|
"""
|
|
|
|
|
Converts a line with a macro into a rgbasm-compatible line.
|
2012-11-30 08:26:49 -08:00
|
|
|
|
|
2013-08-31 07:37:02 -07:00
|
|
|
|
@param show_original_lines: show lines before preprocessing in stdout
|
2013-08-31 07:37:55 -07:00
|
|
|
|
@param do_macro_sanity_check: helpful for debugging macros
|
2013-08-31 07:37:02 -07:00
|
|
|
|
"""
|
2013-08-31 07:46:11 -07:00
|
|
|
|
if macro.macro_name != token:
|
|
|
|
|
raise MacroException("macro/token mismatch")
|
2012-05-23 01:14:15 -07:00
|
|
|
|
|
2012-04-26 12:14:46 -07:00
|
|
|
|
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] == "":
|
2013-08-31 07:51:31 -07:00
|
|
|
|
raise MacroException("macro has no params?")
|
2012-04-26 12:14:46 -07:00
|
|
|
|
|
|
|
|
|
# write out a comment showing the original line
|
2013-01-10 13:42:43 -08:00
|
|
|
|
if show_original_lines:
|
|
|
|
|
sys.stdout.write("; original_line: " + original_line)
|
2012-04-26 12:14:46 -07:00
|
|
|
|
|
2013-08-30 16:26:07 -07:00
|
|
|
|
# rgbasm can handle "db" so no preprocessing is required, plus this wont be
|
|
|
|
|
# reached because of earlier checks in macro_test.
|
|
|
|
|
if macro.macro_name in ["db", "dw"]:
|
2012-05-05 11:30:22 -07:00
|
|
|
|
sys.stdout.write(original_line)
|
|
|
|
|
return
|
|
|
|
|
|
2012-04-26 12:14:46 -07:00
|
|
|
|
# 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:
|
2013-01-10 13:58:24 -08:00
|
|
|
|
sys.stdout.write("db ${0:02X}\n".format(macro.id))
|
2012-04-26 12:14:46 -07:00
|
|
|
|
|
2013-08-31 08:39:49 -07:00
|
|
|
|
# Does the number of parameters on this line match any allowed number of
|
|
|
|
|
# parameters that the macro expects?
|
2013-01-10 13:58:24 -08:00
|
|
|
|
if do_macro_sanity_check:
|
2013-08-31 08:39:49 -07:00
|
|
|
|
check_macro_sanity(params, macro, original_line)
|
2012-04-26 12:14:46 -07:00
|
|
|
|
|
2012-05-16 16:34:03 -07:00
|
|
|
|
# used for storetext
|
|
|
|
|
correction = 0
|
|
|
|
|
|
2013-01-10 14:25:57 -08:00
|
|
|
|
output = ""
|
|
|
|
|
|
2012-04-26 12:14:46 -07:00
|
|
|
|
index = 0
|
2012-05-16 10:44:55 -07:00
|
|
|
|
while index < len(params):
|
2013-08-31 07:29:54 -07:00
|
|
|
|
param_type = macro.param_types[index - correction]
|
2012-04-26 12:14:46 -07:00
|
|
|
|
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()
|
2012-05-23 01:14:15 -07:00
|
|
|
|
|
2012-04-26 12:14:46 -07:00
|
|
|
|
# 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):
|
|
|
|
|
|
2013-01-10 14:25:57 -08:00
|
|
|
|
output += ("; " + description + "\n")
|
2012-05-23 01:14:15 -07:00
|
|
|
|
|
2013-08-28 14:48:29 -07:00
|
|
|
|
if size == 3 and is_based_on(param_klass, "PointerLabelBeforeBank"):
|
2012-04-26 12:14:46 -07:00
|
|
|
|
# write the bank first
|
2013-01-10 14:25:57 -08:00
|
|
|
|
output += ("db " + param + "\n")
|
2012-04-26 12:14:46 -07:00
|
|
|
|
# write the pointer second
|
2013-01-10 14:25:57 -08:00
|
|
|
|
output += ("dw " + params[index+1].strip() + "\n")
|
2012-04-26 12:14:46 -07:00
|
|
|
|
index += 2
|
2012-05-16 16:34:03 -07:00
|
|
|
|
correction += 1
|
2013-08-28 14:48:29 -07:00
|
|
|
|
elif size == 3 and is_based_on(param_klass, "PointerLabelAfterBank"):
|
2012-04-26 12:14:46 -07:00
|
|
|
|
# write the pointer first
|
2013-01-10 14:25:57 -08:00
|
|
|
|
output += ("dw " + param + "\n")
|
2012-04-26 12:14:46 -07:00
|
|
|
|
# write the bank second
|
2013-01-10 14:25:57 -08:00
|
|
|
|
output += ("db " + params[index+1].strip() + "\n")
|
2012-04-26 12:14:46 -07:00
|
|
|
|
index += 2
|
2012-05-16 16:34:03 -07:00
|
|
|
|
correction += 1
|
2013-08-28 14:30:47 -07:00
|
|
|
|
elif size == 3 and "from_asm" in dir(param_klass):
|
|
|
|
|
output += ("db " + param_klass.from_asm(param) + "\n")
|
2012-04-27 14:33:37 -07:00
|
|
|
|
index += 1
|
2012-04-26 12:14:46 -07:00
|
|
|
|
else:
|
2013-08-31 07:51:31 -07:00
|
|
|
|
raise MacroException(
|
2013-08-31 07:50:17 -07:00
|
|
|
|
"dunno what to do with this macro param ({klass}) in line: {line}"
|
|
|
|
|
.format(
|
|
|
|
|
klass=param_klass,
|
|
|
|
|
line=original_line,
|
|
|
|
|
)
|
|
|
|
|
)
|
2012-04-26 12:14:46 -07:00
|
|
|
|
|
|
|
|
|
# or just print out the byte
|
|
|
|
|
else:
|
2013-01-10 14:25:57 -08:00
|
|
|
|
output += (byte_type + " " + param + " ; " + description + "\n")
|
2012-04-26 12:14:46 -07:00
|
|
|
|
|
|
|
|
|
index += 1
|
|
|
|
|
|
2013-01-10 14:25:57 -08:00
|
|
|
|
sys.stdout.write(output)
|
|
|
|
|
|
2013-08-30 16:26:07 -07:00
|
|
|
|
def read_line(l, macro_table):
|
2012-11-30 08:12:27 -08:00
|
|
|
|
"""Preprocesses a given line of asm."""
|
2012-11-30 08:26:49 -08:00
|
|
|
|
|
2013-08-31 10:03:48 -07:00
|
|
|
|
if l in ["\n", ""] or l[0] == ";":
|
2013-08-31 09:57:01 -07:00
|
|
|
|
sys.stdout.write(l)
|
|
|
|
|
return # jump out early
|
|
|
|
|
|
2013-06-25 18:24:09 -07:00
|
|
|
|
# strip comments from asm
|
|
|
|
|
asm, comment = separate_comment(l)
|
2013-06-20 21:58:35 -07:00
|
|
|
|
|
|
|
|
|
# export all labels
|
|
|
|
|
if ':' in asm[:asm.find('"')]:
|
2013-06-25 20:25:50 -07:00
|
|
|
|
sys.stdout.write('GLOBAL ' + asm.split(':')[0] + '\n')
|
2012-11-30 07:56:15 -08:00
|
|
|
|
|
2013-06-20 21:58:35 -07:00
|
|
|
|
# expect preprocessed .asm files
|
|
|
|
|
if "INCLUDE" in asm:
|
|
|
|
|
asm = asm.replace('.asm','.tx')
|
|
|
|
|
sys.stdout.write(asm)
|
2012-11-30 07:56:15 -08:00
|
|
|
|
|
2013-03-01 19:39:27 -08:00
|
|
|
|
# ascii string macro preserves the bytes as ascii (skip the translator)
|
2013-08-31 09:57:01 -07:00
|
|
|
|
elif len(asm) > 6 and ("ascii " == asm[:6] or "\tascii " == asm[:7]):
|
2013-03-01 19:39:27 -08:00
|
|
|
|
asm = asm.replace("ascii", "db", 1)
|
|
|
|
|
sys.stdout.write(asm)
|
|
|
|
|
|
2012-11-30 08:04:56 -08:00
|
|
|
|
# convert text to bytes when a quote appears (not in a comment)
|
|
|
|
|
elif "\"" in asm:
|
2013-06-20 21:58:35 -07:00
|
|
|
|
sys.stdout.write(quote_translator(asm))
|
2012-11-30 07:56:15 -08:00
|
|
|
|
|
2012-11-30 08:04:56 -08:00
|
|
|
|
# check against other preprocessor features
|
|
|
|
|
else:
|
2013-08-28 15:53:26 -07:00
|
|
|
|
macro, token = macro_test(asm, macro_table)
|
2012-11-30 08:04:56 -08:00
|
|
|
|
if macro:
|
2013-08-30 16:26:07 -07:00
|
|
|
|
macro_translator(macro, token, asm)
|
2012-11-30 08:04:56 -08:00
|
|
|
|
else:
|
|
|
|
|
sys.stdout.write(asm)
|
2013-06-25 18:24:09 -07:00
|
|
|
|
|
2013-08-31 09:57:01 -07:00
|
|
|
|
if comment:
|
|
|
|
|
sys.stdout.write(comment)
|
2012-04-26 08:51:37 -07:00
|
|
|
|
|
2013-08-31 09:04:27 -07:00
|
|
|
|
def preprocess(macro_table, lines=None):
|
2012-11-30 08:12:27 -08:00
|
|
|
|
"""Main entry point for the preprocessor."""
|
2013-08-28 15:53:26 -07:00
|
|
|
|
|
2012-11-30 08:12:27 -08:00
|
|
|
|
if not lines:
|
|
|
|
|
# read each line from stdin
|
2013-06-20 21:58:35 -07:00
|
|
|
|
lines = (sys.stdin.readlines())
|
2012-11-30 08:12:27 -08:00
|
|
|
|
elif not isinstance(lines, list):
|
|
|
|
|
# split up the input into individual lines
|
|
|
|
|
lines = lines.split("\n")
|
|
|
|
|
|
|
|
|
|
for l in lines:
|
2013-08-30 16:26:07 -07:00
|
|
|
|
read_line(l, macro_table)
|
2012-11-30 08:12:27 -08:00
|
|
|
|
|
2013-08-31 10:12:09 -07:00
|
|
|
|
def main():
|
2013-08-31 09:04:27 -07:00
|
|
|
|
macros = load_pokecrystal_macros()
|
|
|
|
|
macro_table = make_macro_table(macros)
|
|
|
|
|
preprocess(macro_table)
|
2013-08-31 10:12:09 -07:00
|
|
|
|
|
2012-11-30 08:12:27 -08:00
|
|
|
|
# only run against stdin when not included as a module
|
|
|
|
|
if __name__ == "__main__":
|
2013-08-31 10:12:09 -07:00
|
|
|
|
main()
|