/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

package org.apache.tools.ant.taskdefs.optional.javacc;

import java.io.File;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.Map;

import org.apache.tools.ant.AntClassLoader;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.Execute;
import org.apache.tools.ant.types.Commandline;
import org.apache.tools.ant.types.CommandlineJava;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.util.JavaEnvUtils;

JavaCC compiler compiler task.
/** * JavaCC compiler compiler task. * */
public class JavaCC extends Task { // keys to optional attributes private static final String LOOKAHEAD = "LOOKAHEAD"; private static final String CHOICE_AMBIGUITY_CHECK = "CHOICE_AMBIGUITY_CHECK"; private static final String OTHER_AMBIGUITY_CHECK = "OTHER_AMBIGUITY_CHECK"; private static final String STATIC = "STATIC"; private static final String DEBUG_PARSER = "DEBUG_PARSER"; private static final String DEBUG_LOOKAHEAD = "DEBUG_LOOKAHEAD"; private static final String DEBUG_TOKEN_MANAGER = "DEBUG_TOKEN_MANAGER"; private static final String OPTIMIZE_TOKEN_MANAGER = "OPTIMIZE_TOKEN_MANAGER"; private static final String ERROR_REPORTING = "ERROR_REPORTING"; private static final String JAVA_UNICODE_ESCAPE = "JAVA_UNICODE_ESCAPE"; private static final String UNICODE_INPUT = "UNICODE_INPUT"; private static final String IGNORE_CASE = "IGNORE_CASE"; private static final String COMMON_TOKEN_ACTION = "COMMON_TOKEN_ACTION"; private static final String USER_TOKEN_MANAGER = "USER_TOKEN_MANAGER"; private static final String USER_CHAR_STREAM = "USER_CHAR_STREAM"; private static final String BUILD_PARSER = "BUILD_PARSER"; private static final String BUILD_TOKEN_MANAGER = "BUILD_TOKEN_MANAGER"; private static final String SANITY_CHECK = "SANITY_CHECK"; private static final String FORCE_LA_CHECK = "FORCE_LA_CHECK"; private static final String CACHE_TOKENS = "CACHE_TOKENS"; private static final String KEEP_LINE_COLUMN = "KEEP_LINE_COLUMN"; private static final String JDK_VERSION = "JDK_VERSION"; private final Map<String, Object> optionalAttrs = new Hashtable<>(); // required attributes private File outputDirectory = null; private File targetFile = null; private File javaccHome = null; private CommandlineJava cmdl = new CommandlineJava(); protected static final int TASKDEF_TYPE_JAVACC = 1; protected static final int TASKDEF_TYPE_JJTREE = 2; protected static final int TASKDEF_TYPE_JJDOC = 3; protected static final String[] ARCHIVE_LOCATIONS = //NOSONAR new String[] { "JavaCC.zip", "bin/lib/JavaCC.zip", "bin/lib/javacc.jar", "javacc.jar", // used by jpackage for JavaCC 3.x }; protected static final int[] ARCHIVE_LOCATIONS_VS_MAJOR_VERSION = //NOSONAR new int[] { 1, 2, 3, 3, }; protected static final String COM_PACKAGE = "COM.sun.labs."; protected static final String COM_JAVACC_CLASS = "javacc.Main"; protected static final String COM_JJTREE_CLASS = "jjtree.Main"; protected static final String COM_JJDOC_CLASS = "jjdoc.JJDocMain"; protected static final String ORG_PACKAGE_3_0 = "org.netbeans.javacc."; protected static final String ORG_PACKAGE_3_1 = "org.javacc."; protected static final String ORG_JAVACC_CLASS = "parser.Main"; protected static final String ORG_JJTREE_CLASS = COM_JJTREE_CLASS; protected static final String ORG_JJDOC_CLASS = COM_JJDOC_CLASS; private String maxMemory = null;
Sets the LOOKAHEAD grammar option.
Params:
  • lookahead – an int value.
/** * Sets the LOOKAHEAD grammar option. * @param lookahead an <code>int</code> value. */
public void setLookahead(int lookahead) { optionalAttrs.put(LOOKAHEAD, lookahead); }
Sets the CHOICE_AMBIGUITY_CHECK grammar option.
Params:
  • choiceAmbiguityCheck – an int value.
/** * Sets the CHOICE_AMBIGUITY_CHECK grammar option. * @param choiceAmbiguityCheck an <code>int</code> value. */
public void setChoiceambiguitycheck(int choiceAmbiguityCheck) { optionalAttrs.put(CHOICE_AMBIGUITY_CHECK, choiceAmbiguityCheck); }
Sets the OTHER_AMBIGUITY_CHECK grammar option.
Params:
  • otherAmbiguityCheck – an int value.
/** * Sets the OTHER_AMBIGUITY_CHECK grammar option. * @param otherAmbiguityCheck an <code>int</code> value. */
public void setOtherambiguityCheck(int otherAmbiguityCheck) { optionalAttrs.put(OTHER_AMBIGUITY_CHECK, otherAmbiguityCheck); }
Sets the STATIC grammar option.
Params:
  • staticParser – a boolean value.
/** * Sets the STATIC grammar option. * @param staticParser a <code>boolean</code> value. */
public void setStatic(boolean staticParser) { optionalAttrs.put(STATIC, staticParser ? Boolean.TRUE : Boolean.FALSE); }
Sets the DEBUG_PARSER grammar option.
Params:
  • debugParser – a boolean value.
/** * Sets the DEBUG_PARSER grammar option. * @param debugParser a <code>boolean</code> value. */
public void setDebugparser(boolean debugParser) { optionalAttrs.put(DEBUG_PARSER, debugParser ? Boolean.TRUE : Boolean.FALSE); }
Sets the DEBUG_LOOKAHEAD grammar option.
Params:
  • debugLookahead – a boolean value.
/** * Sets the DEBUG_LOOKAHEAD grammar option. * @param debugLookahead a <code>boolean</code> value. */
public void setDebuglookahead(boolean debugLookahead) { optionalAttrs.put(DEBUG_LOOKAHEAD, debugLookahead ? Boolean.TRUE : Boolean.FALSE); }
Sets the DEBUG_TOKEN_MANAGER grammar option.
Params:
  • debugTokenManager – a boolean value.
/** * Sets the DEBUG_TOKEN_MANAGER grammar option. * @param debugTokenManager a <code>boolean</code> value. */
public void setDebugtokenmanager(boolean debugTokenManager) { optionalAttrs.put(DEBUG_TOKEN_MANAGER, debugTokenManager ? Boolean.TRUE : Boolean.FALSE); }
Sets the OPTIMIZE_TOKEN_MANAGER grammar option.
Params:
  • optimizeTokenManager – a boolean value.
/** * Sets the OPTIMIZE_TOKEN_MANAGER grammar option. * @param optimizeTokenManager a <code>boolean</code> value. */
public void setOptimizetokenmanager(boolean optimizeTokenManager) { optionalAttrs.put(OPTIMIZE_TOKEN_MANAGER, optimizeTokenManager ? Boolean.TRUE : Boolean.FALSE); }
Sets the ERROR_REPORTING grammar option.
Params:
  • errorReporting – a boolean value.
/** * Sets the ERROR_REPORTING grammar option. * @param errorReporting a <code>boolean</code> value. */
public void setErrorreporting(boolean errorReporting) { optionalAttrs.put(ERROR_REPORTING, errorReporting ? Boolean.TRUE : Boolean.FALSE); }
Sets the JAVA_UNICODE_ESCAPE grammar option.
Params:
  • javaUnicodeEscape – a boolean value.
/** * Sets the JAVA_UNICODE_ESCAPE grammar option. * @param javaUnicodeEscape a <code>boolean</code> value. */
public void setJavaunicodeescape(boolean javaUnicodeEscape) { optionalAttrs.put(JAVA_UNICODE_ESCAPE, javaUnicodeEscape ? Boolean.TRUE : Boolean.FALSE); }
Sets the UNICODE_INPUT grammar option.
Params:
  • unicodeInput – a boolean value.
/** * Sets the UNICODE_INPUT grammar option. * @param unicodeInput a <code>boolean</code> value. */
public void setUnicodeinput(boolean unicodeInput) { optionalAttrs.put(UNICODE_INPUT, unicodeInput ? Boolean.TRUE : Boolean.FALSE); }
Sets the IGNORE_CASE grammar option.
Params:
  • ignoreCase – a boolean value.
/** * Sets the IGNORE_CASE grammar option. * @param ignoreCase a <code>boolean</code> value. */
public void setIgnorecase(boolean ignoreCase) { optionalAttrs.put(IGNORE_CASE, ignoreCase ? Boolean.TRUE : Boolean.FALSE); }
Sets the COMMON_TOKEN_ACTION grammar option.
Params:
  • commonTokenAction – a boolean value.
/** * Sets the COMMON_TOKEN_ACTION grammar option. * @param commonTokenAction a <code>boolean</code> value. */
public void setCommontokenaction(boolean commonTokenAction) { optionalAttrs.put(COMMON_TOKEN_ACTION, commonTokenAction ? Boolean.TRUE : Boolean.FALSE); }
Sets the USER_TOKEN_MANAGER grammar option.
Params:
  • userTokenManager – a boolean value.
/** * Sets the USER_TOKEN_MANAGER grammar option. * @param userTokenManager a <code>boolean</code> value. */
public void setUsertokenmanager(boolean userTokenManager) { optionalAttrs.put(USER_TOKEN_MANAGER, userTokenManager ? Boolean.TRUE : Boolean.FALSE); }
Sets the USER_CHAR_STREAM grammar option.
Params:
  • userCharStream – a boolean value.
/** * Sets the USER_CHAR_STREAM grammar option. * @param userCharStream a <code>boolean</code> value. */
public void setUsercharstream(boolean userCharStream) { optionalAttrs.put(USER_CHAR_STREAM, userCharStream ? Boolean.TRUE : Boolean.FALSE); }
Sets the BUILD_PARSER grammar option.
Params:
  • buildParser – a boolean value.
/** * Sets the BUILD_PARSER grammar option. * @param buildParser a <code>boolean</code> value. */
public void setBuildparser(boolean buildParser) { optionalAttrs.put(BUILD_PARSER, buildParser ? Boolean.TRUE : Boolean.FALSE); }
Sets the BUILD_TOKEN_MANAGER grammar option.
Params:
  • buildTokenManager – a boolean value.
/** * Sets the BUILD_TOKEN_MANAGER grammar option. * @param buildTokenManager a <code>boolean</code> value. */
public void setBuildtokenmanager(boolean buildTokenManager) { optionalAttrs.put(BUILD_TOKEN_MANAGER, buildTokenManager ? Boolean.TRUE : Boolean.FALSE); }
Sets the SANITY_CHECK grammar option.
Params:
  • sanityCheck – a boolean value.
/** * Sets the SANITY_CHECK grammar option. * @param sanityCheck a <code>boolean</code> value. */
public void setSanitycheck(boolean sanityCheck) { optionalAttrs.put(SANITY_CHECK, sanityCheck ? Boolean.TRUE : Boolean.FALSE); }
Sets the FORCE_LA_CHECK grammar option.
Params:
  • forceLACheck – a boolean value.
/** * Sets the FORCE_LA_CHECK grammar option. * @param forceLACheck a <code>boolean</code> value. */
public void setForcelacheck(boolean forceLACheck) { optionalAttrs.put(FORCE_LA_CHECK, forceLACheck ? Boolean.TRUE : Boolean.FALSE); }
Sets the CACHE_TOKENS grammar option.
Params:
  • cacheTokens – a boolean value.
/** * Sets the CACHE_TOKENS grammar option. * @param cacheTokens a <code>boolean</code> value. */
public void setCachetokens(boolean cacheTokens) { optionalAttrs.put(CACHE_TOKENS, cacheTokens ? Boolean.TRUE : Boolean.FALSE); }
Sets the KEEP_LINE_COLUMN grammar option.
Params:
  • keepLineColumn – a boolean value.
/** * Sets the KEEP_LINE_COLUMN grammar option. * @param keepLineColumn a <code>boolean</code> value. */
public void setKeeplinecolumn(boolean keepLineColumn) { optionalAttrs.put(KEEP_LINE_COLUMN, keepLineColumn ? Boolean.TRUE : Boolean.FALSE); }
Sets the JDK_VERSION option.
Params:
  • jdkVersion – the version to use.
Since:Ant1.7
/** * Sets the JDK_VERSION option. * @param jdkVersion the version to use. * @since Ant1.7 */
public void setJDKversion(String jdkVersion) { optionalAttrs.put(JDK_VERSION, jdkVersion); }
The directory to write the generated files to. If not set, the files are written to the directory containing the grammar file.
Params:
  • outputDirectory – the output directory.
/** * The directory to write the generated files to. * If not set, the files are written to the directory * containing the grammar file. * @param outputDirectory the output directory. */
public void setOutputdirectory(File outputDirectory) { this.outputDirectory = outputDirectory; }
The grammar file to process.
Params:
  • targetFile – the grammar file.
/** * The grammar file to process. * @param targetFile the grammar file. */
public void setTarget(File targetFile) { this.targetFile = targetFile; }
The directory containing the JavaCC distribution.
Params:
  • javaccHome – the directory.
/** * The directory containing the JavaCC distribution. * @param javaccHome the directory. */
public void setJavacchome(File javaccHome) { this.javaccHome = javaccHome; }
Corresponds -Xmx.
Params:
  • max – max memory parameter.
Since:Ant 1.8.3
/** * Corresponds -Xmx. * * @param max max memory parameter. * @since Ant 1.8.3 */
public void setMaxmemory(String max) { maxMemory = max; }
Constructor
/** * Constructor */
public JavaCC() { cmdl.setVm(JavaEnvUtils.getJreExecutable("java")); }
Run the task.
Throws:
  • BuildException – on error.
/** * Run the task. * @throws BuildException on error. */
@Override public void execute() throws BuildException { // load command line with optional attributes optionalAttrs.forEach((name, value) -> cmdl.createArgument() .setValue("-" + name + ":" + value)); // check the target is a file if (targetFile == null || !targetFile.isFile()) { throw new BuildException("Invalid target: %s", targetFile); } // use the directory containing the target as the output directory if (outputDirectory == null) { outputDirectory = new File(targetFile.getParent()); } else if (!outputDirectory.isDirectory()) { throw new BuildException("Outputdir not a directory."); } cmdl.createArgument().setValue("-OUTPUT_DIRECTORY:" + outputDirectory.getAbsolutePath()); // determine if the generated java file is up-to-date final File javaFile = getOutputJavaFile(outputDirectory, targetFile); if (javaFile.exists() && targetFile.lastModified() < javaFile.lastModified()) { log("Target is already built - skipping (" + targetFile + ")", Project.MSG_VERBOSE); return; } cmdl.createArgument().setValue(targetFile.getAbsolutePath()); final Path classpath = cmdl.createClasspath(getProject()); final File javaccJar = JavaCC.getArchiveFile(javaccHome); classpath.createPathElement().setPath(javaccJar.getAbsolutePath()); classpath.addJavaRuntime(); cmdl.setClassname(JavaCC.getMainClass(classpath, JavaCC.TASKDEF_TYPE_JAVACC)); cmdl.setMaxmemory(maxMemory); final Commandline.Argument arg = cmdl.createVmArgument(); arg.setValue("-Dinstall.root=" + javaccHome.getAbsolutePath()); Execute.runCommand(this, cmdl.getCommandline()); }
Helper method to retrieve the path used to store the JavaCC.zip or javacc.jar which is different from versions.
Params:
  • home – the javacc home path directory.
Throws:
  • BuildException – thrown if the home directory is invalid or if the archive could not be found despite attempts to do so.
Returns:the file object pointing to the JavaCC archive.
/** * Helper method to retrieve the path used to store the JavaCC.zip * or javacc.jar which is different from versions. * * @param home the javacc home path directory. * @throws BuildException thrown if the home directory is invalid * or if the archive could not be found despite attempts to do so. * @return the file object pointing to the JavaCC archive. */
protected static File getArchiveFile(File home) throws BuildException { return new File(home, ARCHIVE_LOCATIONS[getArchiveLocationIndex(home)]); }
Helper method to retrieve main class which is different from versions.
Params:
  • home – the javacc home path directory.
  • type – the taskdef.
Throws:
  • BuildException – thrown if the home directory is invalid or if the archive could not be found despite attempts to do so.
Returns:the main class for the taskdef.
/** * Helper method to retrieve main class which is different from versions. * @param home the javacc home path directory. * @param type the taskdef. * @throws BuildException thrown if the home directory is invalid * or if the archive could not be found despite attempts to do so. * @return the main class for the taskdef. */
protected static String getMainClass(File home, int type) throws BuildException { Path p = new Path(null); p.createPathElement().setLocation(getArchiveFile(home)); p.addJavaRuntime(); return getMainClass(p, type); }
Helper method to retrieve main class which is different from versions.
Params:
  • path – classpath to search in.
  • type – the taskdef.
Throws:
  • BuildException – thrown if the home directory is invalid or if the archive could not be found despite attempts to do so.
Returns:the main class for the taskdef.
Since:Ant 1.7
/** * Helper method to retrieve main class which is different from versions. * @param path classpath to search in. * @param type the taskdef. * @throws BuildException thrown if the home directory is invalid * or if the archive could not be found despite attempts to do so. * @return the main class for the taskdef. * @since Ant 1.7 */
protected static String getMainClass(Path path, int type) throws BuildException { String packagePrefix = null; String mainClass = null; try (AntClassLoader l = AntClassLoader.newAntClassLoader(null, null, path .concatSystemClasspath("ignore"), true)) { String javaccClass = COM_PACKAGE + COM_JAVACC_CLASS; InputStream is = l.getResourceAsStream(javaccClass.replace('.', '/') + ".class"); if (is != null) { packagePrefix = COM_PACKAGE; switch (type) { case TASKDEF_TYPE_JAVACC: mainClass = COM_JAVACC_CLASS; break; case TASKDEF_TYPE_JJTREE: mainClass = COM_JJTREE_CLASS; break; case TASKDEF_TYPE_JJDOC: mainClass = COM_JJDOC_CLASS; break; default: // Fall Through } } else { javaccClass = ORG_PACKAGE_3_1 + ORG_JAVACC_CLASS; is = l.getResourceAsStream(javaccClass.replace('.', '/') + ".class"); if (is != null) { packagePrefix = ORG_PACKAGE_3_1; } else { javaccClass = ORG_PACKAGE_3_0 + ORG_JAVACC_CLASS; is = l.getResourceAsStream(javaccClass.replace('.', '/') + ".class"); if (is != null) { packagePrefix = ORG_PACKAGE_3_0; } } if (is != null) { switch (type) { case TASKDEF_TYPE_JAVACC: mainClass = ORG_JAVACC_CLASS; break; case TASKDEF_TYPE_JJTREE: mainClass = ORG_JJTREE_CLASS; break; case TASKDEF_TYPE_JJDOC: mainClass = ORG_JJDOC_CLASS; break; default: // Fall Through } } } if (packagePrefix == null) { throw new BuildException("failed to load JavaCC"); } if (mainClass == null) { throw new BuildException("unknown task type " + type); } return packagePrefix + mainClass; } }
Helper method to determine the archive location index.
Params:
  • home – the javacc home path directory.
Throws:
  • BuildException – thrown if the home directory is invalid or if the archive could not be found despite attempts to do so.
Returns:the archive location index
/** * Helper method to determine the archive location index. * * @param home the javacc home path directory. * @throws BuildException thrown if the home directory is invalid * or if the archive could not be found despite attempts to do so. * @return the archive location index */
private static int getArchiveLocationIndex(File home) throws BuildException { if (home == null || !home.isDirectory()) { throw new BuildException("JavaCC home must be a valid directory."); } for (int i = 0; i < ARCHIVE_LOCATIONS.length; i++) { File f = new File(home, ARCHIVE_LOCATIONS[i]); if (f.exists()) { return i; } } throw new BuildException( "Could not find a path to JavaCC.zip or javacc.jar from '%s'.", home); }
Helper method to determine the major version number of JavaCC.
Params:
  • home – the javacc home path directory.
Throws:
  • BuildException – thrown if the home directory is invalid or if the archive could not be found despite attempts to do so.
Returns:a the major version number
/** * Helper method to determine the major version number of JavaCC. * * @param home the javacc home path directory. * @throws BuildException thrown if the home directory is invalid * or if the archive could not be found despite attempts to do so. * @return a the major version number */
protected static int getMajorVersionNumber(File home) throws BuildException { return ARCHIVE_LOCATIONS_VS_MAJOR_VERSION[getArchiveLocationIndex(home)]; }
Determines the output Java file to be generated by the given grammar file.
/** * Determines the output Java file to be generated by the given grammar * file. * */
private File getOutputJavaFile(File outputdir, File srcfile) { String path = srcfile.getPath(); // Extract file's base-name int startBasename = path.lastIndexOf(File.separator); if (startBasename != -1) { path = path.substring(startBasename + 1); } // Replace the file's extension with '.java' int startExtn = path.lastIndexOf('.'); if (startExtn != -1) { path = path.substring(0, startExtn) + ".java"; } else { path += ".java"; } // Change the directory if (outputdir != null) { path = outputdir + File.separator + path; } return new File(path); } }