diff options
Diffstat (limited to 'extras/wram.py')
m--------- | extras | 0 | ||||
-rw-r--r-- | extras/wram.py | 313 |
2 files changed, 0 insertions, 313 deletions
diff --git a/extras b/extras new file mode 160000 +Subproject dfe657177453423987544798d9763b2938874b4 diff --git a/extras/wram.py b/extras/wram.py deleted file mode 100644 index b6d7fc6..0000000 --- a/extras/wram.py +++ /dev/null @@ -1,313 +0,0 @@ -# coding: utf-8 -""" -RGBDS BSS section and constant parsing. -""" - -import os - - -def separate_comment(line): - if ';' in line: - i = line.find(';') - return line[:i], line[i:] - return line, None - - -def rgbasm_to_py(text): - return text.replace('$', '0x').replace('%', '0b') - - -def make_wram_labels(wram_sections): - wram_labels = {} - for section in wram_sections: - for label in section['labels']: - if label['address'] not in wram_labels.keys(): - wram_labels[label['address']] = [] - wram_labels[label['address']] += [label['label']] - return wram_labels - -def bracket_value(string, i=0): - return string.split('[')[1 + i*2].split(']')[0] - -class BSSReader: - """ - Read rgbasm BSS/WRAM sections and associate labels with addresses. - Also reads constants/variables, even in macros. - """ - sections = [] - section = None - address = None - macros = {} - constants = {} - - section_types = { - 'VRAM': 0x8000, - 'SRAM': 0xa000, - 'WRAM0': 0xc000, - 'WRAMX': 0xd000, - 'HRAM': 0xff80, - } - - def __init__(self, *args, **kwargs): - self.__dict__.update(kwargs) - - def read_bss_line(self, l): - parts = l.strip().split(' ') - token = parts[0].strip() - params = ' '.join(parts[1:]).split(',') - - if token in ['ds', 'db', 'dw']: - if any(params): - length = eval(rgbasm_to_py(params[0]), self.constants.copy()) - else: - length = {'ds': 1, 'db': 1, 'dw': 2}[token] - self.address += length - # assume adjacent labels to use the same space - for label in self.section['labels'][::-1]: - if label['length'] == 0: - label['length'] = length - else: - break - - elif token in self.macros.keys(): - macro_text = '\n'.join(self.macros[token]) + '\n' - for i, p in enumerate(params): - macro_text = macro_text.replace('\\'+str(i+1),p) - macro_text = macro_text.split('\n') - macro_reader = BSSReader( - sections = list(self.sections), - section = dict(self.section), - address = self.address, - constants = self.constants, - ) - macro_sections = macro_reader.read_bss_sections(macro_text) - self.section = macro_sections[-1] - if self.section['labels']: - self.address = self.section['labels'][-1]['address'] + self.section['labels'][-1]['length'] - - - def read_bss_sections(self, bss): - - if self.section is None: - self.section = { - "labels": [], - } - - if type(bss) is str: - bss = bss.split('\n') - - macro = False - macro_name = None - for line in bss: - line = line.lstrip() - line, comment = separate_comment(line) - line = line.strip() - split_line = line.split() - split_line_upper = map(str.upper, split_line) - - if not line: - pass - - elif line[-4:].upper() == 'ENDM': - macro = False - macro_name = None - - elif macro: - self.macros[macro_name] += [line] - - elif line[-5:].upper() == 'MACRO': - macro_name = line.split(':')[0] - macro = True - self.macros[macro_name] = [] - - elif 'INCLUDE' == line[:7].upper(): - filename = line.split('"')[1] - self.read_bss_sections(open(filename).readlines()) - - elif 'SECTION' == line[:7].upper(): - if self.section: # previous - self.sections += [self.section] - - section_def = line.split(',') - name = section_def[0].split('"')[1] - type_ = section_def[1].strip() - if len(section_def) > 2: - bank = bracket_value(section_def[2]) - else: - bank = None - - if '[' in type_: - self.address = int(rgbasm_to_py(bracket_value(type_)), 16) - else: - if self.address == None or bank != self.section['bank'] or self.section['type'] != type_: - self.address = self.section_types.get(type_, self.address) - # else: keep going from this address - - self.section = { - 'name': name, - 'type': type_, - 'bank': bank, - 'start': self.address, - 'labels': [], - } - - elif ':' in line: - # rgbasm allows labels without :, but prefer convention - label = line[:line.find(':')] - if '\\' in label: - raise Exception, line + ' ' + label - if ';' not in label: - section_label = { - 'label': label, - 'address': self.address, - 'length': 0, - } - self.section['labels'] += [section_label] - self.read_bss_line(line.split(':')[-1]) - - elif any(x in split_line_upper for x in ['EQU', '=', 'SET']): # TODO: refactor - for x in ['EQU', '=', 'SET']: - if x in split_line_upper: - index = split_line_upper.index(x) - real = split_line[index] - name, value = map(' '.join, [split_line[:index], split_line[index+1:]]) - value = rgbasm_to_py(value) - self.constants[name] = eval(value, self.constants.copy()) - - else: - self.read_bss_line(line) - - self.sections += [self.section] - return self.sections - -def read_bss_sections(bss): - reader = BSSReader() - return reader.read_bss_sections(bss) - - -def constants_to_dict(constants): - """Deprecated. Use BSSReader.""" - return dict((eval(rgbasm_to_py(constant[constant.find('EQU')+3:constant.find(';')])), constant[:constant.find('EQU')].strip()) for constant in constants) - -def scrape_constants(text): - if type(text) is not list: - text = text.split('\n') - bss = BSSReader() - bss.read_bss_sections(text) - constants = bss.constants - return {v: k for k, v in constants.items()} - -def read_constants(filepath): - """ - Load lines from a file and grab any constants using BSSReader. - """ - lines = [] - if os.path.exists(filepath): - with open(filepath, "r") as file_handler: - lines = file_handler.readlines() - return scrape_constants(lines) - -class WRAMProcessor(object): - """ - RGBDS BSS section and constant parsing. - """ - - def __init__(self, config): - """ - Setup for WRAM parsing. - """ - self.config = config - - self.paths = {} - - if hasattr(self.config, "wram"): - self.paths["wram"] = self.config.wram - else: - self.paths["wram"] = os.path.join(self.config.path, "wram.asm") - - if hasattr(self.config, "hram"): - self.paths["hram"] = self.config.hram - else: - self.paths["hram"] = os.path.join(self.config.path, "hram.asm") - - if hasattr(self.config, "gbhw"): - self.paths["gbhw"] = self.config.gbhw - else: - self.paths["gbhw"] = os.path.join(self.config.path, "gbhw.asm") - - def initialize(self): - """ - Read constants. - """ - self.setup_wram_sections() - self.setup_wram_labels() - self.setup_hram_constants() - self.setup_gbhw_constants() - - self.reformat_wram_labels() - - def read_wram_sections(self): - """ - Opens the wram file and calls read_bss_sections. - """ - wram_content = None - wram_file_path = self.paths["wram"] - - with open(wram_file_path, "r") as wram: - wram_content = wram.readlines() - - wram_sections = read_bss_sections(wram_content) - return wram_sections - - def setup_wram_sections(self): - """ - Call read_wram_sections and set a variable. - """ - self.wram_sections = self.read_wram_sections() - return self.wram_sections - - def setup_wram_labels(self): - """ - Make wram labels based on self.wram_sections as input. - """ - self.wram_labels = make_wram_labels(self.wram_sections) - return self.wram_labels - - def read_hram_constants(self): - """ - Read constants from hram.asm using read_constants. - """ - hram_constants = read_constants(self.paths["hram"]) - return hram_constants - - def setup_hram_constants(self): - """ - Call read_hram_constants and set a variable. - """ - self.hram_constants = self.read_hram_constants() - return self.hram_constants - - def read_gbhw_constants(self): - """ - Read constants from gbhw.asm using read_constants. - """ - gbhw_constants = read_constants(self.paths["gbhw"]) - return gbhw_constants - - def setup_gbhw_constants(self): - """ - Call read_gbhw_constants and set a variable. - """ - self.gbhw_constants = self.read_gbhw_constants() - return self.gbhw_constants - - def reformat_wram_labels(self): - """ - Flips the wram_labels dictionary the other way around to access - addresses by label. - """ - self.wram = {} - - for (address, labels) in self.wram_labels.iteritems(): - for label in labels: - self.wram[label] = address |