Skip to content

About

A modular C-like compiler built from scratch in C, featuring Lexer, Parser, AST, Semantic Analysis, TAC/IR, Optimization, CFG, Virtual Machine execution, and an interactive Streamlit Compiler Explorer.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

⚡ MiniC Compiler

A modular C-like compiler built from scratch — from source code to optimized IR and Virtual Machine execution.

C TAC Optimization CFG VM Streamlit

Lexer → Parser → AST → Semantic Analysis → TAC → Optimization → CFG → Virtual Machine

GitHub Repository


🚀 Live Demo

Open MiniC Compiler Live Demo

Try the MiniC Compiler directly in your browser.

Write MiniC code, compile it, and explore the complete compilation pipeline including Tokens, AST, Semantic Analysis, TAC/IR, Optimized IR, CFG, and Virtual Machine output.

🔗 Launch MiniC Compiler →


🎬 Demo Video

See the MiniC Compiler in action, including the interactive web interface, compilation stages, optimization, program execution, and error handling.

minic-ui-clean.mp4

The demo showcases the Streamlit-based Compiler Explorer and demonstrates how MiniC processes source code through its compilation pipeline.

📸 Compiler Explorer

The project includes an interactive Streamlit Compiler Explorer for visualizing the complete compilation pipeline.

🖥️ Compiler Interface

MiniC Compiler UI

🔤 Lexical Analysis — Tokens

MiniC Tokens

🌳 Syntax Analysis — AST

MiniC AST

🧠 Semantic Analysis

MiniC Semantic Analysis

⚙️ Intermediate Representation

MiniC IR

🚀 Optimization

MiniC Optimizer

📉 Optimized IR

MiniC Optimized IR

🕸️ Control Flow Graph

MiniC CFG

✅ Program Output

MiniC Program Output


🌐 Try It Online

Resource Link
🚀 Live Compiler Open Streamlit App
💻 Source Code GitHub Repository
📚 Technical Documentation Compiler Construction Guide

🚀 What is MiniC?

MiniC is a compiler implementation for a small C-like programming language, built from scratch in C to demonstrate the core architecture and engineering principles behind modern compilers.

Unlike a simple parser or interpreter, MiniC implements a complete compilation pipeline:

                   ┌────────────────────┐
                   │    MiniC Source    │
                   │       (.mc)        │
                   └─────────┬──────────┘
                             │
                             ▼
                   ┌────────────────────┐
                   │       LEXER        │
                   │   Source → Tokens  │
                   └─────────┬──────────┘
                             │
                             ▼
                   ┌────────────────────┐
                   │      PARSER        │
                   │   Tokens → AST     │
                   └─────────┬──────────┘
                             │
                             ▼
                   ┌────────────────────┐
                   │ SEMANTIC ANALYSIS  │
                   │ Symbol / Validity  │
                   └─────────┬──────────┘
                             │
                             ▼
                   ┌────────────────────┐
                   │    TAC / IR        │
                   │ AST → Intermediate │
                   └─────────┬──────────┘
                             │
                             ▼
                   ┌────────────────────┐
                   │     OPTIMIZER      │
                   │ Folding + DCE      │
                   └─────────┬──────────┘
                             │
                             ▼
                   ┌────────────────────┐
                   │       CFG          │
                   │ Blocks + Edges     │
                   └─────────┬──────────┘
                             │
                             ▼
                   ┌────────────────────┐
                   │   VIRTUAL MACHINE  │
                   │    IR Execution    │
                   └─────────┬──────────┘
                             │
                             ▼
                   ┌────────────────────┐
                   │       OUTPUT       │
                   └────────────────────┘

The project also includes an interactive Streamlit compiler explorer, allowing users to inspect the output of each compiler stage directly in the browser.


💡 Why This Project?

MiniC was designed around a simple principle:

Don't hide the compiler. Expose it.

A source program can be inspected at every major transformation:

Source
  ↓
Tokens
  ↓
AST
  ↓
Semantic Information
  ↓
Three-Address Code
  ↓
Optimized Three-Address Code
  ↓
Control Flow Graph
  ↓
Virtual Machine Execution

This makes MiniC both a compiler implementation and an interactive environment for understanding compiler internals.


✨ Core Capabilities

🔤 Front End

  • Hand-written lexical analyzer
  • Recursive-descent parser
  • Abstract Syntax Tree
  • Symbol-table based semantic analysis
  • Line-aware diagnostics

⚙️ Intermediate Representation

  • Three-Address Code
  • Temporary generation
  • Label generation
  • Explicit control flow
  • Structured IR instructions

🚀 Optimization

  • Constant folding
  • Dead code elimination
  • Optimization statistics
  • Optimized IR generation

🧠 Program Analysis

  • Basic-block construction
  • Control Flow Graph generation
  • Branch analysis
  • Leader identification

🖥️ Execution

  • Custom Virtual Machine
  • Runtime variable storage
  • Temporary registers
  • Arithmetic operations
  • Conditional/unconditional jumps

🌐 Developer Experience

  • Streamlit compiler explorer
  • Stage-by-stage visualization
  • Built-in test programs
  • Execution timeout protection
  • Structured compiler diagnostics

🧩 Compiler Architecture

The implementation is intentionally modular.

Component Responsibility
lexer.c Source code → tokens
parser.c Tokens → AST
ast.c AST representation and utilities
semantic.c Semantic validation and symbol checking
codegen.c AST → Three-Address Code
optimizer.c IR optimization
cfg.c Basic blocks and CFG construction
ops.c Shared operator semantics
vm.c Optimized IR execution
main.c Compiler pipeline orchestration
app.py Interactive Streamlit interface

This separation keeps compiler stages independent and makes the system easier to understand and extend.


🔬 Compilation Pipeline

01 — Lexical Analysis

The lexer converts raw MiniC source code into a stream of tokens.

It recognizes:

  • Keywords
  • Identifiers
  • Integer literals
  • Arithmetic operators
  • Relational operators
  • Logical operators
  • Punctuation
  • End-of-file

Example:

int x = 10;

Conceptually becomes:

INT
IDENT(x)
ASSIGN
NUM(10)
SEMICOLON

Token line information is retained so later compiler stages can provide useful diagnostics.


02 — Parsing

MiniC uses a recursive-descent parser to transform tokens into an Abstract Syntax Tree.

The AST represents constructs such as:

N_NUM
N_VAR
N_BINOP
N_UNOP
N_ASSIGN
N_DECL
N_IF
N_WHILE
N_FOR
N_PRINT
N_BLOCK
N_PROGRAM

Operator precedence is handled during expression parsing.

For:

x + y * 2

the AST represents:

       +
      / \
     x   *
        / \
       y   2

rather than incorrectly evaluating:

(x + y) * 2

03 — Semantic Analysis

Parsing determines whether a program has the correct structure.

Semantic analysis determines whether that structurally valid program actually makes sense.

The semantic analyzer performs checks including:

  • Declaration validation
  • Duplicate declaration detection
  • Use-before-declaration detection
  • Expression validation
  • Statement validation

A symbol table tracks declared variables and their associated information.


04 — Three-Address Code

After semantic validation, the AST is lowered into Three-Address Code (TAC).

TAC breaks complex expressions into simple operations involving temporary values.

For example:

int result = a + b * 2;

can be represented conceptually as:

t1 = 2
t2 = b * t1
t3 = a + t2
result = t3

This creates a clean boundary between the high-level language and the execution engine.


05 — Optimization

MiniC currently implements two important optimization techniques.

Constant Folding

Compile-time evaluation of expressions whose operands are known constants.

2 + 3 * 4

becomes:

14

before runtime.

Dead Code Elimination

Computations whose results are never used can be removed from the IR.

For example:

int unused = 100 + 200;
int x = 10;

print(x);

does not need to retain the computation for unused.


06 — Control Flow Graph

The optimized IR is divided into basic blocks.

A basic block has:

  • A single entry point
  • Sequential execution
  • A controlled exit

MiniC identifies leaders such as:

  • The first instruction
  • Jump targets
  • Instructions immediately following jumps

These blocks are then connected to form a Control Flow Graph.

Example:

                    ┌──────────────┐
                    │    Entry     │
                    └──────┬───────┘
                           │
                       condition
                      /           \
                     ▼             ▼
             ┌────────────┐  ┌────────────┐
             │    THEN    │  │    ELSE    │
             └─────┬──────┘  └──────┬─────┘
                   │                │
                   └───────┬────────┘
                           ▼
                    ┌──────────────┐
                    │     EXIT     │
                    └──────────────┘

This exposes the program's control structure in a form commonly used for compiler analysis and optimization.


07 — Virtual Machine

MiniC does not generate native machine code.

Instead, the optimized TAC is executed by a custom Virtual Machine.

The VM maintains:

Program Counter
Temporary Registers
Variables
Labels
Runtime State

It interprets operations such as:

LOADCONST
LOADVAR
STOREVAR
BINOP
UNOP
PRINT
LABEL
GOTO
IFFALSE_GOTO

This creates a clean backend for experimenting with generated IR without requiring a native machine-code generator.


🔁 Shared Operator Semantics

Operator behavior is centralized in:

ops.c
ops.h

and reused by both the optimizer and the virtual machine.

                ┌──────────────┐
                │   Operator   │
                │    Engine    │
                └──────┬───────┘
                       │
             ┌─────────┴─────────┐
             ▼                   ▼
      ┌──────────────┐    ┌──────────────┐
      │  Optimizer   │    │      VM      │
      │ Compile-time │    │   Runtime    │
      └──────────────┘    └──────────────┘

This avoids maintaining separate implementations of arithmetic and logical semantics across compiler stages.


🌐 Interactive Compiler Explorer

The project includes a Streamlit-based web interface for interacting with the compiler.

Run:

streamlit run app.py

The interface allows users to write MiniC code and inspect the compiler pipeline.

Compiler Views

View Information
🔤 Tokens Lexer output
🌳 AST Parsed syntax tree
🧠 Semantic Semantic analysis
⚙️ IR Generated TAC
🚀 Optimizer Optimization statistics
📉 Optimized IR Optimized TAC
🕸️ CFG Basic blocks and edges
✅ Output Program execution

💻 MiniC Language

MiniC intentionally implements a compact C-like syntax.

Data Type

int

Variables

int x = 10;
x = x + 1;

Arithmetic

+
-
*
/

Comparisons

<
>
<=
>=
==
!=

Conditional Statements

if (x > 10) {
    print(x);
} else {
    print(0);
}

While Loop

while (x < 10) {
    x = x + 1;
}

For Loop

for (int i = 0; i < 5; i = i + 1) {
    print(i);
}

Output

print(x);

🧪 Example

MiniC Source

int a = 10;
int b = 20;

print(a + b);

Compile

./minicompiler tests/mytest.mc

Output

===TOKENS===

===AST===

===SEMANTIC===

===IR===

===OPTIMIZER===

===OPTIMIZED_IR===

===CFG===

===OUTPUT===
30

===END===

The compiler therefore exposes the complete transformation instead of returning only the final result.


# 📁 Repository Structure

```text
MiniC-Compiler/
│
├── lexer.c
├── lexer.h
├── token.h
│
├── parser.c
├── parser.h
│
├── ast.c
├── ast.h
│
├── semantic.c
├── semantic.h
│
├── codegen.c
├── codegen.h
│
├── optimizer.c
├── optimizer.h
│
├── cfg.c
├── cfg.h
│
├── ops.c
├── ops.h
│
├── vm.c
├── vm.h
│
├── main.c
│
├── app.py
├── requirements.txt
│
├── docs/
│   ├── 01-home.png
│   ├── 02-tokens.png
│   ├── 03-ast.png
│   ├── 04-semantic.png
│   ├── 05-ir.png
│   ├── 06-optimizer.png
│   ├── 07-optimized-ir.png
│   ├── 08-cfg.png
│   └── 09-output.png
│
├── tests/
│   ├── test1.mc
│   └── test2_optimizer.mc
│
├── Compiler_Construction_Guide.md
│
├── LICENSE
│
├── README.md
│
└── minicompiler

⚙️ Installation

Requirements

  • GCC
  • Python 3
  • pip
  • Streamlit

Clone

git clone https://github.com/N230881/MiniC-Compiler.git
cd MiniC-Compiler

Build

gcc -Wall -o minicompiler *.c

On Windows/MinGW:

gcc -Wall -o minicompiler.exe *.c

▶️ Run

Linux/macOS:

./minicompiler tests/test1.mc

Windows:

minicompiler.exe tests\test1.mc

🌐 Launch the Web UI

Install the required dependencies:

pip install -r requirements.txt

Start the Streamlit application:

streamlit run app.py

Then open:

http://localhost:8501

🧪 Test Programs

The repository includes test programs designed to exercise different compiler stages.

test1.mc

Exercises:

  • Variable declarations
  • Initialization
  • Arithmetic
  • Operator precedence
  • Conditional statements
  • Loops
  • Printing

test2_optimizer.mc

Exercises:

  • Constant folding
  • Dead code elimination
  • Optimized IR
  • Conditional execution
  • VM execution
  • Optimizer statistics

Run:

./minicompiler tests/test1.mc
./minicompiler tests/test2_optimizer.mc

📊 Engineering Highlights

MiniC demonstrates practical implementation of:

✓ Lexical Analysis
✓ Recursive-Descent Parsing
✓ Abstract Syntax Trees
✓ Symbol Tables
✓ Semantic Analysis
✓ Three-Address Code
✓ Temporary / Label Generation
✓ Constant Folding
✓ Dead Code Elimination
✓ Basic Blocks
✓ Control Flow Graphs
✓ Custom Virtual Machine
✓ Runtime Interpretation
✓ Structured Diagnostics
✓ Streamlit Visualization

🧠 Technical Design Principles

Separation of Concerns

Each compiler stage has a focused responsibility.

Explicit Intermediate Representation

TAC provides a simple and inspectable bridge between the AST and execution.

Reusable Semantics

Operator behavior is centralized instead of duplicated.

Observable Compilation

Every major compiler transformation can be inspected.

Extensibility

The modular architecture makes future additions—new language constructs, optimizations, or backends—easier to implement.


⚠️ Scope

MiniC is intentionally an educational compiler implementation, not a production C compiler.

It currently focuses on:

  • Integer-based computation
  • Compact C-like syntax
  • Compiler pipeline fundamentals
  • IR generation
  • Basic optimization
  • CFG construction
  • VM execution

It does not currently provide native machine-code generation, LLVM lowering, or the complete C language.

The goal is to make compiler internals understandable, executable, and inspectable rather than reproduce GCC or Clang.


🛣️ Roadmap

Language

  • Additional primitive types
  • Arrays
  • Functions
  • Return statements
  • Nested scopes
  • Strings
  • Expanded standard library

Optimization

  • Constant propagation
  • Copy propagation
  • Common subexpression elimination
  • Unreachable-code elimination
  • Strength reduction
  • Loop optimizations
  • SSA-based optimization

Backend

  • LLVM IR generation
  • RISC-V backend
  • x86-64 backend
  • WebAssembly backend

Tooling

  • Graphical AST viewer
  • Interactive CFG visualization
  • IR before/after comparison
  • Syntax highlighting
  • Automated regression suite
  • Compiler benchmarking

📚 Documentation

GitHub Repository

https://github.com/N230881/MiniC-Compiler

Technical Guide

See:

Compiler_Construction_Guide.md

for the project's compiler-construction documentation.


🤝 Contributing

Contributions, bug reports, and compiler experiments are welcome.

Create a feature branch:

git checkout -b feature/my-feature

Build:

gcc -Wall -o minicompiler *.c

Test:

./minicompiler tests/test1.mc
./minicompiler tests/test2_optimizer.mc

Then commit your changes and open a pull request.


📄 License

This project is licensed under the MIT License.

See the LICENSE file for details.


👨‍💻 Author

Shaik Sumayya Ruhi

B.Tech — Artificial Intelligence & Machine Learning

GitHub:

https://github.com/N230881

Project:

https://github.com/N230881/MiniC-Compiler


⭐ If you find this project useful, consider starring the repository.

Built from scratch to understand how compilers actually work.

Source → Tokens → AST → IR → Optimization → CFG → VM

About

A modular C-like compiler built from scratch in C, featuring Lexer, Parser, AST, Semantic Analysis, TAC/IR, Optimization, CFG, Virtual Machine execution, and an interactive Streamlit Compiler Explorer.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages