Attached please find our implemenmtation of a JavaCC task.
Our build file looks like the following:
<target name="javacc">
<mkdir dir="${tool.metamata.work}"/>
<javacc
target="${src.dir}/ch/softwired/.../Scanner.jj"
meatamatahome="${tool.metamata.home}"
workingdir="${tool.metamata.work}"
<userclasspath>
<element location="${src.java}"/>
<element location="${lib.metamata}"/>
</userclasspath>
</javacc>
<javacc>
...
</javacc>
<deltree dir="${tool.metamata.work}"/>
</targ>The variables tool.metamata.home, tool.metamata.workdir and lib.metamata are set like the following:
tool.metamata.home: directory where metamata is installed with the following contents: freebies.key metamata.license lib/JavaCC.zip lib/freebies.jar lib/metamata.jar lib/metamatadebug.jar
tool.metamata.workdir: some directory created and erased used by javacc to put temp. files in.
lib.metamata: points to the jar ${tool.metamata.home}/lib/metamata.jar
Features: javacc cleans up some files left behind javacc lik OO393.class and other stuff. javacc only rebuilds the .java files if the .jj files are newer
Todo: Use file matching or multiple file arguments
This is in production for 3 months now at our site.
Feedback welcomed.
- tom
[EMAIL PROTECTED] (Marius Scurtescu) wrote:
>
> Hi all,
>
> I am writing you because while checking the ANT mailing
> list archives I saw that you were interested in JavaCC
> related tasks for ANT.
>
> Since running JJTree and JavaCC are time consuming my
> main problem is running them only if the source grammar
> file was touched. While you can get this quite easily
> with a classic make utility, there is no support for
> this in ANT. Do you have a solution for this?
>
> The way I run JavaCC is by using a "java" task to
> run the main applications directly:
>
> <target name="jjdoc" depends="jj">
> <java classname="COM.sun.labs.jjdoc.JJDocMain" args="-OUTPUT_FILE= Doc/grammar.html java.jj" fork="yes"/>
> </target>
> <target name="jj" depends="jjt">
> <java classname="COM.sun.labs.javacc.Main" args="-OUTPUT_DIRECTORY= Source/parser java.jj" fork="yes"/>
> </target>
> <target name="jjt">
> <java classname="COM.sun.labs.jjtree.Main" args="-OUTPUT_DIRECTORY= Source/parser java.jjt" fork="yes"/>
> <rename src="Source/parser/java.jj" dest="java.jj"/>
> </target>
>
> This will work assuming that JavaCC.zip is in your class path.
>
> To solve the time stamp based conditional task run I was
> thinking to create a generic task that will add a property
> based on time stamp comparison between two sets of files, the
> inputs and outputs to some other task. This other task/targets
> could then be run only if this property is set.
>
> Please let me know if all this makes sense in your opinion.
>
> Cheers,
> Marius
/* * The Apache Software License, Version 1.1 * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */
package org.apache.tools.ant.taskdefs.optional;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Path;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import java.io.File;
import java.io.IOException;
public class JavaCC extends Task {
private Path userclasspath = new Path();
private File metahome = null;
private File metaworkingdir = null;
private File target = null;
private boolean cleanupHack = false;
private CommandlineJava cmdl = new CommandlineJava();
public void setMetamatahome(String metamatahome) {
this.metahome = new File(metamatahome);
}
public void setWorkingdir(String workingdir) {
this.metaworkingdir = new File(workingdir);
}
public void setTarget(String testcase) {
target = new File(Path.translateFile(testcase));
}
public Path createUserclasspath() {
return userclasspath;
}
public void setCleanupHack(String value) {
cleanupHack = project.toBoolean(value);
}
public JavaCC() {
cmdl.setVm("java");
cmdl.setClassname("com.metamata.jj.MParse");
}
public void execute() throws BuildException {
if (target == null || !target.isFile()) {
throw new BuildException("Invalid target: " + target);
}
final File javaFile = new File(target.toString().substring(0,
target.toString().indexOf(".jj")) + ".java");
if (javaFile.exists() && target.lastModified() <
javaFile.lastModified()) {
project.log("Target is already build - skipping (" + target + ")");
return;
}
cmdl.createArgument().setValue(target.getAbsolutePath());
if (metahome == null || !metahome.isDirectory()) {
throw new BuildException("Metamatahome not valid.");
}
if (metaworkingdir == null || !metaworkingdir.isDirectory()) {
throw new BuildException("Workingdir not set.");
}
if (userclasspath == null) {
throw new BuildException("Userclasspath not set.");
}
final Path classpath = cmdl.createClasspath();
classpath.createElement().setLocation(metahome.getAbsolutePath() +
"/lib/metamatadebug.jar");
classpath.createElement().setLocation(metahome.getAbsolutePath() +
"/lib/metamata.jar");
classpath.createElement().setLocation(metahome.getAbsolutePath() +
"/lib/JavaCC.zip");
final Commandline.Argument arg = cmdl.createVmArgument();
arg.setValue("-mx140M");
arg.setValue("-Dmwp=" + metaworkingdir.getAbsolutePath());
arg.setValue("-Dmetamata.home=" + metahome.getAbsolutePath());
arg.setValue("-Dmetamata.java=java");
arg.setValue("-Dmetamata.java.options=-mx140M");
arg.setValue("-Dmetamata.java.options.classpath=-classpath");
arg.setValue("-Dmetamata.java.compiler=javac");
arg.setValue("-Dmetamata.java.compiler.options.0=-J-mx64M");
arg.setValue("-Dmetamata.java.compiler.options.classpath=-classpath");
arg.setValue("-Dmetamata.language=en");
arg.setValue("-Dmetamata.country=US");
arg.setValue("-Dmetamata.classpath=" + userclasspath);
final Execute process = new Execute(new LogStreamHandler(project,
" JavaCC", Project.MSG_INFO,
"X JavaCC", Project.MSG_INFO), null);
project.log(cmdl.toString(), Project.MSG_VERBOSE);
process.setCommandline(cmdl.getCommandline());
try {
try {
if (process.execute() != 0) {
throw new BuildException("JavaCC failed.");
}
} finally {
if (cleanupHack) {
final File oo393 = new File(javaFile.getParentFile(),
"OO393.class");
if (oo393.exists()) {
project.log("Removing stale file: " + oo393.getName());
oo393.delete();
}
final File sunjj = new File(javaFile.getParentFile(),
"__jj" + javaFile.getName().substring(0,
javaFile.getName().indexOf(".java")) + ".sunjj");
if (sunjj.exists()) {
project.log("Removing stale file: " + sunjj.getName());
sunjj.delete();
}
}
}
}
catch (IOException e) {
throw new BuildException("Failed to launch JavaCC: " + e);
}
}
}
/* * The Apache Software License, Version 1.1 * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.tools.ant; import java.io.File; import java.util.Vector; import java.util.StringTokenizer; import java.text.CharacterIterator; import java.text.StringCharacterIterator; /** * This object represents a path as used by CLASSPATH or PATH * environment variable. * * <code> * <sometask><br> * <somepath> * <element location="/path/to/file.jar" /> * <element path="/path/to/file2.jar:/path/to/class2;/path/to/class3" /> * <element location="/path/to/file3.jar" /> * <element location="/path/to/file4.jar" /> * </somepath> * </sometask><br> * </code> * * The object implemention <code>sometask</code> must provide a method called * <code>createSomepath</code> which returns an instance of <code>Path</code>. * Nested path definitions are handled by the Path object and must be labeled * <code>path</code>.<p> * * The path element takes a parameter <code>path</code> which will be parsed * and split into single elements. It will usually be used * to define a path from an environment variable. * * @author [EMAIL PROTECTED] */ public class Path { final static boolean DETECT_DOS = (File.pathSeparatorChar == ';'); private Vector definition = new Vector(); /** * Adds a element definition to the path. * @param location the location of the element to add (must not be * <code>null</code> nor empty. **/ public void setLocation(String location) { if (location != null && location.length() > 0) { definition.addElement(translateFile(location)); } } /** * Parses a path definition and creates single PatheElements. * @param path the path definition. */ public void setPath(String path) { final Vector elements = translatePath(path); for (int i=0; i < elements.size(); i++) { definition.addElement(elements.elementAt(i)); } } public Path createElement() { return this; } /** * Returns all path elements defined by this and netsed path objects. * @return list of path elements. */ public String[] list() { final String[] result = new String[definition.size()]; definition.copyInto(result); return result; } /** * Returns a textual representation of the path, which can be used as * CLASSPATH or PATH environment variable definition. * @return a textual representation of the path. */ public String toString() { final String[] list = list(); // empty path return empty string if (list.length == 0) return ""; // path containing one or more elements final StringBuffer result = new StringBuffer(list[0].toString()); for (int i=1; i < list.length; i++) { result.append(File.pathSeparatorChar); result.append(list[i]); } return result.toString(); } public static Vector translatePath(String source) { final Vector result = new Vector(); if (source == null) return result; final StringBuffer path = new StringBuffer(source); int start = 0; for (int i=0; i < path.length(); i++) { if (!translateFileSep(path, i)) { if (endOfElement(path, start, i)) { // EMPTY ELEMENT DETECTION if (start < i) { result.addElement(path.substring(start, i)); } start = i+1; } } } if (start < (path.length())) { result.addElement(path.substring(start)); } return result; } public static String translateFile(String source) { if (source == null) return ""; final StringBuffer result = new StringBuffer(source); for (int i=0; i < result.length(); i++) { translateFileSep(result, i); } return result.toString(); } protected static boolean translateFileSep(StringBuffer buffer, int pos) { if (buffer.charAt(pos) == '/' || buffer.charAt(pos) == '\\') { buffer.setCharAt(pos, File.separatorChar); return true; } return false; } protected static boolean endOfElement(StringBuffer buffer, int start, int pos) { final char c = buffer.charAt(pos); // DOS PATH DETECTION: SECOND CHARACTER IN ELEMENT IS : if (DETECT_DOS && c == ':' && (pos - start) == 1) { return false; } // PATH SEPERATOR DETECTION ON ':' AND ';' AND CURRENT PLATFORM return c == ':' || c == ';' || c == File.pathSeparatorChar; } }
