1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 * JFlex Anttask * 3 * Copyright (C) 2001 Rafal Mantiuk <Rafal.Mantiuk@bellstream.pl> * 4 * Copyright (C) 2003 changes by Gerwin Klein <lsf@jflex.de> * 5 * All rights reserved. * 6 * * 7 * License: BSD * 8 * * 9 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 10 11 package jflex.anttask; 12 13 import java.io.File; 14 import java.io.IOException; 15 import java.io.LineNumberReader; 16 import java.io.Reader; 17 import java.nio.charset.StandardCharsets; 18 import java.nio.file.Files; 19 import java.util.regex.Matcher; 20 import java.util.regex.Pattern; 21 import jflex.core.OptionUtils; 22 import jflex.exceptions.GeneratorException; 23 import jflex.generator.LexGenerator; 24 import jflex.option.Options; 25 import org.apache.tools.ant.BuildException; 26 import org.apache.tools.ant.Task; 27 28 /** 29 * JFlex ant task. 30 * 31 * @author Rafal Mantiuk 32 * @version JFlex 1.8.1 33 */ 34 public class JFlexTask extends Task { 35 private static final Pattern PACKAGE_PATTERN = Pattern.compile("package\\s+(\\S+)\\s*;"); 36 private static final Pattern CLASS_PATTERN = Pattern.compile("%class\\s+(\\S+)"); 37 38 private File inputFile; 39 40 // found out by looking into .flex file 41 private String className = null; 42 private String packageName = null; 43 44 /** for javac-like dest dir behaviour */ 45 private File destinationDir; 46 47 /** the actual output directory (outputDir = destinationDir + package)) */ 48 private File outputDir = null; 49 50 /** Constructor for JFlexTask. */ JFlexTask()51 public JFlexTask() { 52 OptionUtils.setDefaultOptions(); 53 // ant default is different from the rest of JFlex 54 setVerbose(false); 55 setUnusedWarning(true); 56 Options.progress = false; 57 } 58 59 /** 60 * Executes the ant task. 61 * 62 * @throws BuildException if any. 63 */ 64 @Override execute()65 public void execute() { 66 try { 67 if (inputFile == null) 68 throw new BuildException("Input file needed. Use <jflex file=\"your_scanner.flex\"/>"); 69 70 if (!inputFile.canRead()) throw new BuildException("Cannot read input file " + inputFile); 71 72 try { 73 findPackageAndClass(); 74 normalizeOutdir(); 75 File destFile = new File(outputDir, className + ".java"); 76 77 if (inputFile.lastModified() > destFile.lastModified()) { 78 new LexGenerator(inputFile).generate(); 79 if (!Options.verbose) System.out.println("Generated: " + destFile.getName()); 80 } 81 } catch (IOException e1) { 82 throw new BuildException("IOException: " + e1.toString()); 83 } 84 } catch (GeneratorException e) { 85 throw new BuildException("JFlex: generation failed!"); 86 } 87 } 88 89 /** 90 * Peek into .flex file to get package and class name 91 * 92 * @throws java.io.IOException if there is a problem reading the .flex file 93 */ findPackageAndClass()94 public void findPackageAndClass() throws IOException { 95 // find name of the package and class in jflex source file 96 packageName = null; 97 className = null; 98 Reader r = Files.newBufferedReader(inputFile.toPath(), StandardCharsets.UTF_8); 99 try (LineNumberReader reader = new LineNumberReader(r)) { 100 while (className == null || packageName == null) { 101 String line = reader.readLine(); 102 if (line == null) { 103 break; 104 } 105 106 if (packageName == null) { 107 Matcher matcher = PACKAGE_PATTERN.matcher(line); 108 if (matcher.find()) { 109 packageName = matcher.group(1); 110 } 111 } 112 113 if (className == null) { 114 Matcher matcher = CLASS_PATTERN.matcher(line); 115 if (matcher.find()) { 116 className = matcher.group(1); 117 } 118 } 119 } 120 121 // package name may be null, but class name not 122 if (className == null) { 123 className = "Yylex"; 124 } 125 } 126 } 127 128 /** 129 * Sets the actual output directory if not already set. 130 * 131 * <p>Uses javac logic to determine output dir = dest dir + package name If not destdir has been 132 * set, output dir = parent of input file 133 * 134 * <p>Assumes that package name is already set. 135 */ normalizeOutdir()136 public void normalizeOutdir() { 137 if (outputDir != null) return; 138 139 // find out what the destination directory is. Append packageName to dest 140 // dir. 141 File destDir; 142 143 // this is not the default the jflex logic, but javac-like 144 if (destinationDir != null) { 145 if (packageName == null) { 146 destDir = destinationDir; 147 } else { 148 String path = packageName.replace('.', File.separatorChar); 149 destDir = new File(destinationDir, path); 150 } 151 } else { // save parser to the same dir as .flex 152 destDir = new File(inputFile.getParent()); 153 } 154 155 setOutdir(destDir); 156 } 157 158 /** 159 * getPackage. 160 * 161 * @return package name of input file 162 * @see #findPackageAndClass() 163 */ getPackage()164 public String getPackage() { 165 return packageName; 166 } 167 168 /** 169 * Getter for the field {@code className}. 170 * 171 * @return class name of input file 172 * @see #findPackageAndClass() 173 */ getClassName()174 public String getClassName() { 175 return className; 176 } 177 178 /** 179 * setDestdir. 180 * 181 * @param destinationDir a {@link java.io.File} object. 182 */ setDestdir(File destinationDir)183 public void setDestdir(File destinationDir) { 184 this.destinationDir = destinationDir; 185 } 186 187 /** 188 * setOutdir. 189 * 190 * @param outDir a {@link java.io.File} object. 191 */ setOutdir(File outDir)192 public void setOutdir(File outDir) { 193 this.outputDir = outDir; 194 OptionUtils.setDir(outputDir); 195 } 196 197 /** 198 * setFile. 199 * 200 * @param file a {@link java.io.File} object. 201 */ setFile(File file)202 public void setFile(File file) { 203 this.inputFile = file; 204 } 205 206 /** 207 * setGenerateDot. 208 * 209 * @param genDot a boolean. 210 */ setGenerateDot(boolean genDot)211 public void setGenerateDot(boolean genDot) { 212 setDot(genDot); 213 } 214 215 /** 216 * setTimeStatistics. 217 * 218 * @param displayTime a boolean. 219 */ setTimeStatistics(boolean displayTime)220 public void setTimeStatistics(boolean displayTime) { 221 Options.time = displayTime; 222 } 223 224 /** 225 * setTime. 226 * 227 * @param displayTime a boolean. 228 */ setTime(boolean displayTime)229 public void setTime(boolean displayTime) { 230 setTimeStatistics(displayTime); 231 } 232 233 /** 234 * setVerbose. 235 * 236 * @param verbose a boolean. 237 */ setVerbose(boolean verbose)238 public void setVerbose(boolean verbose) { 239 Options.verbose = verbose; 240 Options.unused_warning = verbose; 241 } 242 243 /** 244 * setUnusedWarning. 245 * 246 * @param warn a boolean. 247 */ setUnusedWarning(boolean warn)248 public void setUnusedWarning(boolean warn) { 249 Options.unused_warning = warn; 250 } 251 252 /** 253 * setSkeleton. 254 * 255 * @param skeleton a {@link java.io.File} object. 256 */ setSkeleton(File skeleton)257 public void setSkeleton(File skeleton) { 258 OptionUtils.setSkeleton(skeleton); 259 } 260 261 /** 262 * setSkel. 263 * 264 * @param skeleton a {@link java.io.File} object. 265 */ setSkel(File skeleton)266 public void setSkel(File skeleton) { 267 setSkeleton(skeleton); 268 } 269 270 /** 271 * setSkipMinimization. 272 * 273 * @param skipMin a boolean. 274 */ setSkipMinimization(boolean skipMin)275 public void setSkipMinimization(boolean skipMin) { 276 setNomin(skipMin); 277 } 278 279 /** 280 * setNomin. 281 * 282 * @param b a boolean. 283 */ setNomin(boolean b)284 public void setNomin(boolean b) { 285 Options.no_minimize = b; 286 } 287 288 /** 289 * setNobak. 290 * 291 * @param b a boolean. 292 */ setNobak(boolean b)293 public void setNobak(boolean b) { 294 Options.no_backup = b; 295 } 296 297 /** 298 * setPack. 299 * 300 * @param b a boolean. 301 */ setPack(boolean b)302 public void setPack(boolean b) { 303 /* no-op - this is the only available generation method */ 304 } 305 306 /** 307 * setDot. 308 * 309 * @param b a boolean. 310 */ setDot(boolean b)311 public void setDot(boolean b) { 312 Options.dot = b; 313 } 314 315 /** 316 * setDump. 317 * 318 * @param b a boolean. 319 */ setDump(boolean b)320 public void setDump(boolean b) { 321 Options.dump = b; 322 } 323 324 /** 325 * setJLex. 326 * 327 * @param b a boolean. 328 */ setJLex(boolean b)329 public void setJLex(boolean b) { 330 Options.jlex = b; 331 } 332 333 /** 334 * setLegacyDot. 335 * 336 * @param b a boolean. 337 */ setLegacyDot(boolean b)338 public void setLegacyDot(boolean b) { 339 Options.legacy_dot = b; 340 } 341 342 /** 343 * Set the input encoding. If unset will use the JVM default. 344 * 345 * @param encodingName the name of the encoding to set (e.g. "utf-8"). 346 */ setEncoding(String encodingName)347 public void setEncoding(String encodingName) { 348 OptionUtils.setEncoding(encodingName); 349 } 350 } 351