1 /*
2  * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 /*
26  * COMPONENT_NAME: idl.parser
27  *
28  * ORIGINS: 27
29  *
30  * Licensed Materials - Property of IBM
31  * 5639-D57 (C) COPYRIGHT International Business Machines Corp. 1997, 1999
32  * RMI-IIOP v1.0
33  *
34  */
35 
36 package com.sun.tools.corba.se.idl;
37 
38 // NOTES:
39 // -D56351<daz> Update computation of RepositoryIDs to CORBA 2.3 (see spec.).
40 // -D58319<daz> Display version info. for -version option.
41 
42 import java.io.FileNotFoundException;
43 import java.io.IOException;
44 import java.util.Enumeration;
45 import java.util.Hashtable;
46 import java.util.Vector;
47 
48 import com.sun.tools.corba.se.idl.constExpr.ExprFactory;
49 import com.sun.tools.corba.se.idl.constExpr.DefaultExprFactory;
50 
51 /**
52  * Compiler usage:
53  * <br><br>
54  *
55  * java com.sun.tools.corba.se.idl.toJava.compile [options] <idl file>
56  * <br><br>
57  *
58  * where &lt;idl file&gt; is the name of a file containing IDL definitions,
59  * and [options] is any combination of the options listed below.  The options
60  * and the idl file name can appear in any order.
61  * <br><br>
62  *
63  * Options:
64  * <dl>
65  * <dt>-i &lt;include path&gt;
66  * <dd>By default, the current directory is scanned for included files.
67  *     This option adds another directory.  See also Note 1 below.
68  *
69  * <dt>-d &lt;symbol&gt;
70  * <dd>This is equivalent to the following line in an IDL file: #define &lt;symbol&gt;
71  *
72  * <dt>-emitAll
73  * <dd>Emit all types, including those found in #included files.
74  *
75  * <dt>-v
76  * <dd>Verbose mode.
77  * </dl>
78  *
79  * Note 1:  If you have an include path or paths that you will always be using,
80  * it can get tedious putting these on the command with the -i option all the
81  * time.  Instead, these can be placed into a config file called idl.config.
82  * This file must be in the CLASSPATH.  The format of the includes line is:
83  *
84  * <pre>
85  * includes=<path1>;<path2>;...;<pathN>
86  * </pre>
87  *
88  * Note that the path separator character, here shown as a semicolon, is
89  * machine dependent.  For instance, on Windows 95 this character is a
90  * semicolon, on UNIX it is a colon.
91  *
92  * <p>
93  * Note 2:  If you are directly invoking the main method on this class (not
94  * a subclass), then it will only check that the IDL file is syntactically
95  * correct.  It does not generate any files.  Only extensions to this
96  * framework generate files, therefore an extension must be invoked if you
97  * want files to be generated.
98  * <br><br>
99  *
100  * To Extend the compiler:
101  * <br><br>
102  *
103  * You only need to extend the compiler if you want it to generate something
104  * other than what it currently generates.
105  * <br><br>
106  *
107  * Step 1 - Implement the generator interfaces:
108  * <br><br>
109  *
110  * Each generator interface defines one method: generate (Hashtable, XXXEntry, PrintWriter);
111  * <br>
112  * - The Hashtable is the symbol table; each element is a SymtabEntry (or a
113  *   subclass of SymtabEntry) and is keyed by its fully qualified name;
114  *   <br>
115  * - XXXEntry is the appropriate entry for the type to be generated.  For
116  *   example: AttributeGen defines generate (Hashtable, AttributeEntry, PrintWriter);
117  *   ConstGen defines generate (Hashtable, ConstEntry, PrintWriter); etc.
118  *   <br>
119  * - The PrintWriter is a stream to the file being generated.  For the
120  *   generators called by the compiler framework, this will be null.  The
121  *   generator is responsible for creating and opening files.  But for
122  *   generators that are called by other generators - for instance,
123  *   MethodGen.generate will most likely be called by InterfaceGen.generate -
124  *   this parameter is provided so that the proper file can be written to.
125  *   <br><br>
126  *
127  * Step 2 - Implement the GenFactory interface:
128  * <br><br>
129  *
130  * All of the generators implemented in Step 1 must be created somehow.  There
131  * is an interface for a factory, GenFactory, which must be implemented.  The
132  * name of this factory must be set in the extension to the Compile class (see
133  * Step 3, below).
134  * <br><br>
135  *
136  * Step 3 - Extend com.sun.tools.corba.se.idl.Factories:
137  * <br><br>
138  *
139  * Extend com.sun.tools.corba.se.idl.Factories and override the method genFactory.  This
140  * method must return an instance of the factory which you implemented in
141  * step 2.  Your extension of this class may also do more, this is only the
142  * minimum.  See com.sun.tools.corba.se.idl.Factories for more information.
143  * <br><br>
144  *
145  * Step 4 - Extend com.sun.tools.corba.se.idl.Compile:
146  * <br><br>
147  *
148  * Your extension of com.sun.tools.corba.se.idl.Compile should contain a minimum of
149  * two methods:
150  * <dl>
151  * <dt>protected com.sun.tools.corba.se.idl.Factories ()
152  * <dd>This method overrides com.sun.tools.corba.se.idl.Compile.factories and returns your
153  *     extension from Step 3.
154  *
155  * <dt>public static void main (String[] args)
156  * <dd>This main method must instantiate this class and call its start method.
157  * </dl>
158  *
159  * Given that the extension of Factories is MyFactories, the extension of
160  * Compile could be:
161  *
162  * <pre>
163  * public class MyCompile extends com.sun.tools.corba.se.idl.Compile
164  * {
165  *   protected com.sun.tools.corba.se.idl.Factories factories ()
166  *   {
167  *     return new MyFactories ();
168  *   }
169  *   public static void main (String[] args)
170  *   {
171  *     MyCompile compile = new MyCompile ();
172  *     compile.start (args);
173  *   }
174  * }
175  * </pre>
176  *
177  * If you would like a bit more control over the processing of the framework,
178  * you can replace compile.start with what it calls.  But then you also have
179  * to handle the exceptions which start handles for you:
180  * <pre>
181  * public class MyCompile extends com.sun.tools.corba.se.idl.Compile
182  * {
183  *   ...
184  *
185  *   public static void main (String[] args)
186  *   {
187  *     MyCompile compile = new MyCompile ();
188  *     try
189  *     {
190  *       compile.init (args);
191  *       java.util.Enumeration emitList = compile.parse ();
192  *       compile.generate ();
193  *     }
194  *     catch (com.sun.tools.corba.se.idl.InvalidArgument e)
195  *     {
196  *       System.err.println (e);
197  *     }
198  *     catch (java.io.IOException e)
199  *     {
200  *       System.err.println (e);
201  *     }
202  *   }
203  * }
204  * </pre>
205  *
206  * Note that compile.parse returns an enumeration.  This enumerates the
207  * SymtabEntry's which should be generated.  If the parse method detects
208  * errors, it returns null.  Note that you do not have to check that
209  * `emitList' is valid before calling generate (that's done internally), but
210  * if you do any processing between parse and generate, emitList should be
211  * checked before executing that code.
212  * <br><br>
213  **/
214 public class Compile
215 {
Compile()216   public Compile ()
217   {
218     noPragma.init (preprocessor);
219     preprocessor.registerPragma (noPragma);
220 
221     // <d41197> Reset static variables to allow parsing multiple sources.
222     // DO NOT reset SymtabEntry.maxKey because it crashes IDLC.
223     ParseException.detected  = false;
224     SymtabEntry.includeStack = new java.util.Stack ();
225     SymtabEntry.setEmit      = true;
226     //SymtabEntry.maxKey     = -1;
227     Parser.repIDStack        = new java.util.Stack (); // <d56351>
228   } // ctor
229 
main(String[] args)230   public static void main (String[] args)
231   {
232     (new Compile ()).start (args);
233   } // main
234 
factories()235   protected Factories factories ()
236   {
237     return new Factories ();
238   } // genFactoryName
239 
registerPragma(PragmaHandler handler)240   protected void registerPragma (PragmaHandler handler)
241   {
242     handler.init (preprocessor);
243     preprocessor.registerPragma (handler);
244   } // registerPragma
245 
246   /**
247    * Initialize the framework.
248    **/
init(String[] args)249   protected void init (String[] args) throws InvalidArgument
250   {
251     initFactories ();
252     arguments.parseArgs (args);
253     initGenerators ();
254     parser = new Parser (preprocessor, arguments, overrideNames, symbolTable, symtabFactory, exprFactory, keywords);
255     preprocessor.init (parser);
256     parser.includes = includes;
257     parser.includeEntries = includeEntries;
258   } // init
259 
260   /**
261    * Parse the IDL file and return an enumeration of the symbols to be
262    * generated.  All elements of the Enumeration will be extensions of
263    * SymtabEntry.  If any errors were encountered during parsing, null
264    * will be returned.
265    **/
parse()266   protected Enumeration parse () throws IOException
267   {
268     if (arguments.verbose)
269       System.out.println (Util.getMessage ("Compile.parsing", arguments.file));
270     parser.parse (arguments.file);
271     if ( !ParseException.detected )
272     {
273       parser.forwardEntryCheck();
274 
275       // <46082.03> Revert to "IDL:"-style (i.e., regular) repository ID.
276       //parser.updateRepositoryIds();
277     }
278     if (arguments.verbose)
279       System.out.println (Util.getMessage ("Compile.parseDone", arguments.file));
280     if (ParseException.detected)
281     {
282       symbolTable = null;
283       emitList    = null;
284     }
285     else
286     {
287       symbolTable = parser.symbolTable;
288       emitList    = parser.emitList.elements ();
289     }
290     return emitList;
291   } // parse
292 
293   /**
294    * Invoke the generators.
295    **/
generate()296   protected void generate () throws IOException
297   {
298     /*
299     // print the symbol table
300     Enumeration v = parser.symbolTable.elements ();
301     Enumeration k = parser.symbolTable.keys ();
302     while (k.hasMoreElements ())
303       System.out.println (k.nextElement () + ":  " + v.nextElement ());
304     */
305     if (ParseException.detected)
306       emitList = null;
307     else
308       emitList = parser.emitList.elements ();
309     if (emitList != null)
310     {
311       // Emit the output files for all of the types in the IDL file
312       if (arguments.verbose)
313         System.out.println ();
314       while (emitList.hasMoreElements ())
315       {
316         SymtabEntry entry = (SymtabEntry)emitList.nextElement ();
317         if (arguments.verbose)
318           if (entry.generator () instanceof Noop)
319             ; // Nothing will be generated, so don't say so.
320           else if (entry.module () . equals (""))
321             System.out.println (Util.getMessage ("Compile.generating", entry.name ()));
322           else
323             System.out.println (Util.getMessage ("Compile.generating", entry.module () + '/' + entry.name ()));
324         entry.generate (symbolTable, null);
325         if (arguments.verbose)
326           if (entry.generator () instanceof Noop)
327             ; // Nothing will be generated, so don't say so.
328           else if (entry.module () . equals (""))
329             System.out.println (Util.getMessage ("Compile.genDone", entry.name ()));
330           else
331             System.out.println (Util.getMessage ("Compile.genDone", entry.module () + '/' + entry.name ()));
332       }
333     }
334   } // generate
335 
336   /**
337    * Start the parse/code generation process.  This method calls init,
338    * parse, generate.  If more control is desired, rather than call start,
339    * those three methods could be called explicitly.
340    **/
start(String[] args)341   public void start (String[] args)
342   {
343     try
344     {
345       init (args);
346       if (arguments.versionRequest) // <d59319>
347         displayVersion ();
348       else
349       {
350         parse ();
351         generate ();
352       }
353     }
354     catch (InvalidArgument e)
355     {
356       System.err.println (e);
357     }
358     catch (IOException e)
359     {
360       System.err.println (e);
361     }
362   } // start
363 
initFactories()364   private void initFactories ()
365   {
366     // Get the factories.
367     Factories factories = factories ();
368     if (factories == null) factories = new Factories ();
369 
370     // Get the argument processor from the factories.
371     Arguments tmpArgs = factories.arguments ();
372     if (tmpArgs == null)
373       arguments = new Arguments ();
374     else
375       arguments = tmpArgs;
376 
377     // Get the symbol table entry factory from the factories.
378     SymtabFactory tmpSTF = factories.symtabFactory ();
379     if (tmpSTF == null)
380       symtabFactory = new DefaultSymtabFactory ();
381     else
382       symtabFactory = tmpSTF;
383 
384     // Get the expression factory from the factories.
385     ExprFactory tmpExpF = factories.exprFactory ();
386     if (tmpExpF == null)
387       exprFactory = new DefaultExprFactory ();
388     else
389       exprFactory = tmpExpF;
390 
391     // Get the generator factory from the factories.
392     GenFactory tmpGenF = factories.genFactory ();
393     if (tmpGenF == null)
394       genFactory = noop;
395     else
396       genFactory = tmpGenF;
397 
398     // Get the language keywords.
399     keywords = factories.languageKeywords ();
400     if (keywords == null)
401       keywords = new String[0];
402   } // initFactories
403 
initGenerators()404   private void initGenerators ()
405   {
406     AttributeGen agen = genFactory.createAttributeGen ();
407     AttributeEntry.attributeGen = agen == null ? noop : agen;
408 
409     ConstGen cgen = genFactory.createConstGen ();
410     ConstEntry.constGen = cgen == null ? noop : cgen;
411 
412     EnumGen egen = genFactory.createEnumGen ();
413     EnumEntry.enumGen = egen == null ? noop : egen;
414 
415     ExceptionGen exgen = genFactory.createExceptionGen ();
416     ExceptionEntry.exceptionGen = exgen == null ? noop : exgen;
417 
418     ForwardGen fgen = genFactory.createForwardGen ();
419     ForwardEntry.forwardGen = fgen == null ? noop : fgen;
420 
421     ForwardValueGen fvgen = genFactory.createForwardValueGen ();
422     ForwardValueEntry.forwardValueGen = fvgen == null ? noop : fvgen;
423 
424     IncludeGen ingen = genFactory.createIncludeGen ();
425     IncludeEntry.includeGen = ingen == null ? noop : ingen;
426 
427     InterfaceGen igen = genFactory.createInterfaceGen ();
428     InterfaceEntry.interfaceGen = igen == null ? noop : igen;
429 
430     ValueGen vgen = genFactory.createValueGen ();
431     ValueEntry.valueGen = vgen == null ? noop : vgen;
432 
433     ValueBoxGen vbgen = genFactory.createValueBoxGen ();
434     ValueBoxEntry.valueBoxGen = vbgen == null ? noop : vbgen;
435 
436     MethodGen mgen = genFactory.createMethodGen ();
437     MethodEntry.methodGen = mgen == null ? noop : mgen;
438 
439     ModuleGen modgen = genFactory.createModuleGen ();
440     ModuleEntry.moduleGen = modgen == null ? noop : modgen;
441 
442     NativeGen ngen = genFactory.createNativeGen ();
443     NativeEntry.nativeGen = ngen == null ? noop : ngen;
444 
445     ParameterGen pgen = genFactory.createParameterGen ();
446     ParameterEntry.parameterGen = pgen == null ? noop : pgen;
447 
448     PragmaGen prgen = genFactory.createPragmaGen ();
449     PragmaEntry.pragmaGen = prgen == null ? noop : prgen;
450 
451     PrimitiveGen primgen = genFactory.createPrimitiveGen ();
452     PrimitiveEntry.primitiveGen = primgen == null ? noop : primgen;
453 
454     SequenceGen seqgen = genFactory.createSequenceGen ();
455     SequenceEntry.sequenceGen = seqgen == null ? noop : seqgen;
456 
457     StringGen strgen = genFactory.createStringGen ();
458     StringEntry.stringGen = strgen == null ? noop : strgen;
459 
460     StructGen sgen = genFactory.createStructGen ();
461     StructEntry.structGen = sgen == null ? noop : sgen;
462 
463     TypedefGen tgen = genFactory.createTypedefGen ();
464     TypedefEntry.typedefGen = tgen == null ? noop : tgen;
465 
466     UnionGen ugen = genFactory.createUnionGen ();
467     UnionEntry.unionGen = ugen == null ? noop : ugen;
468   } // initGenerators
469 
470   /**
471    * Write the version number of this compiler to standard out.
472    **/
displayVersion()473   protected void displayVersion ()
474   {
475     String message = Util.getMessage ("Version.product", Util.getMessage ("Version.number"));
476     System.out.println (message);
477   }
478 
479   /**
480    * This is the repository of emitter arguments.
481    **/
482   public Arguments arguments           = null;
483   /**
484    * This hashtable contains <real name, alias> pairs.  It is filled in by
485    * extenders in cases where they wish to override an IDL type name with
486    * some other name.  For instance, when mapping to Java, there could be
487    * an overrideNames entry of <"TRUE", "true">.  NOTE:  Do NOT change this
488    * variable to a new Hash table.  Just add elements to it.
489    **/
490   protected Hashtable overrideNames    = new Hashtable ();
491   /**
492    * This is the symbol table.  It will be empty until the parse method
493    * executes.  If errors are encountered, the state of the symbol table
494    * is undefined.
495    **/
496   protected Hashtable symbolTable      = new Hashtable ();
497   /**
498    * This is a vector of strings of the form "IDLfile" or <IDLfile>.  It is
499    * a list of the files included in the given IDL file.  It will be empty
500    * until the parse method executes.  If errors are encountered, the state
501    * of this vector is undefined.
502    **/
503   protected Vector includes            = new Vector ();
504   /**
505    * This is a vector of IncludeEntry's.  It is a list of the files included
506    * in the given IDL file.  It mirrors the includes vector.  It will be empty
507    * until the parse method executes.  If errors are encountered, the state of
508    * this vector is undefined.
509    **/
510   protected Vector includeEntries      = new Vector ();
511   static  Noop          noop           = new Noop ();
512   private GenFactory    genFactory     = null;
513   private SymtabFactory symtabFactory  = null;
514   private ExprFactory   exprFactory    = null;
515   private Parser        parser         = null;
516           Preprocessor  preprocessor   = new Preprocessor ();
517   private NoPragma      noPragma       = new NoPragma ();
518   private Enumeration   emitList       = null;
519   private String[]      keywords       = null;
520 } // class Compile
521