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 {
 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 
 230   public static void main (String[] args)
 231   {
 232     (new Compile ()).start (args);
 233   } // main
 234 
 235   protected Factories factories ()
 236   {
 237     return new Factories ();
 238   } // genFactoryName
 239 
 240   protected void registerPragma (PragmaHandler handler)
 241   {
 242     handler.init (preprocessor);
 243     preprocessor.registerPragma (handler);
 244   } // registerPragma
 245 
 246   /**
 247    * Initialize the framework.
 248    **/
 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    **/
 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    **/
 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    **/
 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 
 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 
 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    **/
 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