def _prepargs(self, command, args): #Rewrite references to AST Reference nodes rawargs = [] i_args = 0 for i in range(0, len(command.params)): commandparam = command.getParam(i) #print(repr(commandparam)) if commandparam.defaultvalue == None: #print(" -> consume! "+repr(args[i_args])) if ParamType.ispointer(commandparam.ptype): rawargs.append(ast.ASTRef(args[i_args])) elif commandparam.definevaluestype != None: defines = self.langdef.getDefines(commandparam.definevaluestype) #Reversed defines lookup, not as elegant as I hoped it key = args[i_args].upper() val = None try: #If defines is a list: try: val = defines.index(key) except: val = next((dval for dval, dkey in defines.items() if dkey == key)) rawargs.append(ast.ASTDefinedValue(key, val)) except: #There is no define for the value, parse it as is # but then ofc. it should be an int. try: rawargs.append(toint(args[i_args])) except: raise Exception("%s is not defined, and could not be converted to an integer!"%args[i_args]) else: rawargs.append(toint(args[i_args])) i_args += 1 return rawargs
def parseline(self, line, lastcommand): if True: instructions = line.split('\'')[0].strip().split(" ") instructions = list(map(lambda x: x.strip(), instructions)) instruction = instructions[0].lower() if instruction == "#include": self.handleInclude(instructions[1]) elif instruction == "#define": deftype = instructions[1] defkey = instructions[2].upper() defval = toint(instructions[3]) if not deftype in self.defines: self.defines[deftype] = {} self.defines[deftype][defval] = defkey elif instruction[0:len("addcmmd")] == "addcmmd": commandname = instructions[1].lower() commandcode = toint(instructions[2]) lastcommand = Command(commandname, commandcode, self.defines) lastcommand.setDescription(stripDescription(line)) #Only store commands of interest for future reference, but keep # lastcommand to append its args to (otherwise they are appended to # the wrong arg) sublangs = re.findall(r"\[([^\]]*)\]", instruction[len("addcmmd"):]) if len(sublangs)==0 or self.sublang in sublangs: self.commands[commandname] = lastcommand elif instruction == "alias": lastcommand = Alias(' '.join(instructions[1:]), self.commands) lastcommand.setDescription(stripDescription(line)) self.aliases.append(lastcommand) elif instruction == "addparm": defaultvalue = None instructiontype = int(instructions[1].split(":")[0]) try: definevaluestype = instructions[1].split(":")[1].strip().lower() except: definevaluestype = None if len(instructions) > 2: try: defaultvalue = toint(instructions[2]) except: if instructions[2][0:4] == "bind": pass #TODO: Restriction elif instructions[2][0:5] == "mask(": #format: mask(number) defaultvalue = toint(instructions[2][5:-1]) elif instructiontype == ParamType.command: defaultvalue = instructions[2] else: raise Exception("Unknown default value for param: "+repr(instructions[2])) lastcommand.addParam(instructiontype, defaultvalue, definevaluestype=definevaluestype, description=stripDescription(line)) return lastcommand
def compile(self, *args): #print("Compile "+repr(self.code)+" with args "+repr(args)) self.checkParamscount(len(args)) usedargs = 0 cbytes = array('B') cbytes.append(self.code) for param in self.params: value = None if param.defaultvalue == None: value = args[usedargs] usedargs += 1 else: value = param.defaultvalue try: value = toint(value) except: #value may not be an integer, but may be a (defined) constant! try: value = value.lower() if value in self.constants: value = self.constants[value] else: raise Exception() except: raise Exception( "The given parameter could not be converted to integer and is also not defined as a constant: " + repr(value)) cbytes.fromstring(ParamType.rewrite(param.ptype, value)) return cbytes
def compile(self, *args): #print("Compile "+repr(self.code)+" with args "+repr(args)) self.checkParamscount(len(args)) usedargs = 0 cbytes = array('B') cbytes.append(self.code) for param in self.params: value = None if param.defaultvalue == None: value = args[usedargs] usedargs += 1 else: value = param.defaultvalue try: value = toint(value) except: #value may not be an integer, but may be a (defined) constant! try: value = value.lower() if value in self.constants: value = self.constants[value] else: raise Exception() except: raise Exception("The given parameter could not be converted to integer and is also not defined as a constant: "+repr(value)) cbytes.fromstring(ParamType.rewrite(param.ptype, value)) return cbytes
def userargsorder(self): '''Returns the order of which user args are required, it is possible to first get $2, and next $1.''' ordered = [] for sigarg in self.signature: if sigarg[0] == "$": ordered.append(toint(sigarg[1:])) return ordered
def parseline(self, line, lastcommand): if True: instructions = line.split('\'')[0].strip().split(" ") instructions = list(map(lambda x: x.strip(), instructions)) instruction = instructions[0].lower() if instruction == "#include": self.handleInclude(instructions[1]) elif instruction == "#define": deftype = instructions[1] defkey = instructions[2].upper() defval = toint(instructions[3]) if not deftype in self.defines: self.defines[deftype] = {} self.defines[deftype][defval] = defkey elif instruction[0:len("addcmmd")] == "addcmmd": commandname = instructions[1].lower() commandcode = toint(instructions[2]) lastcommand = Command(commandname, commandcode, self.defines) lastcommand.setDescription(stripDescription(line)) #Only store commands of interest for future reference, but keep # lastcommand to append its args to (otherwise they are appended to # the wrong arg) sublangs = re.findall(r"\[([^\]]*)\]", instruction[len("addcmmd"):]) if len(sublangs) == 0 or self.sublang in sublangs: self.commands[commandname] = lastcommand elif instruction == "alias": lastcommand = Alias(' '.join(instructions[1:]), self.commands) lastcommand.setDescription(stripDescription(line)) self.aliases.append(lastcommand) elif instruction == "addparm": defaultvalue = None instructiontype = int(instructions[1].split(":")[0]) try: definevaluestype = instructions[1].split( ":")[1].strip().lower() except: definevaluestype = None if len(instructions) > 2: try: defaultvalue = toint(instructions[2]) except: if instructions[2][0:4] == "bind": pass #TODO: Restriction elif instructions[2][ 0:5] == "mask(": #format: mask(number) defaultvalue = toint(instructions[2][5:-1]) elif instructiontype == ParamType.command: defaultvalue = instructions[2] else: raise Exception( "Unknown default value for param: " + repr(instructions[2])) lastcommand.addParam(instructiontype, defaultvalue, definevaluestype=definevaluestype, description=stripDescription(line)) return lastcommand
## Load chars etc. used by the PokeString encode/decode functions ## definitions are placed in files: ./textchars and ./texthashes # texthash: <hash>\t<value> text hash, replace this complete thing with values in a text-string # textchar <char>\t<value> text letter rewrite to hex textchars = {} texthash = {} dirname = os.path.join(os.path.dirname(sys.argv[0]), "gbahackpkmn", "strings") for line in open(dirname + "/textchars", 'r', encoding="iso-8859-15"): if line: (char, val) = line.split("\t") if len(char) > 1: #Chars can be represented as hex numers (&hxx) char = chr(toint(char)) #print("Adding char. "+repr(char)) textchars[char] = toint(val) for line in open(dirname + "/texthashes", 'r', encoding="iso-8859-15"): if line: (hashv, val) = line.split("\t") texthash[hashv] = toint(val) textcharsinv = dict(zip(textchars.values(), textchars)) texthashinv = dict(zip(texthash.values(), texthash)) def decodeChar(char): if char == 0x00: #special case return " "
def parseline(self, line_raw, resource): line = line_raw #remove any comments, if any commentstart = line.find("'") if commentstart >= 0: line = line[:commentstart] line = line.lstrip() lineargs = self._line2args(line) if len(lineargs) == 0: return resource command = lineargs[0] args = lineargs[1:] if command == "#script": offset = args[0] #TODO Validate return self.routineDef(offset) if command == "#text": offset = args[0] #TODO: Validate return self.textDef(offset) if command == "#movement": offset = args[0] return self.movementDef(offset) if command[0] == "$": #$var = Hi I'm John! is sugar for #inline $var return self.parseline ("#inline "+line, resource) #Handle inline commands: #inline $Variable = Hi I'm John! if command == "#inline": offset = args[0] #TODO: Validate #ctype = args[1] #TODO: Make use of it :) raise Exception("TODO, not supported yet") #TODO #All done, inline is over. Continue with normal param return resource #A set of raw commands is added to the stream if command == "#binary" or command == "#raw": if not isinstance(resource, Routine): raise WrongCommandException() for byte in args: resource.ast().append(ast.ASTByte(toint(byte))) return resource #Parse movements if command[0] == ":": if not isinstance(resource, PokeMovement): raise WrongCommandException for byte in args: resource.append(toint(byte)) return resource #Parse strings if command[0] == "=": if not isinstance(resource, PokeString): raise WrongCommandException() resource.append(line_raw[1:].lstrip()) return resource # Still here? -> No pre-defined elements, check aliases and commands for # possible command-compile #Try to find an alias for this line, if it is there, take it. # Only if there is no matching alias, we look for a command to match for alias in self.langdef.aliases: if alias.matches(line): rawargs = self._prepargs(alias, alias.stripParams(line)) resource.ast().append(ast.ASTCommand(alias, rawargs)) return resource #Parse a command if command in self.langdef.commands: if not isinstance(resource, Routine): raise WrongCommandException() lcommand = self.langdef.commands[command] rawargs = self._prepargs(lcommand, args) resource.ast().append(ast.ASTCommand(lcommand, rawargs)) return resource raise Exception("Could not parse line, no rules matched: %s"%line)