Click here to Skip to main content
15,885,914 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 82.8K   1.3K   19  
An article on the usage and design of another Enum Viewer
// cpre_symtable.cpp: Symbol table management methods

#include "CPreParserImp.h"
#include "cpre_symtable.h"
#include "cpre_stringstream.h"
#include "DLGLexer.h"
#include <algorithm>

///////////////////////////////////////////////////////////////////////
// Macro replacement tokens
// These are not part of the token heirarchy, but are capable
// of holding a token type and some text.  Lists of these are
// used to represent the replacement lists and argument lists
// for macros because they are smaller than regular tokens.
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// MacroReplacemntToken ctor/dtor
///////////////////////////////////////////////////////////////////////

MacroReplacementToken::MacroReplacementToken(
   ANTLRTokenType tt_, 
   const char* text_
) :
   tokenType((short)tt_)
{
   text = (char*)memPool.New(strlen(text_)+1);
   strcpy(text, text_);
}

MacroReplacementToken::~MacroReplacementToken()
{
   memPool.Delete(text, strlen(text)+1);
}

// copy ctor: Do not copy refcount from rhs!
MacroReplacementToken::MacroReplacementToken(
   const MacroReplacementToken& rhs
) :
   tokenType((short)rhs.getType())
{
   text = (char*)memPool.New(strlen(rhs.getText())+1);
   strcpy(text, rhs.getText());
}

// assignment op: Do not copy refcount from rhs!
MacroReplacementToken& 
MacroReplacementToken::operator=(
   const MacroReplacementToken& rhs
)
{
   if (&rhs != this)
   {
      tokenType = (short)rhs.getType();
      memPool.Delete(text, strlen(text)+1);
      text = (char*)memPool.New(strlen(rhs.getText())+1);
      strcpy(text, rhs.getText());
   }
   return *this;
}

///////////////////////////////////////////////////////////////////////
// Memory allocation pool
///////////////////////////////////////////////////////////////////////
JLMemPool MacroReplacementToken::memPool(MemPoolLimit, MemPoolBlockSize);
JLFreeList MacroReplacementToken::freeList(sizeof(MacroReplacementToken), FreeListBlockSize);

///////////////////////////////////////////////////////////////////////
// MacroReplacementTokenList ctor:
// Create a replacement token list from a regular token list
///////////////////////////////////////////////////////////////////////
MacroReplacementTokenList::MacroReplacementTokenList(
   const TokenList* tokenList
)
{
   for (
      TokenList::const_iterator iter(tokenList->begin());
      iter != tokenList->end();
      iter++
   )
   {
      const ANTLRAbstractToken* tokPtr = (*iter).operator->();
      push_back(new MacroReplacementToken(tokPtr->getType(), tokPtr->getText()));
   }
}

///////////////////////////////////////////////////////////////////////
// CopyToTokenList;
// Fill a regular token list from a replacement token list
///////////////////////////////////////////////////////////////////////
void 
MacroReplacementTokenList::CopyToTokenList(
   TokenList& outputList
) const
{
   outputList.clear();

   for (
      const_iterator iter(begin());
      iter != end();
      iter++
   )
   {
      outputList.push_back(
         FastToken::newToken((*iter)->getType(), (*iter)->getText())
      );
   }
}

///////////////////////////////////////////////////////////////////////
// contentEquals: compare the contents of two MacroReplacementTokenList
///////////////////////////////////////////////////////////////////////
bool 
MacroReplacementTokenList::contentEquals(
   const MacroReplacementTokenList& rhs
) const
{
   CmpReplacementTokenRefs cmpReplacementTokenRefs;
   return
      size() == rhs.size() &&
      equal(begin(), end(), rhs.begin(), cmpReplacementTokenRefs);
}

///////////////////////////////////////////////////////////////////////
//                    Symbol table support                           //
///////////////////////////////////////////////////////////////////////

// Memory allocation for MacroEntrySimple, MacroEntryFunction
JLFreeList MacroEntrySimple::freeList(sizeof(MacroEntrySimple), FreeListBlockSize);
JLFreeList MacroEntryFunction::freeList(sizeof(MacroEntryFunction), FreeListBlockSize);

///////////////////////////////////////////////////////////////////////
// CPreParserImp::EnterSimpleMacro -- Enter a simple macro definition
//    (i.e., a macro that takes no arguments), into the symbol table
//    that is implemented by member simpleSymtable.
//
// Inputs:
//    const ANTLRTokenPtr&   name           The name of the macro to be entered.
// Members used:
//    TokenList              tempTokenList  The list of tokens that is accumulated
//                                          by the token_list* rules.
//
// Return: none
///////////////////////////////////////////////////////////////////////
void CPreParserImp::EnterSimpleMacro(const ANTLRTokenPtr& name)
{
   if (functionSymtable->contains(name))
   {
      HandleError("Redefining function macro to simple macro", name);
      return;
   }

   // Make entry for table
   MacroEntrySimple *entry = new MacroEntrySimple(tempTokenList);
   
   if (simpleSymtable->contains(name))
   {
      // Compare definitions of the two macros
      MacroEntrySimpleRef entryRef;
      entryRef = (*simpleSymtable->find(name)).second;
      assert(entryRef.get() != 0);

      if (*entryRef != *entry)
      {
         HandleError("Invalid redefinition of simple macro", name);
         return;
      }
   }

   // Put entry in table
   simpleSymtable->insert(
      MacroSymbolTableSimple::value_type(name, MacroEntrySimpleRef(entry))
   );

//   printf("*** defining %s = ", name->getText());
//   DumpTokenList(entry->GetReplacementTokenList());
//   printf("\n");
}

///////////////////////////////////////////////////////////////////////
// CPreParserImp::EnterFunctionMacro -- Enter a function macro definition
//    (i.e., a macro that takes arguments), into the symbol table
//    that is implemented by member functionSymtable.
//
// Inputs:
//    const ANTLRTokenPtr   &name          The name of the macro to be entered.
// Members used:
//    TokenList       tempTokenList        The list of tokens that is accumulated
//                                         by the token_list* rules.
//    TokenList       tempIdentifierList   The list of tokens that is accumulated
//                                         by the identifier_list rule.
//
// Return: none
///////////////////////////////////////////////////////////////////////
void CPreParserImp::EnterFunctionMacro(const ANTLRTokenPtr& name)
{
   // Strip the trailing '('
   JLStr functionName(name->getText());
   functionName.erase(functionName.end()-1);

   // Make a new token for the derived name
   ANTLRTokenPtr keyTok(FastToken::newToken(name->getType(), functionName.c_str(), name->getLine()));

//   printf("*** defining %s(", (const char*)function);
//   DumpTempIdentifierList();
//   printf(") ");
//   DumpTempTokenList();
//   printf("\n");

   if (simpleSymtable->contains(keyTok))
   {
      HandleError("Redefining simple macro to function macro", keyTok);
      return;
   }

   // Make entry in symbol table
   MacroEntryFunction* entry = 
      new MacroEntryFunction(tempIdentifierList, tempTokenList);

   // Make sure it isn't a redefinition
   if (functionSymtable->contains(keyTok))
   {
      // Compare definitions of the two macros
      MacroEntryFunctionRef entryRef;
      entryRef = (*functionSymtable->find(keyTok)).second;
      assert(entryRef.get() != 0);

      if (*entryRef != *entry)
      {
         HandleError("Invalid redefinition of function macro", keyTok);
      }
      return;
   }

   functionSymtable->insert(
      MacroSymbolTableFunction::value_type(keyTok, MacroEntryFunctionRef(entry))
   );

//   printf("*** after table insert: args = ");
//   DumpTokenList(entry->GetArgumentTokenList());
//   printf("\n                 replacement = ");
//   DumpTokenList(entry->GetReplacementTokenList());
//   printf("\n");

   #ifdef COLLECT_TOKEN_STATS
      nbrFunctionMacros++;
      nbrFunctionMacroTokens += tempTokenList.entries();
      HistoToken(name);
      for (TokenListIterator iter(tempTokenList); iter(); ) { HistoToken(iter.key()); }
      for (TokenListIterator iter2(tempIdentifierList); iter2(); ) { HistoToken(iter2.key()); }
   #endif
}

///////////////////////////////////////////////////////////////////////
// CPreParserImp::UndefineMacro -- remove a macro from the macro symbol 
//    table(s) implemented by the simpleSymtable and functionSymtable
//    members.
//
// Inputs:
//    const ANTLRTokenPtr&   name     The name of the macro to be removed.
//
// Return: none
///////////////////////////////////////////////////////////////////////
void CPreParserImp::UndefineMacro(const ANTLRTokenPtr& name)
{
   ANTLRTokenKey key(name);
   functionSymtable->erase(key);
   simpleSymtable->erase(key);
}

///////////////////////////////////////////////////////////////////////
// CPreParserImp::MacroIsDefined -- Return whether a macro name is currently
//    defined as a simple or function macro.
//
// Inputs:
//    const ANTLRTokenPtr&   name     The name of the macro to test
//
// Return: true if the macro name is defined.
///////////////////////////////////////////////////////////////////////
bool CPreParserImp::MacroIsDefined(const ANTLRTokenPtr& name)
{
   ANTLRTokenKey key(name);
   return simpleSymtable->contains(key) || functionSymtable->contains(key);
}

///////////////////////////////////////////////////////////////////////
// CPreParserImp::IsFunctionLikeMacro -- Determine whether the token
// is a entered in the function macro symbol table
//
// Inputs:
//    const ANTLRTokenPtr&    name    The token of interest
//
// Return: non-zero if the token is names a function-like macro
///////////////////////////////////////////////////////////////////////
bool 
CPreParserImp::IsFunctionLikeMacro(
   const ANTLRTokenPtr& name
)
{
   ANTLRTokenKey key(name);
   return functionSymtable->contains(key);
}


#ifdef COLLECT_TOKEN_STATS
void 
CPreParserImp::DumpSymtableStats()
{
   fprintf(
      stderr,
      "\nnbrSimpleMacros = %d, nbrFunctionMacros = %d\n"
      "nbrSimpleMacroTokens = %d, nbrFunctionMacroTokens = %d\n",
      nbrSimpleMacros, nbrFunctionMacros, 
      nbrSimpleMacroTokens, nbrFunctionMacroTokens
   );
   fprintf(stderr, "Token size histogram:\n");
   int nbrTokens = 0;
   for (int i = 0; i < tokenHistoSize; i++)
   {
      nbrTokens += tokenSizes[i];
      if (i % 5 == 0 && i != 0) fprintf(stderr, "\n");
      fprintf(stderr, "%2d:%-5d    ", i, tokenSizes[i]);
   }
   fprintf(stderr, "\n");
   fprintf(stderr, "Percent of tokens equal to or smaller than:\n");
   int sumtokens = 0;
   for (i = 0; i < tokenHistoSize; i++)
   {
      sumtokens += tokenSizes[i];
      if (i % 5 == 0 && i != 0) fprintf(stderr, "\n");
      fprintf(stderr, "%2d:%5.1f%%   ", i, 100.0*sumtokens/nbrTokens);
   }
   fprintf(stderr, "\n");
}
#endif


///////////////////////////////////////////////////////////////////////
// CPreParserImp::EnterSymbolDefinition -- define a symbol
//
// Inputs:
//    const JLStr&   definition    A macro definitions, in 
//                                     one of two forms:
//                                         symbol=value, or
//                                         symbol  (define as 1)
// Return:
//     bool      true if the definition succeeded.
//               false if the definition was invalid
///////////////////////////////////////////////////////////////////////
bool
CPreParserImp::EnterSymbolDefinition(
   const JLStr& symbolDef
)
{
   int pos;
   JLStr symbol;
   JLStr value;
   if ((pos = symbolDef.find('=')) != JLStr::npos)
   {
      if (pos > 0)
      {
         symbol = JLStr(symbolDef.begin(), symbolDef.begin()+pos);
         if (pos+1 < (int)symbolDef.length())
         {
            value = JLStr(symbolDef.begin()+pos+1, symbolDef.end());
         } else {
            value = "1";
         }
      } else {
         // Invalid symbol definition -- internal error?
         return false;
      }
   } else {
      symbol = symbolDef;
      value = "1";
   }

   // Token to hand to lexers
   FastToken tok;
   // Make sure that symbol parses as a valid identifier
   CPreStringInput symInput(symbol);
   DLGLexer symScan(&symInput);
   symScan.setToken(&tok);
   // Upcast to stream because @#$%^ lexer hides getToken()
   ANTLRTokenStream* symStream = &symScan;
   ANTLRTokenPtr symToken = symStream->getToken();
   if (!TokenCanBeDefined(symToken))
   {
      // Invalid symbol definition -- internal error?
      return false;
   }

   // Parse the value token
   CPreStringInput valInput(value);
   DLGLexer valScan(&valInput);
   valScan.setToken(&tok);
   ANTLRTokenStream* valStream = &valScan;
   ANTLRTokenPtr valToken = valStream->getToken();
   
   // Enter the macro
   tempTokenList->clear();
   tempTokenList->push_back(valToken);
   EnterSimpleMacro(symToken);

   // success!
   return true;
}

///////////////////////////////////////////////////////////////////////
// CPreParserImp::SetDefinitions -- define a list of simple macros.
//
// Inputs:
//    const JLStr&   definitions   A list of macro definitions,
//                                     separated by semicolons.  Each
//                                     definition is one of two forms:
//                                         symbol=value, or
//                                         symbol  (define as 1)
// Return: none
// Note: This will TOK_NOT clear the preprocessor symbol table.
///////////////////////////////////////////////////////////////////////
void CPreParserImp::SetDefinitions(
   const JLStr& definitions
)
{
   JLStr tmpDefs(definitions);

   int pos;
   // Extract the semicolon-separated symbol definitions
   while ((pos = tmpDefs.find(';')) != JLStr::npos)
   {
      if (pos > 0)
      {
         // Enter string preceeding ';'
         EnterSymbolDefinition(JLStr(tmpDefs.begin(), tmpDefs.begin()+pos));
         // Set string to stuff past ';'
         tmpDefs = JLStr(tmpDefs.begin()+pos+1, tmpDefs.end());
      }
   }

   if (!tmpDefs.empty())
   {
      // Process the last definition
      EnterSymbolDefinition(tmpDefs);
   }
}

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