Skip to content

Intermediate Representation to Portable C Decompiler

TrishaCarter edited this page May 4, 2025 · 10 revisions

The primary file, "decompiler.py" that parses tokens from the input function in order to translate to C code.

End of C -> IR -> C pipeline; can see full process here: https://github.com/dubya62/optimizer.

️# IR to C Decompiler - Documentation

Overview

The IR to C Decompiler is a Python-based tool that converts an internal intermediate representation (IR) of C-like code into valid C source code. It handles various IR constructs such as type declarations, function definitions, struct/union/enum handling, casting, and complex assignment expressions.

Project Structure

IRToCDecompiler Class

The core class responsible for translating IR tokens into C code. The translation happens primarily inside the method generate_c_code. Modules and Functions get_type(toks: list[Token]) Purpose: Converts type-related tokens like #TYPE, #STRUCT, #UNION, or #ENUM into valid C syntax. handle_multiple_set(tokens) Purpose: Normalizes chained assignments (x = y = z) into sequential assignments.

IRToCDecompiler Class

generate_c_code(tokens, libraries) The main method for decompilation. Processing steps include: Include Headers – Adds necessary includes. Normalize Chained Assignments – Converts multiple assignment patterns. Type Casts and References – Rewrites cast, ref, and access appropriately. Handle Structs, Unions, Enums – Converts to proper C declarations. Function Definitions – Parses function signatures and bodies. Comma-Separated Assignment Fixes – Resolves complex multi-variable assignments. Type Inference and Substitution – Detects untyped vars and replaces consistently. Formatting – Adds newlines and generates final C code string.

Token Handling Logic

Uses a custom Token class with markers like: #FUNC, #TYPE, #STRUCT, #UNION, #ENUM, #FUNCCALL "ref", "access" which can be found in the lexer.py and normalizer.py

Example Use

from ir_to_c_decompiler import IRToCDecompiler
tokens = [...]  # List of Token instances
libraries = ["stdio.h", "stdlib.h"]
decompiler = IRToCDecompiler()
c_code = decompiler.generate_c_code(tokens, libraries)
print(c_code)

where test tokens may look like this:

TEST_TOKENS = ['#3', '=', '0', ';', 
                '@1', ':', 
                '#5', '=', '#3', '<', '10', ';', 
                'if', '#5', '{', 
                '#7', '=', '"Hello, World!\\n"', ';', 
                '#4', 'call', '#7', ';', 
                '#3', ';', 
                '#3', '=', '#3', '+', '1', ';', 
                'goto', '@3', ';', '}', 
                'else', '{',
                # '#3', '=', '#3', '+', '1', ';',
                '}', 
                '@0', ':',  
                '#6', '=', '0', ';', 
                '#8', 'access', '0', '=', '#6', ';', 
                'return', ';']

process`

Clone this wiki locally