View Javadoc
1   /*
2    * Copyright (c) 1999, 2000, 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  // -D57110<daz> Allow ID pragma directive to be applied to modules and update
40  //  feature in accordance to CORBA 2.3.
41  // -D59165<daz> Enable escaped identifiers when processing pragmas.
42  // -f60858.1<daz> Support -corba option, level = 2.2: Accept identifiers that
43  //  collide with keywords, in letter but not case, and issue a warning.
44  // -d62023 <daz> support -noWarn option; suppress inappropriate warnings when
45  //  parsing IBM-specific pragmas (#meta <interface_name> abstract).
46  
47  import java.io.File;
48  import java.io.FileNotFoundException;
49  import java.io.IOException;
50  import java.math.BigInteger;
51  import java.util.Enumeration;
52  import java.util.Hashtable;
53  import java.util.Stack;
54  import java.util.Vector;
55  
56  import com.sun.tools.corba.se.idl.RepositoryID;
57  
58  import com.sun.tools.corba.se.idl.constExpr.*;
59  
60  /**
61   * This class should be extended if new pragmas are desired.  If the
62   * preprocessor encounters a pragma name which it doesn't recognize
63   * (anything other than ID, prefix, or version), it calls the method
64   * otherPragmas.  This is the only method which need be overridden.
65   * The Preprocessor base class has a number of utility-like methods
66   * which can be used by the overridden otherPragmas method.
67   **/
68  public class Preprocessor
69  {
70    /**
71     * Public zero-argument constructor.
72     **/
73    Preprocessor ()
74    {
75    } // ctor
76  
77    /**
78     *
79     **/
80    void init (Parser p)
81    {
82      parser  = p;
83      symbols = p.symbols;
84      macros  = p.macros;
85    } // init
86  
87    /**
88     *
89     **/
90    protected Object clone ()
91    {
92      return new Preprocessor ();
93    } // clone
94  
95    /**
96     *
97     **/
98    Token process (Token t) throws IOException, ParseException
99    {
100     token   = t;
101     scanner = parser.scanner;
102     // <f46082.40> Deactivate escaped identifier processing in Scanner while
103     // preprocessing.
104     //scanner.underscoreOK = true;
105     scanner.escapedOK = false;
106     try
107     {
108       switch (token.type)
109       {
110         case Token.Include:
111           include ();
112           break;
113         case Token.If:
114           ifClause ();
115           break;
116         case Token.Ifdef:
117           ifdef (false);
118           break;
119         case Token.Ifndef:
120           ifdef (true);
121           break;
122         case Token.Else:
123           if (alreadyProcessedABranch.empty ())
124             throw ParseException.elseNoIf (scanner);
125           else if (((Boolean)alreadyProcessedABranch.peek ()).booleanValue ())
126             skipToEndif ();
127           else
128           {
129             alreadyProcessedABranch.pop ();
130             alreadyProcessedABranch.push (new Boolean (true));
131             token = scanner.getToken ();
132           }
133           break;
134         case Token.Elif:
135           elif ();
136           break;
137         case Token.Endif:
138           if (alreadyProcessedABranch.empty ())
139             throw ParseException.endNoIf (scanner);
140           else
141           {
142             alreadyProcessedABranch.pop ();
143             token = scanner.getToken ();
144             break;
145           }
146         case Token.Define:
147           define ();
148           break;
149         case Token.Undef:
150           undefine ();
151           break;
152         case Token.Pragma:
153           pragma ();
154           break;
155         case Token.Unknown:
156           if (!parser.noWarn)
157             ParseException.warning (scanner, Util.getMessage ("Preprocessor.unknown", token.name));
158         case Token.Error:
159         case Token.Line:
160         case Token.Null:
161           // ignore
162         default:
163           scanner.skipLineComment ();
164           token = scanner.getToken ();
165       }
166     }
167     catch (IOException e)
168     {
169       // <f46082.40> Underscore may now precede any identifier, so underscoreOK
170       // is vestigal.  The Preprocessor must reset escapedOK so that Scanner
171       // will process escaped identifiers according to specification.
172       //scanner.underscoreOK = false;
173       scanner.escapedOK = true;
174       throw e;
175     }
176     catch (ParseException e)
177     {
178       // <f46082.40> See above.
179       //scanner.underscoreOK = false;
180       scanner.escapedOK = true;
181       throw e;
182     }
183     // <f46082.40> See above.
184     //scanner.underscoreOK = false;
185     scanner.escapedOK = true;
186     return token;
187   } // process
188 
189   /**
190    *
191    **/
192   private void include () throws IOException, ParseException
193   {
194     match (Token.Include);
195     IncludeEntry include = parser.stFactory.includeEntry (parser.currentModule);
196     include.sourceFile (scanner.fileEntry ());
197     scanner.fileEntry ().addInclude (include);
198     if (token.type == Token.StringLiteral)
199       include2 (include);
200     else if (token.type == Token.LessThan)
201       include3 (include);
202     else
203     {
204       int[] expected = {Token.StringLiteral, Token.LessThan};
205       throw ParseException.syntaxError (scanner, expected, token.type);
206     }
207     if (parser.currentModule instanceof ModuleEntry)
208       ((ModuleEntry)parser.currentModule).addContained (include);
209     else if (parser.currentModule instanceof InterfaceEntry)
210       ((InterfaceEntry)parser.currentModule).addContained (include);
211   } // include
212 
213   /**
214    *
215    **/
216   private void include2 (IncludeEntry include) throws IOException, ParseException
217   {
218     include.name ('"' + token.name + '"');
219     include4 (include, token.name);
220     match (Token.StringLiteral);
221   } // include2
222 
223   /**
224    *
225    **/
226   private void include3 (IncludeEntry include) throws IOException, ParseException
227   {
228     if (token.type != Token.LessThan)
229       // match will throw an exception
230       match (Token.LessThan);
231     else
232     {
233       try
234       {
235         String includeFile = getUntil ('>');
236         token = scanner.getToken ();
237         include.name ('<' + includeFile + '>');
238         include4 (include, includeFile);
239         match (Token.GreaterThan);
240       }
241       catch (IOException e)
242       {
243         throw ParseException.syntaxError (scanner, ">", "EOF");
244       }
245     }
246   } // include3
247 
248   /**
249    *
250    **/
251   private void include4 (IncludeEntry include, String filename) throws IOException, ParseException
252   {
253     try
254     {
255       // If the #include is at the global scope, it is treated as
256       // an import statement.  If it is within some other scope, it
257       // is treated as a normal #include.
258       boolean includeIsImport = parser.currentModule == parser.topLevelModule;
259       //daz
260       include.absFilename (Util.getAbsolutePath (filename, parser.paths));
261       scanner.scanIncludedFile (include, getFilename (filename), includeIsImport);
262     }
263     catch (IOException e)
264     {
265       ParseException.generic (scanner, e.toString ());
266     }
267   } // include4
268 
269   /**
270    *
271    **/
272   private void define () throws IOException, ParseException
273   {
274     match (Token.Define);
275     if (token.equals (Token.Identifier))
276     {
277       String symbol = scanner.getStringToEOL ();
278       symbols.put (token.name, symbol.trim ());
279       match (Token.Identifier);
280     }
281     else if (token.equals (Token.MacroIdentifier))
282     {
283       symbols.put (token.name, '(' + scanner.getStringToEOL () . trim ());
284       macros.addElement (token.name);
285       match (Token.MacroIdentifier);
286     }
287     else
288       throw ParseException.syntaxError (scanner, Token.Identifier, token.type);
289   } // define
290 
291   /**
292    *
293    **/
294   private void undefine () throws IOException, ParseException
295   {
296     match (Token.Undef);
297     if (token.equals (Token.Identifier))
298     {
299       symbols.remove (token.name);
300       macros.removeElement (token.name);
301       match (Token.Identifier);
302     }
303     else
304       throw ParseException.syntaxError (scanner, Token.Identifier, token.type);
305   } // undefine
306 
307   /**
308    *
309    **/
310   private void ifClause () throws IOException, ParseException
311   {
312     match (Token.If);
313     constExpr ();
314   } // ifClause
315 
316   /**
317    *
318    **/
319   private void constExpr () throws IOException, ParseException
320   {
321     SymtabEntry dummyEntry = new SymtabEntry (parser.currentModule);
322     dummyEntry.container (parser.currentModule);
323     parser.parsingConditionalExpr = true;
324     Expression boolExpr = booleanConstExpr (dummyEntry);
325     parser.parsingConditionalExpr = false;
326     boolean expr;
327     if (boolExpr.value () instanceof Boolean)
328       expr = ((Boolean)boolExpr.value ()).booleanValue ();
329     else
330       expr = ((Number)boolExpr.value ()).longValue () != 0;
331     alreadyProcessedABranch.push (new Boolean (expr));
332     if (!expr)
333       skipToEndiforElse ();
334   } // constExpr
335 
336   /**
337    *
338    **/
339   Expression booleanConstExpr (SymtabEntry entry) throws IOException, ParseException
340   {
341     Expression expr = orExpr (null, entry);
342     try
343     {
344       expr.evaluate ();
345     }
346     catch (EvaluationException e)
347     {
348       ParseException.evaluationError (scanner, e.toString ());
349     }
350     return expr;
351   } // booleanConstExpr
352 
353   /**
354    *
355    **/
356   private Expression orExpr (Expression e, SymtabEntry entry) throws IOException, ParseException
357   {
358     if (e == null)
359       e = andExpr (null, entry);
360     else
361     {
362       BinaryExpr b = (BinaryExpr)e;
363       b.right (andExpr (null, entry));
364       e.rep (e.rep () + b.right ().rep ());
365     }
366     if (token.equals (Token.DoubleBar))
367     {
368       match (token.type);
369       BooleanOr or = parser.exprFactory.booleanOr (e, null);
370       or.rep (e.rep () + " || ");
371       return orExpr (or, entry);
372     }
373     else
374       return e;
375   } // orExpr
376 
377   /**
378    *
379    **/
380   private Expression andExpr (Expression e, SymtabEntry entry) throws IOException, ParseException
381   {
382     if (e == null)
383       e = notExpr (entry);
384     else
385     {
386       BinaryExpr b = (BinaryExpr)e;
387       b.right (notExpr (entry));
388       e.rep (e.rep () + b.right ().rep ());
389     }
390     if (token.equals (Token.DoubleAmpersand))
391     {
392       match (token.type);
393       BooleanAnd and = parser.exprFactory.booleanAnd (e, null);
394       and.rep (e.rep () + " && ");
395       return andExpr (and, entry);
396     }
397     else
398       return e;
399   } // andExpr
400 
401   /**
402    *
403    **/
404   private Expression notExpr (/*boolean alreadySawExclamation, */SymtabEntry entry) throws IOException, ParseException
405   {
406     Expression e;
407     if (token.equals (Token.Exclamation))
408     {
409       match (Token.Exclamation);
410       e = parser.exprFactory.booleanNot (definedExpr (entry));
411       e.rep ("!" + ((BooleanNot)e).operand ().rep ());
412     }
413     else
414       e = definedExpr (entry);
415     return e;
416   } // notExpr
417 
418   /**
419    *
420    **/
421   private Expression definedExpr (SymtabEntry entry) throws IOException, ParseException
422   {
423     if (token.equals (Token.Identifier) && token.name.equals ("defined"))
424       match (Token.Identifier);
425     return equalityExpr (null, entry);
426   } // definedExpr
427 
428   /**
429    *
430    **/
431   private Expression equalityExpr (Expression e, SymtabEntry entry) throws IOException, ParseException
432   {
433     if (e == null)
434     {
435       parser.token = token; // Since parser to parse, give it this token
436       e = parser.constExp (entry);
437       token = parser.token; // Since parser last parsed, get its token
438     }
439     else
440     {
441       BinaryExpr b = (BinaryExpr)e;
442       parser.token = token; // Since parser to parse, give it this token
443       Expression constExpr = parser.constExp (entry);
444       token = parser.token; // Since parser last parsed, get its token
445       b.right (constExpr);
446       e.rep (e.rep () + b.right ().rep ());
447     }
448     if (token.equals (Token.DoubleEqual))
449     {
450       match (token.type);
451       Equal eq = parser.exprFactory.equal (e, null);
452       eq.rep (e.rep () + " == ");
453       return equalityExpr (eq, entry);
454     }
455     else if (token.equals (Token.NotEqual))
456     {
457       match (token.type);
458       NotEqual n = parser.exprFactory.notEqual (e, null);
459       n.rep (e.rep () + " != ");
460       return equalityExpr (n, entry);
461     }
462     else if (token.equals (Token.GreaterThan))
463     {
464       match (token.type);
465       GreaterThan g = parser.exprFactory.greaterThan (e, null);
466       g.rep (e.rep () + " > ");
467       return equalityExpr (g, entry);
468     }
469     else if (token.equals (Token.GreaterEqual))
470     {
471       match (token.type);
472       GreaterEqual g = parser.exprFactory.greaterEqual (e, null);
473       g.rep (e.rep () + " >= ");
474       return equalityExpr (g, entry);
475     }
476     else if (token.equals (Token.LessThan))
477     {
478       match (token.type);
479       LessThan l = parser.exprFactory.lessThan (e, null);
480       l.rep (e.rep () + " < ");
481       return equalityExpr (l, entry);
482     }
483     else if (token.equals (Token.LessEqual))
484     {
485       match (token.type);
486       LessEqual l = parser.exprFactory.lessEqual (e, null);
487       l.rep (e.rep () + " <= ");
488       return equalityExpr (l, entry);
489     }
490     else
491       return e;
492   } // equalityExpr
493 
494   /**
495    *
496    **/
497   Expression primaryExpr (SymtabEntry entry) throws IOException, ParseException
498   {
499     Expression primary = null;
500     switch (token.type)
501     {
502       case Token.Identifier:
503         // If an identifier gets this far, it means that no
504         // preprocessor variable was defined with that name.
505         // Generate a FALSE boolean expr.
506         //daz        primary = parser.exprFactory.terminal ("0", new Long (0));
507         primary = parser.exprFactory.terminal ("0", BigInteger.valueOf (0));
508         token = scanner.getToken ();
509         break;
510       case Token.BooleanLiteral:
511       case Token.CharacterLiteral:
512       case Token.IntegerLiteral:
513       case Token.FloatingPointLiteral:
514       case Token.StringLiteral:
515         //daz        primary = parser.literal ();
516         primary = parser.literal (entry);
517         token = parser.token;
518         break;
519       case Token.LeftParen:
520         match (Token.LeftParen);
521         primary = booleanConstExpr (entry);
522         match (Token.RightParen);
523         primary.rep ('(' + primary.rep () + ')');
524         break;
525       default:
526         int[] expected = {Token.Literal, Token.LeftParen};
527         throw ParseException.syntaxError (scanner, expected, token.type);
528     }
529     return primary;
530   } // primaryExpr
531 
532   /**
533    *
534    **/
535   private void ifDefine (boolean inParens, boolean not) throws IOException, ParseException
536   {
537     if (token.equals (Token.Identifier))
538       if ((not && symbols.containsKey (token.name)) || (!not && !symbols.containsKey (token.name)))
539       {
540         alreadyProcessedABranch.push (new Boolean (false));
541         skipToEndiforElse ();
542       }
543       else
544       {
545         alreadyProcessedABranch.push (new Boolean (true));
546         match (Token.Identifier);
547         if (inParens)
548           match (Token.RightParen);
549       }
550     else
551       throw ParseException.syntaxError (scanner, Token.Identifier, token.type);
552   } // ifDefine
553 
554   /**
555    *
556    **/
557   private void ifdef (boolean not) throws IOException, ParseException
558   {
559     if (not)
560       match (Token.Ifndef);
561     else
562       match (Token.Ifdef);
563     if (token.equals (Token.Identifier))
564       if ((not && symbols.containsKey (token.name)) || (!not && !symbols.containsKey (token.name)))
565       {
566         alreadyProcessedABranch.push (new Boolean (false));
567         skipToEndiforElse ();
568       }
569       else
570       {
571         alreadyProcessedABranch.push (new Boolean (true));
572         match (Token.Identifier);
573       }
574     else
575       throw ParseException.syntaxError (scanner, Token.Identifier, token.type);
576   } // ifdef
577 
578   /**
579    *
580    **/
581   private void elif () throws IOException, ParseException
582   {
583     if (alreadyProcessedABranch.empty ())
584       throw ParseException.elseNoIf (scanner);
585     else if (((Boolean)alreadyProcessedABranch.peek ()).booleanValue ())
586       skipToEndif ();
587     else
588     {
589       match (Token.Elif);
590       constExpr ();
591     }
592   } // elif
593 
594   /**
595    *
596    **/
597   private void skipToEndiforElse () throws IOException, ParseException
598   {
599     while (!token.equals (Token.Endif) && !token.equals (Token.Else) && !token.equals (Token.Elif))
600     {
601       if (token.equals (Token.Ifdef) || token.equals (Token.Ifndef))
602       {
603         alreadyProcessedABranch.push (new Boolean (true));
604         skipToEndif ();
605       }
606       else
607         token = scanner.skipUntil ('#');
608     }
609     process (token);
610   } // skipToEndiforElse
611 
612   /**
613    *
614    **/
615   private void skipToEndif () throws IOException, ParseException
616   {
617     while (!token.equals (Token.Endif))
618     {
619       token = scanner.skipUntil ('#');
620       if (token.equals (Token.Ifdef) || token.equals (Token.Ifndef))
621       {
622         alreadyProcessedABranch.push (new Boolean (true));
623         skipToEndif ();
624       }
625     }
626     alreadyProcessedABranch.pop ();
627     match (Token.Endif);
628   } // skipToEndif
629 
630   ///////////////
631   // For Pragma
632 
633   /**
634    *
635    **/
636   private void pragma () throws IOException, ParseException
637   {
638     match (Token.Pragma);
639     String pragmaType = token.name;
640 
641     // <d59165> Enable escaped identifiers while processing pragma internals.
642     // Don't enable until scanning pragma name!
643     scanner.escapedOK = true;
644     match (Token.Identifier);
645 
646     // Add pragma entry to container
647     PragmaEntry pragmaEntry = parser.stFactory.pragmaEntry (parser.currentModule);
648     pragmaEntry.name (pragmaType);
649     pragmaEntry.sourceFile (scanner.fileEntry ());
650     pragmaEntry.data (scanner.currentLine ());
651     if (parser.currentModule instanceof ModuleEntry)
652       ((ModuleEntry)parser.currentModule).addContained (pragmaEntry);
653     else if (parser.currentModule instanceof InterfaceEntry)
654       ((InterfaceEntry)parser.currentModule).addContained (pragmaEntry);
655 
656     // If the token was an identifier, then pragmaType WILL be non-null.
657     if (pragmaType.equals ("ID"))
658       idPragma ();
659     else if (pragmaType.equals ("prefix"))
660       prefixPragma ();
661     else if (pragmaType.equals ("version"))
662       versionPragma ();
663 
664     // we are adding extensions to the Sun's idlj compiler to
665     // handle correct code generation for local Objects, where
666     // the OMG is taking a long time to formalize stuff.  Good
667     // example of this is poa.idl.  Two proprietory pragmas
668     // sun_local and sun_localservant are defined.  sun_local
669     // generates only Holder and Helper classes, where read
670     // and write methods throw marshal exceptions.  sun_localservant
671     // is to generate Helper, Holder, and only Skel with _invoke
672     // throwing an exception, since it does not make sense for
673     // local objects.
674 
675     else if (pragmaType.equals ("sun_local"))
676       localPragma();
677     else if (pragmaType.equals ("sun_localservant"))
678       localServantPragma();
679     else
680     {
681       otherPragmas (pragmaType, tokenToString ());
682       token = scanner.getToken ();
683     }
684 
685     scanner.escapedOK = false; // <d59165> Disable escaped identifiers.
686   } // pragma
687 
688   // <d57110> Pragma ID can be appiled to modules and it is an error to
689   // name a type in more than one ID pragma directive.
690 
691   private Vector PragmaIDs = new Vector ();
692 
693   private void localPragma () throws IOException, ParseException
694   {
695     // Before I can use a parser method, I must make sure it has the current token.
696     parser.token = token;
697     // this makes sense only for interfaces, if specified for modules,
698     // parser should throw an error
699     SymtabEntry anErrorOccurred = new SymtabEntry ();
700     SymtabEntry entry = parser.scopedName (parser.currentModule, anErrorOccurred);
701     // Was the indicated type found in the symbol table?
702     if (entry == anErrorOccurred)
703     {
704         System.out.println("Error occured ");
705       // Don't have to generate an error, scopedName already has.
706       scanner.skipLineComment ();
707       token = scanner.getToken ();
708     }
709     else
710     {
711       // by this time we have already parsed the ModuleName and the
712       // pragma type, therefore setInterfaceType
713       if (entry instanceof InterfaceEntry) {
714           InterfaceEntry ent = (InterfaceEntry) entry;
715           ent.setInterfaceType (InterfaceEntry.LOCAL_SIGNATURE_ONLY);
716       }
717       token = parser.token;
718       String string = token.name;
719       match (Token.StringLiteral);
720       // for non-interfaces it doesn't make sense, so just ignore it
721     }
722   } // localPragma
723 
724   private void localServantPragma () throws IOException, ParseException
725   {
726     // Before I can use a parser method, I must make sure it has the current token.
727     parser.token = token;
728     // this makes sense only for interfaces, if specified for modules,
729     // parser should throw an error
730     SymtabEntry anErrorOccurred = new SymtabEntry ();
731     SymtabEntry entry = parser.scopedName (parser.currentModule, anErrorOccurred);
732 
733     // Was the indicated type found in the symbol table?
734     if (entry == anErrorOccurred)
735     {
736       // Don't have to generate an error, scopedName already has.
737       scanner.skipLineComment ();
738       token = scanner.getToken ();
739         System.out.println("Error occured ");
740     }
741     else
742     {
743       // by this time we have already parsed the ModuleName and the
744       // pragma type, therefore setInterfaceType
745       if (entry instanceof InterfaceEntry) {
746           InterfaceEntry ent = (InterfaceEntry) entry;
747           ent.setInterfaceType (InterfaceEntry.LOCALSERVANT);
748       }
749       token = parser.token;
750       String string = token.name;
751       match (Token.StringLiteral);
752       // for non-interfaces it doesn't make sense, so just ignore it
753     }
754   } // localServantPragma
755 
756 
757   /**
758    *
759    **/
760   private void idPragma () throws IOException, ParseException
761   {
762     // Before I can use a parser method, I must make sure it has the current token.
763     parser.token = token;
764 
765     // <d57110> This flag will relax the restriction that the scopedNamed
766     // in this ID pragma directive cannot resolve to a module.
767     parser.isModuleLegalType (true);
768     SymtabEntry anErrorOccurred = new SymtabEntry ();
769     SymtabEntry entry = parser.scopedName (parser.currentModule, anErrorOccurred);
770     parser.isModuleLegalType (false);  // <57110>
771 
772     // Was the indicated type found in the symbol table?
773     if (entry == anErrorOccurred)
774     {
775       // Don't have to generate an error, scopedName already has.
776       scanner.skipLineComment ();
777       token = scanner.getToken ();
778     }
779     // <d57110>
780     //else if (PragmaIDs.contains (entry))
781     //{
782     //  ParseException.badRepIDAlreadyAssigned (scanner, entry.name ());
783     //  scanner.skipLineComment ();
784     //  token = scanner.getToken ();
785     //}
786     else
787     {
788       token = parser.token;
789       String string = token.name;
790       // Do not match token until after raise exceptions, otherwise
791       // incorrect messages will be emitted!
792       if (PragmaIDs.contains (entry)) // <d57110>
793       {
794         ParseException.badRepIDAlreadyAssigned (scanner, entry.name ());
795       }
796       else if (!RepositoryID.hasValidForm (string)) // <d57110>
797       {
798         ParseException.badRepIDForm (scanner, string);
799       }
800       else
801       {
802         entry.repositoryID (new RepositoryID (string));
803         PragmaIDs.addElement (entry); // <d57110>
804       }
805       match (Token.StringLiteral);
806     }
807   } // idPragma
808 
809   /**
810    *
811    **/
812   private void prefixPragma () throws IOException, ParseException
813   {
814     String string = token.name;
815     match (Token.StringLiteral);
816     ((IDLID)parser.repIDStack.peek ()).prefix (string);
817     ((IDLID)parser.repIDStack.peek ()).name ("");
818   } // prefixPragma
819 
820   /**
821    *
822    **/
823   private void versionPragma () throws IOException, ParseException
824   {
825     // Before I can use a parser method, I must make sure it has the current token.
826     parser.token = token;
827     // This flag will relax the restriction that the scopedNamed
828     // in this Version pragma directive cannot resolve to a module.
829     parser.isModuleLegalType (true);
830     SymtabEntry anErrorOccurred = new SymtabEntry ();
831     SymtabEntry entry = parser.scopedName (parser.currentModule, anErrorOccurred);
832     // reset the flag to original value
833     parser.isModuleLegalType (false);
834     if (entry == anErrorOccurred)
835     {
836       // Don't have to generate an error, scopedName already has.
837       scanner.skipLineComment ();
838       token = scanner.getToken ();
839     }
840     else
841     {
842       token = parser.token;
843       String string = token.name;
844       match (Token.FloatingPointLiteral);
845       if (entry.repositoryID () instanceof IDLID)
846         ((IDLID)entry.repositoryID ()).version (string);
847     }
848   } // versionPragma
849 
850   private Vector pragmaHandlers = new Vector ();
851 
852   /**
853    *
854    **/
855   void registerPragma (PragmaHandler handler)
856   {
857     pragmaHandlers.addElement (handler);
858   } // registerPragma
859 
860   /**
861    *
862    **/
863   private void otherPragmas (String pragmaType, String currentToken) throws IOException
864   {
865     for (int i = pragmaHandlers.size () - 1; i >= 0; --i)
866     {
867       PragmaHandler handler = (PragmaHandler)pragmaHandlers.elementAt (i);
868       if (handler.process (pragmaType, currentToken))
869                 break;
870     }
871   } // otherPragmas
872 
873   /*
874    * These protected methods are used by extenders, by the code
875    * which implements otherPragma.
876    */
877 
878   /**
879    * Get the current token.
880    **/
881   String currentToken ()
882   {
883     return tokenToString ();
884   } // currentToken
885 
886   /**
887    * This method, given an entry name, returns the entry with that name.
888    * It can take fully or partially qualified names and returns the
889    * appropriate entry defined within the current scope.  If no entry
890    * exists, null is returned.
891    **/
892   SymtabEntry getEntryForName (String string)
893   {
894     boolean partialScope = false;
895     boolean globalScope  = false;
896 
897     // Change all ::'s to /'s
898     if (string.startsWith ("::"))
899     {
900       globalScope = true;
901       string = string.substring (2);
902     }
903     int index = string.indexOf ("::");
904     while (index >= 0)
905     {
906       partialScope = true;
907       string = string.substring (0, index) + '/' + string.substring (index + 2);
908       index = string.indexOf ("::");
909     }
910 
911     // Get the entry for that string
912     SymtabEntry entry = null;
913     if (globalScope)
914       entry = parser.recursiveQualifiedEntry (string);
915     else if (partialScope)
916       entry = parser.recursivePQEntry (string, parser.currentModule);
917     else
918       entry = parser.unqualifiedEntryWMod (string, parser.currentModule);
919     return entry;
920   } // getEntryForName
921 
922   /**
923    * This method returns a string of all of the characters from the
924    * input file from the current position up to, but not including,
925    * the end-of-line character(s).
926    **/
927   String getStringToEOL () throws IOException
928   {
929     return scanner.getStringToEOL ();
930   } // getStringToEOL
931 
932   /**
933    * This method returns a string of all of the characters from the
934    * input file from the current position up to, but not including,
935    * the given character.  It encapsulates parenthesis and quoted strings,
936    * meaning it does not stop if the given character is found within
937    * parentheses or quotes.  For instance, given the input of
938    * `start(inside)end', getUntil ('n') will return "start(inside)e"
939    **/
940   String getUntil (char c) throws IOException
941   {
942     return scanner.getUntil (c);
943   } // getUntil
944 
945   private boolean lastWasMacroID = false;
946 
947   /**
948    *
949    **/
950   private String tokenToString ()
951   {
952     if (token.equals (Token.MacroIdentifier))
953     {
954       lastWasMacroID = true;
955       return token.name;
956     }
957     else if (token.equals (Token.Identifier))
958       return token.name;
959     else
960       return token.toString ();
961   } // tokenToString
962 
963   /**
964    * This method returns the next token String from the input file.
965    **/
966   String nextToken () throws IOException
967   {
968     if (lastWasMacroID)
969     {
970       lastWasMacroID = false;
971       return "(";
972     }
973     else
974     {
975       token = scanner.getToken ();
976       return tokenToString ();
977     }
978   } // nextToken
979 
980   /**
981    * This method assumes that the current token marks the beginning
982    * of a scoped name.  It then parses the subsequent identifier and
983    * double colon tokens, builds the scoped name, and finds the symbol
984    * table entry with that name.
985    **/
986   SymtabEntry scopedName () throws IOException
987   {
988     boolean     globalScope  = false;
989     boolean     partialScope = false;
990     String      name         = null;
991     SymtabEntry entry        = null;
992     try
993     {
994       if (token.equals (Token.DoubleColon))
995         globalScope = true;
996       else
997       {
998         if (token.equals (Token.Object))
999         {
1000           name = "Object";
1001           match (Token.Object);
1002         }
1003         else if (token.type == Token.ValueBase)
1004         {
1005           name = "ValueBase";
1006           match (Token.ValueBase);
1007         }
1008         else
1009         {
1010           name = token.name;
1011           match (Token.Identifier);
1012         }
1013       }
1014       while (token.equals (Token.DoubleColon))
1015       {
1016         match (Token.DoubleColon);
1017         partialScope = true;
1018         if (name != null)
1019           name = name + '/' + token.name;
1020         else
1021           name = token.name;
1022         match (Token.Identifier);
1023       }
1024       if (globalScope)
1025         entry = parser.recursiveQualifiedEntry (name);
1026       else if (partialScope)
1027         entry = parser.recursivePQEntry (name, parser.currentModule);
1028       else
1029         entry = parser.unqualifiedEntryWMod (name, parser.currentModule);
1030     }
1031     catch (ParseException e)
1032     {
1033       entry = null;
1034     }
1035     return entry;
1036   } // scopedName
1037 
1038   /**
1039    * Skip to the end of the line.
1040    **/
1041   void skipToEOL () throws IOException
1042   {
1043     scanner.skipLineComment ();
1044   } // skipToEOL
1045 
1046   /**
1047    * This method skips the data in the input file until the specified
1048    * character is encountered, then it returns the next token.
1049    **/
1050   String skipUntil (char c) throws IOException
1051   {
1052     if (!(lastWasMacroID && c == '('))
1053       token = scanner.skipUntil (c);
1054     return tokenToString ();
1055   } // skipUntil
1056 
1057   /**
1058    * This method displays a Parser Exception complete with line number
1059    * and position information with the given message string.
1060    **/
1061   void parseException (String message)
1062   {
1063     // <d62023> Suppress warnings
1064     if (!parser.noWarn)
1065       ParseException.warning (scanner, message);
1066   } // parseException
1067 
1068   // For Pragma
1069   ///////////////
1070   // For macro expansion
1071 
1072   /**
1073    *
1074    **/
1075   String expandMacro (String macroDef, Token t) throws IOException, ParseException
1076   {
1077     token = t;
1078     // Get the parameter values from the macro 'call'
1079     Vector parmValues = getParmValues ();
1080 
1081     // Get the parameter names from the macro definition
1082     // NOTE:  a newline character is appended here so that when
1083     // getStringToEOL is called, it stops scanning at the end
1084     // of this string.
1085     scanner.scanString (macroDef + '\n');
1086     Vector parmNames = new Vector ();
1087     macro (parmNames);
1088 
1089     if (parmValues.size () < parmNames.size ())
1090       throw ParseException.syntaxError (scanner, Token.Comma, Token.RightParen);
1091     else if (parmValues.size () > parmNames.size ())
1092       throw ParseException.syntaxError (scanner, Token.RightParen, Token.Comma);
1093 
1094     macroDef = scanner.getStringToEOL ();
1095     for (int i = 0; i < parmNames.size (); ++i)
1096       macroDef = replaceAll (macroDef, (String)parmNames.elementAt (i), (String)parmValues.elementAt (i));
1097     return removeDoublePound (macroDef);
1098   } // expandMacro
1099 
1100   // This method is only used by the macro expansion methods.
1101   /**
1102    *
1103    **/
1104   private void miniMatch (int type) throws ParseException
1105   {
1106     // A normal production would now execute:
1107     // match (type);
1108     // But match reads the next token.  I don't want to do that now.
1109     // Just make sure the current token is a 'type'.
1110     if (!token.equals (type))
1111       throw ParseException.syntaxError (scanner, type, token.type);
1112   } // miniMatch
1113 
1114   /**
1115    *
1116    **/
1117   private Vector getParmValues () throws IOException, ParseException
1118   {
1119     Vector values = new Vector ();
1120     if (token.equals (Token.Identifier))
1121     {
1122       match (Token.Identifier);
1123       miniMatch (Token.LeftParen);
1124     }
1125     else if (!token.equals (Token.MacroIdentifier))
1126       throw ParseException.syntaxError (scanner, Token.Identifier, token.type);
1127 
1128     if (!token.equals (Token.RightParen))
1129     {
1130       values.addElement (scanner.getUntil (',', ')').trim ());
1131       token = scanner.getToken ();
1132       macroParmValues (values);
1133     }
1134     return values;
1135   } // getParmValues
1136 
1137   /**
1138    *
1139    **/
1140   private void macroParmValues (Vector values) throws IOException, ParseException
1141   {
1142     while (!token.equals (Token.RightParen))
1143     {
1144       miniMatch (Token.Comma);
1145       values.addElement (scanner.getUntil (',', ')').trim ());
1146       token = scanner.getToken ();
1147     }
1148   } // macroParmValues
1149 
1150   /**
1151    *
1152    **/
1153   private void macro (Vector parmNames) throws IOException, ParseException
1154   {
1155     match (token.type);
1156     match (Token.LeftParen);
1157     macroParms (parmNames);
1158     miniMatch (Token.RightParen);
1159   } // macro
1160 
1161   /**
1162    *
1163    **/
1164   private void macroParms (Vector parmNames) throws IOException, ParseException
1165   {
1166     if (!token.equals (Token.RightParen))
1167     {
1168       parmNames.addElement (token.name);
1169       match (Token.Identifier);
1170       macroParms2 (parmNames);
1171     }
1172   } // macroParms
1173 
1174   /**
1175    *
1176    **/
1177   private void macroParms2 (Vector parmNames) throws IOException, ParseException
1178   {
1179     while (!token.equals (Token.RightParen))
1180     {
1181       match (Token.Comma);
1182       parmNames.addElement (token.name);
1183       match (Token.Identifier);
1184     }
1185   } // macroParms2
1186 
1187   /**
1188    *
1189    **/
1190   private String replaceAll (String string, String from, String to)
1191   {
1192     int index = 0;
1193     while (index != -1)
1194     {
1195       index = string.indexOf (from, index);
1196       if (index != -1)
1197       {
1198         if (!embedded (string, index, index + from.length ()))
1199           if (index > 0 && string.charAt(index) == '#')
1200             string = string.substring (0, index) + '"' + to + '"' + string.substring (index + from.length ());
1201           else
1202             string = string.substring (0, index) + to + string.substring (index + from.length ());
1203         index += to.length ();
1204       }
1205     }
1206     return string;
1207   } // replaceAll
1208 
1209   /**
1210    *
1211    **/
1212   private boolean embedded (String string, int index, int endIndex)
1213   {
1214     // Don't replace if found substring is not an independent id.
1215     // For example, don't replace "thither".indexOf ("it", 0)
1216     boolean ret    = false;
1217     char    preCh  = index == 0 ? ' ' : string.charAt (index - 1);
1218     char    postCh = endIndex >= string.length () - 1 ? ' ' : string.charAt (endIndex);
1219     if ((preCh >= 'a' && preCh <= 'z') || (preCh >= 'A' && preCh <= 'Z'))
1220       ret = true;
1221     else if ((postCh >= 'a' && postCh <= 'z') || (postCh >= 'A' && postCh <= 'Z') || (postCh >= '0' && postCh <= '9') || postCh == '_')
1222       ret = true;
1223     else
1224       ret = inQuotes (string, index);
1225     return ret;
1226   } // embedded
1227 
1228   /**
1229    *
1230    **/
1231   private boolean inQuotes (String string, int index)
1232   {
1233     int quoteCount = 0;
1234     for (int i = 0; i < index; ++i)
1235       if (string.charAt (i) == '"') ++quoteCount;
1236     // If there are an odd number of quotes before this region,
1237     // then this region is within quotes
1238     return quoteCount % 2 != 0;
1239   } // inQuotes
1240 
1241   /**
1242    * Remove any occurrences of ##.
1243    **/
1244   private String removeDoublePound (String string)
1245   {
1246     int index = 0;
1247     while (index != -1)
1248     {
1249       index = string.indexOf ("##", index);
1250       if (index != -1)
1251       {
1252         int startSkip = index - 1;
1253         int stopSkip  = index + 2;
1254         if (startSkip < 0)
1255           startSkip = 0;
1256         if (stopSkip >= string.length ())
1257           stopSkip = string.length () - 1;
1258         while (startSkip > 0 &&
1259                (string.charAt (startSkip) == ' ' ||
1260                string.charAt (startSkip) == '\t'))
1261           --startSkip;
1262         while (stopSkip < string.length () - 1 &&
1263                (string.charAt (stopSkip) == ' ' ||
1264                string.charAt (stopSkip) == '\t'))
1265           ++stopSkip;
1266         string = string.substring (0, startSkip + 1) + string.substring (stopSkip);
1267       }
1268     }
1269     return string;
1270   } // removeDoublePound
1271 
1272   // For macro expansion
1273   ///////////////
1274 
1275   /**
1276    *
1277    **/
1278   private String getFilename (String name) throws FileNotFoundException
1279   {
1280     String fullName = null;
1281     File file = new File (name);
1282     if (file.canRead ())
1283       fullName = name;
1284     else
1285     {
1286       Enumeration pathList = parser.paths.elements ();
1287       while (!file.canRead () && pathList.hasMoreElements ())
1288       {
1289         fullName = (String)pathList.nextElement () + File.separatorChar + name;
1290         file = new File (fullName);
1291       }
1292       if (!file.canRead ())
1293         throw new FileNotFoundException (name);
1294     }
1295     return fullName;
1296   } // getFilename
1297 
1298   /**
1299    *
1300    **/
1301   private void match (int type) throws IOException, ParseException
1302   {
1303     if (!token.equals (type))
1304       throw ParseException.syntaxError (scanner, type, token.type);
1305     token = scanner.getToken ();
1306 
1307     // <d62023> Added for convenience, but commented-out because there is
1308     // no reason to issue warnings for tokens scanned during preprocessing.
1309     // See issueTokenWarnings().
1310     //issueTokenWarnings ();
1311 
1312     //System.out.println ("Preprocessor.match token = " + token.type);
1313     //if (token.equals (Token.Identifier) || token.equals (Token.MacroIdentifier))
1314     //  System.out.println ("Preprocessor.match token name = " + token.name);
1315 
1316     // If the token is a defined thingy, scan the defined string
1317     // instead of the input stream for a while.
1318     if (token.equals (Token.Identifier) || token.equals (Token.MacroIdentifier))
1319     {
1320       String string = (String)symbols.get (token.name);
1321       if (string != null && !string.equals (""))
1322         // If this is a macro, parse the macro
1323         if (macros.contains (token.name))
1324         {
1325           scanner.scanString (expandMacro (string, token));
1326           token = scanner.getToken ();
1327         }
1328         // else this is just a normal define
1329         else
1330         {
1331           scanner.scanString (string);
1332           token = scanner.getToken ();
1333         }
1334     }
1335   } // match
1336 
1337   // <d62023>
1338   /**
1339    * Issue warnings about tokens scanned during preprocessing.
1340    **/
1341   private void issueTokenWarnings ()
1342   {
1343     if (parser.noWarn)
1344       return;
1345 
1346     // There are no keywords defined for preprocessing (only directives), so:
1347     //
1348     // 1.) Do not issue warnings for identifiers known to be keywords in
1349     //     another level of IDL.
1350     // 2.) Do not issue warnings for identifiers that collide with keywords
1351     //     in letter, but not case.
1352     // 3.) Do not issue warnings for deprecated keywords.
1353     //
1354     // Should we warn when a macro identifier replaces a keyword?  Hmmm.
1355 
1356     // Deprecated directives?  None to date.
1357     //if (token.isDirective () && token.isDeprecated ())
1358     //  ParseException.warning (scanner, Util.getMesage ("Deprecated.directive", token.name));
1359   } // issueTokenWarnings
1360 
1361   /**
1362    * This method is called when the parser encounters a left curly brace.
1363    * An extender of PragmaHandler may find scope information useful.
1364    * For example, the prefix pragma takes effect as soon as it is
1365    * encountered and stays in effect until the current scope is closed.
1366    * If a similar pragma extension is desired, then the openScope and
1367    * closeScope methods are available for overriding.
1368    * @param entry the symbol table entry whose scope has just been opened.
1369    *  Be aware that, since the scope has just been entered, this entry is
1370    *  incomplete at this point.
1371    **/
1372   void openScope (SymtabEntry entry)
1373   {
1374     for (int i = pragmaHandlers.size () - 1; i >= 0; --i)
1375     {
1376       PragmaHandler handler = (PragmaHandler)pragmaHandlers.elementAt (i);
1377       handler.openScope (entry);
1378     }
1379   } // openScope
1380 
1381   /**
1382    * This method is called when the parser encounters a right curly brace.
1383    * An extender of PragmaHandler may find scope information useful.
1384    * For example, the prefix pragma takes effect as soon as it is
1385    * encountered and stays in effect until the current scope is closed.
1386    * If a similar pragma extension is desired, then the openScope and
1387    * closeScope methods are available for overriding.
1388    * @param entry the symbol table entry whose scope has just been closed.
1389    **/
1390   void closeScope (SymtabEntry entry)
1391   {
1392     for (int i = pragmaHandlers.size () - 1; i >= 0; --i)
1393     {
1394       PragmaHandler handler = (PragmaHandler)pragmaHandlers.elementAt (i);
1395       handler.closeScope (entry);
1396     }
1397   } // closeScope
1398 
1399   private Parser    parser;
1400   private Scanner   scanner;
1401   private Hashtable symbols;
1402   private Vector    macros;
1403 
1404   // The logic associated with this stack is scattered above.
1405   // A concise map of the logic is:
1406   // case #if false, #ifdef false, #ifndef true
1407   //   push (false);
1408   //   skipToEndifOrElse ();
1409   // case #if true, #ifdef true, #ifndef false
1410   //   push (true);
1411   // case #elif <conditional>
1412   //   if (top == true)
1413   //     skipToEndif ();
1414   //   else if (conditional == true)
1415   //     pop ();
1416   //     push (true);
1417   //   else if (conditional == false)
1418   //     skipToEndifOrElse ();
1419   // case #else
1420   //   if (top == true)
1421   //     skipToEndif ();
1422   //   else
1423   //     pop ();
1424   //     push (true);
1425   // case #endif
1426   //   pop ();
1427   private        Stack  alreadyProcessedABranch = new Stack ();
1428                  Token  token;
1429 
1430   private static String indent = "";
1431 }