KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > optional > ANTLR


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

18
19 package org.apache.tools.ant.taskdefs.optional;
20
21 import java.io.BufferedReader JavaDoc;
22 import java.io.ByteArrayOutputStream JavaDoc;
23 import java.io.File JavaDoc;
24 import java.io.FileReader JavaDoc;
25 import java.io.IOException JavaDoc;
26 import org.apache.tools.ant.AntClassLoader;
27 import org.apache.tools.ant.BuildException;
28 import org.apache.tools.ant.Project;
29 import org.apache.tools.ant.Task;
30 import org.apache.tools.ant.taskdefs.Execute;
31 import org.apache.tools.ant.taskdefs.LogOutputStream;
32 import org.apache.tools.ant.taskdefs.PumpStreamHandler;
33 import org.apache.tools.ant.taskdefs.condition.Os;
34 import org.apache.tools.ant.types.Commandline;
35 import org.apache.tools.ant.types.CommandlineJava;
36 import org.apache.tools.ant.types.Path;
37 import org.apache.tools.ant.util.JavaEnvUtils;
38 import org.apache.tools.ant.util.LoaderUtils;
39 import org.apache.tools.ant.util.TeeOutputStream;
40 import org.apache.tools.ant.util.FileUtils;
41
42 /**
43  * Invokes the ANTLR Translator generator on a grammar file.
44  *
45  */

46 public class ANTLR extends Task {
47
48     private CommandlineJava commandline = new CommandlineJava();
49
50     /** the file to process */
51     private File JavaDoc targetFile;
52
53     /** where to output the result */
54     private File JavaDoc outputDirectory;
55
56     /** an optional super grammar file */
57     private File JavaDoc superGrammar;
58
59     /** optional flag to enable html output */
60     private boolean html;
61
62     /** optional flag to print out a diagnostic file */
63     private boolean diagnostic;
64
65     /** optional flag to add trace methods */
66     private boolean trace;
67
68     /** optional flag to add trace methods to the parser only */
69     private boolean traceParser;
70
71     /** optional flag to add trace methods to the lexer only */
72     private boolean traceLexer;
73
74     /** optional flag to add trace methods to the tree walker only */
75     private boolean traceTreeWalker;
76
77     /** working directory */
78     private File JavaDoc workingdir = null;
79
80     /** captures ANTLR's output */
81     private ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
82
83     /** The debug attribute */
84     private boolean debug;
85
86
87     /** Instance of a utility class to use for file operations. */
88     private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
89
90     /** Constructor for ANTLR task. */
91     public ANTLR() {
92         commandline.setVm(JavaEnvUtils.getJreExecutable("java"));
93         commandline.setClassname("antlr.Tool");
94     }
95
96     /**
97      * The grammar file to process.
98      * @param target the gramer file
99      */

100     public void setTarget(File JavaDoc target) {
101         log("Setting target to: " + target.toString(), Project.MSG_VERBOSE);
102         this.targetFile = target;
103     }
104
105     /**
106      * The directory to write the generated files to.
107      * @param outputDirectory the output directory
108      */

109     public void setOutputdirectory(File JavaDoc outputDirectory) {
110         log("Setting output directory to: " + outputDirectory.toString(), Project.MSG_VERBOSE);
111         this.outputDirectory = outputDirectory;
112     }
113
114     /**
115      * Sets an optional super grammar file.
116      * Use setGlib(File superGrammar) instead.
117      * @param superGrammar the super grammar filename
118      * @deprecated since ant 1.6
119      */

120     public void setGlib(String JavaDoc superGrammar) {
121         String JavaDoc sg = null;
122         if (Os.isFamily("dos")) {
123             sg = superGrammar.replace('\\', '/');
124         } else {
125             sg = superGrammar;
126         }
127         setGlib(FILE_UTILS.resolveFile(getProject().getBaseDir(), sg));
128     }
129     /**
130      * Sets an optional super grammar file
131      * @param superGrammar the super grammar file
132      * @since ant 1.6
133      */

134     public void setGlib(File JavaDoc superGrammar) {
135         this.superGrammar = superGrammar;
136     }
137     /**
138      * Sets a flag to enable ParseView debugging
139      * @param enable a <code>boolean</code> value
140      */

141     public void setDebug(boolean enable) {
142         this.debug = enable;
143     }
144
145     /**
146      * If true, emit html
147      * @param enable a <code>boolean</code> value
148      */

149     public void setHtml(boolean enable) {
150         html = enable;
151     }
152
153     /**
154      * Sets a flag to emit diagnostic text
155      * @param enable a <code>boolean</code> value
156      */

157     public void setDiagnostic(boolean enable) {
158         diagnostic = enable;
159     }
160
161     /**
162      * If true, enables all tracing.
163      * @param enable a <code>boolean</code> value
164      */

165     public void setTrace(boolean enable) {
166         trace = enable;
167     }
168
169     /**
170      * If true, enables parser tracing.
171      * @param enable a <code>boolean</code> value
172      */

173     public void setTraceParser(boolean enable) {
174         traceParser = enable;
175     }
176
177     /**
178      * If true, enables lexer tracing.
179      * @param enable a <code>boolean</code> value
180      */

181     public void setTraceLexer(boolean enable) {
182         traceLexer = enable;
183     }
184
185     /**
186      * Sets a flag to allow the user to enable tree walker tracing
187      * @param enable a <code>boolean</code> value
188      */

189     public void setTraceTreeWalker(boolean enable) {
190         traceTreeWalker = enable;
191     }
192
193     // we are forced to fork ANTLR since there is a call
194
// to System.exit() and there is nothing we can do
195
// right now to avoid this. :-( (SBa)
196
// I'm not removing this method to keep backward compatibility
197
/**
198      * @ant.attribute ignore="true"
199      * @param s a <code>boolean</code> value
200      */

201     public void setFork(boolean s) {
202         //this.fork = s;
203
}
204
205     /**
206      * The working directory of the process
207      * @param d the working directory
208      */

209     public void setDir(File JavaDoc d) {
210         this.workingdir = d;
211     }
212
213     /**
214      * Adds a classpath to be set
215      * because a directory might be given for Antlr debug.
216      * @return a path to be configured
217      */

218     public Path createClasspath() {
219         return commandline.createClasspath(getProject()).createPath();
220     }
221
222     /**
223      * Adds a new JVM argument.
224      * @return create a new JVM argument so that any argument can be passed to the JVM.
225      * @see #setFork(boolean)
226      */

227     public Commandline.Argument createJvmarg() {
228         return commandline.createVmArgument();
229     }
230
231     /**
232      * Adds the jars or directories containing Antlr
233      * this should make the forked JVM work without having to
234      * specify it directly.
235      * @throws BuildException on error
236      */

237     public void init() throws BuildException {
238         addClasspathEntry("/antlr/ANTLRGrammarParseBehavior.class");
239     }
240
241     /**
242      * Search for the given resource and add the directory or archive
243      * that contains it to the classpath.
244      *
245      * <p>Doesn't work for archives in JDK 1.1 as the URL returned by
246      * getResource doesn't contain the name of the archive.</p>
247      * @param resource the resource name to search for
248      */

249     protected void addClasspathEntry(String JavaDoc resource) {
250         /*
251          * pre Ant 1.6 this method used to call getClass().getResource
252          * while Ant 1.6 will call ClassLoader.getResource().
253          *
254          * The difference is that Class.getResource expects a leading
255          * slash for "absolute" resources and will strip it before
256          * delegating to ClassLoader.getResource - so we now have to
257          * emulate Class's behavior.
258          */

259         if (resource.startsWith("/")) {
260             resource = resource.substring(1);
261         } else {
262             resource = "org/apache/tools/ant/taskdefs/optional/"
263                 + resource;
264         }
265
266         File JavaDoc f = LoaderUtils.getResourceSource(getClass().getClassLoader(),
267                                                resource);
268         if (f != null) {
269             log("Found " + f.getAbsolutePath(), Project.MSG_DEBUG);
270             createClasspath().setLocation(f);
271         } else {
272             log("Couldn\'t find " + resource, Project.MSG_VERBOSE);
273         }
274     }
275
276     /**
277      * Execute the task.
278      * @throws BuildException on error
279      */

280     public void execute() throws BuildException {
281         validateAttributes();
282
283         //TODO: use ANTLR to parse the grammar file to do this.
284
File JavaDoc generatedFile = getGeneratedFile();
285         boolean targetIsOutOfDate =
286             targetFile.lastModified() > generatedFile.lastModified();
287         boolean superGrammarIsOutOfDate = superGrammar != null
288                 && (superGrammar.lastModified() > generatedFile.lastModified());
289         if (targetIsOutOfDate || superGrammarIsOutOfDate) {
290             if (targetIsOutOfDate) {
291                 log("Compiling " + targetFile + " as it is newer than "
292                     + generatedFile, Project.MSG_VERBOSE);
293             } else if (superGrammarIsOutOfDate) {
294                 log("Compiling " + targetFile + " as " + superGrammar
295                     + " is newer than " + generatedFile, Project.MSG_VERBOSE);
296             }
297             populateAttributes();
298             commandline.createArgument().setValue(targetFile.toString());
299
300             log(commandline.describeCommand(), Project.MSG_VERBOSE);
301             int err = run(commandline.getCommandline());
302             if (err != 0) {
303                 throw new BuildException("ANTLR returned: " + err, getLocation());
304             } else {
305                 String JavaDoc output = bos.toString();
306                 if (output.indexOf("error:") > -1) {
307                     throw new BuildException("ANTLR signaled an error: "
308                                              + output, getLocation());
309                 }
310             }
311         } else {
312             log("Skipped grammar file. Generated file " + generatedFile
313                 + " is newer.", Project.MSG_VERBOSE);
314         }
315     }
316
317     /**
318      * A refactored method for populating all the command line arguments based
319      * on the user-specified attributes.
320      */

321     private void populateAttributes() {
322         commandline.createArgument().setValue("-o");
323         commandline.createArgument().setValue(outputDirectory.toString());
324         if (superGrammar != null) {
325             commandline.createArgument().setValue("-glib");
326             commandline.createArgument().setValue(superGrammar.toString());
327         }
328         if (html) {
329             commandline.createArgument().setValue("-html");
330         }
331         if (diagnostic) {
332             commandline.createArgument().setValue("-diagnostic");
333         }
334         if (trace) {
335             commandline.createArgument().setValue("-trace");
336         }
337         if (traceParser) {
338             commandline.createArgument().setValue("-traceParser");
339         }
340         if (traceLexer) {
341             commandline.createArgument().setValue("-traceLexer");
342         }
343         if (traceTreeWalker) {
344             if (is272()) {
345                 commandline.createArgument().setValue("-traceTreeParser");
346             } else {
347                 commandline.createArgument().setValue("-traceTreeWalker");
348             }
349         }
350         if (debug) {
351             commandline.createArgument().setValue("-debug");
352         }
353     }
354
355     private void validateAttributes() throws BuildException {
356         if (targetFile == null || !targetFile.isFile()) {
357             throw new BuildException("Invalid target: " + targetFile);
358         }
359
360         // if no output directory is specified, used the target's directory
361
if (outputDirectory == null) {
362             setOutputdirectory(new File JavaDoc(targetFile.getParent()));
363         }
364         if (!outputDirectory.isDirectory()) {
365             throw new BuildException("Invalid output directory: " + outputDirectory);
366         }
367     }
368
369     private File JavaDoc getGeneratedFile() throws BuildException {
370         String JavaDoc generatedFileName = null;
371         try {
372             BufferedReader JavaDoc in = new BufferedReader JavaDoc(new FileReader JavaDoc(targetFile));
373             String JavaDoc line;
374             while ((line = in.readLine()) != null) {
375                 int extendsIndex = line.indexOf(" extends ");
376                 if (line.startsWith("class ") && extendsIndex > -1) {
377                     generatedFileName = line.substring(6, extendsIndex).trim();
378                     break;
379                 }
380             }
381             in.close();
382         } catch (Exception JavaDoc e) {
383             throw new BuildException("Unable to determine generated class", e);
384         }
385         if (generatedFileName == null) {
386             throw new BuildException("Unable to determine generated class");
387         }
388         return new File JavaDoc(outputDirectory, generatedFileName
389                         + (html ? ".html" : ".java"));
390     }
391
392     /** execute in a forked VM */
393     private int run(String JavaDoc[] command) throws BuildException {
394         PumpStreamHandler psh =
395             new PumpStreamHandler(new LogOutputStream(this, Project.MSG_INFO),
396                                   new TeeOutputStream(
397                                                       new LogOutputStream(this,
398                                                                           Project.MSG_WARN),
399                                                       bos)
400                                   );
401         Execute exe = new Execute(psh, null);
402         exe.setAntRun(getProject());
403         if (workingdir != null) {
404             exe.setWorkingDirectory(workingdir);
405         }
406         exe.setCommandline(command);
407         try {
408             return exe.execute();
409         } catch (IOException JavaDoc e) {
410             throw new BuildException(e, getLocation());
411         } finally {
412             FileUtils.close(bos);
413         }
414     }
415
416     /**
417      * Whether the antlr version is 2.7.2 (or higher).
418      *
419      * @return true if the version of Antlr present is 2.7.2 or later.
420      * @since Ant 1.6
421      */

422     protected boolean is272() {
423         AntClassLoader l = null;
424         try {
425             l = getProject().createClassLoader(commandline.getClasspath());
426             l.loadClass("antlr.Version");
427             return true;
428         } catch (ClassNotFoundException JavaDoc e) {
429             return false;
430         } finally {
431             if (l != null) {
432                 l.cleanup();
433             }
434         }
435     }
436 }
437
Popular Tags