| @@ -36,18 +36,92 @@ re_lookup = re.compile( | |||||
| r"(/\* @AUTOGEN_LOOKUP_BLOCK_START \*/\n*)(.*?)" | r"(/\* @AUTOGEN_LOOKUP_BLOCK_START \*/\n*)(.*?)" | ||||
| r"(\n*/\* @AUTOGEN_LOOKUP_BLOCK_END \*/)", re.S) | r"(\n*/\* @AUTOGEN_LOOKUP_BLOCK_END \*/)", re.S) | ||||
| def build_inst(name, data): | |||||
| class Instruction(object): | |||||
| """ | """ | ||||
| Convert data for an individual instruction into a C parse function. | |||||
| Represent a single ASM instruction mnemonic. | |||||
| """ | """ | ||||
| # TODO | |||||
| return "INST_FUNC({0})\n{{\n}}".format(name) | |||||
| ARG_TYPES = { | |||||
| "register": "AT_REGISTER", | |||||
| "immediate": "AT_IMMEDIATE", | |||||
| "indirect": "AT_INDIRECT", | |||||
| "indexed": "AT_INDEXED|AT_INDIRECT", | |||||
| "condition": "AT_CONDITION", | |||||
| "port": "AT_PORT" | |||||
| } | |||||
| def __init__(self, name, data): | |||||
| self._name = name | |||||
| self._data = data | |||||
| def _get_arg_parse_mask(self, num): | |||||
| """ | |||||
| Return the appropriate mask to parse_args() for the num-th argument. | |||||
| """ | |||||
| types = set() | |||||
| optional = False | |||||
| for case in self._data["cases"]: | |||||
| if num < len(case["type"]): | |||||
| types.add(self.ARG_TYPES[case["type"][num]]) | |||||
| else: | |||||
| optional = True | |||||
| if not types: | |||||
| return "AT_NONE" | |||||
| if optional: | |||||
| types.add("AT_OPTIONAL") | |||||
| return "|".join(types) | |||||
| def _handle_return(self, arg, indent=1): | |||||
| """ | |||||
| Return code to handle an instruction return statement. | |||||
| """ | |||||
| tabs = TAB * indent | |||||
| if arg == "error": | |||||
| return tabs + "INST_ERROR(ARG_SYNTAX)" | |||||
| else: | |||||
| data = ", ".join("0x%02X" % byte for byte in arg) | |||||
| return tabs + "INST_RETURN({0}, {1})".format(len(arg), data) | |||||
| def _handle_case(self, case): | |||||
| """ | |||||
| TODO | |||||
| """ | |||||
| return [TAB + "// " + str(case)] | |||||
| def render(self): | |||||
| """ | |||||
| Convert data for an individual instruction into a C parse function. | |||||
| """ | |||||
| lines = [] | |||||
| if self._data["args"]: | |||||
| lines.append("{tab}INST_TAKES_ARGS(\n{tab2}{0}, \n{tab2}{1}, " | |||||
| "\n{tab2}{2}\n{tab})".format( | |||||
| self._get_arg_parse_mask(0), self._get_arg_parse_mask(1), | |||||
| self._get_arg_parse_mask(2), tab=TAB, tab2=TAB * 2)) | |||||
| else: | |||||
| lines.append(TAB + "INST_TAKES_NO_ARGS") | |||||
| if "return" in self._data: | |||||
| lines.append(self._handle_return(self._data["return"])) | |||||
| elif "cases" in self._data: | |||||
| for case in self._data["cases"]: | |||||
| lines.extend(self._handle_case(case)) | |||||
| lines.append(TAB + "INST_ERROR(ARG_TYPE)") | |||||
| else: | |||||
| msg = "Missing return or case block for {0} instruction" | |||||
| raise RuntimeError(msg.format(self._name)) | |||||
| contents = "\n".join(lines) | |||||
| return "INST_FUNC({0})\n{{\n{1}\n}}".format(self._name, contents) | |||||
| def build_inst_block(data): | def build_inst_block(data): | ||||
| """ | """ | ||||
| Return the instruction parser block, given instruction data. | Return the instruction parser block, given instruction data. | ||||
| """ | """ | ||||
| return "\n\n".join(build_inst(k, v) for k, v in sorted(data.items())) | |||||
| return "\n\n".join( | |||||
| Instruction(k, v).render() for k, v in sorted(data.items())) | |||||
| def build_lookup_block(data): | def build_lookup_block(data): | ||||
| """ | """ | ||||