This project is a custom programming language interpreter built completely from scratch in Java. It is a simple tree-walking interpreter designed to show how a programming language works internally, from reading source code to producing runtime output.
The project does not use external parser generators such as ANTLR or JavaCC. All major parts are written manually using Java Standard Edition.
The core idea is to build a small interpreted language by following the same major stages used in real language runtimes:
Source Code
-> Lexer
-> Tokens
-> Parser
-> AST
-> Interpreter
-> Output
The lexer breaks raw text into tokens. The parser checks syntax and builds an Abstract Syntax Tree. The interpreter walks that tree and executes the program.
The interpreter currently supports:
- Variable declarations using
let - Variable assignment
printstatementsif/elseconditionswhileloopsforloops- Block statements using
{ } - Nested scopes
- Numbers
- Strings
- Booleans:
trueandfalse null- Arithmetic operators:
+,-,*,/ - Comparison operators:
>,>=,<,<= - Equality operators:
==,!= - Unary operators:
!,- - Single-line comments using
// - Lexer, parser, and runtime errors with line numbers
- Interactive terminal REPL
- Script-file execution
The work was divided into four major responsibilities:
- Person 1: AST classes and environment memory handling
- Person 2: Lexer and token generation
- Person 3: Parser and syntax analysis
- Person 4: Interpreter and execution
Each part connects through a strict pipeline:
Lexer lexer = new Lexer(source);
List<Token> tokens = lexer.scanTokens();
Parser parser = new Parser(tokens);
List<Stmt> statements = parser.parse();
Interpreter interpreter = new Interpreter();
interpreter.interpret(statements);| File | Purpose |
|---|---|
Main.java |
Entry point. Runs a file or starts the interactive prompt. |
Lexer.java |
Converts source code into tokens. |
Token.java |
Stores token type, lexeme, literal value, and line number. |
TokenType.java |
Defines all token categories. |
Parser.java |
Converts tokens into AST statements and expressions. |
Expr.java |
Defines expression AST nodes and visitor methods. |
Stmt.java |
Defines statement AST nodes and visitor methods. |
Interpreter.java |
Walks the AST and executes the program. |
Environment.java |
Stores variables and supports nested scopes. |
LexerException.java |
Custom lexer error. |
ParseException.java |
Custom parser error. |
RuntimeError.java |
Custom runtime error. |
PERSON_3_PARSER_HANDOFF.md |
Parser integration notes for teammates. |
Interpreter_Project_Demo_Guide.pdf |
Shareable demo explanation document. |
Example program:
let x = 2 + 3 * 4;
print x;First, the lexer converts the source into tokens:
LET IDENTIFIER EQUAL NUMBER PLUS NUMBER STAR NUMBER SEMICOLON PRINT IDENTIFIER SEMICOLON EOF
Then the parser builds an AST. It understands operator precedence, so this:
2 + 3 * 4is parsed as:
2 + (3 * 4)
Finally, the interpreter evaluates the AST and prints:
14
for loops are supported without adding a separate ForStmt AST class. The
parser converts a for loop into an equivalent block and while loop.
This:
for (let i = 0; i < 3; i = i + 1) {
print i;
}is internally handled like:
{
let i = 0;
while (i < 3) {
print i;
i = i + 1;
}
}This keeps the interpreter simpler because it only needs to execute existing
BlockStmt, WhileStmt, and ExpressionStmt nodes.
Open PowerShell in the project folder:
cd "C:\Users\ankit\OneDrive\Documents\Ashith Anandnath\python\Interpreter\Interpreter"Compile the Java files:
javac *.javaStart the interactive prompt:
java MainYou can now type code directly into the terminal.
After running java Main, paste these lines:
print "===== DEMO START =====";
let x = 2 + 3 * 4;
print x;
if (x > 10) { print "x is greater than 10"; } else { print "x is small"; }
let total = 0;
for (let i = 1; i <= 5; i = i + 1) { total = total + i; }
print total;
let value = 100;
{ let value = 200; print value; }
print value;
print true;
print null;
print "===== DEMO COMPLETE =====";Expected important output:
===== DEMO START =====
14
x is greater than 10
15
200
100
true
nil
===== DEMO COMPLETE =====
Create a file, for example:
test.script
Put language code inside it:
let total = 0;
for (let i = 1; i <= 10; i = i + 1) {
total = total + i;
}
print total;Run it with:
java Main test.scriptExpected output:
55
The interpreter uses custom errors with line numbers.
Lexer error example:
print @;Parser error example:
let = 10;Runtime error example:
print missingVariable;These errors help identify exactly where the program failed.
This is a simple educational interpreter, not a full production language.
Current limitations:
- No user-defined functions
- No arrays
- No classes
- No
breakorcontinue - No input function
- No advanced standard library
The architecture is modular, so these features can be added later by extending the lexer, parser, AST, and interpreter.
This project demonstrates the complete basic workflow of an interpreter:
- Reading source code
- Tokenizing input
- Parsing grammar
- Building an AST
- Managing variable memory and scope
- Executing code through a tree-walking interpreter
It gives a practical understanding of how programming languages process and run code internally.