Procházet zdrojové kódy

Initial commit: Java 1.2

Mathias Landhäußer před 11 roky
rodič
revize
a1d457780a

+ 39 - 0
jplag.frontend.java-1.2/Readme.txt

@@ -0,0 +1,39 @@
+JPlag Frontend Pack
+
+The JPlag system uses different frontends to transform the input files into a
+token stream, which abstracts very much from the original source code. For
+example in our Java frontend any assignments are translated to J_ASSIGN
+tokens, method invocations become J_APPLY tokens, arithmetic calculations,
+names, and comments are ignored, etc. Only some kind of program structure
+remains, which is then compared to other source files.
+
+This package contains a minimal set of files required to build our 
+Java 1.4 frontend (including ANTLR 2.7.7). The jplag.Program class has been
+reduced to only two functions.
+The grammar is specified with ANTLR 2.7.7 (src/main/antlr/java.g). In 
+some productions the parser adds tokens to the above mentioned token stream. 
+Search for "parser.add(" to find these locations. The token types are defined
+in "src/main/java/jplag/java/JavaToken.java" and "src/main/java/jplag/java/JavaTokenConstants.java".
+
+After building the source with a simple "mvn compile", you can test the parser by 
+invoking the main method of jplag.java.Parser with a Java file to parse as arguemtn:
+
+java -cp "antlr.jar;build" jplag.java.Parser src/main/java/jplag/java/Parser.java
+
+This will show you the listing of src/main/java/jplag/java/Parser.java on the right side 
+of the screen with the generated tokens and their locations on the left side.
+
+To generate a new frontend you have to do the following things:
+- Generate an ANTLR 2.7.7 grammar (note: ANTLR 3 is quite different
+  from ANTLR 2) -> this is done during mvn compile
+- Choose which tokens should be generated
+- Declare the token types in a ...Token.java and ...TokenConstants.java file
+- Add the tokens with "parser.add(..." in the grammar
+- Adapt the other files
+
+I hope this helps you to understand, how our frontends work and to create 
+your own frontend.
+
+It is also possible to use another parser generator. Our Java 1.5 frontend
+for example uses JavaCC 3.2. If you are interested in using JavaCC, we can
+also provide you with the Java 1.5 frontend.

+ 89 - 0
jplag.frontend.java-1.2/pom.xml

@@ -0,0 +1,89 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<artifactId>java-1.2</artifactId>
+	<version>0.0.1-SNAPSHOT</version>
+
+	<repositories>
+		<repository>
+			<id>ipdNexus</id>
+			<name>Recaa Repository</name>
+			<url>http://bob.ipd.kit.edu/nexus/content/repositories/public/</url>
+		</repository>
+	</repositories>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.codehaus.mojo</groupId>
+				<artifactId>build-helper-maven-plugin</artifactId>
+				<version>1.7</version>
+				<configuration>
+					<sources>
+						<source>src/main/antlr</source>
+						<source>target/generated-sources/antlr</source>
+					</sources>
+				</configuration>
+				<executions>
+					<execution>
+						<id>add-antlr-source</id>
+						<phase>generate-sources</phase>
+						<goals>
+							<goal>add-source</goal>
+						</goals>
+
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.codehaus.mojo</groupId>
+				<artifactId>antlr-maven-plugin</artifactId>
+				<version>2.2</version>
+				<configuration>
+					<!-- Comma separated list of grammar files or pattern grammar files 
+						By default, grammar file(s) is in ${basedir}/src/main/antlr -->
+					<grammars>java.g</grammars>
+					<!-- <grammars>*.g</grammars> -->
+				</configuration>
+				<executions>
+					<execution>
+						<goals>
+							<goal>generate</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-jar-plugin</artifactId>
+				<configuration>
+					<archive>
+						<manifest>
+							<mainClass>jplag.java.Parser</mainClass>
+							<packageName>jplag.java</packageName>
+						</manifest>
+					</archive>
+				</configuration>
+			</plugin>
+
+		</plugins>
+	</build>
+
+	<dependencies>
+		<dependency>
+			<groupId>antlr</groupId>
+			<artifactId>antlr</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>edu.kit.ipd.jplag</groupId>
+			<artifactId>frontend-utils</artifactId>
+			<version>0.0.1-SNAPSHOT</version>
+		</dependency>
+	</dependencies>
+	<parent>
+		<groupId>edu.kit.ipd.jplag.frontend</groupId>
+		<artifactId>frontend-parent</artifactId>
+		<version>0.2-SNAPSHOT</version>
+	</parent>
+</project>

+ 1272 - 0
jplag.frontend.java-1.2/src/main/antlr/java.g

@@ -0,0 +1,1272 @@
+header {
+  package jplag.java.grammar;
+  
+  import java.io.IOException;
+  import jplag.java.*;
+  import jplag.InputState;
+  import jplag.ParserToken;
+}
+
+/** Java 1.2 Recognizer
+ *
+ * Run 'java Main <directory full of java files>'
+ *
+ * Contributing authors:
+ *		John Mitchell		johnm@non.net
+ *		Terence Parr		parrt@magelang.com
+ *		John Lilley			jlilley@empathy.com
+ *		Scott Stanchfield	thetick@magelang.com
+ *		Markus Mohnen       mohnen@informatik.rwth-aachen.de
+ *		Peter Williams		pwilliams@netdynamics.com
+ *
+ * Version 1.00 December 9, 1997 -- initial release
+ * Version 1.01 December 10, 1997
+ *		fixed bug in octal def (0..7 not 0..8)
+ * Version 1.10 August 1998 (parrt)
+ *		added tree construction
+ *		fixed definition of WS,comments for mac,pc,unix newlines
+ *		added unary plus
+ * Version 1.11 (Nov 20, 1998)
+ *		Added "shutup" option to turn off last ambig warning.
+ *		Fixed inner class def to allow named class defs as statements
+ *		synchronized requires compound not simple statement
+ *		add [] after builtInType DOT class in primaryExpression
+ *		"const" is reserved but not valid..removed from modifiers
+ * Version 1.12 (Feb 2, 1999)
+ *		Changed LITERAL_xxx to xxx in tree grammar.
+ *		Updated java.g to use tokens {...} now for 2.6.0 (new feature).
+ *
+ * Version 1.13 (Apr 23, 1999)
+ *		Didn't have (stat)? for else clause in tree parser.
+ *		Didn't gen ASTs for interface extends.  Updated tree parser too.
+ *		Updated to 2.6.0.
+ * Version 1.14 (Jun 20, 1999)
+ *		Allowed final/abstract on local classes.
+ *		Removed local interfaces from methods
+ *		Put instanceof precedence where it belongs...in relationalExpr
+ *			It also had expr not type as arg; fixed it.
+ *		Missing ! on SEMI in classBlock
+ *		fixed: (expr) + "string" was parsed incorrectly (+ as unary plus).
+ *		fixed: didn't like Object[].class in parser or tree parser
+ * Version 1.15 (Jun 26, 1999)
+ *		Screwed up rule with instanceof in it. :(  Fixed.
+ *		Tree parser didn't like (expr).something; fixed.
+ *		Allowed multiple inheritance in tree grammar. oops.
+ * Version 1.16 (August 22, 1999)
+ *		Extending an interface built a wacky tree: had extra EXTENDS.
+ *		Tree grammar didn't allow multiple superinterfaces.
+ *		Tree grammar didn't allow empty var initializer: {}
+ * Version 1.17 (October 12, 1999)
+ *		ESC lexer rule allowed 399 max not 377 max.
+ *		java.tree.g didn't handle the expression of synchronized
+ *			statements.
+ *
+ * Version tracking now done with following ID:
+ *
+ * $Id: //depot/code/org.antlr/release/antlr-2.7.0/examples/java/java/java.g#1 $
+ *
+ * BUG:
+ * 		Doesn't like boolean.class!
+ *
+ * class Test {
+ *   public static void main( String args[] ) {
+ *     if (boolean.class.equals(boolean.class)) {
+ *       System.out.println("works");
+ *     }
+ *   }
+ * }
+ *
+ * This grammar is in the PUBLIC DOMAIN
+ */
+
+class JRecognizer extends Parser;
+options {
+  k = 2;                           // two token lookahead
+  exportVocab=J;                   // Call its vocabulary "Java"
+  codeGenMakeSwitchThreshold = 2;  // Some optimizations
+  codeGenBitsetTestThreshold = 3;
+  defaultErrorHandler = false;     // Don't generate parser error handlers
+  buildAST = false;
+  ASTLabelType = "ParserToken";
+  classHeaderSuffix = "JavaTokenConstants";
+}
+
+tokens {
+  BLOCK; MODIFIERS; OBJBLOCK; SLIST; CTOR_DEF; METHOD_DEF; VARIABLE_DEF; 
+  INSTANCE_INIT; STATIC_INIT; TYPE; CLASS_DEF; INTERFACE_DEF; 
+  PACKAGE_DEF; ARRAY_DECLARATOR; EXTENDS_CLAUSE; IMPLEMENTS_CLAUSE;
+  PARAMETERS; PARAMETER_DEF; LABELED_STAT; TYPECAST; INDEX_OP; 
+  POST_INC; POST_DEC; METHOD_CALL; EXPR; ARRAY_INIT; 
+  IMPORT; UNARY_MINUS; UNARY_PLUS; CASE_GROUP; ELIST; FOR_INIT; FOR_CONDITION; 
+  FOR_ITERATOR; EMPTY_STAT; FINAL="final"; ABSTRACT="abstract";
+}
+	
+	// Emeric 13.01.05 feld jplag.java.Parser parser
+	
+	{public jplag.java.Parser parser ;}
+	
+// Compilation Unit: In Java, this is a single file.  This is the start
+//   rule for this parser
+compilationUnit
+	:      // A compilation unit starts with an optional package definition
+		(	packageDefinition
+		|	/* nothing */
+		)
+
+		// Next we have a series of zero or more import statements
+		( importDefinition )*
+
+		// Wrapping things up with any number of class or interface
+		//    definitions
+		( typeDefinition )*
+
+		EOF
+	;
+
+
+// Package statement: "package" followed by an identifier.
+packageDefinition
+	options {defaultErrorHandler = true;} // let ANTLR handle errors
+	:	p:"package"^ identifier SEMI!
+                { parser.add(J_PACKAGE, p); }
+	;
+
+
+// Import statement: import followed by a package or class name
+importDefinition
+	options {defaultErrorHandler = true;}
+	:	i:"import"^ identifierStar SEMI!
+                { parser.add(J_IMPORT, i); }
+	;
+
+// A type definition in a file is either a class or interface definition.
+typeDefinition
+//	options {defaultErrorHandler = true;}
+        { Token end = null; }
+	:	modifiers!
+		( end=classDefinition
+		| interfaceDefinition
+		)
+	|	SEMI!
+	;
+
+/** A declaration is the creation of a reference or primitive-type variable
+ *  Create a separate Type/Var tree for each var in the var list.
+ */
+declaration!
+	:	m:modifiers t:typeSpec v:variableDefinitions
+        ;
+
+// A list of zero or more modifiers.  We could have used (modifier)* in
+//   place of a call to modifiers, but I thought it was a good idea to keep
+//   this rule separate so they can easily be collected in a Vector if
+//   someone so desires
+modifiers
+	:	( modifier )*
+	;
+
+
+// A type specification is a type name with possible brackets afterwards
+//   (which would make it an array type).
+typeSpec
+	: classTypeSpec
+	| builtInTypeSpec
+	;
+
+// A class type specification is a class type with possible brackets afterwards
+//   (which would make it an array type).
+classTypeSpec
+	:	identifier (lb:LBRACK^ RBRACK!)*
+	;
+
+// A builtin type specification is a builtin type with possible brackets
+// afterwards (which would make it an array type).
+builtInTypeSpec
+	:	builtInType (lb:LBRACK^ RBRACK!)*
+	;
+
+// A type name. which is either a (possibly qualified) class name or
+//   a primitive (builtin) type
+type
+	:	identifier
+	|	builtInType
+	;
+
+// The primitive types.
+builtInType
+	:	v:"void"
+                { parser.add(J_VOID, v); }
+	|	"boolean"
+	|	"byte"
+	|	"char"
+	|	"short"
+	|	"int"
+	|	"float"
+	|	"long"
+	|	"double"
+	;
+
+// A (possibly-qualified) java identifier.  We start with the first IDENT
+//   and expand its name by adding dots and following IDENTS
+identifier
+	:	IDENT  ( DOT^ IDENT )*
+	;
+
+identifierStar
+	:	IDENT
+		( DOT^ IDENT )*
+		( DOT^ STAR  )?
+	;
+
+
+// modifiers for Java classes, interfaces, class/instance vars and methods
+modifier
+	:	"private"
+	|	"public"
+	|	"protected"
+	|	"static"
+	|	"transient"
+	|	"final"
+	|	"abstract"
+	|	"native"
+	|	"threadsafe"
+	|	"synchronized"
+//	|	"const"			// reserved word; leave out
+	|	"volatile"
+	;
+
+
+// Definition of a Java class
+classDefinition! returns [Token end]
+{ end = null; }
+	:	c:"class" IDENT
+                { parser.add(J_CLASS_BEGIN, c); }
+		// it _might_ have a superclass...
+		sc:superClassClause
+		// it might implement some interfaces...
+		ic:implementsClause
+		// now parse the body of the class
+		end=classBlock
+                { parser.add(J_CLASS_END, end); }
+	;
+
+superClassClause!
+	:	( "extends" id:identifier )?
+	;
+
+// Definition of a Java Interface
+interfaceDefinition!
+{ Token end = null; }
+	:	i:"interface" IDENT
+                { parser.add(J_INTERFACE_BEGIN, i); }
+		// it might extend some other interfaces
+		ie:interfaceExtends
+		// now parse the body of the interface (looks like a class...)
+		end=classBlock
+                { parser.add(J_INTERFACE_END, end); }
+	;
+
+
+// This is the body of a class.  You can have fields and extra semicolons,
+// That's about it (until you see what a field is...)
+classBlock returns [Token end]
+{ end = null; }
+	:	LCURLY!
+			( field | SEMI! )*
+		b:RCURLY
+                { end = b; }
+	;
+
+// special case:
+innerClassBlock
+	:	lc:LCURLY!
+                { parser.add(J_IN_CLASS_BEGIN, lc); }
+			( field | SEMI! )*
+		rc:RCURLY
+                { parser.add(J_IN_CLASS_END, rc); }
+	;
+
+// An interface can extend several other interfaces...
+interfaceExtends
+	:	(
+		e:"extends"!
+		identifier ( COMMA! identifier )*
+		)?
+	;
+
+// A class can implement several interfaces...
+implementsClause
+	:	(
+			i:"implements"! identifier ( COMMA! identifier )*
+		)?
+	;
+
+// Now the various things that can be defined inside a class or interface...
+// Note that not all of these are really valid in an interface (constructors,
+//   for example), and if this grammar were used for a compiler there would
+//   need to be some semantic checks to make sure we're doing the right thing...
+field!
+{ Token end = null; }
+	:	// method, constructor, or variable declaration
+		mods:modifiers
+		(	h:ctorHead end=compoundStatement  // constructor
+		        { parser.add(J_CONSTR_END, end); }
+		|	end=classDefinition              // inner class
+		|	interfaceDefinition          // inner interface
+		|	typeSpec  // method or variable declaration(s)
+			(	id:IDENT  // the name of the method
+			        { parser.add(J_METHOD_BEGIN, id); }
+				// parse the formal parameter declarations.
+				LPAREN! param:parameterDeclarationList RPAREN!
+
+				rt:returnTypeBrackersOnEndOfMethodHead
+
+				// get the list of exceptions that this method is declared to throw
+				(tc:throwsClause)?
+
+				( end=compoundStatement
+				  { parser.add(J_METHOD_END, end); }
+				| s:SEMI
+				  { parser.add(J_METHOD_END, s); }
+				)
+			|	v:variableDefinitions SEMI
+			)
+		)
+
+    // "static { ... }" class initializer
+	|	s2:"static"
+                { parser.add(J_INIT_BEGIN, s2); }
+                end=compoundStatement
+                { parser.add(J_INIT_END, end); }
+
+    // "{ ... }" instance initializer
+	|	initCompoundStatement
+	;
+
+variableDefinitions
+	:	variableDeclarator
+		(	COMMA!
+			variableDeclarator
+		)*
+	;
+
+/** Declaration of a variable.  This can be a class/instance variable,
+ *   or a local variable in a method
+ * It can also include possible initialization.
+ */
+variableDeclarator!
+	:	id:IDENT
+                { parser.add(J_VARDEF, id); }
+                d:declaratorBrackets v:varInitializer
+	;
+
+declaratorBrackets
+	:	
+		(lb:LBRACK^ RBRACK!)*
+	;
+
+varInitializer
+	:	( ass:ASSIGN^
+                { parser.add(J_ASSIGN, ass); }
+		  initializer )?
+	;
+
+// This is an initializer used to set up an array.
+arrayInitializer
+	:	lc:LCURLY
+                { parser.add(J_ARRAY_INIT_BEGIN, lc); }
+			(	initializer
+				(
+		    // CONFLICT: does a COMMA after an initializer start a new
+		    //           initializer or start the option ',' at end?
+		    //           ANTLR generates proper code by matching
+		    //			 the comma as soon as possible.
+					options {
+						warnWhenFollowAmbig = false;
+					}
+				:
+					COMMA! initializer
+				)*
+				(COMMA!)?
+			)?
+		rc:RCURLY
+                { parser.add(J_ARRAY_INIT_END, rc); }
+	;
+
+
+// The two "things" that can initialize an array element are an expression
+//   and another (nested) array initializer.
+initializer
+	:	expression
+	|	arrayInitializer
+	;
+
+// This is the header of a method.  It includes the name and parameters
+//   for the method.
+//   This also watches for a list of exception classes in a "throws" clause.
+ctorHead
+	:	id:IDENT  // the name of the method
+                { parser.add(J_CONSTR_BEGIN, id); }
+
+		// parse the formal parameter declarations.
+		LPAREN! parameterDeclarationList RPAREN!
+
+		// get the list of exceptions that this method is declared to throw
+		(throwsClause)?
+	;
+
+// This is a list of exception classes that the method is declared to throw
+throwsClause
+	:	"throws"^ identifier ( COMMA! identifier )*
+	;
+
+
+returnTypeBrackersOnEndOfMethodHead
+	:	
+		(lb:LBRACK^ RBRACK!)*
+	;
+
+// A list of formal parameters
+parameterDeclarationList
+	:	( parameterDeclaration ( COMMA! parameterDeclaration )* )?
+	;
+
+// A formal parameter.
+parameterDeclaration!
+	:	pm:parameterModifier t:typeSpec id:IDENT
+		pd:parameterDeclaratorBrackets
+	;
+
+parameterDeclaratorBrackets
+	:	
+		(lb:LBRACK^ RBRACK!)*
+	;
+
+parameterModifier
+	:	(f:"final")?
+	;
+
+// Compound statement.  This is used in many contexts:
+//   Inside a class definition prefixed with "static":
+//      it is a class initializer
+//   Inside a class definition without "static":
+//      it is an instance initializer
+//   As the body of a method
+//   As a completely indepdent braced block of code inside a method
+//      it starts a new scope for variable definitions
+
+compoundStatement returns [Token end]
+{ end = null; }
+	:	lc:LCURLY^
+			// include the (possibly-empty) list of statements
+			(end=statement)*
+		rc:RCURLY
+                { end = rc; }
+	;
+
+// special rule...
+initCompoundStatement
+{ Token end = null; }
+	:	lc:LCURLY^
+                { parser.add(J_INIT_BEGIN, lc); }
+                // include the (possibly-empty) list of statements
+                (end=statement)*
+		rc:RCURLY
+                { parser.add(J_INIT_END, rc); }
+	;
+
+
+statement returns [Token end]
+{ end = null; }
+	// A list of statements in curly braces -- start a new scope!
+	:	end=compoundStatement
+
+	// class definition
+	|	end=classDefinition
+
+	// final class definition
+	|	"final"! end=classDefinition
+
+	// abstract class definition
+	|	"abstract"! end=classDefinition
+
+	// declarations are ambiguous with "ID DOT" relative to expression
+	// statements.  Must backtrack to be sure.  Could use a semantic
+	// predicate to test symbol table to see what the type was coming
+	// up, but that's pretty hard without a symbol table ;)
+	|	(declaration)=> declaration s1:SEMI    { end = s1; }
+
+	// An expression statement.  This could be a method call,
+	// assignment statement, or any other expression evaluated for
+	// side-effects.
+        |	expression s2:SEMI     { end = s2; }
+
+	// Attach a label to the front of a statement
+	|	IDENT COLON^ end=statement
+
+	// If-else statement
+	|	i1:"if"^
+                { parser.add(J_IF_BEGIN, i1); }
+	        LPAREN! expression RPAREN! end=statement
+		(
+			// CONFLICT: the old "dangling-else" problem...
+			//           ANTLR generates proper code matching
+			//			 as soon as possible.  Hush warning.
+			options {
+				warnWhenFollowAmbig = false;
+			}
+		:
+			e1:"else"!
+                        { parser.add(J_ELSE, e1); }
+			end=statement
+		)?
+                { parser.add(J_IF_END, end); }
+
+	// For statement
+	|	f1:"for"^
+                { parser.add(J_FOR_BEGIN, f1); }
+			LPAREN!
+				forInit SEMI!   // initializer
+				forCond	SEMI!   // condition test
+				forIter         // updater
+			RPAREN!
+			end=statement                 // statement to loop over
+                { parser.add(J_FOR_END, end); }
+
+	// While statement
+	|	w1:"while"^
+                { parser.add(J_WHILE_BEGIN, w1); }
+	        LPAREN! expression RPAREN!
+		end=statement
+                { parser.add(J_WHILE_END, end); }
+
+	// do-while statement
+	|	d1:"do"^
+                { parser.add(J_DO_BEGIN, d1); }
+	        end=statement "while"! LPAREN! expression RPAREN!
+		s3:SEMI
+                { parser.add(J_DO_END, end=s3); }
+
+	// get out of a loop (or switch)
+	|	b1:"break"^
+                { parser.add(J_BREAK, b1); }
+                (IDENT)? s4:SEMI       { end = s4; }
+
+	// do next iteration of a loop
+	|	c1:"continue"^
+                { parser.add(J_CONTINUE, c1); }
+                (IDENT)? s5:SEMI       { end = s5; }
+
+	// Return an expression
+	|	r1:"return"^
+                { parser.add(J_RETURN, r1); }
+                (expression)? s6:SEMI  { end = s6; }
+
+	// switch/case statement
+	|	s7:"switch"^
+                { parser.add(J_SWITCH_BEGIN, s7); }
+                LPAREN! expression RPAREN! LCURLY!
+		    ( casesGroup )*
+		rc:RCURLY
+                { parser.add(J_SWITCH_END, end=rc); }
+
+	// exception try-catch block
+	|	end=tryBlock
+
+	// throw an exception
+	|	t1:"throw"^
+                { parser.add(J_THROW, t1); }
+                expression s8:SEMI     { end = s8; }
+
+	// synchronize a statement
+	|	s9:"synchronized"^
+                { parser.add(J_SYNC_BEGIN, s9); }
+                LPAREN! expression RPAREN!
+		end=compoundStatement
+                { parser.add(J_SYNC_END, end); }
+
+
+	// empty statement
+        |	s10:SEMI               { end = s10; }
+	;
+
+
+casesGroup
+	:	(	// CONFLICT: to which case group do the statements bind?
+			//           ANTLR generates proper code: it groups the
+			//           many "case"/"default" labels together then
+			//           follows them with the statements
+			options {
+				warnWhenFollowAmbig = false;
+			}
+			:
+			aCase
+		)+
+		caseSList
+	;
+
+aCase
+	:	( c:"case"^
+                  { parser.add(J_CASE, c); }
+	          expression
+		| d:"default"
+                  { parser.add(J_CASE, d); }
+                ) COLON!
+	;
+
+caseSList
+{ Token end = null; }
+	:	(end=statement)*
+	;
+
+// The initializer for a for loop
+forInit
+		// if it looks like a declaration, it is
+	:	(	(declaration)=> declaration
+		// otherwise it could be an expression list...
+		|	expressionList
+		)?
+	;
+
+forCond
+	:	(expression)?
+	;
+
+forIter
+	:	(expressionList)?
+	;
+
+// an exception handler try/catch block
+tryBlock returns [Token end]
+{ end = null; }
+	:	t:"try"^
+                { parser.add(J_TRY_BEGIN, t); }
+	        end=compoundStatement
+		(end=handler)*
+		( f:"finally"^
+                  { parser.add(J_FINALLY, f); }
+		  end=compoundStatement )?
+                { parser.add(J_CATCH_END, end); }
+	;
+
+
+// an exception handler
+handler returns [Token end]
+{ end = null; }
+	:	c:"catch"^
+                { parser.add(J_CATCH_BEGIN, c); }
+	        LPAREN! parameterDeclaration RPAREN!
+	        end=compoundStatement
+	;
+
+
+// expressions
+// Note that most of these expressions follow the pattern
+//   thisLevelExpression :
+//       nextHigherPrecedenceExpression
+//           (OPERATOR nextHigherPrecedenceExpression)*
+// which is a standard recursive definition for a parsing an expression.
+// The operators in java have the following precedences:
+//    lowest  (13)  = *= /= %= += -= <<= >>= >>>= &= ^= |=
+//            (12)  ?:
+//            (11)  ||
+//            (10)  &&
+//            ( 9)  |
+//            ( 8)  ^
+//            ( 7)  &
+//            ( 6)  == !=
+//            ( 5)  < <= > >=
+//            ( 4)  << >>
+//            ( 3)  +(binary) -(binary)
+//            ( 2)  * / %
+//            ( 1)  ++ -- +(unary) -(unary)  ~  !  (type)
+//                  []   () (method call)  . (dot -- identifier qualification)
+//                  new   ()  (explicit parenthesis)
+//
+// the last two are not usually on a precedence chart; I put them in
+// to point out that new has a higher precedence than '.', so you
+// can validy use
+//     new Frame().show()
+// 
+// Note that the above precedence levels map to the rules below...
+// Once you have a precedence chart, writing the appropriate rules as below
+//   is usually very straightfoward
+
+
+
+// the mother of all expressions
+expression
+	:	assignmentExpression
+	;
+
+
+// This is a list of expressions.
+expressionList
+	:	expression (COMMA! expression)*
+	;
+
+
+// assignment expression (level 13)
+assignmentExpression
+  :	conditionalExpression
+  (	(   a:ASSIGN^               { parser.add(J_ASSIGN, a); }
+	|   a2:PLUS_ASSIGN^         { parser.add(J_ASSIGN, a2); }
+	|   a3:MINUS_ASSIGN^        { parser.add(J_ASSIGN, a3); }
+	|   a4:STAR_ASSIGN^         { parser.add(J_ASSIGN, a4); }
+	|   a5:DIV_ASSIGN^          { parser.add(J_ASSIGN, a5); }
+	|   a6:MOD_ASSIGN^          { parser.add(J_ASSIGN, a6); }
+	|   a7:SR_ASSIGN^           { parser.add(J_ASSIGN, a7); }
+	|   a8:BSR_ASSIGN^          { parser.add(J_ASSIGN, a8); }
+        |   a9:SL_ASSIGN^           { parser.add(J_ASSIGN, a9); }
+        |   aa:BAND_ASSIGN^         { parser.add(J_ASSIGN, aa); }
+        |   ab:BXOR_ASSIGN^         { parser.add(J_ASSIGN, ab); }
+        |   ac:BOR_ASSIGN^          { parser.add(J_ASSIGN, ac); }
+        )
+	assignmentExpression
+   )?
+;
+
+
+// conditional test (level 12)
+conditionalExpression
+	:	logicalOrExpression
+		( q:QUESTION^
+                  { parser.add(J_COND, q); }
+		  assignmentExpression COLON! conditionalExpression )?
+	;
+
+
+// logical or (||)  (level 11)
+logicalOrExpression
+	:	logicalAndExpression (LOR^ logicalAndExpression)*
+	;
+
+
+// logical and (&&)  (level 10)
+logicalAndExpression
+	:	inclusiveOrExpression (LAND^ inclusiveOrExpression)*
+	;
+
+
+// bitwise or non-short-circuiting or (|)  (level 9)
+inclusiveOrExpression
+	:	exclusiveOrExpression (BOR^ exclusiveOrExpression)*
+	;
+
+
+// exclusive or (^)  (level 8)
+exclusiveOrExpression
+	:	andExpression (BXOR^ andExpression)*
+	;
+
+
+// bitwise or non-short-circuiting and (&)  (level 7)
+andExpression
+	:	equalityExpression (BAND^ equalityExpression)*
+	;
+
+
+// equality/inequality (==/!=) (level 6)
+equalityExpression
+	:	relationalExpression ((NOT_EQUAL^ | EQUAL^) relationalExpression)*
+	;
+
+
+// boolean relational expressions (level 5)
+relationalExpression
+	:	shiftExpression
+		(	(	(	LT^
+				|	GT^
+				|	LE^
+				|	GE^
+				)
+				shiftExpression
+			)*
+		|	"instanceof"^ typeSpec
+		)
+	;
+
+
+// bit shift expressions (level 4)
+shiftExpression
+	:	additiveExpression ((SL^ | SR^ | BSR^) additiveExpression)*
+	;
+
+
+// binary addition/subtraction (level 3)
+additiveExpression
+	:	multiplicativeExpression ((PLUS^ | MINUS^) multiplicativeExpression)*
+	;
+
+
+// multiplication/division/modulo (level 2)
+multiplicativeExpression
+	:	unaryExpression ((STAR^ | DIV^ | MOD^ ) unaryExpression)*
+	;
+
+unaryExpression
+	:	i:INC^ unaryExpression
+                  { parser.add(J_ASSIGN, i); }
+	|	d:DEC^ unaryExpression
+                  { parser.add(J_ASSIGN, d); }
+	|	MINUS^ unaryExpression
+	|	PLUS^ unaryExpression
+	|	unaryExpressionNotPlusMinus
+	;
+
+unaryExpressionNotPlusMinus
+	:	BNOT^ unaryExpression
+	|	LNOT^ unaryExpression
+
+	|	(	// subrule allows option to shut off warnings
+			options {
+				// "(int" ambig with postfixExpr due to lack of sequence
+				// info in linear approximate LL(k).  It's ok.  Shut up.
+				generateAmbigWarnings=false;
+			}
+		:	// If typecast is built in type, must be numeric operand
+			// Also, no reason to backtrack if type keyword like int, float...
+			lpb:LPAREN^ builtInTypeSpec RPAREN!
+			unaryExpression
+
+			// Have to backtrack to see if operator follows.  If no operator
+			// follows, it's a typecast.  No semantic checking needed to parse.
+			// if it _looks_ like a cast, it _is_ a cast; else it's a "(expr)"
+		|	(LPAREN classTypeSpec RPAREN unaryExpressionNotPlusMinus)=>
+			lp:LPAREN^ classTypeSpec RPAREN!
+			unaryExpressionNotPlusMinus
+
+		|	postfixExpression
+		)
+	;
+
+// qualified names, array expressions, method invocation, post inc/dec
+postfixExpression
+{ Token id = null; }
+	:	id=primaryExpression // start with a primary
+
+		(	// qualified id (id.id.id.id...) -- build the name
+ 		        DOT^ ( i:IDENT { id = i; }
+			     | t:"this" { id = t; }
+			     | c:"class" { id = c; }
+			     | id=newExpression
+			     | s:"super" LPAREN ( expressionList )? RPAREN
+                               { id = s; }
+                 | "super" DOT^ i2:IDENT { id = i2; }
+			     )
+			// the above line needs a semantic check to make sure "class"
+			//   is the _last_ qualifier.
+
+			// allow ClassName[].class
+		|	( lbc:LBRACK^ RBRACK! )+
+			DOT^ "class"
+
+			// an array indexing operation
+		|	lb:LBRACK^ expression RBRACK!
+
+			// method invocation
+			// The next line is not strictly proper; it allows x(3)(4) or
+			//  x[2](4) which are not valid in Java.  If this grammar were used
+			//  to validate a Java program a semantic check would be needed, or
+			//   this rule would get really ugly...
+		|	lp:LPAREN^
+		        { if (id == null) id = lp;
+                          parser.add(J_APPLY, id); }
+			argList
+			RPAREN!
+		)*
+
+		// possibly add on a post-increment or post-decrement.
+		// allows INC/DEC on too much, but semantics can check
+		(	in:INC^
+		        { parser.add(J_ASSIGN, in); }
+	 	|	de:DEC^
+                        { parser.add(J_ASSIGN, de); }
+		|	// nothing
+		)
+
+		// look for int.class and int[].class
+	|	builtInType 
+		( lbt:LBRACK^ RBRACK! )*
+		DOT^ "class"
+	;
+
+// the basic element of an expression
+primaryExpression returns [Token id]
+{id = null; }
+        :	i:IDENT           { id = i; }
+	|	id=newExpression
+	|	constant
+	|	s:"super"         { id = s; }
+	|	"true"
+	|	"false"
+	|	t:"this"          { id = t;} 
+	|	"null"
+	|	LPAREN! assignmentExpression RPAREN!
+	;
+
+/** object instantiation.
+ *  Trees are built as illustrated by the following input/tree pairs:
+ *  
+ *  new T()
+ *  
+ *  new
+ *   |
+ *   T --  ELIST
+ *           |
+ *          arg1 -- arg2 -- .. -- argn
+ *  
+ *  new int[]
+ *
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR
+ *  
+ *  new int[] {1,2}
+ *
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR -- ARRAY_INIT
+ *                                  |
+ *                                EXPR -- EXPR
+ *                                  |      |
+ *                                  1      2
+ *  
+ *  new int[3]
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR
+ *                |
+ *              EXPR
+ *                |
+ *                3
+ *  
+ *  new int[1][2]
+ *  
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR
+ *               |
+ *         ARRAY_DECLARATOR -- EXPR
+ *               |              |
+ *             EXPR             1
+ *               |
+ *               2
+ *  
+ */
+newExpression returns [Token id]
+{ id = null;
+  Token end = null;
+}
+        :	n:"new"^ type { id = n; }
+		(	
+                  { parser.add(J_NEWCLASS, n); }
+		  LPAREN! argList RPAREN!
+		  (innerClassBlock)?
+
+			//java 1.1
+			// Note: This will allow bad constructs like
+			//    new int[4][][3] {exp,exp}.
+			//    There needs to be a semantic check here...
+			// to make sure:
+			//   a) [ expr ] and [ ] are not mixed
+			//   b) [ expr ] and an init are not used together
+
+		|	{ parser.add(J_NEWARRAY, n); }
+		        newArrayDeclarator (arrayInitializer)?
+		)
+	;
+
+argList
+	:	(	expressionList
+		|	/*nothing*/
+		)
+	;
+
+newArrayDeclarator
+	:	(
+			// CONFLICT:
+			// newExpression is a primaryExpression which can be
+			// followed by an array index reference.  This is ok,
+			// as the generated code will stay in this loop as
+			// long as it sees an LBRACK (proper behavior)
+			options {
+				warnWhenFollowAmbig = false;
+			}
+		:
+			lb:LBRACK^
+				(expression)?
+			RBRACK!
+		)+
+	;
+
+constant
+	:	NUM_INT
+	|	CHAR_LITERAL
+	|	STRING_LITERAL
+	|	NUM_FLOAT
+	;
+
+
+//----------------------------------------------------------------------------
+// The Java scanner
+//----------------------------------------------------------------------------
+class JLexer extends Lexer;
+
+options {
+  exportVocab=J;      // call the vocabulary "Java"
+  testLiterals=false;    // don't automatically test for literals
+  k=4;                   // four characters of lookahead
+  charVocabulary = '\u0000'..'\u00ff';
+}
+
+{
+  public void newline() {
+    super.newline();
+    ((InputState)inputState).column = 1;
+  }
+  
+  public void consume() throws antlr.CharStreamException {
+    if ( inputState.guessing == 0 ) {
+      InputState state = (InputState)inputState;
+      if (text.length()==0) {
+	// remember token start column
+	state.tokColumn = state.column;
+      }
+      state.column++;
+    }
+    super.consume();
+  }
+  
+  protected Token makeToken(int t) {
+    ParserToken tok = (ParserToken)super.makeToken(t);
+    tok.setColumn(((InputState)inputState).tokColumn);
+    return tok;
+  }
+}
+
+
+// OPERATORS
+QUESTION		:	'?'		;
+LPAREN			:	'('		;
+RPAREN			:	')'		;
+LBRACK			:	'['		;
+RBRACK			:	']'		;
+LCURLY			:	'{'		;
+RCURLY			:	'}'		;
+COLON			:	':'		;
+COMMA			:	','		;
+//DOT			:	'.'		;
+ASSIGN			:	'='		;
+EQUAL			:	"=="	;
+LNOT			:	'!'		;
+BNOT			:	'~'		;
+NOT_EQUAL		:	"!="	;
+DIV				:	'/'		;
+DIV_ASSIGN		:	"/="	;
+PLUS			:	'+'		;
+PLUS_ASSIGN		:	"+="	;
+INC				:	"++"	;
+MINUS			:	'-'		;
+MINUS_ASSIGN	:	"-="	;
+DEC				:	"--"	;
+STAR			:	'*'		;
+STAR_ASSIGN		:	"*="	;
+MOD				:	'%'		;
+MOD_ASSIGN		:	"%="	;
+SR				:	">>"	;
+SR_ASSIGN		:	">>="	;
+BSR				:	">>>"	;
+BSR_ASSIGN		:	">>>="	;
+GE				:	">="	;
+GT				:	">"		;
+SL				:	"<<"	;
+SL_ASSIGN		:	"<<="	;
+LE				:	"<="	;
+LT				:	'<'		;
+BXOR			:	'^'		;
+BXOR_ASSIGN		:	"^="	;
+BOR				:	'|'		;
+BOR_ASSIGN		:	"|="	;
+LOR				:	"||"	;
+BAND			:	'&'		;
+BAND_ASSIGN		:	"&="	;
+LAND			:	"&&"	;
+SEMI			:	';'		;
+
+
+// Whitespace -- ignored
+WS	:
+  (	' '
+  |	'\t' //{ ((InputState)inputState).column += 7; }
+  |	'\f'
+  | '\u001a'
+  // handle newlines
+  |	(	"\r\n"  // Evil DOS
+	|	'\r'    // Macintosh
+	|	'\n'    // Unix (the right way)
+	) { newline(); }
+  ) { _ttype = Token.SKIP; }
+;
+
+// Single-line comments
+SL_COMMENT
+	:	"//"
+		(~('\n'|'\r'))* ('\n'|'\r'('\n')?)?
+		{$setType(Token.SKIP); newline();}
+	;
+
+// multiple-line comments
+ML_COMMENT :   
+  "/*"
+  (	/*	'\r' '\n' can be matched in one alternative or by matching
+		'\r' in one iteration and '\n' in another.  I am trying to
+		handle any flavor of newline that comes in, but the language
+		that allows both "\r\n" and "\r" and "\n" to all be valid
+		newline is ambiguous.  Consequently, the resulting grammar
+		must be ambiguous.  I'm shutting this warning off.
+	*/
+   options { generateAmbigWarnings=false; } : { LA(2)!='/' }? '*'
+  |	'\r' '\n'		{newline();}
+  |	'\r'			{newline();}
+  |	'\n'			{newline();}
+  |	~('*'|'\n'|'\r')
+   )*
+  "*/" {$setType(Token.SKIP);}
+;
+
+
+// character literals
+CHAR_LITERAL
+	:	'\'' ( ESC | ~'\'' ) '\''
+	;
+
+// string literals
+STRING_LITERAL
+	:	'"' (ESC|~('"'|'\\'))* '"'
+	;
+
+
+// escape sequence -- note that this is protected; it can only be called
+//   from another lexer rule -- it will not ever directly return a token to
+//   the parser
+// There are various ambiguities hushed in this rule.  The optional
+// '0'...'9' digit matches should be matched here rather than letting
+// them go back to STRING_LITERAL to be matched.  ANTLR does the
+// right thing by matching immediately; hence, it's ok to shut off
+// the FOLLOW ambig warnings.
+protected
+ESC
+	:	'\\'
+		(	'n'
+		|	'r'
+		|	't'
+		|	'b'
+		|	'f'
+		|	'"'
+		|	'\''
+		|	'\\'
+		|	('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT 
+		|	('0'..'3')
+			(
+				options {
+					warnWhenFollowAmbig = false;
+				}
+			:	('0'..'7')
+				(	
+					options {
+						warnWhenFollowAmbig = false;
+					}
+				:	'0'..'7'
+				)?
+			)?
+		|	('4'..'7')
+			(
+				options {
+					warnWhenFollowAmbig = false;
+				}
+			:	('0'..'9')
+			)?
+		)
+	;
+
+
+// hexadecimal digit (again, note it's protected!)
+protected
+HEX_DIGIT
+	:	('0'..'9'|'A'..'F'|'a'..'f')
+	;
+
+
+// a dummy rule to force vocabulary to be all characters (except special
+//   ones that ANTLR uses internally (0 to 2)
+protected
+VOCAB
+	:	'\3'..'\377'
+	;
+
+
+// an identifier.  Note that testLiterals is set to true!  This means
+// that after we match the rule, we look in the literals table to see
+// if it's a literal or really an identifer
+IDENT
+	options {testLiterals=true;}
+        :
+    ( '\u0024' | '\u0041'..'\u005a' | '\u005f' | '\u0061'..'\u007a' |
+      '\u00c0'..'\u00d6' | '\u00d8'..'\u00f6' | '\u00f8'..'\u00ff' )
+      
+    ( '\u0024' | '\u0041'..'\u005a' | '\u005f' | '\u0061'..'\u007a' |
+      '\u00c0'..'\u00d6' | '\u00d8'..'\u00f6' | '\u00f8'..'\u00ff' | 
+      
+      '\u0030'..'\u0039' )*
+//	:	('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'$')*
+	;
+
+
+// a numeric literal
+NUM_INT
+	{boolean isDecimal=false;}
+	:	'.' {_ttype = DOT;}
+			(('0'..'9')+ (EXPONENT)? (FLOAT_SUFFIX)? { _ttype = NUM_FLOAT; })?
+	|	(	'0' {isDecimal = true;} // special case for just '0'
+			(	('x'|'X')
+				(											// hex
+					// the 'e'|'E' and float suffix stuff look
+					// like hex digits, hence the (...)+ doesn't
+					// know when to stop: ambig.  ANTLR resolves
+					// it correctly by matching immediately.  It
+					// is therefor ok to hush warning.
+					options {
+						warnWhenFollowAmbig=false;
+					}
+				:	HEX_DIGIT
+				)+
+			|	('0'..'7')+									// octal
+			)?
+		|	('1'..'9') ('0'..'9')*  {isDecimal=true;}		// non-zero decimal
+		)
+		(	('l'|'L')
+		
+		// only check to see if it's a float if looks like decimal so far
+		|	{isDecimal}?
+			(	'.' ('0'..'9')* (EXPONENT)? (FLOAT_SUFFIX)?
+			|	EXPONENT (FLOAT_SUFFIX)?
+			|	FLOAT_SUFFIX
+			)
+			{ _ttype = NUM_FLOAT; }
+		)?
+	;
+
+
+// a couple protected methods to assist in matching floating point numbers
+protected
+EXPONENT
+	:	('e'|'E') ('+'|'-')? ('0'..'9')+
+	;
+
+
+protected
+FLOAT_SUFFIX
+	:	'f'|'F'|'d'|'D'
+	;
+

+ 92 - 0
jplag.frontend.java-1.2/src/main/java/jplag/java/JavaToken.java

@@ -0,0 +1,92 @@
+package jplag.java;
+
+public class JavaToken extends jplag.Token implements JavaTokenConstants {
+	private static final long serialVersionUID = 1581274829013336295L;
+	private int line, column, length;
+
+	public JavaToken(int type, String file, int line, int column, int length) {
+		super(type, file, line, column, length);
+	}
+
+	public int getLine() {
+		return line;
+	}
+
+	public int getColumn() {
+		return column;
+	}
+
+	public int getLength() {
+		return length;
+	}
+
+	public void setLine(int line) {
+		this.line = line;
+	}
+
+	public void setColumn(int column) {
+		this.column = column;
+	}
+
+	public void setLength(int length) {
+		this.length = length;
+	}
+
+  public static String type2string(int type) {
+    switch (type) {
+    case JavaTokenConstants.FILE_END:
+                            return "********";
+    case J_PACKAGE:         return "PACKAGE ";
+    case J_IMPORT:          return "IMPORT  ";
+    case J_CLASS_BEGIN:     return "CLASS{  ";
+    case J_CLASS_END:       return "}CLASS  ";
+    case J_METHOD_BEGIN:    return "METHOD{ ";
+    case J_METHOD_END:      return "}METHOD ";
+    case J_VARDEF:          return "VARDEF  ";
+    case J_SYNC_BEGIN:      return "SYNC{   ";
+    case J_SYNC_END:        return "}SYNC   ";
+    case J_DO_BEGIN:        return "DO{     ";
+    case J_DO_END:          return "}DO     ";
+    case J_WHILE_BEGIN:     return "WHILE{  ";
+    case J_WHILE_END:       return "}WHILE  ";
+    case J_FOR_BEGIN:       return "FOR{    ";
+    case J_FOR_END:         return "}FOR    ";
+    case J_SWITCH_BEGIN:    return "SWITCH{ ";
+    case J_SWITCH_END:      return "}SWITCH ";
+    case J_CASE:            return "CASE    ";
+    case J_TRY_BEGIN:       return "TRY{    ";
+    case J_CATCH_BEGIN:     return "CATCH{  ";
+    case J_CATCH_END:       return "}CATCH  ";
+    case J_FINALLY:         return "FINALLY ";
+    case J_IF_BEGIN:        return "IF{     ";
+    case J_ELSE:            return "ELSE    ";
+    case J_IF_END:          return "}IF     ";
+    case J_COND:            return "COND    ";
+    case J_BREAK:           return "BREAK   ";
+    case J_CONTINUE:        return "CONTINUE";
+    case J_RETURN:          return "RETURN  ";
+    case J_THROW:           return "THROW   ";
+    case J_IN_CLASS_BEGIN:  return "INCLASS{";
+    case J_IN_CLASS_END:    return "}INCLASS";
+    case J_APPLY:           return "APPLY   ";
+    case J_NEWCLASS:        return "NEWCLASS";
+    case J_NEWARRAY:        return "NEWARRAY";
+    case J_ASSIGN:          return "ASSIGN  ";
+    case J_INTERFACE_BEGIN: return "INTERF{ ";
+    case J_INTERFACE_END:   return "}INTERF ";
+    case J_CONSTR_BEGIN:    return "CONSTR{ ";
+    case J_CONSTR_END:      return "}CONSTR ";
+    case J_INIT_BEGIN:      return "INIT{   ";
+    case J_INIT_END:        return "}INIT   ";
+    case J_VOID:            return "VOID    ";
+    case J_ARRAY_INIT_BEGIN:return "ARRINIT{";
+    case J_ARRAY_INIT_END:  return "ARRINIT}";
+
+    default:           return "<UNBEKANNT>";
+    }
+  }
+  
+  public static int numberOfTokens() { 
+    return NUM_DIFF_TOKENS;
+  } 
+}

+ 53 - 0
jplag.frontend.java-1.2/src/main/java/jplag/java/JavaTokenConstants.java

@@ -0,0 +1,53 @@
+package jplag.java;
+
+public interface JavaTokenConstants extends jplag.TokenConstants {
+  final static int FILE_END = 0;
+
+  final static int J_PACKAGE = 1;               //
+  final static int J_IMPORT = 2;                //
+  final static int J_CLASS_BEGIN = 3;           //
+  final static int J_CLASS_END = 4;             //
+  final static int J_METHOD_BEGIN = 5;          //
+  final static int J_METHOD_END = 6;            //
+  final static int J_VARDEF = 7;                //
+  final static int J_SYNC_BEGIN = 8;            //
+  final static int J_SYNC_END = 9;              //
+  final static int J_DO_BEGIN = 10;             //
+  final static int J_DO_END = 11;               //
+  final static int J_WHILE_BEGIN = 12;          //
+  final static int J_WHILE_END = 13;            //
+  final static int J_FOR_BEGIN = 14;            //
+  final static int J_FOR_END = 15;              //
+  final static int J_SWITCH_BEGIN = 16;         //
+  final static int J_SWITCH_END = 17;           //
+  final static int J_CASE = 18;                 //
+  final static int J_TRY_BEGIN = 19;            //
+  final static int J_CATCH_BEGIN = 20;          //
+  final static int J_CATCH_END = 21;            //
+  final static int J_FINALLY = 22;              //
+  final static int J_IF_BEGIN = 23;             //
+  final static int J_ELSE = 24;                 //
+  final static int J_IF_END = 25;               //
+  final static int J_COND = 26;                 //
+  final static int J_BREAK = 27;                //
+  final static int J_CONTINUE = 28;             //
+  final static int J_RETURN = 29;               //
+  final static int J_THROW = 30;                //
+  final static int J_IN_CLASS_BEGIN=31;         //
+  final static int J_IN_CLASS_END = 32;         //
+  final static int J_APPLY = 33;                //
+  final static int J_NEWCLASS = 34;             //
+  final static int J_NEWARRAY = 35;             //
+  final static int J_ASSIGN = 36;               //
+  final static int J_INTERFACE_BEGIN=37;        //
+  final static int J_INTERFACE_END = 38;        //
+  final static int J_CONSTR_BEGIN = 39;         //
+  final static int J_CONSTR_END = 40;           //
+  final static int J_INIT_BEGIN = 41;           //
+  final static int J_INIT_END = 42;             //
+  final static int J_VOID = 43;                 //
+  final static int J_ARRAY_INIT_BEGIN = 44;     //
+  final static int J_ARRAY_INIT_END = 45;       //
+
+  final static int NUM_DIFF_TOKENS = 46;
+}

+ 63 - 0
jplag.frontend.java-1.2/src/main/java/jplag/java/Language.java

@@ -0,0 +1,63 @@
+package jplag.java;
+
+import java.io.File;
+
+import jplag.ProgramI;
+
+public class Language implements jplag.Language {
+	private Parser parser;
+
+	public Language(ProgramI program) {
+		this.parser = new Parser();
+		this.parser.setProgram(program);
+	}
+
+	public String[] suffixes() {
+		String[] res = { ".java", ".jav", ".JAVA", ".JAV" };
+		return res;
+	}
+
+	public int errorsCount() {
+		return this.parser.errorsCount();
+	}
+
+	public String name() {
+		return "Java1.2 Parser";
+	}
+
+	public String getShortName() {
+		return "java12";
+	}
+
+	public int min_token_match() {
+		return 9;
+	}
+
+	public jplag.Structure parse(File dir, String[] files) {
+		return this.parser.parse(dir, files);
+	}
+
+	public boolean errors() {
+		return this.parser.getErrors();
+	}
+
+	public boolean supportsColumns() {
+		return true;
+	}
+
+	public boolean isPreformated() {
+		return true;
+	}
+
+	public boolean usesIndex() {
+		return false;
+	}
+
+	public int noOfTokens() {
+		return jplag.java.JavaToken.numberOfTokens();
+	}
+
+	public String type2string(int type) {
+		return jplag.java.JavaToken.type2string(type);
+	}
+}

+ 111 - 0
jplag.frontend.java-1.2/src/main/java/jplag/java/Parser.java

@@ -0,0 +1,111 @@
+package jplag.java;
+
+/**
+ * The two classes jplag.java.grammar.[JLexer|JRecognizer] are being generated by antlr into the directory
+ * target/generated-sources/antlr/... Generate the classes with antlr or use mvn compile
+ */
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.IOException;
+
+import jplag.InputState;
+import jplag.ParserToken;
+import jplag.Structure;
+import jplag.java.grammar.JLexer;
+import jplag.java.grammar.JRecognizer;
+
+public class Parser extends jplag.Parser implements JavaTokenConstants {
+	private Structure struct;
+	private String currentFile;
+
+	public static void main(String args[]) {
+		if (args.length != 1) {
+			System.out.println("Only one parameter allowed.");
+			System.exit(-1);
+		}
+		Parser parser = new Parser();
+		parser.setProgram(new jplag.StrippedProgram());
+		jplag.Structure struct = parser.parse(null, args);
+		try {
+			BufferedReader reader = new BufferedReader(new FileReader(new File(args[0])));
+			int lineNr = 1;
+			int token = 0;
+			String line;
+			while ((line = reader.readLine()) != null) {
+				if (token < struct.size()) {
+					boolean first = true;
+					while (struct.tokens[token] != null && struct.tokens[token].getLine() == lineNr) {
+						if (!first)
+							System.out.println();
+						JavaToken tok = (JavaToken) struct.tokens[token];
+						System.out.print(JavaToken.type2string(tok.type) + " (" + tok.getLine() + "," + tok.getColumn() + ","
+								+ tok.getLength() + ")\t");
+						first = false;
+						token++;
+					}
+					if (first)
+						System.out.print("                \t");
+				}
+				System.out.println(line);
+				lineNr++;
+			}
+			reader.close();
+		} catch (IOException e) {
+			System.out.println(e);
+		}
+	}
+
+	public jplag.Structure parse(File dir, String files[]) {
+		struct = new Structure();
+		errors = 0;
+		for (int i = 0; i < files.length; i++) {
+			getProgram().print(null, "Parsing file " + files[i] + "\n");
+			if (!parseFile(dir, files[i]))
+				errors++;
+			System.gc();//Emeric
+			struct.addToken(new JavaToken(FILE_END, files[i], -1, -1, -1));
+		}
+		this.parseEnd();
+		return struct;
+	}
+
+	public boolean parseFile(File dir, String file) {
+		InputState inputState = null;
+		try {
+			FileInputStream fis = new FileInputStream(new File(dir, file));
+			currentFile = file;
+			// Create a scanner that reads from the input stream passed to us
+			inputState = new InputState(fis);
+			JLexer lexer = new JLexer(inputState);
+			lexer.setFilename(file);
+			lexer.setTokenObjectClass("jplag.ParserToken");
+
+			// Create a parser that reads from the scanner
+			JRecognizer parser = new JRecognizer(lexer);
+			parser.setFilename(file);
+			parser.parser = this;
+
+			// start parsing at the compilationUnit rule
+			parser.compilationUnit();
+
+			// close file
+			fis.close();
+		} catch (Exception e) {
+			getProgram().addError(
+					"  Parsing Error in '" + file + "':\n" + "  Parse error at line "
+							+ (inputState != null ? "" + inputState.getLine() : "UNKNOWN") + ", column "
+							+ (inputState != null ? "" + inputState.tokColumn : "UNKNOWN") + ": " + e.getMessage() + "\n");
+			return false;
+		}
+
+		return true;
+	}
+
+	public void add(int type, antlr.Token tok) {
+		ParserToken ptok = (ParserToken) tok;
+		struct.addToken(new JavaToken(type, currentFile, ptok.getLine(), ptok.getColumn(), ptok.getLength()));
+	}
+}