- You may copy and modify the MiniJava.jflex file you're developing for Assignment 1 for this exercise
- Try to bring the MiniJava.jflex file you copied to a compilable state (It needs not to define the complete MiniJava lexical specification). Some
compilable state of your code is good enough for this exercise.
- Add the following line at the very beginning of your .jflex file.
import java_cup.runtime.*;
JFlex is built to be integrated with CUP parser generator (which is the tool to be used in
Assignment 2), so the statement above imports the CUP classes into our lexer.
- In the section that follows the first %%, we need to add the following list of directives.
%cupsym Sym
%cup
%cupdebug
As also stated in the JFlex manual:
%cup
The %cup directive enables the CUP compatibility.
%cupsym "classname"
Customizes the name of the CUP generated class/interface containing the names of terminal tokens. The directive should not be used after
%cup directive, but before.
%cupdebug
Creates a main function in the generated class that expects the name of an input file on the command line and then runs the scanner on this input file.
Prints line, column, matched text, and CUP symbol name for each returned token to standard out.
- Sym is the name of the class where we define the names of our token classes. For every terminal you have used in MiniJava.jflex, you need to add a
constant to the file Sym.java. Download this file and compile it. This file will be automatically generated by the CUP parser
generator in Assignment #2.
- Next, into the first %{ ... %} section of your MiniJava.jflex file insert the following methods.
Sym sym;
private Symbol symbol(int type) {
return new Symbol(type, yyline, yycolumn);
}
private Symbol symbol(int type, Object value) {
return new Symbol(type, yyline, yycolumn, value);
}
The above two methods creates the tokens that are communicated to the parser. Out of the two methods first one defines a token with no semantic value,
whereas the second one defines a token with some semantic value.
- Finally, modify all your action statements from
reg_exp_1 { System.out.println("SOME_TOKEN"); }
reg_exp_2 { System.out.println("TOKEN_W_SEMANTIC_VALUE(" + yytext() + ")" ); }
to
reg_exp_1 { return symbol(sym.SOME_TOKEN); }
reg_exp_2 { return symbol(sym.TOKEN_W_SEMANTIC_VALUE, new SOME_CLASS_CONSTRUCTOR( yytext() )); }
In order to return a Java String or a Java Integer object, you need to replace the new SOME_CLASS_CONSTRUCTOR() with new String() or with new Integer() as
applicable.
- Compile and build the lexer. However, to get this to compile, you must have the path to CUP classes in your CLASSPATH.
One way to accomplish this is to pass the CLASSPATH as an argument to the Java compiler:
/usr/csshare/pkgs/jdk1.5.0_05/bin/javac -classpath /usr/csshare/pkgs/jdk1.5.0_05/jre/lib/ext/java-cup-v11a.jar:. Lexer.java Sym.java
- Test the Lexer class on several test programs:
/usr/csshare/pkgs/jdk1.5.0_05/bin/java -classpath /usr/csshare/pkgs/jdk1.5.0_05/jre/lib/ext/java-cup-v11a.jar:. Lexer <YOUR TEST FILE>
Due to the %cupdebug directive in the MiniJava.jflex file, no actions (i.e. return of tokens in our case) will get executed; instead, the lexer will output
the token, the actual text and line and column where the token was found.