Click here to Skip to main content
15,892,643 members
Articles / Desktop Programming / MFC

Another Enum Viewer

Rate me:
Please Sign up or sign in to vote.
4.50/5 (2 votes)
22 Oct 20015 min read 83K   1.3K   19  
An article on the usage and design of another Enum Viewer
// CPPSymTableScope.cpp: Scope-manipulation for CPPSymTable.

#include "CPPSymTable.h"
#include "CPPScopeNormal.h"
#include "CPPTypeClass.h"
#include "CPPTypeTemplated.h"
#include "CPPDecl.h"
#include "JLCast.h"
#include "CPPScopeState.h"
#include "CPPScopeContainers.h"
#include "CPPTypeClassBaseClass.h"
#include "CPPExpr.h"

/////////////////////////////////////////////////////////////////////
// SaveScope: Return a struct signifying the position of the scope
// stack.  This is used before an arbitrary series of scope
// pushes, so that the scope stack can be restored to a given state.
// 
// Inputs: none
// Outputs: none
// Return:
//    CPPScopeState   The state of the stack (i.e., its size)
/////////////////////////////////////////////////////////////////////
// virtual 
CPPScopeState
CPPSymTable::SaveScope() const
{
   return CPPScopeState((int)scopeStack->size());
}

/////////////////////////////////////////////////////////////////////
// RestoreScope: Pop the scope stack to the indicated position.
//
// Inputs:
//    CPPScopeState  state   The scope stack state to which
//                                   it should be restored.
// Outputs: none
// Return: none
/////////////////////////////////////////////////////////////////////
// virtual 
void 
CPPSymTable::RestoreScope(
   CPPScopeState state
)
{
   // Make sure this isn't a bogus state
   assert(state.position > 0);
   assert(state.position <= (int)scopeStack->size());

   while ( (int)scopeStack->size() > state.position)
   {
      // The top of the stack is the front of the list
      scopeStack->pop_front();
   }
}

///////////////////////////////////////////////////////////////////////
CPPScopeLevel 
CPPSymTable::PopScope()
{
   assert((int)scopeStack->size() > 1);
   CPPScopeLevel topScope = scopeStack->front();
   scopeStack->pop_front();
   return topScope;
}

///////////////////////////////////////////////////////////////////////
void 
CPPSymTable::PushScope(
   CPPScopeLevel scopeLevel
)
{
   scopeStack->push_front(scopeLevel);
}

/////////////////////////////////////////////////////////////////////
// EnterNamedScope: Push the scope for a class or namespace on the 
// stack.  Drags in the scopes of the base classes (and parent classes
// if "resolved" is false).
//
// Inputs:
//    const JLStr&   name       The name of the class or namespace
//    bool           resolved   If true, then put the scopes on the
//                              stack in "resolved" mode so that only
//                              the scopes of the class/namespace and 
//                              any base classes are searchable.
//
// Outputs: none
// Return:
//    bool    true on success, false if the scope could not be found.
//
// Note: Used with resolved==false when a class member 
// function is entered, like:
//     class A { int f(); };
//     int A::f() { ... }
//
// Note: Used with resolved=false during class definitions to enter
// the scope of defined base classes:
//     class A : public B { ... };
//
// Note: Used with resolved=true when the scope resolution operator 
// is encountered with a class or namespace name:
//     A::B::x
//
// Note: Use SaveScope/Restore scope to pop this scope when finished.
/////////////////////////////////////////////////////////////////////
// virtual 
bool 
CPPSymTable::EnterNamedScope(
   const JLStr& name,
   bool resolved
)
{
   // Find the scope
   CPPScopeRefI theScope;
   if (LookupScope(name, theScope, true))
   {
      // Push the scope for the namespace on the stack.
      EnterScopeContext(theScope, resolved);
      return true;
   } else {
      // non-existent class/namespace.
      return false;
   }
}

/////////////////////////////////////////////////////////////////////
// EnterClassScope: Enter the given class scope.  Drags in the 
// scopes of the base classes.
//
// Inputs:
//   const CPPTypeRefI   theClass     The class for the scope being entered.
//   bool                resolved     If true, then the scope is entered in
//                                    "resolved" mode.
//
// Outputs: none
// Return: none
/////////////////////////////////////////////////////////////////////
void 
CPPSymTable::EnterClassScope(
   CPPTypeRefI theClass,
   bool resolved
)
{
   if (resolved)
   {
      // Push a "resolved" empty scope
      EnterScope(emptyScope, true);
   }

   theClass = theClass->StripTemplateModifiers();

   // Get the list of base classes for the class
   assert(theClass->GetFlavor() == CPPType::Class);
   CPPTypeClass::BaseClassListCRefI baseClasses = 
      STATIC_CAST(CPPTypeClass*, theClass.get())->GetBaseClasses();

   // Recursively push the scopes for the base classes on the stack
   for (
      CPPTypeClass::BaseClassList::const_iterator iter = baseClasses->begin();
      iter != baseClasses->end();
      iter++
   )
   {
      EnterClassScope((*iter).GetBaseClass(), false);
   }

   // Push the scope for the class itself on the stack.
   EnterScope(
      STATIC_CAST(CPPTypeClass*,theClass.get())->GetMemberScope(),
      false
   );
}

/////////////////////////////////////////////////////////////////////
// EnterScopeContext: Enter a scope context, which is the scope, its
// parents, and base classes
//
// Inputs:
//    CPPScopeRefI    scope     The scope whose context is to be entered
//    bool            resolved  If true, then the scope is entered in
//                              "resolved" mode, and no parent scopes are
//                               entered.
// Outputs: none
// Return: none
//
// Note: Used to enter the context of a class member function, or to
// enter the scope of a scope-override prefix.
/////////////////////////////////////////////////////////////////////
void 
CPPSymTable::EnterScopeContext(
   CPPScopeRefI scope,
   bool resolved
)
{
   if (!resolved)
   {
      // Push the parent scopes first
      if (scope->GetParentScope().get() != 0)
      {
         switch (scope->GetParentScope()->GetFlavor())
         {
            case CPPScope::ScopeClass:
            case CPPScope::ScopeNamespace:
               // Only class/namespace should be pushed
               EnterScopeContext(scope->GetParentScope(), false);
               break;
         }
      }
   } else {
      // Push a "resolved" empty scope
      EnterScope(emptyScope, true);
   }

   // Look for a class or class template by that name
   CPPTypeRefI classType;
   if (scope->GetParentScope().get() != 0)
   {
      CPPDeclRefI theDecl;
      theDecl = scope->GetParentScope()->FindClassDeclByName(scope->GetName());
      if (theDecl.get() != 0)
      {
         classType = theDecl->GetType();
      } else {
         // try for a templated class
         theDecl = scope->GetParentScope()->FindTemplatedDeclByName(scope->GetName());
         if (theDecl->IsType())
         {
            classType = theDecl->GetType()->StripTemplateModifiers();
            if (classType->GetFlavor() != CPPType::Class)
            {
               classType = (CPPType*)0;
            }
         }
      }
   }

   if (classType.get() != 0)
   {
      // Recursively push the base classes for the class on the stack.
      EnterClassScope(classType, false);
   } else {
      EnterScope(scope, false);
   }
}


/////////////////////////////////////////////////////////////////////
// EnterResolvedGlobalScope: Start a new global scope for qualifying names.
//
// Inputs: none
// Outputs: none
// Return: none
//
// Note: Used when a qualified name is being parsed, like:
//    int x;
//    class A { A(); int x; };
//    A::A() { x = ::x; }
// To make sure that "::x" only searches the global scope.
//
// Note: Use SaveScope/Restore scope to pop this scope when finished.
/////////////////////////////////////////////////////////////////////
// virtual 
void 
CPPSymTable::EnterResolvedGlobalScope()
{
   EnterScope(globalScope, true);
}

/////////////////////////////////////////////////////////////////////
// EnterLocalScope: Start a new scope for code blocks, including
//    function definitions
//
// Inputs: none
// Outputs: none
// Return: none
//
// Note: Use SaveScope/Restore scope to pop this scope when finished.
/////////////////////////////////////////////////////////////////////
// virtual 
void 
CPPSymTable::EnterLocalScope()
{
   EnterScope(
      new CPPScopeNormal(CPPScope::ScopeLocal, ""),
      false
   );
}

/////////////////////////////////////////////////////////////////////
// EnterLocalScope: Start a new scope to hold template declarations.
//
// Inputs: none
// Outputs: none
// Return: none
//
// Note: Use SaveScope/Restore scope to pop this scope when finished.
/////////////////////////////////////////////////////////////////////
// virtual 
void 
CPPSymTable::EnterWorkScope()
{
   EnterScope(
      new CPPScopeNormal(CPPScope::ScopeWork, ""),
      false
   );
}

/////////////////////////////////////////////////////////////////////
// EnterScope: Push the given scope on the scope stack.
//
// Inputs:
//    CPPScopeRefI    scope     The scope to enter
//    bool            resolved  true to enter scope in resolved mode
//
// Outputs: none
// Return: none
//
// Note: Use SaveScope/Restore scope to pop this scope when finished.
/////////////////////////////////////////////////////////////////////
void 
CPPSymTable::EnterScope(
   const CPPScopeRefI& scope,
   bool resolved
)
{
   // The top of the stack is the front of the list
   scopeStack->push_front(
      CPPScopeLevel(
         scope,
         resolved
      )
   );
}


/////////////////////////////////////////////////////////////////////
// EnterExprScope: Given an expression, find the type of the
// expression; if the type is a class, then enter it's member scope
//
// Inputs:
//    CPPExprRefI     expr      The expression
//    bool            resolved  true to enter scope in resolved mode
//
// Outputs: none
// Return: none
//
// Note: Use SaveScope/Restore scope to pop this scope when finished.
/////////////////////////////////////////////////////////////////////
void
CPPSymTable::EnterExprScope(
   CPPExprRefI expr,
   bool resolved
)
{
   // TODO: Get the expression type and do this for real.
   // For now: fake it for id expressions only
   CPPTypeRefI exprType = expr->GetType();
   if (exprType.get() != 0)
   {
      // Strip off template, const, volatile and indirection modifiers.
      // Only strip one template/indirection
      // TODO: this sort of type processing should be centralized
      bool strippedTemplate = false;
      bool strippedIndirection = false;
      bool strippedModifier;
      do {
         strippedModifier = false;

         if (!strippedTemplate && exprType->GetFlavor() == CPPType::Templated)
         {
            exprType = exprType->GetBaseType();
            strippedTemplate = true;
            strippedModifier = true;
         }
         if (!strippedIndirection && exprType->GetFlavor() == CPPType::Indirection)
         {
            exprType = exprType->GetBaseType();
            strippedIndirection = true;
            strippedModifier = true;
         }
         if (exprType->GetFlavor() == CPPType::CVQualified)
         {
            exprType = exprType->GetBaseType();
            strippedModifier = true;
         }
      } while (strippedModifier);

      // After stripping the modifiers, if what's left is a class, then
      // enter the class scope;
      if (exprType->GetFlavor() == CPPType::Class)
      {
         EnterClassScope(exprType, resolved);
      }
   }
}

/////////////////////////////////////////////////////////////////////
// GetEnclosingClassName: Get the name of the enclosing class scope
//    if any exists.
//
// Inputs: none
// Outputs: none
// Return:
//    const JLStr&    The name of the enclosing class scope, or
//                     the empty string if none exists;
/////////////////////////////////////////////////////////////////////
// virtual 
const JLStr& 
CPPSymTable::GetEnclosingClassName() const
{
   static const JLStr dummy;

   // The top of the stack is the front of the list
   for (
      CPPScopeStack::iterator iter = scopeStack->begin();
      iter != scopeStack->end();
      iter++
   )
   {
      if ((*iter).GetScope()->GetFlavor() == CPPScope::ScopeClass)
      {
         return (*iter).GetScope()->GetName();
      }

      if ((*iter).GetResolved())
      {
         // Don't search beyond a resolved scope
         break;
      }
   }

   return dummy;
}


/////////////////////////////////////////////////////////////////////
// GetCurrentScope: Get the current scope.
//
// Inputs: none
// Outputs: none
// Return:
//    CPPScopeRefI   The current scope
/////////////////////////////////////////////////////////////////////
// virtual 
CPPScopeRefI
CPPSymTable::GetCurrentScope() const
{
   return scopeStack->front().GetScope().get();
}

/////////////////////////////////////////////////////////////////////
// GetCurrentScopeName: Get the current scope name
//
// Inputs: none
// Outputs: none
// Return:
//    JLStr   The current scope name
/////////////////////////////////////////////////////////////////////
// virtual 
JLStr
CPPSymTable::GetCurrentScopeName() const
{
   return scopeStack->front().GetScope()->GetName();
}

/////////////////////////////////////////////////////////////////////
// SetCurrentScopeAccess: Set the current access for succeeding
// declarations in the scope.
//
// Inputs:
//    AccessSpecifier    as   The next default access.
// Outputs: none
// Return: none
/////////////////////////////////////////////////////////////////////
// virtual 
void 
CPPSymTable::SetCurrentScopeAccess(
   CPPConst::AccessSpecifier as
)
{
   scopeStack->front().GetScope()->SetCurrentAccess(as);
}

/////////////////////////////////////////////////////////////////////
// GetCurrentScopeAccess: Get the current access for succeeding
// declarations in the scope.
//
// Inputs: none
// Outputs: none
// Return:
//    AccessSpecifier    The default access.
/////////////////////////////////////////////////////////////////////
// virtual 
CPPConst::AccessSpecifier 
CPPSymTable::GetCurrentScopeAccess() const
{
   return scopeStack->front().GetScope()->GetCurrentAccess();
}


//////////////////////////////////////////////////////////////////////
// CPPSymTable::GetEnclosingPermanentScope: Get the nearest enclosing
// permanent scope from the scope stack.  Note that work scopes are
// considered to be permanent scopes.
//
// Inputs: none
// Outputs: none
// Return:
//    CPPScopeRefI   The enclosing permanent scope
//////////////////////////////////////////////////////////////////////
CPPScopeRefI
CPPSymTable::GetEnclosingPermanentScope() const
{
   // Search the scope stack to find the closest local or global scope
   for (
      CPPScopeStack::iterator stackIter = scopeStack->begin();
      stackIter != scopeStack->end();
      stackIter++
   )
   {
      switch ((*stackIter).GetScope()->GetFlavor())
      {
         case CPPScope::ScopeGlobal:
         case CPPScope::ScopeClass:
         case CPPScope::ScopeNamespace:
         case CPPScope::ScopeWork:
            return (*stackIter).GetScope();
         default:
            break;
      }
   }

   // We should always hit a global scope before we finish
   assert(0);
   return CPPScopeRefI();
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions