| @@ -36,18 +36,92 @@ re_lookup = re.compile( | |||
| r"(/\* @AUTOGEN_LOOKUP_BLOCK_START \*/\n*)(.*?)" | |||
| 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): | |||
| """ | |||
| 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): | |||
| """ | |||