Assignment 01 - MacroJava to MiniJava
The goal of this assignment is to write a MacroJava to MiniJava translator using Flex and Bison.
| Release Date | 27/07/2026 |
| Deadline | 14/08/2026, 23:59 hours |
This assignment is graded out of 15: 9 for this take-home part and 6 for an extension you implement in the lab session on 18/08/2026. See the assignments page for how the lab component works.
Installation
This assignment needs flex, bison and a C compiler. The course repository
ships a container with these already installed, along with everything the later
assignments need; see Development
environment. To install
natively instead:
Ubuntu / WSL
$ sudo apt install build-essential flex bison libfl-dev
macOS
I recommend installing through Homebrew. Install Homebrew first using the instructions on the Homebrew website and then:
$ brew install flex bison
Windows
Use Ubuntu on WSL, then follow the Ubuntu instructions above.
Submission details
Your submission should be named <YOUR-ROLLNO>_P0.tar.gz compressed file. For
example, if your roll number is cs99b999, then the file should be named
cs99b999_P0.tar.gz. The compressed gzip archive should contain a folder named
<YOUR-ROLLNO>_P0 with two files and nothing else. A Flex file named as
A1.l and a Bison file named as A1.y.
If X.java is a valid MacroJava program, then the following commands should
generate the correct MiniJava code Y.java. Take input from standard input and
write to standard output.
$ bison -d A1.y
$ flex A1.l
$ cc A1.tab.c lex.yy.c -lfl -o A1
$ ./A1 < X.java > Y.java
bison -d is what writes A1.tab.h, which your A1.l needs to include in
order to use the token names. On macOS the flex library has a different name:
use -ll in place of -lfl. The Makefile in selftest/ does all of this
for you and picks the right library for your platform.
C or C++
You may write the action code in either. The grader builds your submission as
C first, and if that fails, builds it again as C++, so you do not have to
declare which you are using. The standard library is linked for you, so the
STL is available; you still have to include the headers you use, in the
%{ ... %} block:
%{
#include <map>
#include <string>
%}
If you write C++, put this as the first line of A1.l:
%option noyywrap
It is needed because the lex library is a C library, and it cannot be linked
into a C++ build: on GNU/Linux the library itself refers to yylex, and
compiling the lexer as C++ changes that name, so the link fails with
undefined reference to yylex. Dropping the library means your lexer has to
supply yywrap, and that option is what does it. Leave it out and the grader
will tell you so.
Building it yourself is then the same as above with c++ in place of cc and
no lex library. The generated files are named .c, but the compiler you invoke
decides the language, not the file extension:
$ c++ A1.tab.c lex.yy.c -o A1
Two things catch people out when moving to C++. Function declarations are
stricter: int yyerror(); in C means “unspecified arguments” and lets you call
yyerror("..."), while in C++ it means “no arguments” and that call will not
compile. Declare and define it with the parameters you actually pass. And a
declaration and its definition must agree exactly, or the two will be different
symbols and the link will fail.
Still submit exactly A1.l and A1.y. Any other source file is ignored,
whichever language you use.
Checking your work before you submit
selftest/ runs the same program that marks you, over a subset of the tests:
$ python3 selftest/evaluator.py cs99b999_P0.tar.gz
It builds your archive the way the grader does, so packaging mistakes surface here instead of costing you marks. See selftest/README.md for what it checks.
There are three sets of testcases: the public set ships in selftest/ and
you can read it; the private set runs in the online checker and reports
counts only; the hidden set is used for marking and you never see it.
You are marked on all three together, every test counting equally, so passing
the first two is necessary and not sufficient. A submission that does not build
scores zero.
If the X.java file is not a valid MacroJava program, then output
$ ./A1 < X.java
//Failed to parse input code
Useful commands for assignment submission
Assume that you have a folder called cs99b999_P0 with the solution files. For
assignment 1, this will contain just the Flex and the Bison files.
$ ls cs99b999_P0
A1.l A1.y
You can create a compressed archive (specifically a .tar.gz file) as
follows:
$ tar cvzf cs99b999_P0.tar.gz cs99b999_P0
a cs99b999_P0
a cs99b999_P0/A1.y
a cs99b999_P0/A1.l
$ file cs99b999_P0.tar.gz
cs99b999_P0.tar.gz.: gzip compressed data, last modified: ....
You can uncompress the archive as follows:
tar xvzf cs99b999_P0.tar.gz
x cs99b999_P0/
x cs99b999_P0/A1.y
x cs99b999_P0/A1.l
MacroJava
MacroJava is a subset of Java extended with C style macros. The meaning of a
MacroJava program is given by its meaning as a Java program (after macro
processing). Overloading is not allowed in MacroJava. The MacroJava statement
System.out.println( ... ); can only print integers. The MacroJava expression
e1 && e2 is of type boolean, and both e1 and e2 must be of type boolean.
MacroJava supports both inline as well as C style comments, but does not support
nested comments.
Some sample MacroJava programs can be found here.
Specification
Goal ::= (MacroDefinition)* MainClass ( TypeDeclaration )* <EOF>
MainClass ::= class Identifier { public static void main ( String [] Identifier ) { System.out.println ( Expression ); } }
TypeDeclaration ::= class Identifier { ( Type Identifier ;)* ( MethodDeclaration )* }
| class Identifier extends Identifier { ( Type Identifier;)* ( MethodDeclaration )* }
MethodDeclaration ::= public Type Identifier ( ( Type Identifier (, Type Identifier)*)? ) { ( Type Identifier ;)* ( Statement )* return Expression ; }
Type ::= int [ ]
| boolean
| int
| Identifier
Statement ::= { ( Statement )* }
| System.out.println ( Expression );
| Identifier = Expression ;
| Identifier [ Expression ] = Expression ;
| if ( Expression ) Statement
| if ( Expression ) Statement else Statement
| while ( Expression ) Statement
| Identifier ( (Expression (, Expression )*)?); /* Macro stmt call */
Expression ::= PrimaryExpression && PrimaryExpression
| PrimaryExpression || PrimaryExpression
| PrimaryExpression != PrimaryExpression
| PrimaryExpression <= PrimaryExpression
| PrimaryExpression + PrimaryExpression
| PrimaryExpression - PrimaryExpression
| PrimaryExpression * PrimaryExpression
| PrimaryExpression / PrimaryExpression
| PrimaryExpression [ PrimaryExpression ]
| PrimaryExpression . length
| PrimaryExpression
| PrimaryExpression . Identifier ( (Expression (, Expression )*)? )
| Identifier ( (Expression (, Expression )*)? )/* Macro expr call */
PrimaryExpression ::= Integer
| true
| false
| Identifier
| this
| new int [ Expression ]
| new Identifier ( )
| ! Expression
| ( Expression )
MacroDefinition ::= MacroDefExpression
| MacroDefStatement
MacroDefStatement ::= #defineStmt Identifier (Identifier , Identifier, Identifier (, Identifier )*? ) { ( Statement )* }/* More than 2 arguments */
| #defineStmt0 Identifier () { ( Statement )* }
| #defineStmt1 Identifier ( Identifier ) { ( Statement )* }
| #defineStmt2 Identifier (Identifier , Identifier ) { ( Statement )* }
MacroDefExpression ::= #defineExpr Identifier (Identifier , Identifier, Identifier (, Identifier )*? ) ( Expression ) /* More than 2 arguments */
| #defineExpr0 Identifier () ( Expression )
| #defineExpr1 Identifier ( Identifier ) ( Expression )
| #defineExpr2 Identifier (Identifier , Identifier ) ( Expression )
Identifier ::= <IDENTIFIER>
Integer ::= <INTEGER_LITERAL>
MiniJava
MiniJava is a subset of Java. The meaning of a MiniJava program is given by its
meaning as a Java program. Overloading is not allowed in MiniJava. The MiniJava
statement System.out.println( ... ); can only print integers. The MiniJava
expression e1 && e2 is of type boolean, and both e1 and e2 must be of type
boolean.
Some sample MiniJava programs can be found here.
Specification
Use the canonical MiniJava grammar. The corresponding JavaCC grammar is the authoritative specification used to generate the assignment parser.
Clarification (10 August 2026). An earlier version of this page also listed
private and protected method access and ternary expressions as MiniJava
extensions. Submissions that support these extensions remain valid. This
clarification does not change the released test cases or grading.