/* ---------------------------------------------------------------------
%   Copyright (C) 2007 Association for the COINS Compiler Infrastructure
%       (Read COPYING for detailed information.)
--------------------------------------------------------------------- */
package coins.sym;

//===================================================================//
//                            (##11): modified on Jan. 2002.
//                            (##10): modified on Dec. 2001.
//                            (##8):  restructuring Sep. 2001.
//                            (##6):  modified on Jun. - Aug. 2001.

/** SymTable Symbol tabel interface.
<PRE>
 *
 *  An instance of SymTable is created for each scope
 *  of symbols corresponding such language constructs
 *  as program, subprogram, struct, etc.
 *
 * Relations between symbol table and program constructs:
 *   Several symbol tables are constructed according to the
 *   structure of given source program.
 *   At first, a global symbol table is created by initiate()
 *   of SymRoot and symbols inherent to the source language are
 *   recorded in it.
 *   When a new scope of symbols is opened, a new symbol table
 *   is created and linked to ancestor symbol table that contains
 *   symbols to be inherited by the new scope (pushSymTable()).
 *   When the current scope is closed, the current symbol table is
 *   closed and the ancestor symbol table becomes the current
 *   symbol table again (by using popSymTable()).
 *   Symbols are searched in the current symbol table
 *   (symTableCurrent of SymRoot) and its ancestors in the reverse
 *   order of scope addition.
 *   Popped symbol table is not discarded unless it is empty but
 *   made invisible for search procedures so as to make
 *   inter-procedure optimization and parallelization can be done.
 *   A symbol table usually has corresponding program construct
 *   such as subprogram. There are links between such constructs
 *   and corresponding symbol table to show their correspondence
 *  (getOwner). Anonymous construct (anlnymous Struct, BlockStmt, etc.)
 *  may have name generated by the compiler.
 * Scope of symbols:
 *   Source program symbols (symbols appearing in source program)
 *   have their scope as defined by the grammar of the language.
 *   Each Struct and Union opens a new scope.
 *   Scope of constants is the entire compile unit.
 *   Scope of registers is the subprogram using them.
 *   Scope of temporal variables generated by the compiler
 *   is the subprogram within which the temporal variables
 *   are defined.
</PRE>
 **/

public interface
SymTable
{

/** pushSymTable
 *  Make this (current) symbol table as an ancestor symbol table
 *  and create a new symbol table making it as the current symbol
 *  table. Linkage between the new current symbol table and the
 *  ancestor symbol table is made and the new current symbol table
 *  is made a direct descendant symbol table of the ancestor.
 *  "this" should be the current symbol table that is to be made
 *      as the ancestor.
 *  If pOwner is a subprogram, then symRoot.subpCurrent is set to
 *  pOwner and symRoot.symTableCurrentSubp is set to the created
 *  symbol tablbe.
 *  @param pOwner Symbol owning the the new SymTable
 *      (subprogram, etc.), null if no symbol corresponds.
 *  @return the newly created current symbol table.
**/
SymTable
pushSymTable( Sym pOwner );

/** popSymTable
 *  Close this (current) symbol table and make its ancestor symbol
 *  table as the current symbol table if this has the ancestor.
 *  The closed symbol table can be reopened by reopenSymTable.
 *  "this" should be the current symbol table to be closed.
 *  If theowner of the popped symbol table is a subprogram, then
 *  symRoot.subpCurrent is set to that subprogram and
 *  symRoot.symTableCurrentSubp is set to the popped
 *  symbol tablbe.
 *  @return the ancestor symbol table that is resumed as
 *      the current symbol table. If this has no ancestor,
 *      then return null.
**/
SymTable
popSymTable();

/** reopenSymTable
 *  Push this (current) symbol table as the ancestor symbol table
 *  and make the symbol table specified by the parameter as
 *  the new current symbol table.
 *  "this" should be the current symbol table that is to be made
 *      as the ancestor.
 *  @param pPreviousSymTable a symbol table that was once
 *      a direct descentdant symbol table of this symbol table.
 *  @return pPreviousSymTable that is made as the new current
 *      symbol table.
**/
SymTable
reopenSymTable( SymTable pPreviousSymTable);

/** getParent
 *  Get parent symbol table of this table.
**/
public SymTable
getParent();

/** getFirstChild
 *  @return the first child symbol table of this.
 *      If there is no child, return null.
**/
public SymTable
getFirstChild();

/** getBrother
 *  @return the next brother symbol table of this.
 *      If there is no next brother, return null.
**/
public SymTable
getBrother();

/** searchTableHaving
 *  Search the symbol table that has pSym
 *  starting from this symbol table and ascending to its sncestors.
 *  Stop searching if found without searching further ancestors.
 *  @param pSym symbol in a symbol table.
 *  @return symbol table that has pSym
 *     or return symTableRoot if no table is found.
**/
public SymTable
searchTableHaving(Sym pSym);

/** defineUnique
<PRE>
 *  Define a new symbol specified by the parameter pInternedName
 *  in the current symbol table without traversing ancestor symbol tables.
 *  If there is already a symbol with the same name as pInternedName,
 *  then it is treated as an erronous call and no new symbol is created.
 *  "this" should be the current symbol table.
 *  Note:
 *      If pSymKind is either symKindSubp, symKindVar, symKindParam,
 *      symKindElem, or symKindConst, etc. then either Subp, Var,
 *      Param, Elem, or Const instance is created each respectively.
 *      Several linkages are made between the defined symbol and
 *      pDefinedIn symbol (see definedIn(), getFirstParam(), getFirstLocalVar(),
 *      getFirstElem(), getNext(), getNextSubp(), etc.)
 *      These rules are applied also to Define and redefine.
 *  @param pInternedName unique string representing the symbol to be defined.
 *  @param pSymKind kind of the symbol to be created (see GlobalConstants).
 *  @param pDefinedIn symbol representing language construct such as
 *      subprogram name or structure name that encloses the definition of
 *      the symbol to be defined; If there is no such construct, specify null.
 *      (See definedIn().)
 *  @return the new symbol having the name same to pInternedName and whose
 *      symbol kind is pSymKind; If there is already a symbol with the same
 *      name as pInternedName, then return null.
</PRE>
**/
Sym
defineUnique( String pInternedName, int pSymKind, Sym pDefinedIn);

/** define
<PRE>
 *  Define a new symbol specified by the parameter pInternedName
 *  in the current symbol table. If there is already an old symbol with
 *  the same name as pInternedName and with the same kind as pSymKind
 *  in this symbol table, then no new symbol is created and the old
 *  symbol is returned.
 *  Ancestor symbol tables are not traversed to find the same symbol.
 *  "this" should be the current symbol table.
 *  @param pInternedName unique string representing the symbol to be defined.
 *  @param pSymKind kind of the symbol to be created (see GlobalConstants).
 *  @param pDefinedIn language construct symbol that encloses the definition
 *      of pInternedName; If there is no such construct, specify null.
 *  @return the symbol having the name same to pInternedName and whose
 *      symbol kind is pSymKind; If there is already a symbol with the same
 *      name as pInternedName and the same kind as pSymKind, then return it.
</PRE>
**/
Sym
define( String pInternedName, int pSymKind, Sym pDefinedIn);

/** search
<PRE>
 *  Search the symbol specified by the parameter pInternedName in the
 *  current symbol table and its ancestors. The symbol is searched in
 *  the current symbol table first, and if not found, then
 *  searched in its direct ancestor, and if not found again,
 *  then searched in ancestor's ancestor, and so on.
 *  If there are more than one symbols having the same name then
 *  the one encountered first in the above search process is returned.
 *  "this" should be the current symbol table.
 *  See searchSymOfThisKind and redefine.
 *  @param pInternedName unique string representing the symbol to be searched.
 *  @return the symbol having the name same to pInternedName,
 *      where the symbol kind of the returned symbol may
 *      differ from that of pInternedName given this time;
 *      If there is no same symbol in this SymTable and its ancestors,
 *      then return null.
</PRE>
**/
Sym
search( String pInternedName);

/** search
 *  Search symbol having pInternedName as its name and
 *  pSymKind as its kind.
 *  Other things are the same as the search(String pInternedName).
 *  @param pInternedName unique string representing the symbol to be searched.
 *  @param pSymKind symbol kind (Sym.KIND_VAR, etc.).
 *  @return the symbol having the name same to pInternedName
 *      and its symbol kind is pSymKind;
 *      If no such symbol was found, return null.
**/
public Sym
search(String pInternedName,int pSymKind);


/** searchLocal
 *  Search the symbol which is specified by parameter pInternedName
 *  and whose kind is the same as pSymKind.
 *  Searching is done in this symbol table only (do not search
 *  ancestors).
 *  @param pInternedName symbol name which is Interned.
 *  @param pSymKind symbol kind (Sym.KIND_VAR, etc.).
 *  @return a symbol whose name and kind are the same as
 *      pInternedName and pSymKind;
 *      If there is no same symbol in this SymTable,
 *      then return null.
**/
public Sym
searchLocal(String pInternedName,int pSymKind);

/** searchLocal
 *  Search the symbol which is specified by parameter pInternedName.
 *  Searching is done in this symbol table only (do not search
 *  ancestors).
 *  If pSpecifiedKind is true, then search symbol of the same kind,
 *  else search symbol disregarding symbol kind.
 *  @param pInternedName symbol name which is Interned.
 *  @param pSymKind symbol kind (Sym.KIND_VAR, etc.).
 *  @param pSpecifiedKind If ture, search symbol of the same name
 *      and the same kind.
 *  @return a symbol whose name (and kind) is the same as
 *      pInternedName (and pSymKind);
 *      If there is no same symbol in this SymTable,
 *      then return null.
**/
public Sym
searchLocal( String pInternedName, int pSymKind, boolean pSpecifiedKind );

/** searchSymOfThisKind
 *  Search for the smbol having the same name as the parameter pSym and
 *  its kind is the same to pSymKind in the same manner as Search.
 *  If one is found then it is returned. If not found, then
 *  null is returned.
 *  "this" should be the current symbol table.
 *  @param pSym a symbol having the same name as the one to be searched.
 *  @param pSymKind kind of the symbol to be searched;
 *      It may be different from the symbol kind of pSym.
 *  @return the symbol whose name is the same to pSym
 *      and its kind is the same to pSymKind,
 *      or return null if not found.
 **/
Sym
searchSymOfThisKind( Sym pSym, int pSymKind);

/** redefine
<PRE>
 *  Create a new symbol that has the name same as this symbol but
 *  having the symbol kind indicated by the parameter pSymKind
 *  in the current symbol table.
 *  "this" should be the current symbol table.
 *  Usage of redefine
 *    If the source language permits the same name to be defined
 *    as a name of different kind in the same scope, then Search may
 *    return a symbol having the same name but with different kind.
 *    In that case, search ancestors again by searchSymOfThisKind
 *    and if not found, then use redefine to define the symbol
 *    as the new one of pSymKind. For example, enumerator may have
 *    the same name as that of some subprogram in C.
 *  @param pSymKind symbol kind of the symbol to be created.
 *  @param pDefinedIn language construct symbol that encloses the
definition
 *      of pSym; If there is no such construct, specify null.
 *  @return the created symbol.
</PRE>
**/
Sym
redefine( Sym pSym, int pSymKind, Sym pDefinedIn);

/** searchOrAddSym
 *  Search the symbol pSym in this symbol table
 *  If found, return it.
 *  If not found, add it in this symbol table and return
 *  the added symbol.
 *  This may be used in such cases as type declaration
 *  or multiple external declaration where 2nd, 3rd declaration
 *  do not add new entry but use the entry created by the 1st
 *  declaration.
 *  @param pSym symbol to be searched.
 *  @return the symbol found or added.
**/
public Sym
searchOrAddSym(Sym pSym);

/** searchOrAdd
<PRE>
 *  Search the symbol which is specified by parameter pInternedName,
 *  pSymKind.
 *  If pWithinThisTable is false search all parents symbol table are
 *  as well as searched.
 *  If pSpecifiedKind is ture, search the symbol which is same as
 *  pInternedName and pSymKind.
 *  If the symbol is found and then return it.
 *  If not, make new symbol, then add to this symbol table.
 *  @param String pInternedName symbol name which is Interned.
 *  @param int pSymKind symbol kind.
 *  @param boolean pWithinThisTable If ture, search this symbol
 *      table only. If false, search ancester symbol tables.
 *  @param pSpecifiedKind If ture, search the symbol which is
 *      same name as pInternedName and same kind as pSymKind.
 *  @return Sym found symbol or generated symbol.
</PRE>
**/
public Sym
searchOrAdd( String  pInternedName, int pSymKind, Sym pDefinedIn,
             boolean pWithinThisTable, boolean pSpecifiedKind );

/** searchOrAddEntry
 *  Search a symbol table entry where a symbol is to be placed.
 *  This enables to get a SymTable slot to which a symbol
 *  is to be placed and then create the symbol object
 *  whereas searchOrAdd creates a symbol object in it
 *  if the symbol is not yet created.
 *  @return a symbol table entry to which pInternedName is to be
 *      recorded; This is used to get blank symbol table entry
 *      corresponding to pInternedName and then write a symbol
 *      object to the entry by setEntrySym of SymTableEntry.
**/
public SymTableEntry
searchOrAddEntry( String  pInternedName, int pSymKind, Sym pDefinedIn,
             boolean pWithinThisTable, boolean pSpecifiedKind );
/** linkSym
 *  Link pNewSym as the last symbol of this symbol table.
 *  Set fRecordedIn of pNewSym as this symbol table.
**/
public void
linkSym( Sym pNewSym );

/** subpSymTable
 *  Get the symbol table of current subprogram.
 *  If this SymTable is a SymTable defined inside a subprogram,
 *  then get the SymTable of the enclosing subprogram.
 *  If current subprogram is not yet defined, then
 *  get symTableRoot.
 *  This method is used in generating temporal variable, etc.
**/
public SymTable
subpSymTable();

//##70 BEGIN
/**
 * Generate symbol name which is unique in this SymTable
 * and its ancestors.
 * @param pHeader is a string to be used as header of the generated name.
 * @return the generated name
 */
public String
generateSymName( String pHeader );
//##70 END

/** generateVar
 *  Generate a variable of type pType in the symbol table
 *  of current subprogram symRoot.subpCurrent
 *  (to be used as temporal variable, etc.).
 *  If subpCurrent is null, the variable is recorded in
 *  symTableRoot.
 *  @param pType type of the variable to be generated.
 *  @return the generated variable.
**/
public Var
generateVar( Type pType );

/** generateVar
 *  Generate a variable of type pType in subpSymTable()
 *  starting with "_var" (to be used as temporal variable, etc.).
 *  "this" should be the current symbol table.
 *  @param pType type of the variable to be generated.
 *  @param pDefinedIn language construct symbol that encloses the
 *      definition of the generated variable; If there is no such
 *      construct, specify null.
 *  @return the generated variable.
 */
Var
generateVar( Type pType, Sym pDefinedIn);

/** generateParam
 *  Generate a parameter of type pType in subpSymTable().
 *  The name starts with "_param".
 *  Anonymous parameter should be given a name (by generateParam).
 *  "this" should be symTableCurrentSubp.
 *  @param pType type of the parameter to be generated.
 *  @param pDefinedIn Subprogram defining the parameter.
 *  @return the generated parameter.
 */
Param
generateParam( Type pType, Sym pDefinedIn);

/** generateElem
 *  Generate an element of type pType in this symbol table.
 *  The name starts with "_elem".
 *  "this" should be the current symbol table.
 *  @param pType type of the element to be generated.
 *  @param pDefinedIn language construct symbol that encloses the
definition
 *      of the element (structure or union name).
 *  @return the generated element.
 */
Elem
generateElem( Type pType, Sym pDefinedIn);

/** generateLabel
 *  Generate an internal label in subpSymTable().
 *  The name starts with "_lab".
 *  @return the generated label.
**/
Label
generateLabel( );

/** generateTag
 *  Generate a tag name in subpSymTable().
 *  The name starts with "_tag".
 *  @return the generated tag symbol.
**/
public Sym
generateTag();
public Sym
generateTag(String tagname); ///////////////////// S.Fukuda 2001.12.11

/** generateSym
 *  Generate a symbol of type pType in subpSymTable().
 *  (to be used as block name, etc.).
 *  @param pType type of the symbol to be generated.
 *  @param pSymKind symbol kind number of the symbol to be generated.
 *  @param pPrefix prefix to be attached to the symbol name;
 *      Another prefix "_" preceeds the given prefix pPrefix.
 *  @param pDefinedIn language construct symbol that encloses the
 *      definition of the generated variable; If there is no such
 *      construct, specify null.
 *  @return the generated symbol.
 *  As for variable, parameter, element, label, tag,
 *  use generateVar, generateParam, generateElem,
 *  generateLabel, generateTag.
**/
public Sym
generateSym( Type pType, int pSymKind, String pPrefix,
             Sym pDefinedIn );

/** generateDerivedSym
 *  Generate a symbol having the same type and kind as that of
 *  pSym in this symbol table. The generated name has a name
 *  beginning with the name of pSym preceeded by "_" and ending with
 *  one of suffixes _1, _2, _3, ... . The suffix is selected so that
 *  the same name does not appear in the symbol table.
 *  "this" should be symTableCurrentSubp or symTableCurrent.
 *  @param pSym symbol from which the generated symbol
 *      is to be derived.
 *  @return the generated symbol.
**/
public Sym
generateDerivedSym( Sym pBaseSym );

/** setUniqueNameToAllSym
 *  Set unique name to all symbols of the kind
 *  Var, Param, Subp, Label in the whole compile unit.
 *  This operation is performed for all symbol tables
 *  under symTableRoot.
 *  Normally, this should be called only once after generating HIR
 *  for all subprograms and immediately before generating LIR
 *  (by ConvToNewLIR).
**/
public void
setUniqueNameToAllSym();

/**
 * Generate unique name for symbols in the form of
 * subprogramName_originalName_n, where, subprogramName is
 * the name of the subprogram defining the symbol ("" for global symbol),
 * oroginalName is the name of the symbol, n is sequence number (1, 2, 3, ...)
 * attached to avoid duplication if there are same names declared in one
 * subprogram.
 * @param pOldSym
 * @param pSubp
 * @return unique name string.
 */
public String
generateUniqueName( Sym pOldSym, Subp pSubp);

/** getOwner
 *  Get the owner node to which this symbol table is attached.
 *  @return the owner symbol (subprogram, block name, struct, union, etc.).
**/
Sym
getOwner();

/** getOwnerName
 *  Get the name of the owner of this symbol table.
 *  @return the owner name. If the owner is null, return "null".
**/
String
getOwnerName();

/** getSubp
 *  Get the subprogram to which this symbol table is attached
 *  or in which the owner of this symbol table is contained.
 *  @return the subprogram owning or containing this symbol table.
**/
public Subp
getSubp();

/** getSymCount
 *  Get the number of symbols recorded in the symbol table.
 *  (It will not be decreased even if a symbol is deleted.)
 *  Empty symbol table will return 0.
**/
int
getSymCount();

/** getSymIterator
 *  Get iterator to scan all symbols
 *  recorded in this symbol table.
**/
public SymIterator
getSymIterator();

/** getSymNestIterator   (##6)
 *  Get iterator to scan all symbols
 *  recorded in this symbol table and its children.
**/
public SymNestIterator
getSymNestIterator();

/** getSymTableIterator   (##10)
 *  Get iterator to scan all symbols tables
 *  starting from this symbol table and its children.
**/
public SymTableIterator
getSymTableIterator();

/** getVarIterator
 *  Get iterator to scan all variables and parameters
 *  recorded in this symbol table.
**/
/*##
public VarIterator
getVarIterator();
##*/

/** getFirstSym
 *  Get the first symbol recorded in this symbol table.
 *  The rest of symbols can be get by getNextSym() of Sym interface.
 *  This method is not necessary when SymIterator is used.
**/
public Sym
getFirstSym();

/** isInThisSymTable
 *  @param pSym Any symbol.
 *  @return true if pSym is contained in this SymTable
 *      otherwise return false;
**/
public boolean
isInThisSymTable( Sym pSym );

/** printSymTable                         (##2)
 *  Print symbols in this symbol table using toString().
**/
void printSymTable();

/** printSymTableDetail                   (##2)
 *  Print symbols in this symbol table using toStringDetail().
 *      ExpId is printed if ioRoot.dbgSym.getLevel() > 2.
**/
void printSymTableDetail();

/** printSymTableAll                         (##2)
 *  Print symbols in pSymTable and all its descendent
 *  symbol tables using printSymTable.
 *  @param pSymTable any symbol table.
**/
void printSymTableAll( SymTable pSymTable );

/** printSymTableAllDetail                         (##2)
 *  Print symbols in pSymTable and all its descendent
 *  symbol tables using printSymTableDetail.
 *  @param pSymTable any symbol table.
**/
void printSymTableAllDetail( SymTable pSymTable );

//##70 BEGIN
/** printSymTableAllDetail with no param.
 *  Print symbols in pSymTable and all its descendent
 *  symbol tables using printSymTableDetail.
 *  This also print symRoot.symTableConst.
 *  and if dbgSym.getLevel() > 3, print symRoot.symTableUnique, too.
**/
void printSymTableAllDetail( );
//##70 END

} // SymTable interface

