/*
 * Copyright 1999-2009 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */
/*
 * COMPONENT_NAME: idl.parser
 *
 * ORIGINS: 27
 *
 * Licensed Materials - Property of IBM
 * 5639-D57 (C) COPYRIGHT International Business Machines Corp. 1997, 1999
 * RMI-IIOP v1.0
 *
 */

package com.sun.tools.corba.se.idl;

// NOTES:
// -F46082.51<daz> Remove -stateful feature.
// -D52042<daz> Allow floating-point constants to be initialized with
//  integral as well as floating-point literals.  No other variations allowed.
// -D58058<daz> Set index array type to long rather than array element type.
// -D56351<daz> Update computation of RepositoryIDs to CORBA 2.3 (see spec.).
// -D57110<daz> Provide method() to set/clear ability for scoped names to
//  resolve to modules.  Allows rep. ids to be assigned to modules.
// -D46094<daz> Prohibit exceptions from appearing wihtin structs, unions, exceptions.
// -D46094<daz> Prohibit attributes from appearing as operation parameter types,
//  operation return types, attribute types.
// -D59067<daz> Prohibit nested value boxes.
// -D59166<daz> Prohibit collisions between keywords and non-escaped identifiers.
// -D59809<daz> At Pigeonhole(), add map short name of CORBA types to long name
//  (e.g., CORBA/StringValue --> org/omg/CORBA/StringValue), which allows fully-
//  qualified CORBA type names to resolve successfully.
// -F60858.1<daz> Support "-corba" option, level <= 2.2: issue warning for
//  keyowrd collisions;
// -D60942<daz> Prohibit operations from appearing within parameter types.
// -D61643<daz> Repair pigeonhole() to correctly filter bad RepIDs.
// -D62023<daz> Support -noWarn option; Issue warnings when tokens are
//  deprecated keywords or keywords in greater release version.
// -D61919<daz> Emit entries for modules originally opened in #include files
//  appearing at global scope and then reopened in the main IDL file.  Only
//  types appearing in the main IDL source will be emitted.

import java.io.EOFException;
import java.io.IOException;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Stack;
import java.util.Vector;
import java.util.List ;
import java.util.ArrayList ;
import java.util.Iterator ;

import java.math.BigInteger;

import com.sun.tools.corba.se.idl.constExpr.*;

/**
 *
 **/
class Parser
{
  /**
   *
   **/
  Parser (Preprocessor preprocessor, Arguments arguments, Hashtable overrides,
      Hashtable symtab, SymtabFactory stFac, ExprFactory exprFac, String [] genKeywords)
  {
    this.arguments = arguments;
    noWarn         = arguments.noWarn; // <d62023>
    corbaLevel     = arguments.corbaLevel; // <f60858.1>
    paths          = arguments.includePaths;
    symbols        = arguments.definedSymbols;
    verbose        = arguments.verbose;
    emitAll        = arguments.emitAll;
    // <f46082.46.01>
    cppModule      = arguments.cppModule;
    // <f46082.51> Remove -stateful feature.
    //parseStateful  = arguments.parseStateful;
    overrideNames  = (overrides == null) ? new Hashtable () : overrides;
    symbolTable    = (symtab == null) ? new Hashtable () : symtab;
    keywords       = (genKeywords == null) ? new String [0] : genKeywords;
    stFactory      = stFac;
    exprFactory    = exprFac;
    currentModule  = topLevelModule = new ModuleEntry ();
    prep           = preprocessor;
    repIDStack.push (new IDLID ());
    addPrimEntries ();
  } // ctor

  /**
   *
   **/
  void parse (String file) throws IOException
  {
    IncludeEntry fileEntry = stFactory.includeEntry ();
    fileEntry.name ('"' + file + '"');
    try
    {
      // Set absolute file path
      fileEntry.absFilename (Util.getAbsolutePath (file, paths));
    }
    catch (IOException ioe)
    {}

    // <f46082.51> Remove -stateful feature.
    //scanner = new Scanner (fileEntry, keywords, verbose, parseStateful, emitAll);
    // <f60585.1> Support "-corba [level]" option.
    //scanner = new Scanner (fileEntry, keywords, verbose, emitAll);
    scanner = new Scanner (fileEntry, keywords, verbose, emitAll, corbaLevel,
        arguments.scannerDebugFlag );
    topLevelModule.sourceFile (fileEntry);

    // Prime the pump...
    // Match handles preprocessor directives, so use match to
    // call scanner.getToken just in case the first token is
    // such a directive.  But match depends on the token
    // already having a value, so fudge something.
    token = new Token (0);
    tokenHistory.insert (token); // Initialize look back buffer <26jul1997daz>.
    try
    {
      match (0);
      if (token.equals (Token.EOF))
        ParseException.nothing (file);
      else
        specification (topLevelModule);
    }
    catch (ParseException exception)  // Match MIGHT throw this
    {
      // It has already been reported, just end.
    }
    catch (EOFException exception)  // skipToSemicolon MIGHT throw this
    {
      // It has already been reported, just end.
    }
  } // parse

  /**
   *
   **/
  private void addPrimEntries ()
  {
    symbolTable.put ("short", stFactory.primitiveEntry ("short"));
    symbolTable.put ("long", stFactory.primitiveEntry ("long"));
    symbolTable.put ("long long", stFactory.primitiveEntry ("long long"));
    symbolTable.put ("unsigned short", stFactory.primitiveEntry ("unsigned short"));
    symbolTable.put ("unsigned long", stFactory.primitiveEntry ("unsigned long"));
    symbolTable.put ("unsigned long long", stFactory.primitiveEntry ("unsigned long long"));
    symbolTable.put ("char", stFactory.primitiveEntry ("char"));
    symbolTable.put ("wchar", stFactory.primitiveEntry ("wchar"));
    symbolTable.put ("float", stFactory.primitiveEntry ("float"));
    //Support fixed type: symbolTable.put ("fixed", stFactory.primitiveEntry ("fixed"));
    symbolTable.put ("double", stFactory.primitiveEntry ("double"));
    symbolTable.put ("boolean", stFactory.primitiveEntry ("boolean"));
    symbolTable.put ("octet", stFactory.primitiveEntry ("octet"));
    symbolTable.put ("any", stFactory.primitiveEntry ("any"));

    InterfaceEntry object = stFactory.interfaceEntry();
    object.name ("Object");
    symbolTable.put ("Object", object);

    ValueEntry valueBase = stFactory.valueEntry();
    valueBase.name ("ValueBase");
    symbolTable.put ("ValueBase", valueBase);

    // put these same entries in the lowercase symbol table
    lcSymbolTable.put ("short", stFactory.primitiveEntry ("short"));
    lcSymbolTable.put ("long", stFactory.primitiveEntry ("long"));
    lcSymbolTable.put ("long long", stFactory.primitiveEntry ("long long"));
    lcSymbolTable.put ("unsigned short", stFactory.primitiveEntry ("unsigned short"));
    lcSymbolTable.put ("unsigned long", stFactory.primitiveEntry ("unsigned long"));
    lcSymbolTable.put ("unsigned long long", stFactory.primitiveEntry ("unsigned long long"));
    lcSymbolTable.put ("char", stFactory.primitiveEntry ("char"));
    lcSymbolTable.put ("wchar", stFactory.primitiveEntry ("wchar"));
    lcSymbolTable.put ("float", stFactory.primitiveEntry ("float"));
    // Support fixed type: lcSymbolTable.put ("fixed", stFactory.primitiveEntry ("fixed"));
    lcSymbolTable.put ("double", stFactory.primitiveEntry ("double"));
    lcSymbolTable.put ("boolean", stFactory.primitiveEntry ("boolean"));
    lcSymbolTable.put ("octet", stFactory.primitiveEntry ("octet"));
    lcSymbolTable.put ("any", stFactory.primitiveEntry ("any"));
    lcSymbolTable.put ("object", object);
    lcSymbolTable.put ("valuebase", valueBase);
  } // addPrimEntries

  /**
   *
   **/
  private void specification (ModuleEntry entry) throws IOException
  {
    while (!token.equals (Token.EOF))
    {
      definition (entry);
      addToEmitList (entry);
    }
  } // specification

  // ModuleEntry is the topLevelModule; add its contained types to the emit list.
  /**
   *
   **/
  private void addToEmitList (ModuleEntry entry)
  {
    for (Enumeration e = entry.contained ().elements (); e.hasMoreElements();)
    {
      SymtabEntry emitEntry = (SymtabEntry)e.nextElement ();
      if (emitEntry.emit ())
      {
        emitList.addElement (emitEntry);

        // <d61919> I think the absence of the following statement was an
        // oversight.  If module X.Y.Z first appears in an include file, then is
        // reopened in the main IDL source, this statement guarantees that X.Y.Z
        // definitions within the main IDL source are emitted.
        ///---------------------------------------------------------------------
        // If any of this module's elements should be emitted, add
        // this module to the emit list.
        if (emitEntry instanceof ModuleEntry)
          checkContained ((ModuleEntry)emitEntry);
        if (emitEntry instanceof IncludeEntry)
        {
          includes.addElement (emitEntry.name ());
          includeEntries.addElement (emitEntry);
        }
      }
      else
        // If any of this module's elements should be emitted, add
        // this module to the emit list.
        if (emitEntry instanceof ModuleEntry)
          checkContained ((ModuleEntry)emitEntry);
    }
    entry.contained ().removeAllElements ();
  } // addToEmitList

  /**
   *
   **/
  private void checkContained (ModuleEntry entry)
  {
    // If any of this module's elements is to be emitted,
    // then add the module to the emit list.
    for (Enumeration e = entry.contained ().elements (); e.hasMoreElements ();)
    {
      SymtabEntry contained = (SymtabEntry)e.nextElement ();
      if (contained instanceof ModuleEntry)
        checkContained ((ModuleEntry)contained);
      if (contained.emit ())
      {
        if (!emitList.contains (entry))
          emitList.addElement (entry);
        entry.emit (true);
        break;
      }
    }
  } // checkContained

  /**
   *
   **/
  private void definition (ModuleEntry entry) throws IOException
  {
    try
    {
      switch (token.type)
      {
        case Token.Typedef:
        case Token.Struct:
        case Token.Union:
        case Token.Enum:
          typeDcl (entry);
          break;
        case Token.Const:
          constDcl (entry);
          break;
        case Token.Native:
          nativeDcl (entry);
          break;
        case Token.Exception:
          exceptDcl (entry);
          break;
        case Token.Interface:
          interfaceProd (entry, InterfaceEntry.NORMAL);
          break;
        case Token.Local:
          match( Token.Local ) ;
          if (token.type ==  Token.Interface)
              interfaceProd( entry, InterfaceEntry.LOCAL ) ;
          else
              throw ParseException.syntaxError( scanner, new int[] {
                  Token.Interface }, token.type ) ;
          break ;
        case Token.Module:
          module (entry);
          break;
        case Token.Abstract:
          match (Token.Abstract);
          if (token.type == Token.Interface)
            interfaceProd (entry, InterfaceEntry.ABSTRACT);
          else if (token.type == Token.Valuetype)
            valueProd (entry, true);
          else
            throw ParseException.syntaxError (scanner, new int[] {
                Token.Interface, Token.Valuetype }, token.type);
          break;
        case Token.Custom:
        case Token.Valuetype:
          valueProd (entry, false);
          break;
        default:
          throw ParseException.syntaxError (scanner, new int[] {
              Token.Typedef, Token.Struct,    Token.Union,     Token.Enum,
              Token.Const,   Token.Exception, Token.Interface, Token.Valuetype,
              Token.Module }, token.type);
      }
      match (Token.Semicolon);
    }
    catch (ParseException e)
    {
      skipToSemicolon ();
    }
  } // definition

  /**
   *
   **/
  private void module (ModuleEntry entry) throws IOException, ParseException
  {
    match (Token.Module);
    repIDStack.push (((IDLID)repIDStack.peek ()).clone ());
    ModuleEntry newEntry = newModule (entry);
    ((IDLID)repIDStack.peek ()).appendToName (newEntry.name ());
    // comment must immediately precede "module" keyword
    newEntry.comment (tokenHistory.lookBack (1).comment);
    currentModule = newEntry;
    match (Token.Identifier);
    prep.openScope (newEntry);
    match (Token.LeftBrace);
    definition (newEntry);
    while (!token.equals (Token.EOF) && !token.equals (Token.RightBrace))
      definition (newEntry);
    prep.closeScope (newEntry);
    match (Token.RightBrace);
    currentModule = entry;
    repIDStack.pop ();
  } // module

  /**
   *
   **/
  private void interfaceProd (ModuleEntry entry, int interfaceType)
      throws IOException, ParseException
  {
    match (Token.Interface);
    String name = token.name;
    match (Token.Identifier);
    interface2 (entry, name, interfaceType);
  } // interfaceProd

  /**
   *
   **/
  private void interface2 (ModuleEntry module, String name, int interfaceType)
      throws IOException, ParseException
  {
    if (token.type == Token.Colon || token.type == Token.LeftBrace) {
        repIDStack.push (((IDLID)repIDStack.peek ()).clone ());
        InterfaceEntry entry = stFactory.interfaceEntry (module,
            (IDLID)repIDStack.peek ());
        entry.sourceFile (scanner.fileEntry ());
        entry.name (name);
        entry.setInterfaceType(interfaceType);
        // Comment must immediately precede "[local | abstract] interface" keyword
        entry.comment (tokenHistory.lookBack (
            entry.getInterfaceType() == InterfaceEntry.NORMAL ? 2 : 3).comment);

        if (!ForwardEntry.replaceForwardDecl (entry))
            ParseException.badAbstract (scanner, entry.fullName ());
        pigeonhole (module, entry);
        ((IDLID)repIDStack.peek ()).appendToName (name);
        currentModule = entry;
        interfaceDcl (entry);
        currentModule = module;
        repIDStack.pop ();
    } else  { // This is a forward declaration
        ForwardEntry entry = stFactory.forwardEntry (module, (IDLID)repIDStack.peek ());
        entry.sourceFile (scanner.fileEntry ());
        entry.name (name);
        entry.setInterfaceType(interfaceType);
        // comment must immediately precede "interface" keyword.
        entry.comment (tokenHistory.lookBack (
            entry.getInterfaceType() == InterfaceEntry.NORMAL ? 2 : 3).comment);
        pigeonhole (module, entry);
    }
  } // interface2

  /**
   *
   **/
  private void interfaceDcl (InterfaceEntry entry) throws IOException, ParseException
  {
    if (token.type != Token.LeftBrace)
        inheritanceSpec (entry);
    else if (!entry.isAbstract ()) {
        SymtabEntry objectEntry = qualifiedEntry ("Object");
        SymtabEntry realOEntry  = typeOf (objectEntry);
        if (objectEntry == null)
            ;  // qualifiedEntry already generated an error message
        else if (!isInterface(realOEntry))
            ParseException.wrongType (scanner, overrideName ("Object"),
                "interface", objectEntry.typeName ());
        else
            entry.derivedFromAddElement (realOEntry, scanner);
    }

    prep.openScope (entry);
    match (Token.LeftBrace);
    while (token.type != Token.RightBrace)
        export (entry);
    prep.closeScope (entry);
    match (Token.RightBrace);
  } // interfaceDcl

  /**
   *
   **/
  private void export (InterfaceEntry entry) throws IOException
  {
    try
    {
      switch (token.type)
      {
        case Token.Typedef:
        case Token.Struct:
        case Token.Union:
        case Token.Enum:
          typeDcl (entry);
          break;
        case Token.Const:
          constDcl (entry);
          break;
        case Token.Native:
          nativeDcl (entry);
          break;
        case Token.Exception:
          exceptDcl (entry);
          break;
        case Token.Readonly:
        case Token.Attribute:
          attrDcl (entry);
          break;
        case Token.Oneway:
        case Token.Float:
        case Token.Double:
        case Token.Long:
        case Token.Short:
        case Token.Unsigned:
        case Token.Char:
        case Token.Wchar:
        case Token.Boolean:
        case Token.Octet:
        case Token.Any:
        case Token.String:
        case Token.Wstring:
        case Token.Identifier:
        case Token.Object:
        // <f46082.40> Value base type.
        case Token.ValueBase:
        case Token.DoubleColon:
        case Token.Void:
          opDcl (entry);
          break;
        // <f46082.51> Remove -stateful feature.
        //case Token.State:       if (parseStateful) {
        //                          stateDef (entry);
        //                          break; }
        default:
          throw ParseException.syntaxError(scanner, new int [] {
              Token.Typedef,  Token.Struct,      Token.Union,        Token.Enum,
              Token.Const,    Token.Exception,   Token.Readonly,     Token.Attribute,
              Token.Oneway,   Token.Float,       Token.Double,       Token.Long,
              Token.Short,    Token.Unsigned,    Token.Char,         Token.Wchar,
              Token.Boolean,  Token.Octet,       Token.Any,          Token.String,
              Token.Wstring,  Token.Identifier,  Token.DoubleColon,  Token.Void,
              Token.ValueBase }, token.type);
      }
      match (Token.Semicolon);
    }
    catch (ParseException exception)
    {
      skipToSemicolon ();
    }
  } // export

  private void inheritanceSpec (InterfaceEntry entry) throws IOException, ParseException
  {
    for (match (Token.Colon); ; match (Token.Comma)) {
        SymtabEntry parent = scopedName (entry.container (),
            stFactory.interfaceEntry ());
        SymtabEntry realParent = typeOf (parent);

        if (isInterfaceOnly (realParent)) {
            boolean isInterface = (realParent instanceof InterfaceEntry);
            if (entry.derivedFrom ().contains (realParent))
                ParseException.alreadyDerived (scanner, realParent.fullName (), entry.fullName ());
            else if (!entry.isAbstract () ||
                (((InterfaceType)realParent).getInterfaceType() == InterfaceType.ABSTRACT))
                entry.derivedFromAddElement (realParent, scanner);
            else
                ParseException.nonAbstractParent (scanner, entry.fullName (), parent.fullName ());
        } else if (isForward( realParent )) {
            ParseException.illegalForwardInheritance( scanner,
                entry.fullName(), parent.fullName() ) ;
        } else
            ParseException.wrongType (scanner, parent.fullName (), "interface", entryName (parent));

        if ((parent instanceof InterfaceEntry) && (((InterfaceEntry)parent).state () != null))
            if (entry.state () == null)
                entry.initState ();
            else
                throw ParseException.badState (scanner, entry.fullName ());

        if (token.type != Token.Comma)
            break;
    }
  } // inheritanceSpec

  // <57110> Member _moduleIsLegalType may be set by any feature to allow
  // method scopedName() and any of its helper methods -- qualifiedName(),
  // partlyQualifiedName(), and unqualifiedName() -- to return a ModuleEntry
  // rather than a parse error in the event a name resolves to a module.  The
  // flag must be cleared (set to false) to resume normal parsing behavior.
  //
  // Currently, this is used only when preprocessing the ID pragma directive.

  private boolean _isModuleLegalType = false;

  /**
   *
   **/
  public boolean isModuleLegalType ()
  {
    return _isModuleLegalType;
  }; // moduleIsLegaType

  /**
   *
   **/
  public void isModuleLegalType (boolean b)
  {
    _isModuleLegalType = b;
  }; // moduleIsLegalType

  /**
   *
   **/
  SymtabEntry scopedName (SymtabEntry container,
    SymtabEntry expected) throws IOException, ParseException
  {
    return scopedName( container, expected, true ) ;
  }

  SymtabEntry scopedName (SymtabEntry container, SymtabEntry expected,
    boolean mustBeReferencable ) throws IOException, ParseException
  {
    boolean globalScope  = false;
    boolean partialScope = false;
    String  name         = null;
    if (token.type == Token.DoubleColon)
      globalScope = true;
    else
    {
      if (token.type == Token.Object)
      {
        name = "Object";
        match (Token.Object);
      }
      else if (token.type == Token.ValueBase) // <f46082.40>
      {
        name = "ValueBase";
        match (Token.ValueBase);
      }
      else
      {
        name = token.name;
        match (Token.Identifier);
      }
    }
    while (token.type == Token.DoubleColon)
    {
      match (Token.DoubleColon);
      partialScope = true;
      if (name != null)
        name += '/' + token.name;
      else name = token.name;
        match (Token.Identifier);
    }
    SymtabEntry entry = null;
    if (globalScope)
      entry = qualifiedEntry (name);
    else if (partialScope)
      entry = partlyQualifiedEntry (name, container);
    else
      entry = unqualifiedEntry (name, container);

    if (entry == null)
      // Make the entry the expected entry.  The generators will
      // not be called now, since a semantic exception ocurred, but
      // the parse has to finish and something valid has to be
      // returned.
      (entry = expected).name (name);
    else if (!entry.isReferencable() && mustBeReferencable)
      throw ParseException.illegalIncompleteTypeReference( scanner, name ) ;

    return entry;
  } // scopedName

  private void valueProd (ModuleEntry entry, boolean isAbstract) throws IOException, ParseException
  {
    boolean isCustom = (token.type == Token.Custom);
    if (isCustom)
      match (Token.Custom);
    match (Token.Valuetype);
    String name = token.name;
    match (Token.Identifier);

    switch (token.type)
    {
      case Token.LeftBrace:
      case Token.Colon:
      case Token.Supports:
        value2 (entry, name, isAbstract, isCustom);
        return;
      case Token.Semicolon:
        if (isCustom)
          break;
        valueForwardDcl (entry, name, isAbstract);
        return;
    }
    if (isCustom)
      throw ParseException.badCustom (scanner);
    if (isAbstract)
      throw ParseException.abstractValueBox (scanner);
    valueBox (entry, name);
  }  // valueProd

  /**
   *
   **/
  private void value2 (ModuleEntry module, String name, boolean isAbstract,
      boolean isCustom) throws IOException, ParseException
  {
    repIDStack.push (((IDLID)repIDStack.peek ()).clone ());
    // The 'actual' repository ID will be calculated at the end of the
    // parsing phase, since it is based on the entire contents of the
    // declaration, and needs to have all forward references resolved:
    ValueEntry entry = stFactory.valueEntry (module, (IDLID)repIDStack.peek ());
    entry.sourceFile (scanner.fileEntry ());
    entry.name (name);
    entry.setInterfaceType (isAbstract ? InterfaceType.ABSTRACT : InterfaceType.NORMAL);
    entry.setCustom (isCustom);
    // Comment must immediately precede "[abstract | custom] value" keyword
    entry.comment (tokenHistory.lookBack ((isAbstract || isCustom) ? 3 : 2).comment);
    // If this value has been forward declared, there are probably
    // other values which derive from a ForwardValueEntry.  Replace
    // those ForwardValueEntry's with this ValueEntry:
    if (!ForwardEntry.replaceForwardDecl (entry))
      ParseException.badAbstract (scanner, entry.fullName ());
    pigeonhole (module, entry);
    ((IDLID)repIDStack.peek ()).appendToName (name);
    currentModule = entry;
    valueDcl (entry);
    entry.tagMethods ();
    currentModule = module;
    repIDStack.pop ();
  } // value2

  /**
   *
   **/
  private void valueDcl (ValueEntry entry) throws IOException, ParseException
  {
    if (token.type == Token.Colon)
      valueInheritanceSpec (entry);
    else if (!entry.isAbstract ())
    {
      SymtabEntry objectEntry = qualifiedEntry ("ValueBase");
      SymtabEntry realOEntry  = typeOf (objectEntry);
      if (objectEntry == null)
        ; // qualifiedEntry already generated an error message
      else if (!isValue (realOEntry))
        ParseException.wrongType (scanner, overrideName ("ValueBase"), "value", objectEntry.typeName ());
      else
        entry.derivedFromAddElement (realOEntry, false, scanner);
    }
    if (token.type == Token.Supports)
      valueSupportsSpec (entry);
    prep.openScope (entry);
    match (Token.LeftBrace);
    while (token.type != Token.RightBrace)
    {
      valueElement (entry);
    }
    prep.closeScope (entry);
    match (Token.RightBrace);
  } // valueDcl

  /**
   *
   **/
  private void valueInheritanceSpec (ValueEntry entry) throws IOException, ParseException
  {
    match (Token.Colon);
    boolean isTruncatable = (token.type == Token.Truncatable);
    if (isTruncatable)
        match (Token.Truncatable);
    for (; ; match (Token.Comma), isTruncatable = false) {
        SymtabEntry parent = scopedName (entry.container (),
            stFactory.valueEntry ());
        SymtabEntry realParent = typeOf (parent);
        if (isValue (realParent) && !(realParent instanceof ValueBoxEntry))
            entry.derivedFromAddElement (realParent, isTruncatable,
                scanner);
        else if (isForward(realParent))
            ParseException.illegalForwardInheritance( scanner,
                entry.fullName(), parent.fullName() ) ;
        else
            ParseException.wrongType (scanner,
                parent.fullName (), "value", entryName (parent));
        if (token.type != Token.Comma)
            break;
    }
  } // valueInheritanceSpec

  /**
   *
   **/
  private void valueSupportsSpec (ValueEntry entry) throws IOException, ParseException
  {
    match (Token.Supports) ;
    for (; ; match( Token.Comma ) ) {
        SymtabEntry parent = scopedName (entry.container (), stFactory.interfaceEntry ());
        SymtabEntry realParent = typeOf (parent);
        if (isInterface(realParent))
            entry.derivedFromAddElement (realParent, scanner);
        else
            ParseException.wrongType (scanner, parent.fullName (), "interface",
                entryName (parent));

        if (token.type != Token.Comma)
            break;
    }
  }  // valueSupportsSpec

  private void valueElement (ValueEntry entry) throws IOException, ParseException
  {
    if (entry.isAbstract ())
      export (entry);
    else
      switch (token.type)
      {
        case Token.Private:
        case Token.Public:
          valueStateMember (entry);
          break;
        case Token.Init:
        case Token.Factory:  // <d62023> "factory" supplants "init" in 2.4RTF
          initDcl (entry);
          break;
        case Token.Typedef:
        case Token.Struct:
        case Token.Union:
        case Token.Enum:
        case Token.Const:
        case Token.Native:
        case Token.Exception:
        case Token.Readonly:
        case Token.Attribute:
        case Token.Oneway:
        case Token.Float:
        case Token.Double:
        case Token.Long:
        case Token.Short:
        case Token.Unsigned:
        case Token.Char:
        case Token.Wchar:
        case Token.Boolean:
        case Token.Octet:
        case Token.Any:
        case Token.String:
        case Token.Wstring:
        case Token.Identifier:
        case Token.Object:
        case Token.ValueBase:
        case Token.DoubleColon:
        case Token.Void:
          export (entry);
          break;
        default:
          throw ParseException.syntaxError(scanner, new int[] {
              Token.Private,  Token.Public,      Token.Init,         Token.ValueBase,
              Token.Typedef,  Token.Struct,      Token.Union,        Token.Enum,
              Token.Const,    Token.Exception,   Token.Readonly,     Token.Attribute,
              Token.Oneway,   Token.Float,       Token.Double,       Token.Long,
              Token.Short,    Token.Unsigned,    Token.Char,         Token.Wchar,
              Token.Boolean,  Token.Octet,       Token.Any,          Token.String,
              Token.Wstring,  Token.Identifier,  Token.DoubleColon,  Token.Void },
              token.type);
      }  // switch
  }  // valueElement

  // <f46082.40>
  /**
   *
   **/
  private void valueStateMember (ValueEntry entry) throws IOException, ParseException
  {
    TypedefEntry typedefEntry =
        stFactory.typedefEntry (entry, (IDLID)repIDStack.peek ());
    typedefEntry.sourceFile (scanner.fileEntry ());
    // comment must immediately precede "public", "private" keywords
    typedefEntry.comment (token.comment);
    boolean isPublic = (token.type == Token.Public);
    if (isPublic)
      match (Token.Public);
    else
      match (Token.Private);
    // <f46082.40> Add constructed types declared "inline" to the contained
    // vector of this value entry.
    boolean isConstTypeSpec =
        (token.type == Token.Struct || token.type == Token.Union || token.type == Token.Enum);
    // <f46082.40> Make typedefEntry anonymous.  If this line is removed,
    // the entry will be named incorrectly.  See <d50618>.
    typedefEntry.name ("");
    typedefEntry.type (typeSpec (typedefEntry));
    addDeclarators (entry, typedefEntry, isPublic);
    // <f46082.40>
    if (isConstTypeSpec)
      entry.addContained (typedefEntry);
    match (Token.Semicolon);
  }  // valueStateMember


  private void addDeclarators (ValueEntry entry, TypedefEntry typedefEntry,
      boolean isPublic) throws IOException, ParseException
  {
    int modifier = isPublic ? InterfaceState.Public : InterfaceState.Private;
    try
    {
      Vector typedefList = new Vector ();
      declarators (typedefEntry, typedefList);
      for (Enumeration e = typedefList.elements (); e.hasMoreElements ();)
        entry.addStateElement (
            new InterfaceState (modifier, (TypedefEntry)e.nextElement ()), scanner);
    }
    catch (ParseException exception)
    {
      skipToSemicolon ();
    }
  } // addDeclarators

  /**
   *
   **/
  private void initDcl (ValueEntry entry) throws IOException, ParseException
  {
    MethodEntry method = stFactory.methodEntry (entry, (IDLID)repIDStack.peek ());
    method.sourceFile (scanner.fileEntry ());
    // Comment must immediately precede "init" keyword:
    method.comment (token.comment);
    repIDStack.push (((IDLID)repIDStack.peek ()).clone ());
    ((IDLID)repIDStack.peek ()).appendToName (token.name);

    // <d62023> In 2.3 prelim, <init_dcl> ::= "init" "(" ...
    if (token.type == Token.Init)
    {
      method.name ("init");
      match (Token.Init);
      match (Token.LeftParen);
    }
    else // <d62023> In 2.4rtf, <init_dcl> ::= "factory" <Indentifier> "(" ...
    {
      match (Token.Factory);
      method.name (token.name);
      if (token.type == Token.MacroIdentifier)
        match (Token.MacroIdentifier);  // "(" already consumed.
      else
      {
        match (Token.Identifier);
        match (Token.LeftParen);
      }
    }

    if (token.type != Token.RightParen)
      for (;;)
      {
        initParamDcl (method);
        if (token.type == Token.RightParen)
          break;
        match (Token.Comma);
      }
    entry.initializersAddElement (method, scanner);
    match (Token.RightParen);
    match (Token.Semicolon);
    repIDStack.pop ();
  } // initDcl

  /**
   *
   **/
  private void initParamDcl (MethodEntry entry) throws IOException, ParseException
  {
    ParameterEntry parmEntry = stFactory.parameterEntry (entry, (IDLID)repIDStack.peek ());
    parmEntry.sourceFile (scanner.fileEntry());
    // Comment must immediately precede parameter attribute
    parmEntry.comment (token.comment);
    match (Token.In);
    parmEntry.passType (ParameterEntry.In);
    parmEntry.type (paramTypeSpec (entry));
    parmEntry.name (token.name);
    match (Token.Identifier);
    if (isntInList (entry.parameters (), parmEntry.name ()))
      entry.addParameter (parmEntry);
  } // initParamDcl

  /**
   *
   **/
  private void valueBox (ModuleEntry module, String name) throws IOException, ParseException
  {
    repIDStack.push (((IDLID)repIDStack.peek ()).clone ());
    // Note: The 'actual' repository ID will be calculated at the end of
    // the parsing phase, since it is based on the entire contents of the
    // declaration, and needs to have all forward references resolved:
    ValueEntry entry = stFactory.valueBoxEntry (module, (IDLID)repIDStack.peek ());
    entry.sourceFile (scanner.fileEntry ());
    entry.name (name);
    // comment must immediately precede "value" keyword
    entry.comment (tokenHistory.lookBack (2).comment);
    // <f46082.40> Value boxes may not be forwarded.
    // If this value has been forward declared, there are probably
    // other values which derive from a ForwardValueEntry.
    // Replace those ForwardValueEntry's with this ValueEntry:
    //if (!ForwardValueEntry.replaceForwardDecl (entry))
    //   ParseException.badAbstract (scanner, entry.fullName());
    SymtabEntry valueForward = (SymtabEntry)Parser.symbolTable.get (entry.fullName ());
    if (valueForward != null && valueForward instanceof ForwardEntry)
      ParseException.forwardedValueBox (scanner, entry.fullName ());
    pigeonhole (module, entry);
    ((IDLID)repIDStack.peek ()).appendToName (name);
    currentModule = entry;
    TypedefEntry typedefEntry = stFactory.typedefEntry (entry, (IDLID)repIDStack.peek ());
    typedefEntry.sourceFile (scanner.fileEntry ());
    typedefEntry.comment (token.comment);
    // <d50237> Workaround to place typedefEntry in the _contained vector of
    // this value box entry ONLY when <type_spec> is a constructed type declared
    // at this point (i.e., not an identifier that resolves to a constructed
    // type), so that emitters may generate bindings for it. <daz>
    boolean isConstTypeSpec =
        token.type == Token.Struct || token.type == Token.Union || token.type == Token.Enum;
    // <d50618> Make typedefEntry anonymous.  If this line is removed, the
    // entry will be named incorrectly.
    typedefEntry.name ("");
    typedefEntry.type (typeSpec (typedefEntry));
    // <d59067> Value boxes cannot be nested.
    if (typedefEntry.type () instanceof ValueBoxEntry)
      ParseException.nestedValueBox (scanner);
    //typedefEntry.name ("");
    entry.addStateElement (new InterfaceState (InterfaceState.Public, typedefEntry), scanner);
    if (isConstTypeSpec)
      entry.addContained (typedefEntry);
    currentModule = module;
    repIDStack.pop ();
  } // valueBox

  /**
   *
   **/
  private void valueForwardDcl (ModuleEntry module, String name, boolean isAbstract)
      throws IOException, ParseException
  {
    ForwardValueEntry entry = stFactory.forwardValueEntry (module, (IDLID)repIDStack.peek ());
    entry.sourceFile (scanner.fileEntry ());
    entry.name (name);
    entry.setInterfaceType(isAbstract ? InterfaceType.ABSTRACT : InterfaceType.NORMAL );
    // Comment must immediately precede "[abstract] value" keyword[s]
    entry.comment (tokenHistory.lookBack (isAbstract? 3 : 2).comment);
    pigeonhole (module, entry);
  } // valueForwardDcl

  private void nativeDcl (SymtabEntry entry) throws IOException, ParseException
  {
    match (Token.Native);
    NativeEntry nativeEntry = stFactory.nativeEntry (entry, (IDLID)repIDStack.peek ());
    nativeEntry.sourceFile (scanner.fileEntry ());
    // Comment must immediately precede "native" keyword
    nativeEntry.comment (tokenHistory.lookBack (1).comment);
    nativeEntry.name (token.name);
    match (Token.Identifier);
    pigeonhole (entry, nativeEntry);
  } // nativeDcl
  /**
   *
   **/
  private void constDcl (SymtabEntry entry) throws IOException, ParseException
  {
    match (Token.Const);
    ConstEntry constEntry = stFactory.constEntry (entry, (IDLID)repIDStack.peek ());
    constEntry.sourceFile (scanner.fileEntry ());
    // Comment must immediately precede "const" keyword
    constEntry.comment (tokenHistory.lookBack (1).comment);
    constType (constEntry);
    constEntry.name (token.name);
    match (Token.Identifier);
    match (Token.Equal);
    constEntry.value (constExp (constEntry));
    verifyConstType (constEntry.value (), typeOf (constEntry.type ()));
    pigeonhole (entry, constEntry);
  } // constDcl

  /**
   *
   **/
  private void constType (SymtabEntry entry) throws IOException, ParseException
  {
    switch (token.type)
    {
      case Token.Octet:
        entry.type( octetType()) ;
        break ;
      case Token.Long:
      case Token.Short:
      case Token.Unsigned:
        entry.type (integerType (entry));
        break;
      case Token.Char:
      case Token.Wchar:
        entry.type (charType ());
        break;
      case Token.Boolean:
        entry.type (booleanType ());
        break;
      case Token.Float:
      case Token.Double:
        entry.type (floatingPtType ());
        break;
      case Token.String:
      case Token.Wstring:
        entry.type (stringType (entry));
        break;
      case Token.Identifier:
      case Token.DoubleColon:
        entry.type (scopedName (entry.container (), stFactory.primitiveEntry ()));
        if (hasArrayInfo (entry.type ()))
          ParseException.illegalArray (scanner, "const");
        SymtabEntry entryType = typeOf (entry.type ());
        if (!((entryType instanceof PrimitiveEntry) || (entryType instanceof StringEntry)))
        {
          ParseException.wrongType(scanner, entry.fullName (), "primitive or string", entryName (entry.type ()));
          entry.type (qualifiedEntry ("long"));
        }
        else if (entryType instanceof PrimitiveEntry)
        {
          String any = overrideName ("any");
          if (entryType.name().equals (any))
          {
            ParseException.wrongType (scanner, entry.fullName (), "primitive or string (except " + any + ')', any);
            entry.type (qualifiedEntry ("long"));
          }
        }
        break;
      default:
        throw ParseException.syntaxError (scanner, new int [] {
                      Token.Long,   Token.Short,   Token.Unsigned, Token.Char,
                      Token.Wchar,  Token.Boolean, Token.Float,    Token.Double,
                      Token.String, Token.Wstring, Token.Identifier,
                      Token.DoubleColon }, token.type);
    }
  } // constType

  /**
   *
   **/
  private boolean hasArrayInfo (SymtabEntry entry)
  {
    while (entry instanceof TypedefEntry)
    {
      if (((TypedefEntry)entry).arrayInfo ().size () != 0)
        return true;
      entry = entry.type ();
    }
  return false;
  } // hasArrayInfo

  /**
   *
   **/
  public static String overrideName (String string)
  {
    String name = (String)overrideNames.get (string);
    return (name == null) ? string : name;
  } // overrideName

  // If entry is boolean, expression value must be boolean
  // If entry is float/double, expression value must be float/double
  // If entry is integral, expression value must be integral
  // If entry is string, expression value must be string

  /**
   *
   **/
  private void verifyConstType (Expression e, SymtabEntry t)
  {
    Object value = e.value ();
    if (value instanceof BigInteger)
      verifyIntegral ((Number)value, t);
    else if (value instanceof String)
      verifyString (e, t);
    else if (value instanceof Boolean)
      verifyBoolean (t);
    else if (value instanceof Character)
      verifyCharacter (e, t);
    else if (value instanceof Float || value instanceof Double)
      verifyFloat((Number)value, t);
    else if (value instanceof ConstEntry)
      verifyConstType (((ConstEntry)value).value (), t);
    else
      ParseException.wrongExprType (scanner, t.fullName (),
          (value == null) ? "" : value.toString ());
  } // verifyConstType

  private static final int MAX_SHORT  = 32767;
  private static final int MIN_SHORT  = -32768;
  private static final int MAX_USHORT = 65535;

  /**
   *
   **/
  private void verifyIntegral (Number n, SymtabEntry t)
  {
    boolean outOfRange = false;
    //KEEP: Useful for debugging com.sun.tools.corba.se.idl.constExpr package
    //System.out.println ("verifyIntegral, n = " + n.toString ());

    if (t == qualifiedEntry( "octet" )) {
        if ((n.longValue() > 255) || (n.longValue() < 0))
            outOfRange = true ;
    } else if (t == qualifiedEntry ("long")) {
        if (n.longValue () > Integer.MAX_VALUE || n.longValue() < Integer.MIN_VALUE)
            outOfRange = true;
    } else if (t == qualifiedEntry ("short")) {
        if (n.intValue () > Short.MAX_VALUE || n.intValue () < Short.MIN_VALUE)
            outOfRange = true;
    } else if (t == qualifiedEntry ("unsigned long")) {
        if (n.longValue () > (long)Integer.MAX_VALUE*2+1 || n.longValue() < 0)
            outOfRange = true;
    } else if (t == qualifiedEntry ("unsigned short")) {
        if (n.intValue () > (int) Short.MAX_VALUE*2+1 || n.intValue () < 0)
            outOfRange = true;
    } else if (t == qualifiedEntry ("long long")) {
        // BigInteger required because value being compared may exceed
        // java.lang.Long.MAX_VALUE/MIN_VALUE:
        BigInteger llMax = BigInteger.valueOf (Long.MAX_VALUE);
        BigInteger llMin = BigInteger.valueOf (Long.MIN_VALUE);
        if (((BigInteger)n).compareTo (llMax) > 0 ||
            ((BigInteger)n).compareTo (llMin) < 0)
            outOfRange = true;
    } else if (t == qualifiedEntry ("unsigned long long")) {
        BigInteger ullMax = BigInteger.valueOf (Long.MAX_VALUE).
            multiply (BigInteger.valueOf (2)).
            add (BigInteger.valueOf (1));
        BigInteger ullMin = BigInteger.valueOf (0);
        if (((BigInteger)n).compareTo (ullMax) > 0 ||
            ((BigInteger)n).compareTo (ullMin) < 0)
            outOfRange = true;
    } else {
        String got = null;
        // THIS MUST BE CHANGED; BIGINTEGER IS ALWAYS THE CONTAINER
        /*
        if (n instanceof Short)
          got = "short";
        else if (n instanceof Integer)
          got = "long";
        else
          got = "long long";
        */
        got = "long";
        ParseException.wrongExprType (scanner, t.fullName (), got);
    }

    if (outOfRange)
        ParseException.outOfRange (scanner, n.toString (), t.fullName ());
  } // verifyIntegral

  /**
   *
   **/
  private void verifyString (Expression e, SymtabEntry t)
  {
    String string = (String)(e.value()) ;
    if (!(t instanceof StringEntry)) {
        ParseException.wrongExprType (scanner, t.fullName (), e.type() );
    } else if (((StringEntry)t).maxSize () != null) {
        Expression maxExp = ((StringEntry)t).maxSize ();
        try {
            Number max = (Number)maxExp.value ();
            if (string.length () > max.intValue ())
                ParseException.stringTooLong (scanner, string, max.toString ());
        } catch (Exception exception) {
            // If the above statement is not valid and throws an
            // exception, then an error occurred and was reported
            // earlier.  Move on.
        }
    }

    if (!e.type().equals( t.name())) {
        // cannot mix strings and wide strings
        ParseException.wrongExprType (scanner, t.name(), e.type() ) ;
    }
  } // verifyString

  /**
   *
   **/
  private void verifyBoolean (SymtabEntry t)
  {
    if (!t.name ().equals (overrideName ("boolean")))
      ParseException.wrongExprType(scanner, t.name(), "boolean");
  } // verifyBoolean

  /**
   *
   **/
  private void verifyCharacter (Expression e, SymtabEntry t)
  {
    // Bug fix 4382578:  Can't compile a wchar literal.
    // Allow a Character to be either a char or a wchar.
    if (!t.name ().equals (overrideName ("char")) &&
        !t.name ().equals (overrideName ("wchar")) ||
        !t.name().equals(e.type()) )
        ParseException.wrongExprType (scanner, t.fullName(), e.type() ) ;
  } // verifyCharacter

  /**
   *
   **/
  private void verifyFloat (Number f, SymtabEntry t)
  {
    // <d52042> Added range checking for floats.
    //if (!(t.name ().equals (overrideName ("float")) ||
    //    t.name ().equals (overrideName ("double"))))
    //  ParseException.wrongExprType (scanner,
    //      t.fullName (), (f instanceof Float) ? "float" : "double");
    //KEEP: Useful for debugging com.sun.tools.corba.se.idl.constExpr package
    //System.out.println ("verifyFloat, f = " + f.toString ());
    boolean outOfRange = false;
    if (t.name ().equals (overrideName ("float")))
    {
      double absVal = (f.doubleValue () < 0.0) ?
          f.doubleValue () * -1.0 : f.doubleValue ();
      if ((absVal != 0.0) &&
          (absVal > Float.MAX_VALUE || absVal < Float.MIN_VALUE))
        outOfRange = true;
    }
    else if (t.name ().equals (overrideName ("double")))
    {
      // Cannot check range of double until BigDecimal is the basis
      // of all floating-point types.  Currently, it is Double.  The
      // parser will fail when instantiating a Double with an exception.
    }
    else
    {
      ParseException.wrongExprType (scanner, t.fullName (),
        (f instanceof Float) ? "float" : "double");
    }
    if (outOfRange)
      ParseException.outOfRange (scanner, f.toString (), t.fullName ());
  } // verifyFloat

  /**
   *
   **/
  Expression constExp (SymtabEntry entry) throws IOException, ParseException
  {
    // Parse the expression.
    Expression expr = orExpr (null, entry);

    // Set its target type.
    if (expr.type() == null)
      expr.type (entry.typeName ());
    // Compute its value and <d53042> coerce it to the target type.
    try
    {
      expr.evaluate ();

      // <d54042> Coerces integral value to Double if an integer literal
      // was used to initialize a floating-point constant expression.
      if (expr instanceof Terminal &&
          expr.value () instanceof BigInteger &&
          (overrideName (expr.type ()).equals ("float") ||
               overrideName (expr.type ()).indexOf ("double") >= 0))
      {
        expr.value (new Double (((BigInteger)expr.value ()).doubleValue ()));
      }
    }
    catch (EvaluationException exception)
    {
      ParseException.evaluationError (scanner, exception.toString ());
    }
    return expr;
  } // constExp

  /**
   *
   **/
  private Expression orExpr (Expression e, SymtabEntry entry) throws IOException, ParseException
  {
    if (e == null)
      e = xorExpr (null, entry);
    else
    {
      BinaryExpr b = (BinaryExpr)e;
      b.right (xorExpr (null, entry));
      e.rep (e.rep () + b.right ().rep ());
    }
    if (token.equals (Token.Bar))
    {
      match (token.type);
      Or or = exprFactory.or (e, null);
      or.type (entry.typeName ());
      or.rep (e.rep () + " | ");
      return orExpr (or, entry);
    }
    return e;
  } // orExpr

  /**
   *
   **/
  private Expression xorExpr (Expression e, SymtabEntry entry) throws IOException, ParseException
  {
    if (e == null)
      e = andExpr (null, entry);
    else
    {
      BinaryExpr b = (BinaryExpr)e;
      b.right (andExpr (null, entry));
      e.rep (e.rep () + b.right ().rep ());
    }
    if (token.equals (Token.Carat))
    {
      match (token.type);
      Xor xor = exprFactory.xor (e, null);
      xor.rep (e.rep () + " ^ ");
      xor.type (entry.typeName ());
      return xorExpr (xor, entry);
    }
    return e;
  } // xorExpr

  /**
   *
   **/
  private Expression andExpr (Expression e, SymtabEntry entry) throws IOException, ParseException
  {
    if (e == null)
      e = shiftExpr (null, entry);
    else
    {
      BinaryExpr b = (BinaryExpr)e;
      b.right (shiftExpr (null, entry));
      e.rep (e.rep () + b.right ().rep ());
    }
    if (token.equals (Token.Ampersand))
    {
      match (token.type);
      And and = exprFactory.and (e, null);
      and.rep(e.rep () + " & ");
      and.type (entry.typeName ());
      return andExpr (and, entry);
    }
    return e;
  } // andExpr

  /**
   *
   **/
  private Expression shiftExpr (Expression e, SymtabEntry entry) throws IOException, ParseException
  {
    if (e == null)
      e = addExpr (null, entry);
    else
    {
      BinaryExpr b = (BinaryExpr)e;
      b.right (addExpr (null, entry));
      e.rep (e.rep () + b.right ().rep ());
    }
    if (token.equals (Token.ShiftLeft))
    {
      match (token.type);
      ShiftLeft sl = exprFactory.shiftLeft (e, null);
      sl.type (entry.typeName ());
      sl.rep (e.rep () + " << ");
      return shiftExpr (sl, entry);
    }
    if (token.equals (Token.ShiftRight))
    {
      match (token.type);
      ShiftRight sr = exprFactory.shiftRight (e, null);
      sr.type (entry.typeName ());
      sr.rep (e.rep () + " >> ");
      return shiftExpr (sr, entry);
    }
    return e;
  } // shiftExpr

  /**
   *
   **/
  private Expression addExpr (Expression e, SymtabEntry entry) throws IOException, ParseException
  {
    if (e == null)
      e = multExpr (null, entry);
    else
    {
      BinaryExpr b = (BinaryExpr)e;
      b.right (multExpr (null, entry));
      e.rep (e.rep () + b.right ().rep ());
    }
    if (token.equals (Token.Plus))
    {
      match (token.type);
      Plus p = exprFactory.plus (e, null);
      p.type (entry.typeName ());
      p.rep (e.rep () + " + ");
      return addExpr (p, entry);
    }
    if (token.equals (Token.Minus))
    {
      match (token.type);
      Minus m = exprFactory.minus (e, null);
      m.type (entry.typeName ());
      m.rep (e.rep () + " - ");
      return addExpr (m, entry);
    }
    return e;
  } // addExpr

  /**
   *
   **/
  private Expression multExpr (Expression e, SymtabEntry entry) throws IOException, ParseException
  {
    if (e == null)
    e = unaryExpr (entry);
    else
    {
      BinaryExpr b = (BinaryExpr)e;
      b.right (unaryExpr (entry));
      e.rep (e.rep () + b.right ().rep ());
    }
    if (token.equals (Token.Star))
    {
      match (token.type);
      Times t = exprFactory.times (e, null);
      t.type (entry.typeName ());
      t.rep (e.rep () + " * ");
      return multExpr (t, entry);
    }
    if (token.equals (Token.Slash))
    {
      match (token.type);
      Divide d = exprFactory.divide (e, null);
      d.type (entry.typeName ());
      d.rep (e.rep () + " / ");
      return multExpr (d, entry);
    }
    if (token.equals (Token.Percent))
    {
      match (token.type);
      Modulo m = exprFactory.modulo (e, null);
      m.type (entry.typeName ());
      m.rep (e.rep () + " % ");
      return multExpr (m, entry);
    }
    return e;
  } // multExpr

  /**
   *
   **/
  private Expression unaryExpr (SymtabEntry entry) throws IOException, ParseException
  {
    if (token.equals (Token.Plus))
    {
      match (token.type);
      Expression e   = primaryExpr (entry);
      Positive   pos = exprFactory.positive (e);
      pos.type (entry.typeName());
      pos.rep ('+' + e.rep());
      return pos;
    }
    if (token.equals (Token.Minus))
    {
      match (token.type);
      Expression e   = primaryExpr (entry);
      Negative   neg = exprFactory.negative (e);
      neg.type (entry.typeName());
      neg.rep ('-' + e.rep());
      return neg;
    }
    if (token.equals (Token.Tilde))
    {
      match (token.type);
      Expression e   = primaryExpr (entry);
      Not        not = exprFactory.not (e);
      not.type (entry.typeName());
      not.rep ('~' + e.rep());
      return not;
    }
    return primaryExpr (entry);
  } // unaryExpr

  /**
   *
   **/
  private Expression primaryExpr (SymtabEntry entry)
      throws IOException, ParseException
  {
    Expression primary = null;
    if (parsingConditionalExpr)
    {
      prep.token = token; // Give current token to preprocessor
      primary    = prep.primaryExpr (entry);
      token      = prep.token; // Get the current token from preprocessor
    }
    else
      switch (token.type)
      {
        case Token.Identifier:
        case Token.DoubleColon:
          ConstEntry expectedC = stFactory.constEntry ();
          expectedC.value (exprFactory.terminal ("1", BigInteger.valueOf (1)));
          SymtabEntry ref = scopedName (entry.container (), expectedC);
          if (!(ref instanceof ConstEntry))
          {
            ParseException.invalidConst (scanner, ref.fullName ());
            // An error occurred.  Just give it some bogus value. <daz>
            //primary = exprFactory.terminal ("1", new Long (1));
            primary = exprFactory.terminal ("1", BigInteger.valueOf (1));
          }
          else
            primary = exprFactory.terminal ((ConstEntry)ref);
          break;
        case Token.BooleanLiteral:
        case Token.CharacterLiteral:
        case Token.IntegerLiteral:
        case Token.FloatingPointLiteral:
        case Token.StringLiteral:
          primary = literal (entry);
          break;
        case Token.LeftParen:
          match (Token.LeftParen);
          primary = constExp (entry);
          match (Token.RightParen);
          primary.rep ('(' + primary.rep () + ')');
          break;
        default:
          throw ParseException.syntaxError (scanner, new int [] {
              Token.Identifier, Token.DoubleColon, Token.Literal, Token.LeftParen},
              token.type);
      }
    return primary;
  } // primaryExpr

  /**
   *
   **/
  Expression literal (SymtabEntry entry) throws IOException, ParseException
  {
    String     string  = token.name;
    Expression literal = null;
    switch (token.type)
    {
      case Token.IntegerLiteral:
        match (Token.IntegerLiteral);
        try
        {
          literal = exprFactory.terminal (string, parseString (string));
          literal.type (entry.typeName ());
        }
        catch (NumberFormatException exception)
        {
          ParseException.notANumber (scanner, string);
          literal = exprFactory.terminal ("0", BigInteger.valueOf (0));
        }
        break;
      case Token.CharacterLiteral:
        boolean isWide = token.isWide();
        match (Token.CharacterLiteral);
        literal = exprFactory.terminal ("'" + string.substring (1) + "'",
            new Character (string.charAt (0)), isWide );
        break;
      case Token.FloatingPointLiteral:
        match (Token.FloatingPointLiteral);
        try
        {
          literal = exprFactory.terminal (string, new Double (string));
          literal.type (entry.typeName ());
        }
        catch (NumberFormatException e)
        {
          ParseException.notANumber (scanner, string);
        }
        break;
      case Token.BooleanLiteral:
        literal = booleanLiteral ();
        break;
      case Token.StringLiteral:
        literal = stringLiteral ();
        break;
      default:
        throw ParseException.syntaxError (scanner, Token.Literal,token.type);
    }
    return literal;
  } // literal

  /**
   *
   **/
  private BigInteger parseString (String string) throws NumberFormatException
  {
    int radix = 10;
    if (string.length() > 1)
      if (string.charAt (0) == '0')
        if (string.charAt (1) == 'x' || string.charAt (1) == 'X')
        {
          string = string.substring (2);
          radix = 16;
        }
        else
          radix = 8;
    return new BigInteger (string, radix);
  } // parseString

  /**
   *
   **/
  private Terminal booleanLiteral () throws IOException, ParseException
  {
    Boolean bool = null;
    if (token.name.equals ("TRUE"))
      bool = new Boolean (true);
    else if (token.name.equals ("FALSE"))
      bool = new Boolean (false);
    else
    {
      ParseException.invalidConst (scanner, token.name);
      bool = new Boolean (false);
    }
    String name = token.name;
    match (Token.BooleanLiteral);
    return exprFactory.terminal (name, bool);
  } // booleanLiteral

  /**
   *
   **/
  private Expression stringLiteral () throws IOException, ParseException
  {
    // If string literals appear together, concatenate them.  Ie:
    // "Twas " "brillig " "and " "the " "slithy " "toves"
    // becomes
    // "Twas brillig and the slithy toves"
    boolean isWide = token.isWide() ;
    String literal = "";
    do
    {
      literal += token.name;
      match (Token.StringLiteral);
    } while (token.equals (Token.StringLiteral));
    Expression stringExpr = exprFactory.terminal (literal, isWide );
    stringExpr.rep ('"' + literal + '"');
    return stringExpr;
  } // stringLiteral

  /**
   *
   **/
  private Expression positiveIntConst (SymtabEntry entry) throws IOException, ParseException
  {
    Expression e     = constExp (entry);
    Object     value = e.value ();
    while (value instanceof ConstEntry)
      value = ((ConstEntry)value).value ().value ();
    if (!(value instanceof Number) || value instanceof Float || value instanceof Double)
    {
      ParseException.notPositiveInt (scanner, e.rep ());
      //e = exprFactory.terminal ("1", new Long (1));
      e = exprFactory.terminal ("1", BigInteger.valueOf (1));
    }
    //else if (((Number)value).longValue () <= 0) {
    //   ParseException.notPositiveInt (scanner, value.toString ());
    //   e = exprFactory.terminal ("1", new Long (1)); }
    else if (((BigInteger)value).compareTo (BigInteger.valueOf (0)) <= 0)
    {
      ParseException.notPositiveInt (scanner, value.toString ());
      //e = exprFactory.terminal ("1", new Long (1)); <daz>
      e = exprFactory.terminal ("1", BigInteger.valueOf (1));
    }
    return e;
  } // positiveIntConst

  /**
   *
   **/
  private SymtabEntry typeDcl (SymtabEntry entry) throws IOException, ParseException
  {
    switch (token.type)
    {
      case Token.Typedef:
        match (Token.Typedef);
        return typeDeclarator (entry);
      case Token.Struct:
        return structType (entry);
      case Token.Union:
        return unionType (entry);
      case Token.Enum:
        return enumType (entry);
      default:
        throw ParseException.syntaxError (scanner, new int [] {
            Token.Typedef, Token.Struct, Token.Union, Token.Enum}, token.type);
    }
  } // typeDcl

  /**
   *
   **/
  private TypedefEntry typeDeclarator (SymtabEntry entry) throws IOException, ParseException
  {
    TypedefEntry typedefEntry = stFactory.typedefEntry (entry, (IDLID)repIDStack.peek ());
    typedefEntry.sourceFile (scanner.fileEntry ());
    // Comment must immediately precede "typedef" keyword
    typedefEntry.comment (tokenHistory.lookBack (1).comment);
    typedefEntry.type (typeSpec (entry));
    Vector typedefList = new Vector ();
    declarators (typedefEntry, typedefList);
    for (Enumeration e = typedefList.elements(); e.hasMoreElements();)
      pigeonhole (entry, (SymtabEntry)e.nextElement ());
    return typedefEntry;
  } // typeDeclarator

  /**
   *
   **/
  private SymtabEntry typeSpec (SymtabEntry entry) throws IOException, ParseException
  {
    return ((token.type == Token.Struct) ||
            (token.type == Token.Union)  ||
            (token.type == Token.Enum))
        ? constrTypeSpec (entry)
        : simpleTypeSpec (entry, true);
  } // typeSpec

  /**
   *
   **/
  private SymtabEntry simpleTypeSpec (SymtabEntry entry,
    boolean mustBeReferencable ) throws IOException, ParseException
  {
    // <f46082.40>
    //if ((token.type == Token.Identifier)  ||
    //    (token.type == Token.DoubleColon) ||
    //    (token.type == Token.Object)) {
    if ((token.type == Token.Identifier)  ||
        (token.type == Token.DoubleColon) ||
        (token.type == Token.Object)      ||
        (token.type == Token.ValueBase))
    {
      SymtabEntry container = ((entry instanceof InterfaceEntry) ||
                               (entry instanceof ModuleEntry)    ||
                               (entry instanceof StructEntry)    ||
                               (entry instanceof UnionEntry))
          ? entry
          : entry.container ();
      return scopedName (container, stFactory.primitiveEntry (),
        mustBeReferencable);
    }
    return ((token.type == Token.Sequence) ||
            (token.type == Token.String)   ||
            (token.type == Token.Wstring))
        ? templateTypeSpec (entry)
        : baseTypeSpec (entry);
  } // simpleTypeSpec

  /**
   *
   **/
  private SymtabEntry baseTypeSpec (SymtabEntry entry) throws IOException, ParseException
  {
    switch (token.type)
    {
      case Token.Float:
      case Token.Double:
        return floatingPtType ();
      case Token.Long:
      case Token.Short:
     case Token.Unsigned:
        return integerType (entry);
      case Token.Char:
      case Token.Wchar:
        return charType ();
      case Token.Boolean:
        return booleanType ();
     case Token.Octet:
        return octetType ();
      case Token.Any:
        return anyType ();
      // NOTE: Object and ValueBase are <base_type_spec>s, but both
      // are processed at simpleTypeSpec(), not here.  parmTypeSpec()
      // directly checks for these types.  Could make baseTypeSpec() do
      // the same
      default:
        throw ParseException.syntaxError (scanner, new int [] {
            Token.Float,    Token.Double, Token.Long,  Token.Short,
            Token.Unsigned, Token.Char,   Token.Wchar, Token.Boolean,
            Token.Octet,    Token.Any}, token.type);
    }
  } // baseTypeSpec

  /**
   *
   **/
  private SymtabEntry templateTypeSpec (SymtabEntry entry) throws IOException, ParseException
  {
    switch (token.type)
    {
      case Token.Sequence:
        return sequenceType (entry);
      case Token.String:
      case Token.Wstring:
        return stringType (entry);
    }
    throw ParseException.syntaxError (scanner, new int [] {Token.Sequence, Token.String, Token.Wstring}, token.type);
  } // templateTypeSpec

  /**
   *
   **/
  private SymtabEntry constrTypeSpec (SymtabEntry entry) throws IOException, ParseException
  {
    switch (token.type)
    {
      case Token.Struct:
        return structType (entry);
      case Token.Union:
        return unionType (entry);
      case Token.Enum:
        return enumType (entry);
    }
    throw ParseException.syntaxError (scanner, new int [] {Token.Struct, Token.Union, Token.Enum}, token.type);
  } // constrTypeSpec

  /**
   *
   **/
  private void declarators (TypedefEntry entry, Vector list) throws IOException, ParseException
  {
    for (; ; match (Token.Comma))
    {
      TypedefEntry newEntry = (TypedefEntry)entry.clone ();
      declarator (newEntry);
      if (isntInList (list, newEntry.name ()))
        list.addElement (newEntry);
      if (token.type != Token.Comma)
        break;
    }
  } // declarators

  /**
   *
   **/
  private void declarator (TypedefEntry entry) throws IOException, ParseException
  {
    entry.name (token.name);
    // If the declarator is commented then override the comment cloned from the parent
    // entry. <08aug1997daz>
    if (!token.comment.text ().equals (""))
      entry.comment (token.comment);
    match (Token.Identifier);
    while (token.type == Token.LeftBracket)
      fixedArraySize (entry);
  } // declarator

  /**
   *
   **/
  private PrimitiveEntry floatingPtType () throws IOException, ParseException
  {
    String name = "double";
    if (token.type == Token.Float)
    {
      match (Token.Float);
      name = "float";
    }
    else if (token.type == Token.Double)
      match (Token.Double);
    else
    {
      int [] expected = {Token.Float, Token.Double};
      ParseException.syntaxError (scanner, new int [] {Token.Float, Token.Double }, token.type);
    }
    PrimitiveEntry ret = null;
    try
    {
      ret = (PrimitiveEntry)qualifiedEntry (name);
    }
    catch (ClassCastException exception)
    {
      ParseException.undeclaredType (scanner, name);
    }
    return ret;
  } // floatingPtType

  /**
   *
   **/
  private PrimitiveEntry integerType (SymtabEntry entry) throws IOException, ParseException
  {
    String name = "";
    if (token.type == Token.Unsigned)
    {
      match (Token.Unsigned);
      name = "unsigned ";
    }
    name += signedInt();
    PrimitiveEntry ret = null;
    try
    {
      ret = (PrimitiveEntry) qualifiedEntry (name);
    }
    catch (ClassCastException exception)
    {
      ParseException.undeclaredType (scanner, name);
    }
    return ret;
  } // integerType

  /**
   *
   **/
  private String signedInt () throws IOException, ParseException
  {
    String ret = "long";
    if (token.type == Token.Long)
    {
      match (Token.Long);
      // <signedInt'> ::= "long" | e
      if (token.type == Token.Long)
      {
        ret = "long long";
        match (Token.Long);
      }
    }
    else if (token.type == Token.Short)
    {
      ret = "short";
      match (Token.Short);
    }
    else
      ParseException.syntaxError (scanner, new int [] {Token.Long, Token.Short}, token.type);
    return ret;
  } // signedInt

  /**
   *
   **/
  private PrimitiveEntry charType () throws IOException, ParseException
  {
    String tokenName;
    if (token.type == Token.Char)
    {
      match (Token.Char);
      tokenName = "char";
    }
    else
    {
      match (Token.Wchar);
      tokenName = "wchar";
    }
    PrimitiveEntry ret = null;
    try
    {
      ret = (PrimitiveEntry) qualifiedEntry (tokenName);
    }
    catch (ClassCastException exception)
    {
      ParseException.undeclaredType (scanner, overrideName (tokenName));
    }
    return ret;
  } // charType

  /**
   *
   **/
  private PrimitiveEntry booleanType () throws IOException, ParseException
  {
    PrimitiveEntry ret = null;
    match (Token.Boolean);
    try
    {
      ret = (PrimitiveEntry) qualifiedEntry ("boolean");
    }
    catch (ClassCastException exception)
    {
      ParseException.undeclaredType (scanner, overrideName ("boolean"));
    }
    return ret;
  } // booleanType

  /**
   *
   **/
  private PrimitiveEntry octetType () throws IOException, ParseException
  {
    PrimitiveEntry ret = null;
    match (Token.Octet);
    try
    {
      ret = (PrimitiveEntry) qualifiedEntry ("octet");
    }
    catch (ClassCastException exception)
    {
      ParseException.undeclaredType (scanner, overrideName ("octet"));
    }
    return ret;
  } // octetType

  /**
   *
   **/
  private SymtabEntry anyType () throws IOException, ParseException
  {
    match (Token.Any);
    try
    {
      return qualifiedEntry ("any");
    }
    catch (ClassCastException exception)
    {
      ParseException.undeclaredType (scanner, overrideName ("any"));
      return null;
    }
  } // anyType

  /**
   *
   **/
  private StructEntry structType (SymtabEntry entry) throws IOException,
    ParseException
  {
    match (Token.Struct);
    String name = token.name;
    match (Token.Identifier);
    StructEntry structEntry = null ;

    if (token.type == Token.LeftBrace) {
      repIDStack.push(((IDLID)repIDStack.peek ()).clone ()) ;
      structEntry = makeStructEntry( name, entry, false ) ;
      ((IDLID)repIDStack.peek ()).appendToName (name);
      prep.openScope (structEntry);
      match (Token.LeftBrace) ;
      member (structEntry) ;
      memberList2 (structEntry) ;
      prep.closeScope (structEntry);
      match (Token.RightBrace) ;
      repIDStack.pop() ;
    } else if (token.equals( Token.Semicolon )) {
      structEntry = makeStructEntry( name, entry, true ) ;
    } else {
      throw ParseException.syntaxError (scanner,
        new int[] { Token.Semicolon, Token.LeftBrace }, token.type);
    }
    return structEntry;
  } // structType

  private StructEntry makeStructEntry( String name, SymtabEntry entry,
    boolean isForward )
  {
    StructEntry structEntry = stFactory.structEntry (entry,
      (IDLID)repIDStack.peek () );
    structEntry.isReferencable( !isForward ) ;
    structEntry.sourceFile (scanner.fileEntry ());
    structEntry.name (name);
    // Comment must immediately preceed "struct" keyword
    structEntry.comment (tokenHistory.lookBack (1).comment);
    pigeonhole( entry, structEntry ) ;
    return structEntry ;
  }

  /**
   *
   **/
  private void memberList2 (StructEntry entry) throws IOException
  {
    while (token.type != Token.RightBrace)
      member (entry);
  } // memberList2

  /**
   *
   **/
  private void member (StructEntry entry) throws IOException
  {
    TypedefEntry newEntry = stFactory.typedefEntry(entry, (IDLID)repIDStack.peek());
    newEntry.sourceFile (scanner.fileEntry ());
    // comment must immediately precede <type_spec> lexeme
    newEntry.comment (token.comment);
    try
    {
      newEntry.type (typeSpec (entry));
      if (newEntry.type () == entry)
        throw ParseException.recursive (scanner, entry.fullName (),
            (token.name == null) ? "" : token.name);
      // <d46094> Exception cannot appear within a struct, union, or exception
      if (typeOf (newEntry) instanceof ExceptionEntry)
        throw ParseException.illegalException (scanner, entryName (entry));
      declarators (newEntry, entry.members ());
      match (Token.Semicolon);
    }
    catch (ParseException exception)
    {
      skipToSemicolon ();
    }
  } // member

  /**
   *
   **/
  private final boolean isConstTypeSpec (Token t)
  {
    return (t.type == Token.Struct || t.type == Token.Union || t.type == Token.Enum);
  } // isConstTypeSpec

  /**
   *
   **/
  private UnionEntry unionType (SymtabEntry entry) throws IOException, ParseException
  {
    match (Token.Union) ;
    String name = token.name ;
    match (Token.Identifier) ;
    UnionEntry unionEntry = null ;

    if (token.type == Token.Switch) {
      repIDStack.push (((IDLID)repIDStack.peek ()).clone ());
      unionEntry = makeUnionEntry( name, entry, false ) ;
      ((IDLID)repIDStack.peek ()).appendToName (name);
      match (Token.Switch);
      match (Token.LeftParen);
      unionEntry.type (switchTypeSpec (unionEntry));
      match (Token.RightParen);
      prep.openScope (unionEntry);
      match (Token.LeftBrace);
      switchBody (unionEntry);
      verifyUnion (unionEntry);
      prep.closeScope (unionEntry);
      match (Token.RightBrace);
      repIDStack.pop ();
    } else if (token.equals( Token.Semicolon )) {
      unionEntry = makeUnionEntry( name, entry, true ) ;
    } else {
      throw ParseException.syntaxError (scanner,
        new int[] { Token.Semicolon, Token.Switch }, token.type);
    }

    return unionEntry ;
  } // unionType

  private UnionEntry makeUnionEntry( String name, SymtabEntry entry,
    boolean isForward )
  {
    UnionEntry unionEntry = stFactory.unionEntry (entry,
      (IDLID)repIDStack.peek () );
    unionEntry.isReferencable( !isForward ) ;
    unionEntry.sourceFile (scanner.fileEntry ());
    unionEntry.name (name);
    // Comment must immediately preceed "union" keyword
    unionEntry.comment (tokenHistory.lookBack (1).comment);
    pigeonhole( entry, unionEntry ) ;
    return unionEntry ;
  }

  /**
   *
   **/
  private void verifyUnion (UnionEntry u)
  {
    if (u.typeName ().equals (overrideName ("boolean")))
    {
      if (caseCount (u) > 2)
        ParseException.noDefault (scanner);
    }
    else if (u.type () instanceof EnumEntry)
    {
      if (caseCount (u) > ((EnumEntry)u.type ()).elements ().size ())
        ParseException.noDefault (scanner);
    }
  } // verifyUnion

  /**
   *
   **/
  private long caseCount (UnionEntry u)
  {
    long cases = 0;
    Enumeration branches = u.branches ().elements ();
    while (branches.hasMoreElements ())
    {
      UnionBranch branch = (UnionBranch)branches.nextElement ();
      cases += branch.labels.size ();
      if (branch.isDefault)
        ++cases;
    }
    return cases;
  } // caseCount

  /**
   *
   **/
  private SymtabEntry switchTypeSpec (UnionEntry entry) throws IOException, ParseException
  {
    SymtabEntry ret = null;
    switch (token.type)
    {
       case Token.Long:
       case Token.Short:
       case Token.Unsigned:
         return integerType (entry);
       case Token.Char:
       case Token.Wchar:
         return charType();
       case Token.Boolean:
         return booleanType();
       case Token.Enum:
         return enumType (entry);
       case Token.Identifier:
       case Token.DoubleColon:
         ret = scopedName (entry, stFactory.primitiveEntry ());
         if (hasArrayInfo (entry.type ()))
           ParseException.illegalArray (scanner, "switch");
         SymtabEntry retType = typeOf (ret);
         if (!(retType instanceof EnumEntry || retType instanceof PrimitiveEntry))
           ParseException.wrongType (scanner, ret.fullName (),
               "long, unsigned long, short, unsigned short, char, boolean, enum",
               entryName (ret.type ()));
         else if (ret instanceof PrimitiveEntry)
         {
           SymtabEntry octet = qualifiedEntry ("octet");
           SymtabEntry flt   = qualifiedEntry ("float");
           SymtabEntry dbl   = qualifiedEntry ("double");
           if (retType == octet || retType == flt || retType == dbl)
             ParseException.wrongType (scanner, ret.fullName(),
                 "long, unsigned long, short, unsigned short, char, boolean, enum",
                 entryName(ret.type ()));
         }
         break;
       default:
         throw ParseException.syntaxError (scanner, new int [] {
             Token.Long,    Token.Short, Token.Unsigned, Token.Char,
             Token.Boolean, Token.Enum,  Token.Identifier,
             Token.DoubleColon }, token.type);
    }
    return ret;
  } // switchTypeSpec

  // This is only used by the union methods
  UnionBranch defaultBranch = null;

  /**
   *
   **/
  private void switchBody (UnionEntry entry) throws IOException, ParseException
  {
    caseProd (entry);
    while (!token.equals (Token.RightBrace))
      caseProd (entry);
    entry.defaultBranch ((defaultBranch == null) ? null : defaultBranch.typedef);
    defaultBranch = null;
  } // switchBody

  /**
   *
   **/
  private void caseProd (UnionEntry entry) throws IOException, ParseException
  {
    UnionBranch branch = new UnionBranch ();
    entry.addBranch (branch);
    caseLabel (entry, branch);
    while (token.equals (Token.Case) || token.equals (Token.Default))
      caseLabel (entry, branch);
    elementSpec (entry, branch);
    match (Token.Semicolon);
  } // caseProd

  /**
   *
   **/
  private void caseLabel (UnionEntry entry, UnionBranch branch) throws IOException, ParseException
  {
    if (token.type == Token.Case)
    {
      match (Token.Case);
      ConstEntry tmpEntry = stFactory.constEntry (entry, (IDLID)repIDStack.peek ());
      tmpEntry.sourceFile (scanner.fileEntry ());
      tmpEntry.type (entry);

      Expression  label;
      SymtabEntry type = typeOf (entry.type ());
      if (type instanceof EnumEntry)
        label = matchEnum ((EnumEntry)type);
      else
      {
        label = constExp (tmpEntry);
        verifyConstType (label, type);
      }
      if (entry.has (label))
        ParseException.branchLabel (scanner, label.rep ());
      branch.labels.addElement (label);
      match (Token.Colon);
    }
    else if (token.type == Token.Default)
    {
      match (Token.Default);
      match (Token.Colon);
      if (entry.defaultBranch () != null)
        ParseException.alreadyDefaulted (scanner);
      branch.isDefault = true;
      defaultBranch    = branch;
    }
    else
      throw ParseException.syntaxError (scanner, new int [] { Token.Case, Token.Default }, token.type);
  } // caselabel

  /**
   *
   **/
  private Expression matchEnum (EnumEntry entry) throws IOException, ParseException
  {
    // Get the symbol table entry for the case label based on the
    // scope of the EnumEntry, NOT the UnionEntry (the union could be
    // in a different scope than the enum).  Given
    // module M { enum E {A, B, C, D}; };
    // a case label for A could be one of the following:
    // case A:
    // case M::A:
    // case ::M::A:
    SymtabEntry label = scopedName (entry.container(), new SymtabEntry ());
    return exprFactory.terminal (label.name (), false);
  } // matchEnum

  /**
   *
   **/
  private void elementSpec (UnionEntry entry, UnionBranch branch) throws IOException, ParseException
  {
    TypedefEntry typedef = stFactory.typedefEntry (entry, (IDLID)repIDStack.peek ());
    typedef.sourceFile (scanner.fileEntry ());
    // Comment must immediately precede <type_spec> lexeme
    typedef.comment (token.comment);
    typedef.type (typeSpec (entry));
    if (typedef.type () == entry)
      throw ParseException.recursive (scanner, entry.fullName (), (token.name == null)? "" : token.name);
    // <d46094> Exception cannot appear within a struct, union, or exception
    if (typeOf (typedef) instanceof ExceptionEntry)
      throw ParseException.illegalException (scanner, entryName (entry));
    declarator (typedef);
    branch.typedef = typedef;
    // Ensure a branch with the same name doesn't already exist.
    if (entry.has (typedef))
      ParseException.branchName (scanner, typedef.name ());
  } // elementSpec

  /**
   *
   **/
  private EnumEntry enumType (SymtabEntry entry) throws IOException, ParseException
  {
    match (Token.Enum);
    EnumEntry enumEntry = newEnumEntry (entry);
    // comment must immediately precede "enum" keyword
    enumEntry.comment (tokenHistory.lookBack (1).comment);
    enumEntry.name (token.name);
    match (Token.Identifier);
    prep.openScope (enumEntry);
    match (Token.LeftBrace);
    if (isntInStringList (enumEntry.elements (), token.name))
    {
      enumEntry.addElement (token.name);
      SymtabEntry element = new SymtabEntry (entry, (IDLID)repIDStack.peek ());
      // if block taken from EnumEntry ctor
      if (element.module ().equals (""))
        element.module (element.name ());
      else if (!element.name ().equals (""))
        element.module (element.module () + "/" + element.name ());
      element.name (token.name);
      // <d50237> Place the SymtabEntry representing this enumeration
      // contant into the SymtabEntry defining its scope (e.g., InterfaceEntry,
      // ValueEntry, etc.) rather than the SymtabEntry passed in, which
      // may not define the contant's scope (e.g., TypedefEntry).
      //pigeonhole (entry, element); } <daz>
      pigeonhole (enumEntry.container (), element);
    }
    match (Token.Identifier);
    enumType2 (enumEntry);
    prep.closeScope (enumEntry);
    match (Token.RightBrace);
    return enumEntry;
  } // enumType

  /**
   *
   **/
  private void enumType2 (EnumEntry entry) throws IOException, ParseException
  {
    while (token.type == Token.Comma)
    {
      match (Token.Comma);
      String name = token.name;
      match (Token.Identifier);
      if (isntInStringList (entry.elements (), name))
      {
        entry.addElement (name);
        SymtabEntry element = new SymtabEntry (entry.container (), (IDLID)repIDStack.peek ());
        // if block taken from EnumEntry ctor:
        if (element.module ().equals (""))
          element.module (element.name ());
        else if (!element.name().equals (""))
          element.module (element.module () + "/" + element.name ());
        element.name (name);
        pigeonhole (entry.container  (), element);
      }
    }
  } // enumType2

  /**
   *
   **/
  private SequenceEntry sequenceType (SymtabEntry entry) throws IOException, ParseException
  {
    match (Token.Sequence);
    match (Token.LessThan);

    SequenceEntry newEntry = newSequenceEntry (entry);
    SymtabEntry tsentry = simpleTypeSpec (newEntry, false );
    newEntry.type (tsentry);
    if (!tsentry.isReferencable()) {
        // This is a sequence type that is referencing an
        // incomplete forward declaration of a struct or
        // union.  Save the sequence in a list for later
        // backpatching.
        try {
            List fwdTypes = (List)tsentry.dynamicVariable( ftlKey ) ;
            if (fwdTypes == null) {
                fwdTypes = new ArrayList() ;
                tsentry.dynamicVariable( ftlKey, fwdTypes ) ;
            }
            fwdTypes.add( newEntry ) ;
        } catch (NoSuchFieldException exc) {
            throw new IllegalStateException() ;
        }
    }

    if (token.type == Token.Comma)
    {
      match (Token.Comma);
      ConstEntry tmpEntry = stFactory.constEntry (newEntry, (IDLID)repIDStack.peek ());
      tmpEntry.sourceFile (scanner.fileEntry ());
      tmpEntry.type (qualifiedEntry ("long"));
      newEntry.maxSize (positiveIntConst (tmpEntry));
      verifyConstType (newEntry.maxSize(), qualifiedEntry ("long"));
    }
    match (Token.GreaterThan);
    return newEntry;
  } // sequenceType

  /**
   *
   **/
  private StringEntry stringType (SymtabEntry entry) throws IOException, ParseException
  {
    StringEntry string = stFactory.stringEntry ();
    if (token.type == Token.String)
    {
      string.name (overrideName ("string"));
      match (Token.String);
    }
    else
    {
      string.name (overrideName ("wstring"));
      match (Token.Wstring);
    }
    string.maxSize (stringType2 (entry));
    return string;
  } // stringType

  /**
   *
   **/
  private Expression stringType2 (SymtabEntry entry) throws IOException, ParseException
  {
    if (token.type == Token.LessThan)
    {
      match (Token.LessThan);

      // START IBM.11417 failure in the IDL compiler
      //Expression maxSize = positiveIntConst (entry);   IBM.11417

      ConstEntry tmpEntry = stFactory.constEntry (entry, (IDLID)repIDStack.peek
());
      tmpEntry.sourceFile (scanner.fileEntry ());
      tmpEntry.type (qualifiedEntry ("long"));
      Expression maxSize = positiveIntConst (tmpEntry);

      // END IBM.11417

      verifyConstType (maxSize, qualifiedEntry ("long"));
      match (Token.GreaterThan);
      return maxSize;
    }
    return null;
  } // stringType2

  /**
   *
   **/
  private void fixedArraySize (TypedefEntry entry) throws IOException, ParseException
  {
    match (Token.LeftBracket);
    ConstEntry tmpEntry = stFactory.constEntry (entry, (IDLID)repIDStack.peek ());
    tmpEntry.sourceFile (scanner.fileEntry ());
    // <d58058> Set type of tmpExpr to "long", which is the array index type.
    // Previously, this type was erroneously set to the array element type.
    //tmpEntry.type (entry.type ());
    tmpEntry.type (qualifiedEntry ("long"));
    Expression expr = positiveIntConst (tmpEntry);
    entry.addArrayInfo (expr);
    verifyConstType (expr, qualifiedEntry ("long"));
    match (Token.RightBracket);
  } // fixedArraySize

  /**
   *
   **/
  private void attrDcl (InterfaceEntry entry) throws IOException, ParseException
  {
    AttributeEntry attribute = stFactory.attributeEntry (entry, (IDLID)repIDStack.peek ());
    attribute.sourceFile (scanner.fileEntry ());
    // Comment must immediately precede the "attribute" keyword.  Save the
    // comment preceding the declaration for use below.
    attribute.comment (token.comment);
    Comment dclComment = attribute.comment ();

    if (token.type == Token.Readonly)
    {
      match (Token.Readonly);
      attribute.readOnly (true);
    }
    match (Token.Attribute);
    attribute.type (paramTypeSpec (attribute));
    attribute.name (token.name);
    // Override declaration comment if attribute identifier is commented
    if (!token.comment.text ().equals (""))
      attribute.comment (token.comment);
    entry.methodsAddElement (attribute, scanner);
    pigeonholeMethod (entry, attribute);
    // Declaration comment was overriden:
    if (!token.comment.text ().equals (""))
    {
      // Create a temporary attribute with declaration comment so cloning in
      // attrdcl2() can use declaration comment as default.
      AttributeEntry attributeClone = (AttributeEntry) attribute.clone ();
      attributeClone.comment (dclComment);

      match (Token.Identifier);
      attrDcl2 (entry, attributeClone);
    }
    else
    {
      match (Token.Identifier);
      attrDcl2 (entry, attribute);
    }
    //match (Token.Identifier);
    //attrDcl2 (entry, attribute);
  } // attrDcl

  /**
   *
   **/
  private void attrDcl2 (InterfaceEntry entry, AttributeEntry clone)
          throws IOException, ParseException
  {
    while (token.type == Token.Comma)
    {
      match (Token.Comma);
      AttributeEntry attribute = (AttributeEntry)clone.clone ();
      attribute.name (token.name);
      // Override the declaration comment (i.e., that preceding the
      // "attribute" keyword) if the attribute identifier is commented.
      if (!token.comment.text ().equals (""))
        attribute.comment (token.comment);
      entry.methodsAddElement (attribute, scanner);
      pigeonholeMethod (entry, attribute);
      match (Token.Identifier);
    }
  } // attrDcl2

  /**
   *
   **/
  private void exceptDcl (SymtabEntry entry) throws IOException, ParseException
  {
    match (Token.Exception);
    repIDStack.push (((IDLID)repIDStack.peek ()).clone ());
    ExceptionEntry exceptEntry = stFactory.exceptionEntry (entry, (IDLID)repIDStack.peek ());
    ((IDLID)repIDStack.peek ()).appendToName (token.name);
    exceptEntry.sourceFile (scanner.fileEntry ());
    // Comment must immediately precede "exception" keyword
    exceptEntry.comment (tokenHistory.lookBack (1).comment);
    exceptEntry.name (token.name);
    match (Token.Identifier);
    pigeonhole (entry, exceptEntry);
    if (token.equals (Token.LeftBrace))
    {
      prep.openScope (exceptEntry);
      match (Token.LeftBrace);
      memberList2 (exceptEntry);
      prep.closeScope (exceptEntry);
      match (Token.RightBrace);
      repIDStack.pop ();
    }
    else
      throw ParseException.syntaxError (scanner, Token.LeftBrace,token.type);
  } // exceptDcl

  /**
   *
   **/
  private void opDcl (InterfaceEntry entry) throws IOException, ParseException
  {
    MethodEntry method = stFactory.methodEntry (entry, (IDLID)repIDStack.peek ());
    method.sourceFile (scanner.fileEntry ());
    // Comment must immediately precede "oneway" keyword or <return_type_spec>
    method.comment (token.comment);
    if (token.type == Token.Oneway)
    {
      match (Token.Oneway);
      method.oneway (true);
    }
    method.type (opTypeSpec (method));
    repIDStack.push (((IDLID)repIDStack.peek ()).clone ());
    ((IDLID)repIDStack.peek ()).appendToName (token.name);
    method.name (token.name);
    entry.methodsAddElement (method, scanner);
    pigeonholeMethod (entry, method);
    opDcl2 (method);
    if (method.oneway ())
      checkIfOpLegalForOneway (method);
    repIDStack.pop ();
  } // opDcl

  /**
   *
   **/
  private void checkIfOpLegalForOneway (MethodEntry method)
  {
    boolean notLegal = false;
    if ((method.type() != null) ||
         (method.exceptions().size() != 0)) notLegal = true;
    else
    {
      for (Enumeration e = method.parameters().elements(); e.hasMoreElements();)
      {
        if (((ParameterEntry)e.nextElement ()).passType () != ParameterEntry.In)
        {
          notLegal = true;
          break;
        }
      }
    }
    if (notLegal)
      ParseException.oneway (scanner, method.name ());
  } // checkifOpLegalForOneway

  /**
   *
   **/
  private void opDcl2 (MethodEntry method) throws IOException, ParseException
  {
    if (token.equals (Token.MacroIdentifier))
    {
      match (Token.MacroIdentifier);
      parameterDcls2 (method);
    }
    else
    {
      match (Token.Identifier);
      parameterDcls (method);
     }
    opDcl3 (method);
  } // opDcl2

  /**
   *
   **/
  private void opDcl3 (MethodEntry entry) throws IOException, ParseException
  {
    if (token.type != Token.Semicolon)
    {
      if (!token.equals (Token.Raises) && !token.equals (Token.Context))
        throw ParseException.syntaxError (scanner, new int [] {
            Token.Raises, Token.Context, Token.Semicolon }, token.type);
      if (token.type == Token.Raises)
        raisesExpr (entry);
      if (token.type == Token.Context)
        contextExpr (entry);
    }
  } // opDcl3

  /**
   *
   **/
  private SymtabEntry opTypeSpec (SymtabEntry entry) throws IOException, ParseException
  {
    SymtabEntry ret = null;
    if (token.type == Token.Void)
      match (Token.Void);
    else
      ret = paramTypeSpec (entry);
    return ret;
  } // opTypeSpec

  /**
   *
   **/
  private void parameterDcls (MethodEntry entry) throws IOException, ParseException
  {
    match (Token.LeftParen);
    parameterDcls2 (entry);
  } // parameterDcls

  /**
   *
   **/
  private void parameterDcls2 (MethodEntry entry) throws IOException, ParseException
  {
    if (token.type == Token.RightParen)
      match (Token.RightParen);
    else
    {
      paramDcl (entry);
      while (token.type == Token.Comma)
      {
        match (Token.Comma);
        paramDcl (entry);
      }
      match (Token.RightParen);
    }
  } // paraneterDcls2

  /**
   *
   **/
  private void paramDcl (MethodEntry entry) throws IOException, ParseException
  {
    ParameterEntry parmEntry = stFactory.parameterEntry (entry, (IDLID)repIDStack.peek ());
    parmEntry.sourceFile (scanner.fileEntry ());
    // Comment must immeiately precede the parameter attribute
    parmEntry.comment (token.comment);
    paramAttribute (parmEntry);
    parmEntry.type (paramTypeSpec (entry));
    parmEntry.name (token.name);
    match (Token.Identifier);
    if (isntInList (entry.parameters (), parmEntry.name ()))
      entry.addParameter (parmEntry);
  } // paramDcl

  /**
   *
   **/
  private void paramAttribute (ParameterEntry entry) throws IOException, ParseException
  {
    if (token.type == Token.In)
    {
      entry.passType (ParameterEntry.In);
      match (Token.In);
    }
    else if (token.type == Token.Out)
    {
      entry.passType (ParameterEntry.Out);
      match (Token.Out);
    }
    else if (token.type == Token.Inout)
    {
      entry.passType (ParameterEntry.Inout);
      match (Token.Inout);
    }
    else
      throw ParseException.syntaxError (scanner, new int [] {
          Token.In, Token.Out, Token.Inout }, token.type);
  } // paramAttribute

  /**
   *
   **/
  private void raisesExpr (MethodEntry entry) throws IOException, ParseException
  {
    match (Token.Raises);
    match (Token.LeftParen);
    // Comment must immediately precede <scoped_name> for exception
    Comment tempComment = token.comment;
    SymtabEntry exception = scopedName(entry.container (), stFactory.exceptionEntry ());
    if (typeOf (exception) instanceof ExceptionEntry)
    {
      // Comment must immediately precede <scoped_name> for exception
      exception.comment (tempComment);
      if (isntInList (entry.exceptions (), exception))
        entry.exceptionsAddElement ((ExceptionEntry) exception);
    }
    else
      ParseException.wrongType (scanner, exception.fullName(),
          "exception", entryName (exception.type ()));
    raisesExpr2 (entry);
    match (Token.RightParen);
  } // raisesExpr

  /**
   *
   **/
  private void raisesExpr2 (MethodEntry entry) throws IOException, ParseException
  {
    while (token.type == Token.Comma)
    {
      match (Token.Comma);
      // Comment must immediately precede <scoped_name> of exception
      Comment tempComment = token.comment;
      SymtabEntry exception = scopedName (entry.container (), stFactory.exceptionEntry ());
      if (typeOf (exception) instanceof ExceptionEntry)
      {
        // Comment must immediately precede <scoped_name> of exception
        exception.comment (tempComment);
        if (isntInList (entry.exceptions (), exception))
          entry.addException ((ExceptionEntry)exception);
      }
      else
        ParseException.wrongType (scanner, exception.fullName (),
            "exception", entryName (exception.type ()));
    }
  } // raisesExpr2

  /**
   *
   **/
  private void contextExpr (MethodEntry entry) throws IOException, ParseException
  {
    match (Token.Context);
    match (Token.LeftParen);
    String stringLit = (String)stringLiteral ().value ();
    if (isntInStringList (entry.contexts (), stringLit))
      entry.addContext (stringLit);
    contextExpr2 (entry);
    match (Token.RightParen);
  } // contextExpr


  private void contextExpr2 (MethodEntry entry) throws IOException, ParseException
  {
    while (token.type == Token.Comma)
    {
      match (Token.Comma);
      String stringLit = (String)stringLiteral ().value ();
      if (isntInStringList (entry.contexts (), stringLit))
        entry.addContext (stringLit);
    }
  } // contextExpr2

  /**
   *
   **/
  private SymtabEntry paramTypeSpec (SymtabEntry entry) throws IOException, ParseException
  {
    SymtabEntry ret = null;
    switch (token.type)
    {
      case Token.Float:
      case Token.Double:
      case Token.Long:
      case Token.Short:
      case Token.Unsigned:
      case Token.Char:
      case Token.Wchar:
      case Token.Boolean:
      case Token.Octet:
      case Token.Any:
        return baseTypeSpec (entry);
      case Token.String:
      case Token.Wstring:
        return stringType (entry);
      case Token.Identifier:
      case Token.Object:
      // <f46082.40>
      case Token.ValueBase:
      case Token.DoubleColon:
        ret = scopedName (entry.container (), stFactory.primitiveEntry ());
        if (typeOf (ret) instanceof AttributeEntry)
          //ParseException.attributeParamType (scanner);
          ParseException.attributeNotType (scanner, ret.name ());
        else // <d60942>
          if (typeOf (ret) instanceof MethodEntry)
            ParseException.operationNotType (scanner, ret.name ());

        //if (!(returnType instanceof PrimitiveEntry ||
        //     returnType instanceof StringEntry))
        //ParseException.wrongType (scanner, ret.fullName(),
        //                          "primitive or string", entryName (ret.type()));
        break;
      default:
        throw ParseException.syntaxError (scanner, new int [] {
            Token.Float,      Token.Double,      Token.Long,    Token.Short,
            Token.Unsigned,   Token.Char,        Token.Wchar,   Token.Boolean,
            Token.Octet,      Token.Any,         Token.String,  Token.Wstring,
            Token.Identifier, Token.DoubleColon, Token.ValueBase }, token.type);
    }
    return ret;
  } // paramTypeSpec

  /**
   *
   **/
  private void match (int type) throws IOException, ParseException
  {
    ParseException exception = null;
    if (!token.equals (type))
    {
      exception = ParseException.syntaxError (scanner, type, token.type);
      // Missing a semicolon is a common error.  If a semicolon was expected,
      // assume it exists and keep the current token (don't get the next one).
      // BEWARE!!! THIS HAS THE POTENTIAL FOR AN INFINITE LOOP!
      if (type == Token.Semicolon)
        return;
    }
    // <f46082.40> Unecessary due to new valueElement() algorithm.
    //if (!tokenStack.empty())
    //{
    //  token = (Token)tokenStack.pop ();
    //  return;
    //}

    // Fetch the next token.
    token = scanner.getToken ();

    // <d62023> Issue warnings about tokens.
    issueTokenWarnings ();

    // Maintain history of most recent tokens.
    tokenHistory.insert (token);

    // <d59166> Identifiers that collide with keywords are illegal.  Note
    // that escaped identifers never collide!
    /*
    if (token.collidesWithKeyword ())
    {
      // <f60858.1> Issue a warning only
      if (corbaLevel <= 2.2f)
        ParseException.keywordCollisionWarning (scanner, token.name);
      else
        exception = ParseException.keywordCollision (scanner, token.name);
    }
    */

    while (token.isDirective ())
      token = prep.process (token);

    // If the token is a defined thingy, scan the defined string
    // instead of the input stream for a while.
    if (token.equals (Token.Identifier) || token.equals (Token.MacroIdentifier))
    {
      String string = (String)symbols.get (token.name);
      if (string != null && !string.equals (""))
      {
        // If this is a macro, parse the macro
        if (macros.contains (token.name))
        {
          scanner.scanString (prep.expandMacro (string, token));
          match (token.type);
        }
        else // This is just a normal define.
        {
          scanner.scanString (string);
          match (token.type);
        }
      }
    }
    if (exception != null)
      throw exception;
  } // match

  // <d62023>
  /**
   * Issue warnings according to attributes of current Token.
   **/
  private void issueTokenWarnings ()
  {
    if (noWarn)
      return;

    if ((token.equals (Token.Identifier) || token.equals (Token.MacroIdentifier))
        && !token.isEscaped ())
    {
      // Identifier collision with keyword in another release.
      // Identifier collision with keyword in letter, but not in case.
      if (token.collidesWithKeyword ())
        ParseException.warning (scanner, Util.getMessage ("Migration.keywordCollision", token.name));
    }
    // Deprecated keyword.
    if (token.isKeyword () && token.isDeprecated ())
      ParseException.warning (scanner, Util.getMessage ("Deprecated.keyword", token.toString ()));
  } // issueTokenWarnings

  /**
   *
   **/
  private ModuleEntry newModule (ModuleEntry oldEntry)
  {
    ModuleEntry entry = stFactory.moduleEntry (oldEntry, (IDLID)repIDStack.peek ());
    entry.sourceFile (scanner.fileEntry ());
    entry.name (token.name);
    // If this named module already exists, just reopen it.
    /* <46082.46.01> if cppModule, always create new module entry */
    SymtabEntry prevEntry = (SymtabEntry) symbolTable.get (entry.fullName ());
    if (!cppModule && prevEntry != null && prevEntry instanceof ModuleEntry)
    {
      // A module has been reopened, return that ModuleEntry.
      entry = (ModuleEntry) prevEntry;
      if (oldEntry == topLevelModule)
      {
        // Do a little checking:
        if (!entry.emit ())
          // The entry module is being reopened to put new stuff into it.
          // The module itself is not marked as "emit", but the new stuff
          // may be, so put the module on the emitList (add it to topLevelModule).
          addToContainer (oldEntry, entry);
        else if (!oldEntry.contained().contains (entry))
          // <d50767> The entry module being reopened is to be emitted, but
          // will not be placed on the emitList! I.E., it was not added to
          // topLevelModule.  Occurs when a generator manually inserts
          // ModuleEntrys into the symbol table (e.g., org; see preParse()
          // in ...idl.toJava.Compile). <daz>
          addToContainer (oldEntry, entry);
      }
    }
    else
      pigeonhole (oldEntry, entry);
    return entry;
  } // newModule

  /**
   *
   **/
  private EnumEntry newEnumEntry (SymtabEntry oldEntry)
  {
    EnumEntry entry = stFactory.enumEntry (oldEntry, (IDLID)repIDStack.peek ());
    entry.sourceFile (scanner.fileEntry ());
    entry.name (token.name);
    pigeonhole (oldEntry, entry);
    return entry;
  } // newEnumEntry

  /**
   *
   **/
  private SequenceEntry newSequenceEntry (SymtabEntry oldEntry)
  {
    SequenceEntry entry = stFactory.sequenceEntry (oldEntry, (IDLID)repIDStack.peek ());
     entry.sourceFile (scanner.fileEntry ());
     entry.name ("");
     pigeonhole (oldEntry, entry);
     return entry;
  } // newSequenceEntry

    private void updateSymbolTable( String fullName, SymtabEntry entry, boolean lcCheck )
    {
        // Check for case-insensitive collision (IDL error).
        String lcFullName = fullName.toLowerCase();
        if (lcCheck)
            if (lcSymbolTable.get (lcFullName) != null) {
                ParseException.alreadyDeclared (scanner, fullName);
            }
        symbolTable.put (fullName, entry);
        lcSymbolTable.put (lcFullName, entry);
        // <d59809> Allow fully-qualified CORBA types to be resolved by mapping
        // short name (e.g., CORBA/StringValue) to long name, actual name.
        String omgPrefix = "org/omg/CORBA" ;
        if (fullName.startsWith (omgPrefix)) {
            overrideNames.put (
                "CORBA" + fullName.substring (omgPrefix.length()), fullName);
        }
    }

    private void pigeonhole (SymtabEntry container, SymtabEntry entry)
    {
        if (entry.name().equals (""))
            entry.name (unknownNamePrefix + ++sequence);

        // If this object is not in the overrides list, then it is
        // ok to put it in the table (if it IS in the overrides list,
        // it is already in the table under a different name).
        String fullName = entry.fullName();
        if (overrideNames.get (fullName) == null) {
            addToContainer (container, entry);

            // It is an error is this name already exists in the symbol
            // table, unless this is a redefinition of a forward decl.
            // Re-opening a module is also legal, but not handled here.
            SymtabEntry oldEntry = (SymtabEntry) symbolTable.get (fullName);

            if (oldEntry == null) {
                updateSymbolTable( fullName, entry, true ) ;
            } else if (oldEntry instanceof ForwardEntry &&
                entry instanceof InterfaceEntry) {

                String repIDPrefix = ((IDLID)entry.repositoryID ()).prefix ();
                String oldRepIDPrefix = ((IDLID)oldEntry.repositoryID ()).prefix ();
                if (repIDPrefix.equals (oldRepIDPrefix)) {
                    updateSymbolTable( fullName, entry, false ) ;
                } else {
                    ParseException.badRepIDPrefix (scanner, fullName,
                        oldRepIDPrefix, repIDPrefix);
                }
            } else if (entry instanceof ForwardEntry &&
                       (oldEntry instanceof InterfaceEntry ||
                        oldEntry instanceof ForwardEntry)) {
                if (oldEntry instanceof ForwardEntry &&
                    entry.repositoryID () instanceof IDLID &&
                    oldEntry.repositoryID () instanceof IDLID) {

                    String repIDPrefix =
                        ((IDLID)entry.repositoryID ()).prefix ();
                    String oldRepIDPrefix =
                        ((IDLID)oldEntry.repositoryID ()).prefix ();

                    if (!(repIDPrefix.equals (oldRepIDPrefix))) {
                        // Disallow multiple ForwardEntry's having same Repository
                        // ID prefixes (CORBA 2.3).
                        ParseException.badRepIDPrefix (scanner, fullName,
                            oldRepIDPrefix, repIDPrefix);
                    }
                }
            } else if (cppModule && entry instanceof ModuleEntry &&
                oldEntry instanceof ModuleEntry) {
                // Allow multiple ModuleEntrys when user submits
                // the -cppModule flag.
            } else if (fullName.startsWith ("org/omg/CORBA") ||
                fullName.startsWith ("CORBA")) {
                // Ignore CORBA PIDL types entered at preParse() by generator.
            } else if (isForwardable( oldEntry, entry )) {
                // Both oldEntry and entry are structs or unions.
                // Legality depends on isReferencable on the two entries:
                // oldEntry     Entry
                //      T           T       ERROR alreadyDeclared
                //      T           F       legal fwd decl
                //      F           T       if defined in same file legal,
                //                          otherwise ERROR
                //      F           F       legal fwd decl
                if (oldEntry.isReferencable() && entry.isReferencable())
                    ParseException.alreadyDeclared (scanner, fullName);

                if (entry.isReferencable()) {
                    String firstFile =
                        oldEntry.sourceFile().absFilename() ;
                    String defFile =
                        entry.sourceFile().absFilename() ;
                    if (!firstFile.equals( defFile ))
                        ParseException.declNotInSameFile( scanner,
                            fullName, firstFile ) ;
                    else {
                        updateSymbolTable( fullName, entry, false ) ;

                        List oldRefList ;

                        try {
                            oldRefList = (List)oldEntry.dynamicVariable(
                                ftlKey ) ;
                        } catch (NoSuchFieldException exc) {
                            throw new IllegalStateException() ;
                        }

                        if (oldRefList != null) {
                            // Update entries in backpatch list
                            Iterator iter = oldRefList.iterator() ;
                            while (iter.hasNext()) {
                                SymtabEntry elem = (SymtabEntry)iter.next() ;
                                elem.type( entry ) ;
                            }
                        }
                    }
                }
            } else {
                ParseException.alreadyDeclared (scanner, fullName);
            }
        }
    } // pigeonhole

    private boolean isForwardable( SymtabEntry oldEntry,
        SymtabEntry entry )
    {
        return ((oldEntry instanceof StructEntry) &&
            (entry instanceof StructEntry)) ||
           ((oldEntry instanceof UnionEntry) &&
            (entry instanceof UnionEntry)) ;
    }

  // pigeonhole checks to see if this entry is already in the symbol
  // table and generates an error if it is.  Methods must be checked
  // not only against the symbol table but also against their
  // interface's parent's methods.  This is done in InterfaceEntry.
  // verifyMethod, so no checking need be done here.

  /**
   *
   **/
  private void pigeonholeMethod (InterfaceEntry container, MethodEntry entry)
  {
    if (entry.name ().equals (""))
       entry.name (unknownNamePrefix + ++sequence);

    // If this object is not in the overrides list, then it is
    // ok to put it in the table (if it IS in the overrides list,
    // it is already in the table under a different name).
    String fullName = entry.fullName ();
    if (overrideNames.get (fullName) == null)
    {
      addToContainer (container, entry);
      String lcFullName = fullName.toLowerCase ();
      symbolTable.put (fullName, entry);
      lcSymbolTable.put (lcFullName, entry);
      // <d59809> Allow fully-qualified CORBA types to be resolved by mapping
      // short name (e.g., CORBA/StringValue) to long name, actual name.
      if (fullName.startsWith ("org/omg/CORBA"))
        overrideNames.put ("CORBA" + fullName.substring (13), fullName);
    }
  } // pigeonholeMethod

  /**
   *
   **/
  private void addToContainer (SymtabEntry container, SymtabEntry contained)
  {
    if (container instanceof ModuleEntry)
      ((ModuleEntry)container).addContained (contained);
    else if (container instanceof InterfaceEntry)
      ((InterfaceEntry)container).addContained (contained);
    else if (container instanceof StructEntry)
      ((StructEntry)container).addContained (contained);
    else if (container instanceof UnionEntry)
      ((UnionEntry)container).addContained (contained);
    else if (container instanceof SequenceEntry)
      ((SequenceEntry)container).addContained (contained);
  } // addToContainer

  // NOTE: qualifiedEntry/partlyQualifiedEntry/unqualifiedEntry and
  // their court could probably use some performance improvements,
  // but I'm scared to touch anything.  It's the most complex bit of
  // code in this parser.

  // The qualified named type is searched for in the following order:
  // 1.  OverrideNames
  // 2.  Global scope
  // 3.  Inheritance scope (if container is an interface)
  // A qualified name is one which begins with :: or is assumed to be
  // in the global scope (like long, short, etc).

  /**
   *
   **/
  SymtabEntry qualifiedEntry (String typeName)
  {
    SymtabEntry type = recursiveQualifiedEntry (typeName);
    if (type == null)
      // Then it's not anywhere, report the error.
      ParseException.undeclaredType (scanner, typeName);

    // <d57110> Relax this retriction when parsing ID pragma directive, e.g..
    //else if (type instanceof ModuleEntry) {
    else if (type instanceof ModuleEntry && !_isModuleLegalType)
    {
      // Module's are not valid types.
      ParseException.moduleNotType (scanner, typeName);
      type = null;
    }
    return type;
  } // qualifiedEntry

  /**
   *
   **/
  SymtabEntry recursiveQualifiedEntry (String typeName)
  {
    SymtabEntry type = null;
    if (typeName != null && !typeName.equals ("void"))
    {
      int index = typeName.lastIndexOf ('/');
      if (index >= 0)
      {
        // Figure out if the container of this thing exists, converting any typedefs to interfaces if necessary.
        type = recursiveQualifiedEntry (typeName.substring (0, index));
        if (type == null)
          return null;
        else if (type instanceof TypedefEntry)
          typeName = typeOf (type).fullName () + typeName.substring (index);
      }

      // If we got this far, a container exists, start over looking
      // for the thing itself (this is the meat of the method):
      type = searchOverrideNames (typeName);
      if (type == null)
        type = (SymtabEntry) symbolTable.get (typeName); // search global scope:
      if (type == null)
        type = searchGlobalInheritanceScope (typeName);
    }
    return type;
  } // recursiveQualifiedEntry

  // A partially qualified name is of the form <scope>::<name>.
  // First the scope is defined (meaning it is fully qualified);
  // Then the name is searched for in the scope.

  /**
   *
   **/
  SymtabEntry partlyQualifiedEntry (String typeName, SymtabEntry container)
  {
    // This is the simple logic of this method:
    // type = searchModuleScope (typeName.substring (0, typeName.lastIndexOf ('/')), container);
    // type = qualifiedEntry (type.fullName () + typeName.substring (typeName.lastIndexOf ('/')));
    // But searchModuleScope only finds the first module that fits.
    // The name might not be in that module but in one further out
    // in the module scope.  Should others be searched?
    SymtabEntry type = null;
    if (typeName != null)
    {
      int index = typeName.lastIndexOf ('/');

      // Figure out if the container of this thing exists, converting any
      // typedefs to interfaces if necessary:
      type = recursivePQEntry (typeName.substring (0, index), container);
      if (type instanceof TypedefEntry)
        typeName = typeOf (type).fullName () + typeName.substring (index);

      // If we got this far, a container exists, start over looking
      // for the thing itself.

      if (container != null)
        type = searchModuleScope (typeName.substring (0, typeName.lastIndexOf ('/')), container);
      if (type == null)
        type = qualifiedEntry (typeName);
      else
        type = qualifiedEntry (type.fullName () + typeName.substring (typeName.lastIndexOf ('/')));
    }
    return type;
  } // partlyQualifiedEntry

  // partlyQualifiedEntry and recursivePQEntry are almost identical.
  // They are different because when the recursive one is looking for
  // the existence of containers, the error check for a module type
  // must not occur (this check is done in qualifiedEntry).  Only
  // when the full partly qualified name is being processed must this
  // check be performed.

  /**
   *
   **/
  SymtabEntry recursivePQEntry (String typeName, SymtabEntry container)
  {
    SymtabEntry type = null;
    if (typeName != null)
    {
      int index = typeName.lastIndexOf ('/');
      if (index < 0)
        type = searchModuleScope (typeName, container);
      else
      {
        // Figure out if the container of this thing exists, converting any
        // typedefs to interfaces if necessary:
        type = recursivePQEntry (typeName.substring (0, index), container);
        if (type == null)
          return null;
        else if (type instanceof TypedefEntry)
          typeName = typeOf (type).fullName () + typeName.substring (index);

        // If we got this far, a container exists, start over, looking
        // for the thing itself (This is the meat of the method):
        if (container != null)
          type = searchModuleScope (typeName.substring (0, typeName.lastIndexOf ('/')), container);
          if (type == null)
            recursiveQualifiedEntry (typeName);
          else
            type = recursiveQualifiedEntry (type.fullName () + typeName.substring (typeName.lastIndexOf ('/')));
      }
    }
    return type;
  } // recursivePQEntry

  // The named type is searched for in the following order:
  // 1.  Local scope
  // 2.  Inheritance scope
  // 3.  OverrideNames
  // 4.  Module scope

  /**
   *
   **/
  SymtabEntry unqualifiedEntry (String typeName, SymtabEntry container)
  {
    SymtabEntry type = unqualifiedEntryWMod (typeName, container);

    // <d57110> Relax this retriction in special cases, e.g., when
    // parsing a ID pragma directive.
    //if (type instanceof ModuleEntry) {
    if (type instanceof ModuleEntry && !_isModuleLegalType)
    {
      // Module's are not valid types:
      ParseException.moduleNotType (scanner, typeName);
      type = null;
    }
    return type;
  } // unqualifiedEntry

  /**
   *
   **/
  SymtabEntry unqualifiedEntryWMod (String typeName, SymtabEntry container)
  {
    SymtabEntry type = null;
    if ((typeName != null) && !typeName.equals ("void"))
    {
      // Search local scope:
      type = (SymtabEntry)symbolTable.get (container.fullName () + '/' + typeName);
      if (type == null)
        type = searchLocalInheritanceScope (typeName, container);
      if (type == null)
        type = searchOverrideNames (typeName);
      if ((type == null) && (container != null))
        type = searchModuleScope (typeName, container);
      if (type == null)
        type = searchParentInheritanceScope (typeName, container);
    }
    if (type == null)
      // Then it's not anywhere, report the error:
      ParseException.undeclaredType (scanner, typeName);
    return type;
  } // unqualifiedEntryWMod

  /**
   * Walks up the enclosing scopes until it finds an interface type. Then,
   * searches up that interface inheritance tree for the type definition.
   *
   * @param name type name to be searched for.
   * @param ptype parent type entry.
   **/
  SymtabEntry searchParentInheritanceScope(String name, SymtabEntry ptype) {

    String cname = ptype.fullName();

    while ((ptype != null) && !(cname.equals ("")) &&
           !(ptype instanceof InterfaceEntry)) {
        int index = cname.lastIndexOf ('/');
        if (index < 0) {
            cname = "";
        } else {
            cname = cname.substring (0, index);
            ptype = (SymtabEntry) symbolTable.get(cname);
        }
    }

    if ((ptype == null) || !(ptype instanceof InterfaceEntry)) {
        return null; // could not find an enclosing interface type - give up.
    }

    // check if the enclosing interface supports the type definition.
    String fullName = ptype.fullName () + '/' + name;
    SymtabEntry type = (SymtabEntry) symbolTable.get (fullName);
    if (type != null) {
        return type; // found type definition.
    }

    // search up the interface inheritance tree.
    return searchLocalInheritanceScope(name, ptype);
  }

  /**
   *
   **/
  SymtabEntry searchGlobalInheritanceScope (String name)
  {
    // See if the container of this named object is an interface:
    int         index = name.lastIndexOf ('/');
    SymtabEntry entry = null;
    if (index >= 0)
    {
      String containerName = name.substring (0, index);
      entry = (SymtabEntry)symbolTable.get (containerName);
      entry = (entry instanceof InterfaceEntry)
          // It's an interface, now look in its inheritance scope:
          ? searchLocalInheritanceScope (name.substring (index + 1), entry)
          : null;
    }
    return entry;
  } // searchGlobalInheritanceScope

  /**
   *
   **/
  SymtabEntry searchLocalInheritanceScope (String name, SymtabEntry container)
  {
    return (container instanceof InterfaceEntry)
        ? searchDerivedFrom (name, (InterfaceEntry) container)
        : null;
  } // searchLocalInheritanceScope

  /**
   *
   **/
  SymtabEntry searchOverrideNames (String name)
  {
    String overrideName = (String)overrideNames.get (name);
    return (overrideName != null)
        ? (SymtabEntry)symbolTable.get (overrideName)
        : null;
  } // searchOverrideNames

  /**
   *
   **/
  SymtabEntry searchModuleScope (String name, SymtabEntry container)
  {
    String      module   = container.fullName ();
    String      fullName = module + '/' + name;
    SymtabEntry type     = (SymtabEntry)symbolTable.get (fullName);
    while ((type == null) && !module.equals (""))
    {
      int index = module.lastIndexOf ('/');
      if (index < 0)
        module = "";
      else
      {
        module   = module.substring (0, index);
        fullName = module + '/' + name;
        type     = (SymtabEntry)symbolTable.get (fullName);
      }
    }
    return (type == null) ? (SymtabEntry)symbolTable.get (name) : type;
  } // searchModuleScope

  /**
   *
   **/
  SymtabEntry searchDerivedFrom (String name, InterfaceEntry i)
  {
    for (Enumeration e = i.derivedFrom ().elements (); e.hasMoreElements ();)
    {
      SymtabEntry tmp = (SymtabEntry)e.nextElement ();
      if (tmp instanceof InterfaceEntry)
      {
        InterfaceEntry parent = (InterfaceEntry)tmp;
        String fullName = parent.fullName () + '/' + name;
        SymtabEntry type = (SymtabEntry)symbolTable.get (fullName);
        if (type != null)
          return type;
        type = searchDerivedFrom (name, parent);
        if (type != null)
          return type;
      }
      // else it is a ForwardEntry and nothing can be done at this point.
    }
    return null;
  } // searchDerivedFrom

  /**
   *
   **/
  String entryName (SymtabEntry entry)
  {
    if (entry instanceof AttributeEntry)
      return "attribute";
    if (entry instanceof ConstEntry)
      return "constant";
    if (entry instanceof EnumEntry)
      return "enumeration";
    if (entry instanceof ExceptionEntry)
      return "exception";
    if (entry instanceof ValueBoxEntry)
      return "value box";
    if (entry instanceof ForwardValueEntry || entry instanceof ValueEntry)
      return "value";
    if (entry instanceof ForwardEntry || entry instanceof InterfaceEntry)
      return "interface";
    if (entry instanceof MethodEntry)
      return "method";
    if (entry instanceof ModuleEntry)
      return "module";
    if (entry instanceof ParameterEntry)
      return "parameter";
    if (entry instanceof PrimitiveEntry)
      return "primitive";
    if (entry instanceof SequenceEntry)
      return "sequence";
    if (entry instanceof StringEntry)
      return "string";
    if (entry instanceof StructEntry)
      return "struct";
    if (entry instanceof TypedefEntry)
      return "typedef";
    if (entry instanceof UnionEntry)
      return "union";
    return "void";
  } // entryName

  /**
   *
   **/
  private boolean isInterface (SymtabEntry entry)
  {
    return entry instanceof InterfaceEntry || (entry instanceof ForwardEntry
        && !(entry instanceof ForwardValueEntry)) ;
  }

  private boolean isValue (SymtabEntry entry)
  {
    return entry instanceof ValueEntry ; // || entry instanceof ForwardValueEntry;
  }

  private boolean isInterfaceOnly (SymtabEntry entry)
  {
    return entry instanceof InterfaceEntry ;
  }

  private boolean isForward(SymtabEntry entry)
  {
      return entry instanceof ForwardEntry ;
  }

  // list must be a vector of Strings.
  /**
   *
   **/
  private boolean isntInStringList (Vector list, String name)
  {
    boolean isnt = true;
    Enumeration e = list.elements ();
    while (e.hasMoreElements ())
      if (name.equals ((String)e.nextElement ()))
      {
        ParseException.alreadyDeclared (scanner, name);
        isnt = false;
        break;
      }
    return isnt;
  } // isntInStringList

  // list must be a vector of SymtabEntry's.
  /**
   *
   **/
  private boolean isntInList (Vector list, String name)
  {
    boolean isnt = true;
    for (Enumeration e = list.elements (); e.hasMoreElements ();)
      if (name.equals (((SymtabEntry)e.nextElement ()).name ()))
      {
        ParseException.alreadyDeclared (scanner, name);
        isnt = false;
        break;
      }
    return isnt;
  } // isntInList

  // list must be a vector of SymtabEntry's.
  /**
   *
   **/
  private boolean isntInList (Vector list, SymtabEntry entry)
  {
    boolean isnt = true;
    for (Enumeration e = list.elements (); e.hasMoreElements ();)
    {
      SymtabEntry eEntry = (SymtabEntry)e.nextElement ();
      if (entry == eEntry)  // && entry.fullName().equals (eEntry.fullName()))
      {
        ParseException.alreadyDeclared (scanner, entry.fullName ());
        isnt = false;
        break;
      }
     }
     return isnt;
  } // isntInList

  /**
   *
   **/
  public static SymtabEntry typeOf (SymtabEntry entry)
  {
    while (entry instanceof TypedefEntry)
      entry = entry.type ();
    return entry;
  } // typeOf

  /**
   *
   **/
  void forwardEntryCheck ()
  {
    for (Enumeration e = symbolTable.elements (); e.hasMoreElements ();)
    {
      SymtabEntry entry = (SymtabEntry)e.nextElement ();
      if (entry instanceof ForwardEntry)
        ParseException.forwardEntry (scanner, entry.fullName ());
    }
  } // forwardEntryCheck

  // <46082.03> Revert to "IDL:"-style (i.e., regular) repository ID.
  /*
  void updateRepositoryIds () {
     for (Enumeration e = symbolTable.elements(); e.hasMoreElements();) {
         SymtabEntry entry = (SymtabEntry) e.nextElement();
         if (entry instanceof ValueEntry)
           ((ValueEntry) entry).calcRepId();
     }
  } // updateRepositoryIds
  */

  ////////////////////
  // Error Handling Methods

  // A syntax error occurred.  Skip until a semicolon is encountered.
  // Ignore semicolons within {...} blocks
  /**
   *
   **/
  private void skipToSemicolon () throws IOException
  {
    while (!token.equals (Token.EOF) && !token.equals (Token.Semicolon))
    {
      if (token.equals (Token.LeftBrace))
        skipToRightBrace();
      try
      {
        match (token.type);
      }
      catch (ParseException exception)
      {
        // The error has already been reported...
      }
    }
    if (token.equals (Token.EOF))
      throw new EOFException ();
    try
    {
      match (Token.Semicolon);
    }
    catch (Exception exception)
    {
    }
  } // skipToSemicolon

  /**
   *
   **/
  private void skipToRightBrace () throws IOException
  {
    boolean firstTime = true;
    while (!token.equals (Token.EOF) && !token.equals (Token.RightBrace))
    {
      if (firstTime)
        firstTime = false;
      else if (token.equals (Token.LeftBrace))
        skipToRightBrace ();
      try
      {
        match (token.type);
      }
      catch (ParseException exception)
      {
        // The error has already been reported...
      }
    }
    if (token.equals (Token.EOF))
      throw new EOFException();
  } // skipToRightBrace

  // Error Handling Methods
  ////////////////////

  // <d56351> In CORBA 2.3, an IDL file provides a new scope for Repository IDs.
  // The following methods provide a means for other classes in the framework
  // to manage this scoping (see Preprocessor and Scanner).

  // public static int nPush = 0;
  // public static int nPop = 0;

  /**
   *
   **/
  public static void enteringInclude ()
  {
    repIDStack.push (new IDLID ());
  } // enteringInclude

  /**
   *
   **/
  public static void exitingInclude ()
  {
    repIDStack.pop ();
  } // exitingInclude


  public static final String unknownNamePrefix = "uN__";

       static Hashtable   symbolTable;
              Hashtable   lcSymbolTable  = new Hashtable ();
       static Hashtable   overrideNames;
              Vector      emitList       = new Vector ();
              boolean     emitAll;
  // <f46082.46.01>
              boolean     cppModule;
  // <d62023>
              boolean     noWarn;
              Scanner     scanner;
  // <f46082.40> No longer necessary due to new valueElement() algorithm.
  //          Stack       tokenStack     = new Stack();
              Hashtable   symbols;
              Vector      macros         = new Vector ();
              Vector      paths;

  // Only needed for the pragma directive
              SymtabEntry currentModule  = null;

  // <d56351> Static field necessary to allow Scanner access to enterind/exiting
  // Include() methods. Must reset in Compile class, too!
  //          Stack       repIDStack     = new Stack ();
       static Stack       repIDStack     = new Stack ();

  // Dynamic variable key used for forward type lists.
  // A struct or union X entry may have this attached,
  // which always contains a List<SymtabEntry>.
  // The elements are entries E such that E.type() == X.
  // This list must be resolved in pigeonhole when the
  // type is finally defined.  This is similar to
  // ForwardEntry.replaceForwardDecl.
  private static int ftlKey = SymtabEntry.getVariableKey() ;

              int         sequence       = 0;
              Vector      includes;
              Vector      includeEntries;

  // Only needed in primaryExpr.  Set in Preprocessor.booleanConstExpr.
              boolean     parsingConditionalExpr = false;

              Token         token;
              ModuleEntry   topLevelModule;
  private     Preprocessor  prep;
  private     boolean       verbose;
              SymtabFactory stFactory;
              ExprFactory   exprFactory;
  private     String[]      keywords;
  // <f46082.51> Remove -stateful feature.
  //private     boolean       parseStateful = false;

  // Circular buffer containing most recent tokens, including the current token.
  private     TokenBuffer tokenHistory = new TokenBuffer ();
  protected   float       corbaLevel; // <f60858.1>
  private     Arguments   arguments;

} // class Parser
