Skip to content

A complete compiler and interpreter for a small programming language called "minic". The compiler processes source code written in "minic", checks it for errors, and then executes it. This involves several classic compiler stages including Lexical Analysis (Lexing), Syntax Analysis (Parsing), Semantic Analysis and Execution (Interpretation)

License

Notifications You must be signed in to change notification settings

RohanMankame/mini-C-Compiler-Interpreter

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 

Repository files navigation

MiniC Compiler and Interpreter

This project is a fully functional compiler and interpreter for "minic", a small, statically-typed programming language. It was built using Java and compiler construction tools like JFlex (for lexical analysis) and BYACC/J (for parsing).

The compiler parses source code written in minic, performs semantic analysis to catch errors, and then directly interprets the program to execute it.

Minic Language Features

The "minic" language supports a variety of modern programming constructs like...

  • Data Types: num (for floating-point numbers) and bool (for true/false).
  • Variables: Declare variables using the var keyword.
  • Arrays: Create and use arrays of num or bool.
  • Functions: Define functions with parameters and return values using the func keyword.
  • Control Flow:
    • Conditional logic with if-then-else-end blocks.
    • Looping with while-begin-end blocks.
  • Expressions:
    • Arithmetic: +, -, *, /, %
    • Relational: =, <>, !=, <, <=, >, >=
    • Logical: and, or, not
  • Built-in Functions:
    • print: Prints a value to the console.
    • .size: Gets the size of an array.
  • Comments: Supports // for single-line comments.

Project Structure

minic-SemanticChecker & Executor/
├── src/
│   ├── Compiler.java         # Main compiler driver
│   ├── Grammar.txt           # Language grammar and token definitions
│   ├── Lexer.java            # Lexical analyzer (generated by JFlex)
│   ├── Parser.java           # Parser (generated by BYACC/J)
│   ├── ParserImpl.java       # Semantic actions and tree construction logic
│   ├── ParseTree.java        # Defines the AST nodes and interpreter logic
│   ├── ParseTreeInfo.java    # Helper classes for storing info in the AST
│   ├── Env.java              # Symbol table for managing scope and types
│   ├── Token.java            # Represents a single lexical token
│   ├── Program.java          # Main entry point for running the compiler
│   └── ...
└── samples/
    ├── succ_01.minc          # Example of a valid minic program
    └── fail_01a.minc         # Example of an invalid minic program

How It Works

The compilation and execution process follows these steps:

  1. Lexical Analysis: Lexer.java reads the .minc file and converts it into a stream of tokens based on the rules in Grammar.txt.
  2. Parsing: Parser.java consumes the tokens and, with the help of the grammar rules, builds a Parse Tree. The code to actually build the tree is in ParserImpl.java.
  3. Semantic Analysis: As the tree is built, the code in ParserImpl.java performs semantic checks. It uses Env.java to keep track of variables and functions in scope to detect errors like type mismatches, undeclared variables, or incorrect function calls.
  4. Interpretation: If no errors are found, the Compiler calls the Exec() method on the root of the ParseTree. This triggers a walk down the tree, where each node executes its specific logic (e.g., performing arithmetic, assigning values, calling functions).

How to Run

  1. Prerequisites: You need to have a Java Development Kit (JDK) installed.
  2. Compile: Navigate to the src directory and compile all the Java files.
    cd "minic-SemanticChecker & Executor/src"
    javac *.java
  3. Run: Execute the Program class, passing the path to a .minc sample file as an argument.
    java Program ../samples/succ_01.minc
    You can try any of the files in the samples directory to see the compiler in action.

Example "minic" Code

Example of success test - succ_04.minc

func main :: num ()
begin
    var i :: num ;
    var x :: num ;
    var y :: bool[];
    var z :: num [];

    x := 1;

    y := new bool[3];
    y[0] := true;
    y[1] := true and false;
    y[2] := y[1] or true;
    print y;

    i := 5;
    z := new num[i];
    i := 0    ; z[i] := 0;
    i := i + 1; z[i] := z[i-1] + i;
    i := i + 1; z[i] := z[i-1] + i;
    i := i + 1; z[i] := z[i-1] + i;
    i := i + 1; z[i] := z[i-1] + i;
    print z;

    return 1 ;
end

the output of my program is...

Success: no semantic error is found.

================================================================================
Code with indentations:
func main::num()
begin
    var num::i;
    var num::x;
    var bool[]::y;
    var num[]::z;
    x := 1.0;
    y := new bool[3.0];
    y[0.0] := true;
    y[1.0] := true and false;
    y[2.0] := y[1.0] or true;
    print y;
    i := 5.0;
    z := new num[i];
    i := 0.0;
    z[i] := 0.0;
    i := i + 1.0;
    z[i] := z[i - 1.0] + i;
    i := i + 1.0;
    z[i] := z[i - 1.0] + i;
    i := i + 1.0;
    z[i] := z[i - 1.0] + i;
    i := i + 1.0;
    z[i] := z[i - 1.0] + i;
    print z;
    return 1.0;
end
================================================================================
Code with indentations and comments for running environment:
func main::num()
begin
    var num::i; // relative address of local variable i from this func call base pointer is 1
    var num::x; // relative address of local variable x from this func call base pointer is 2
    var bool[]::y; // relative address of local variable y from this func call base pointer is 3
    var num[]::z; // relative address of local variable z from this func call base pointer is 4
    x{addr:2} := 1.0;
    y{addr:3} := new bool[3.0];
    y{addr:3}[0.0] := true;
    y{addr:3}[1.0] := true and false;
    y{addr:3}[2.0] := y[1.0] or true;
    print y{addr:3};
    i{addr:1} := 5.0;
    z{addr:4} := new num[i{addr:1}];
    i{addr:1} := 0.0;
    z{addr:4}[i{addr:1}] := 0.0;
    i{addr:1} := i{addr:1} + 1.0;
    z{addr:4}[i{addr:1}] := z[i{addr:1} - 1.0] + i{addr:1};
    i{addr:1} := i{addr:1} + 1.0;
    z{addr:4}[i{addr:1}] := z[i{addr:1} - 1.0] + i{addr:1};
    i{addr:1} := i{addr:1} + 1.0;
    z{addr:4}[i{addr:1}] := z[i{addr:1} - 1.0] + i{addr:1};
    i{addr:1} := i{addr:1} + 1.0;
    z{addr:4}[i{addr:1}] := z[i{addr:1} - 1.0] + i{addr:1};
    print z{addr:4};
    return 1.0;
end
================================================================================
Execute:
[true, false, true]
[0.0, 1.0, 3.0, 6.0, 10.0]
Returned value by main: 1.0
================================================================================

Example of success test - succ_01.minc

func main :: num ()
begin
    // there is no error in this code.
{
    The block comment should be excluded in the parse tree
}
    return 3.142592;
end

the output of my program is...

================================================================================
Code with indentations:
func main::num()
begin
    return 3.142592;
end
================================================================================
Code with indentations and comments for running environment:
func main::num()
begin
    return 3.142592;
end
================================================================================
Execute:
Returned value by main: 3.142592
================================================================================
end

Example of Fail test - fail_01d.minc

func main :: num ()
begin
    // there is no error in this code.
{
    The block comment should be excluded in the parse tree
}
    return not 3.142592;
end

the output of my program is...

Error: there is semantic error(s).
[Error] Unary operation not cannot be used with num value.

Example of Fail test - fail_04a.minc

func main :: num ()
begin
    var i :: num ;
    var x :: num ;
    var y :: bool[];
    var z :: num [];

    x := 1;

    y := new bool[3];
    y[true] := true;
    y[1] := true and false;
    y[2] := y[1] or true;
    print y;

    i := 5;
    z := new num[i];
    i := 0    ; z[i] := 0;
    i := i + 1; z[i] := z[i-1] + i;
    i := i + 1; z[i] := z[i-1] + i;
    i := i + 1; z[i] := z[i-1] + i;
    i := i + 1; z[i] := z[i-1] + i;
    print z;

    return 1 ;
end

the output of my program is...

Error: there is semantic error(s).
[Error] Array index must be num value.

Author

Rohan Mankame

About

A complete compiler and interpreter for a small programming language called "minic". The compiler processes source code written in "minic", checks it for errors, and then executes it. This involves several classic compiler stages including Lexical Analysis (Lexing), Syntax Analysis (Parsing), Semantic Analysis and Execution (Interpretation)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published