pokecrystal-board/extras/labels.py

170 lines
5.6 KiB
Python
Raw Normal View History

2013-01-27 15:05:52 -08:00
# -*- coding: utf-8 -*-
"""
Various label/line-related functions.
"""
2013-01-27 15:05:52 -08:00
from pointers import (
calculate_pointer,
calculate_bank,
)
def remove_quoted_text(line):
"""get rid of content inside quotes
and also removes the quotes from the input string"""
while line.count("\"") % 2 == 0 and line.count("\"") > 0:
first = line.find("\"")
second = line.find("\"", first+1)
line = line[0:first] + line[second+1:]
while line.count("\'") % 2 == 0 and line.count("'") > 0:
first = line.find("\'")
second = line.find("\'", first+1)
line = line[0:first] + line[second+1:]
return line
def line_has_comment_address(line, returnable={}, bank=None):
"""checks that a given line has a comment
with a valid address, and returns the address in the object.
Note: bank is required if you have a 4-letter-or-less address,
because otherwise there is no way to figure out which bank
is curretly being scanned."""
#first set the bank/offset to nada
returnable["bank"] = None
returnable["offset"] = None
returnable["address"] = None
#only valid characters are 0-9A-F
valid = [str(x) for x in range(0,10)] + [chr(x) for x in range(97, 102+1)]
#check if there is a comment in this line
if ";" not in line:
return False
#first throw away anything in quotes
if (line.count("\"") % 2 == 0 and line.count("\"")!=0) \
or (line.count("\'") % 2 == 0 and line.count("\'")!=0):
line = remove_quoted_text(line)
#check if there is still a comment in this line after quotes removed
if ";" not in line:
return False
#but even if there's a semicolon there must be later text
if line[-1] == ";":
return False
#and just a space doesn't count
if line[-2:] == "; ":
return False
#and multiple whitespace doesn't count either
line = line.rstrip(" ").lstrip(" ")
if line[-1] == ";":
return False
#there must be more content after the semicolon
if len(line)-1 == line.find(";"):
return False
#split it up into the main comment part
comment = line[line.find(";")+1:]
#don't want no leading whitespace
comment = comment.lstrip(" ").rstrip(" ")
#split up multi-token comments into single tokens
token = comment
if " " in comment:
#use the first token in the comment
token = comment.split(" ")[0]
if token in ["0x", "$", "x", ":"]:
return False
offset = None
#process a token with a A:B format
if ":" in token: #3:3F0A, $3:$3F0A, 0x3:0x3F0A, 3:3F0A
#split up the token
bank_piece = token.split(":")[0].lower()
offset_piece = token.split(":")[1].lower()
#filter out blanks/duds
if bank_piece in ["$", "0x", "x"] \
or offset_piece in ["$", "0x", "x"]:
return False
#they can't have both "$" and "x"
if "$" in bank_piece and "x" in bank_piece:
return False
if "$" in offset_piece and "x" in offset_piece:
return False
#process the bank piece
if "$" in bank_piece:
bank_piece = bank_piece.replace("$", "0x")
#check characters for validity?
for c in bank_piece.replace("x", ""):
if c not in valid:
return False
bank = int(bank_piece, 16)
#process the offset piece
if "$" in offset_piece:
offset_piece = offset_piece.replace("$", "0x")
#check characters for validity?
for c in offset_piece.replace("x", ""):
if c not in valid:
return False
if len(offset_piece) == 0:
return None
offset = int(offset_piece, 16)
#filter out blanks/duds
elif token in ["$", "0x", "x"]:
return False
#can't have both "$" and "x" in the number
elif "$" in token and "x" in token:
return False
elif "x" in token and not "0x" in token: #it should be 0x
return False
elif "$" in token and not "x" in token:
token = token.replace("$", "0x")
offset = int(token, 16)
elif "0x" in token and not "$" in token:
offset = int(token, 16)
else: #might just be "1" at this point
token = token.lower()
#check if there are bad characters
for c in token:
if c not in valid:
return False
offset = int(token, 16)
if offset == None and bank == None:
return False
if bank == None:
bank = calculate_bank(offset)
returnable["bank"] = bank
returnable["offset"] = offset
returnable["address"] = calculate_pointer(offset, bank=bank)
return True
def get_address_from_line_comment(line, bank=None):
""" wrapper for line_has_comment_address
"""
returnable = {}
result = line_has_comment_address(line, returnable=returnable, bank=bank)
if not result:
return False
return returnable["address"]
def line_has_label(line):
"""returns True if the line has an asm label"""
if not isinstance(line, str):
raise Exception, "can't check this type of object"
line = line.rstrip(" ").lstrip(" ")
line = remove_quoted_text(line)
if ";" in line:
line = line.split(";")[0]
if 0 <= len(line) <= 1:
return False
if ":" not in line:
return False
if line[0] == ";":
return False
if line[0] == "\"":
return False
if "::" in line:
return False
return True
def get_label_from_line(line):
"""returns the label from the line"""
#check if the line has a label
if not line_has_label(line):
return None
#split up the line
label = line.split(":")[0]
return label