def _format_indirect_call_multitarget(self, branch: blocks.Branch, uuid: int) -> str: paths = branch.next_target_sequence() max_index = len(paths) paths_array_name = f'paths_{uuid}' paths_array = self._create_target_sequence_array( paths, paths_array_name) func_array = self._create_call_target_array(branch.get_targets(), f'array_{uuid}') result = ( f'static int index_{uuid} = 0;\n' f'{paths_array}' f'{func_array}' f'void (*f_{uuid})(void) = ' f'array_{uuid}[{paths_array_name}[index_{uuid}++ % {max_index}]];\n' f'f_{uuid}();\n') return result
def _format_branch_indirect(self, branch: blocks.Branch) -> str: target = branch.next_valid_target() label = self.format_code_block_label(self.code_blocks[target]) branch_id = id(branch) fake_label = f'label{branch_id}' result = (f'{fake_label}:;\n' 'int label_target = 0;\nvoid* array[] = {' f'&&{label}' f', &&{fake_label}' '};\n' 'goto *(array[label_target]);\n') return result
def _build_switch_cases(self, branch: blocks.Branch) -> str: result = '' for i in range(len(branch.targets)): target = branch.get_target_from_index(i) new_string = f'case {i}:\n' if target is None: # Fallthrough branch new_string = f'{new_string}\tbreak;\n' else: label = self.format_code_block_label(self.code_blocks[target]) new_string = f'{new_string}\tgoto {label};\n' result += new_string return result
def _format_branch_conditional_direct(self, branch: blocks.Branch) -> str: paths = branch.next_target_sequence() max_index = len(paths) branch_id = id(branch) paths_array_name = f'paths_{branch_id}' paths_array = self._create_target_sequence_array( paths, paths_array_name) switch_cases = self._build_switch_cases(branch) result = ( f'static int index_{branch_id} = 0;\n' f'{paths_array}' f'switch ({paths_array_name}[index_{branch_id}++ % {max_index}]) ' '{\n' f'{switch_cases}' '}\n') return result
def _format_branch_indirect_call(self, branch: blocks.Branch, uuid: int = None) -> str: """Format an indirect call. Args: branch: blocks.Branch instance. Must have branch_type of INDIRECT_CALL. uuid: Unique suffix to use for local variables. Used to differentiate multiple branches in a single function and to avoid any overlapping variables provided in user defined instructions. Leaving unspecified will let the program decide a unique suffix. Returns: A str representing an indirect call in C. """ if uuid is None: uuid = id(branch) if len(branch.get_targets()) == 1: return self._format_indirect_call_singletarget(branch, uuid) return self._format_indirect_call_multitarget(branch, uuid)
def _format_branch_direct(self, branch: blocks.Branch) -> str: target = branch.next_valid_target() label = self.format_code_block_label(self.code_blocks[target]) return f'goto {label};\n'
def _format_branch_direct_call(self, branch: blocks.Branch) -> str: target = branch.next_valid_target() string = self.function_call_signature_for(target) return f'{string}();\n'
def _format_indirect_call_singletarget(self, branch: blocks.Branch, uuid: int) -> str: target = branch.next_valid_target() sig = self.function_call_signature_for(target) return (f'void (*frontend_{uuid})(void) = {sig};\n' f'frontend_{uuid}();\n')