home *** CD-ROM | disk | FTP | other *** search
/ Game Audio Programming / GameAudioProgramming.iso / Game_Audio / audio_sdk / src / AudioScript / Lexer.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2002-06-27  |  44.7 KB  |  1,519 lines

  1. /***********************************************************\
  2. Copyright (C) James Boer, 2002. 
  3. All rights reserved worldwide.
  4.  
  5. This software is provided "as is" without express or implied
  6. warranties. You may freely copy and compile this source into
  7. applications you distribute provided that the copyright text
  8. below is included in the resulting source code, for example:
  9. "Portions Copyright (C) James Boer, 2002"
  10. \***********************************************************/
  11.  
  12. #include "Audio.h"
  13. #include "Lexer.h"
  14.  
  15. using namespace std;
  16. using namespace Audio;
  17.  
  18. const int MAX_LINE_LENGTH = 1024;
  19.  
  20. const int INITIAL_RESERVED_OPERATORS =     50;
  21. const int INITIAL_RESERVED_KEYWORDS =    20;
  22.  
  23. // These strings are part of the standard set of operators required in order to 
  24. // perform standard parsing functions
  25. const char* g_pszStringDelimiter        = "\"";
  26. const char* g_pszSingleLineComment        = "//";
  27. const char* g_pszOpeningComment            = "/*";
  28. const char* g_pszClosingComment            = "*/";
  29. const char* g_pszDecimalPoint            = ".";
  30. const char* g_pszNewLine                = "/n";
  31. const char* g_pszPoundSign                = "#";
  32. const char* g_pszLeftParen                = "(";
  33. const char* g_pszRightParen                = ")";
  34. const char* g_pszMinusSign                = "-";
  35. const char* g_pszDivideSign                = "/";
  36. const char* g_pszMultiplySign            = "*";
  37. const char* g_pszBackSlash                = "\\";
  38. const char* g_pszComma                    = ",";
  39. const char* g_pszSemiColon                = ";";
  40.  
  41. // Several keywords are predefined for built-in functionality
  42. const char* g_pszInclude                = "include";
  43. const char* g_pszDefine                    = "define";
  44. const char* g_pszDefineGUID                = "DEFINE_GUID";
  45. const char* g_pszVector                    = "vector";
  46. const char* g_pszTrue                    = "true";
  47. const char* g_pszFalse                    = "false";
  48.  
  49.  
  50.  
  51. //------------------------------------------------------------------------//
  52. void Macro::Clear()
  53. {
  54.     m_sName = "";
  55.     m_ArgumentVector.clear();
  56.     m_SubstitutionVector.clear();
  57.     m_MacroList.clear();
  58.     m_iTotalArguments = 0;
  59.     m_iCurrentArgument = 0;
  60. }
  61.  
  62.  
  63. //------------------------------------------------------------------------//
  64. void Lexer::Clear()
  65. {
  66.     while(!m_CurrentFileStack.empty())
  67.         m_CurrentFileStack.pop();
  68.     m_iCurrentLineNumber = 0;
  69.     m_iTotalLinesParsed = 0;
  70.     m_bMarkEndOfLine = false;
  71.     m_OperatorVector.clear();
  72.     m_KeywordVector.clear();
  73.     m_pTokenList = NULL;
  74.     m_bEnableComments = true;
  75.     m_bCStyleCommentActive = false;
  76.     m_bProcessHeaders = false;
  77.     m_bProcessMacros = false;
  78.  
  79. }
  80.  
  81. //------------------------------------------------------------------------//
  82. bool Lexer::Init(bool bReserveCommonOperators)
  83. {
  84.     m_OperatorVector.reserve(INITIAL_RESERVED_OPERATORS);
  85.  
  86.     // These are all required operators for standard functionality
  87.     m_OperatorVector.push_back(g_pszDecimalPoint);
  88.     m_OperatorVector.push_back(g_pszOpeningComment);
  89.     m_OperatorVector.push_back(g_pszClosingComment);
  90.     m_OperatorVector.push_back(g_pszSingleLineComment);
  91.     m_OperatorVector.push_back(g_pszStringDelimiter);
  92.     m_OperatorVector.push_back(g_pszNewLine);
  93.     m_OperatorVector.push_back(g_pszMinusSign);
  94.     m_OperatorVector.push_back(g_pszPoundSign);
  95.     m_OperatorVector.push_back(g_pszDivideSign);
  96.     m_OperatorVector.push_back(g_pszMultiplySign);
  97.     m_OperatorVector.push_back(g_pszLeftParen);
  98.     m_OperatorVector.push_back(g_pszRightParen);
  99.     m_OperatorVector.push_back(g_pszBackSlash);
  100.     m_OperatorVector.push_back(g_pszComma);
  101.     m_OperatorVector.push_back(g_pszSemiColon);
  102.     sort(m_OperatorVector.begin(), m_OperatorVector.end());
  103.  
  104.     // define the most common operators
  105.     if(bReserveCommonOperators)
  106.         ReserveCommonOperators();
  107.  
  108.     // reserved default number of keywords
  109.     m_KeywordVector.reserve(INITIAL_RESERVED_KEYWORDS);
  110.     m_KeywordVector.push_back(g_pszInclude);
  111.     m_KeywordVector.push_back(g_pszDefine);
  112.     m_KeywordVector.push_back(g_pszDefineGUID);
  113.     m_KeywordVector.push_back(g_pszVector);
  114.     m_KeywordVector.push_back(g_pszTrue);
  115.     m_KeywordVector.push_back(g_pszFalse);
  116.     sort(m_KeywordVector.begin(), m_KeywordVector.end());
  117.  
  118.     return true;
  119. }
  120.  
  121. //------------------------------------------------------------------------//
  122. void Lexer::Term()
  123. {
  124.     ClearMacros();
  125.     Clear();
  126. }
  127.  
  128. //------------------------------------------------------------------------//
  129. void Lexer::ReserveOperator(string sOperator)
  130. {
  131.     m_OperatorVector.push_back(sOperator);
  132.     sort(m_OperatorVector.begin(), m_OperatorVector.end());
  133. }
  134.  
  135. //------------------------------------------------------------------------//
  136. void Lexer::ReserveKeyword(string sKeyword)
  137. {
  138.     m_KeywordVector.push_back(sKeyword);
  139.     sort(m_KeywordVector.begin(), m_KeywordVector.end());
  140. }
  141.  
  142. //------------------------------------------------------------------------//
  143. void Lexer::ReserveCommonOperators()
  144. {
  145.     // You can add or remove any operators from this list, or
  146.     // create specialized functions to create custom lists of
  147.     // common operators.
  148.     m_OperatorVector.push_back("=");
  149.     m_OperatorVector.push_back("==");
  150.     m_OperatorVector.push_back("!");
  151.     m_OperatorVector.push_back("!=");
  152.     m_OperatorVector.push_back("+");
  153.     m_OperatorVector.push_back("++");
  154.     m_OperatorVector.push_back("--");
  155.     m_OperatorVector.push_back("+=");
  156.     m_OperatorVector.push_back("-=");
  157.     m_OperatorVector.push_back("*=");
  158.     m_OperatorVector.push_back("/=");
  159.     m_OperatorVector.push_back("<");
  160.     m_OperatorVector.push_back(">");
  161.     m_OperatorVector.push_back("<=");
  162.     m_OperatorVector.push_back(">=");
  163.     m_OperatorVector.push_back("<<");
  164.     m_OperatorVector.push_back(">>");
  165.     m_OperatorVector.push_back("&");
  166.     m_OperatorVector.push_back("&&");
  167.     m_OperatorVector.push_back("^");
  168.     m_OperatorVector.push_back("{");
  169.     m_OperatorVector.push_back("}");
  170.     m_OperatorVector.push_back("[");
  171.     m_OperatorVector.push_back("]");
  172.     m_OperatorVector.push_back(":");
  173.     m_OperatorVector.push_back("::");
  174.     m_OperatorVector.push_back("?");
  175.     m_OperatorVector.push_back("->");
  176.     sort(m_OperatorVector.begin(), m_OperatorVector.end());
  177. }
  178.  
  179.  
  180. //------------------------------------------------------------------------//
  181. // Read and tokenize a single file and store the results in the token list
  182. bool Lexer::Process(string sFilename, TokenList& tokenlist)
  183. {
  184.     uint8* pData;
  185.     uint32 nDataSize;
  186.  
  187.     IAudioStream* pStream;
  188.     CreateAudioStream cas(pStream);
  189.     if(!pStream)
  190.         return Error::Handle("ERROR: file %s can't be created",(const char*)sFilename.c_str());
  191.     
  192.     HRESULT hr = pStream->Open(sFilename);
  193.     if(FAILED(hr))
  194.         return Error::Handle("ERROR: file %s can't be opened",(const char*)sFilename.c_str());
  195.  
  196.     // Get the stream size
  197.     STATSTG stats;
  198.     pStream->Stat(&stats, 0);
  199.     nDataSize = (uint32)stats.cbSize.QuadPart;
  200.  
  201.     // Read the stream into a data buffer
  202.     pData = new uint8[nDataSize];
  203.     hr = pStream->Read(pData, nDataSize, 0);
  204.     if(FAILED(hr))
  205.     {
  206.         SAFE_DELETE_ARRAY(pData);
  207.         return Error::Handle("ERROR: file %s can't be read",(const char*)sFilename.c_str());
  208.     }
  209.  
  210.     // Process the data buffer
  211.     m_CurrentFileStack.push(sFilename);
  212.     bool bErr = Process(pData, nDataSize, tokenlist);
  213.     SAFE_DELETE_ARRAY(pData);
  214.     m_CurrentFileStack.pop();
  215.  
  216.     if(!bErr)
  217.         return Error::Handle("Could not parse file %s.", (const char*)sFilename.c_str());
  218.  
  219.     return true;
  220. }
  221.  
  222. //------------------------------------------------------------------------//
  223. // Read and tokenize a memory buffer and store the results in the token list
  224. bool Lexer::Process(uint8* pData, uint32 nDataSize, TokenList& tokenlist)
  225. {
  226.     m_pTokenList = &tokenlist;
  227.     m_iCurrentLineNumber = 0;
  228.     
  229.     uint32 nCharactersProcessed = 0;
  230.     uint8* pCurrentPos = pData;
  231.     uint8* pLineStart = pData;
  232.     int32  iLineLength = 0;
  233.  
  234.     bool bFormFeed = false;
  235.     bool bCarriageReturn = false;
  236.  
  237.     // cycle through the input buffer and check each character
  238.     while(nCharactersProcessed < nDataSize)
  239.     {
  240.         // Because we're usually opening the file in binary mode (because
  241.         // of the zip file packer), we have to explicitly check for
  242.         // formfeed and carriage return bytes.
  243.         if(pCurrentPos[0] == 0x0D)
  244.             bFormFeed = true;
  245.         if(pCurrentPos[0] == 0x0A)
  246.             bCarriageReturn = true;
  247.         if(bCarriageReturn)
  248.         {
  249.             ParseLine(pLineStart, iLineLength);
  250.             if(m_bMarkEndOfLine)
  251.                 MakeToken(string(g_pszNewLine), Token::OPERATOR);
  252.             pLineStart = pCurrentPos + 1;
  253.             iLineLength = 0;
  254.             bFormFeed = false;
  255.             bCarriageReturn = false;
  256.             m_iCurrentLineNumber++;
  257.             m_iTotalLinesParsed++;
  258.         }
  259.  
  260.         nCharactersProcessed++;
  261.         pCurrentPos++;
  262.         iLineLength++;
  263.     }
  264.  
  265.     // After the initial processing is done, process any header
  266.     // files located in the list
  267.     if(m_bProcessHeaders)
  268.     {
  269.         if(!ProcessHeaders(tokenlist))
  270.         {
  271.             return false;
  272.         }
  273.     }
  274.     // Finally, perform all macro substitutions
  275.     if(m_bProcessMacros)
  276.     {
  277.         if(!ProcessMacros(tokenlist))
  278.         {
  279.             return false;
  280.         }
  281.     }
  282.  
  283.     return true;
  284. }
  285.  
  286.  
  287. //------------------------------------------------------------------------//
  288. bool Lexer::ParseLine(uint8* pLineBuffer, uint32 nLineLength)
  289. {
  290.     // Use this as a temporary buffer for token parsing
  291.     string sTokenBuffer;
  292.  
  293.     char cTempBuffer[MAX_LINE_LENGTH];
  294.  
  295.     // flag to indicate that an opening string has been found
  296.     bool bStringOpened = false;
  297.  
  298.     // flag to indicate that the string has been closed
  299.     bool bStringClosed = false;
  300.  
  301.     // comments should become active at the end of the parse cycle
  302.     bool bCommentEnded = false;
  303.  
  304.     // marker for where the current token starts
  305.     int iTokenStart = 0;
  306.  
  307.     int iCurrentPosition = 0;
  308.     int iCopiedCharacters = 1;
  309.  
  310.     // store off our last operator match
  311.     string sLastMatch;
  312.  
  313.     // store off our last operator match's position
  314.     int iLastMatchPosition = 0;
  315.  
  316.     // lets us know when we've found an operator match
  317.     bool bFoundMatch = false;
  318.  
  319.     // signals the end of a line, so we know to look for the last token
  320.     bool bEndOfLine = false;
  321.  
  322.     // Did we find an operator?
  323.     bool bFoundOperator = false;
  324.  
  325.     // Now we're ready to begin parsing.  Here's basically how this works:
  326.  
  327.     // We cycle through the line one character at a time, checking all the
  328.     // time for operators.  If an operator is found, we then check to see
  329.     // if it is a subset of a longer operator which then gets precedence.
  330.     // The reason we look for operators first is that they can be used to
  331.     // break up other tokens in addition to whitespace.  After we've checked
  332.     // for operators (both in combination with other tokens and those which
  333.     // are standing alone) we then extract all tokens by passing them into
  334.     // the function MakeToken().  
  335.  
  336.     // Handling strings is another headache entirely.  Since we want to
  337.     // preserve the strings in their entirety, we make some special cases
  338.     // to explicitly handle them by checking for opening and closing
  339.     // double-quote marks.  Strings read by this parsing routine cannot
  340.     // extend past a single line.
  341.  
  342.     // Cycle through the entire string and break into tokens in a single pass
  343.     while(iCurrentPosition <= nLineLength)
  344.     {
  345.         // We need to read in the strings without regard to any tokens or
  346.         // whitespace, so we'll special-case that here
  347.         if(bStringOpened)
  348.         {
  349.             // Check to see if the quote character has been read, but exclude it if
  350.             // it is preceded by the backslash character.  This allows double-quote
  351.             // characters to reside within strings.
  352.             if((pLineBuffer[iCurrentPosition] == '\"') && 
  353.                 (pLineBuffer[iCurrentPosition - 1] != '\\'))
  354.             {
  355.                 bStringOpened = false;
  356.                 bStringClosed = true;
  357.                 sLastMatch = "";
  358.             }
  359.         }
  360.         else
  361.         {
  362.             // As long as we're finding operator matches, we'll continue to look for
  363.             // longer and longer matches.
  364.             do
  365.             {
  366.                 bFoundMatch = false;
  367.  
  368.                 // if we're trying to copy too many characters then break out of the loop
  369.                 if((iCurrentPosition + iCopiedCharacters) > nLineLength)
  370.                 {
  371.                     // signal that we've hit the end of the line so we'll know later
  372.                     // to check for the last remaining token
  373.                     bEndOfLine = true;
  374.                     break;
  375.                 }
  376.  
  377.                 // copy the appropriate characters to the temporary string buffer
  378.                 // If the number of copied characters doesn't match what we though, then
  379.                 // we've hit the end of the line.
  380.                 //sLineBuffer.copy(cTempBuffer, iCopiedCharacters, iCurrentPosition);
  381.                 memcpy(cTempBuffer, pLineBuffer + iCurrentPosition, iCopiedCharacters);
  382.                 // place a null terminator after the copied character
  383.                 cTempBuffer[iCopiedCharacters] = NULL;
  384.  
  385.                 // assign the character buffer to a string
  386.                 sTokenBuffer = cTempBuffer;
  387.  
  388.                 // next let's see if this character or characters belong match to any
  389.                 // operators stored in our operator list
  390.                 if(binary_search(m_OperatorVector.begin(), m_OperatorVector.end(), sTokenBuffer))
  391.                 {
  392.                     // store the match in the last match string
  393.                     sLastMatch = sTokenBuffer;
  394.                     bFoundMatch = true;
  395.                     bFoundOperator = true;
  396.                     iLastMatchPosition = iCurrentPosition;
  397.  
  398.                 }
  399.                 // increment the number of characters to copy for the next loop
  400.                 iCopiedCharacters++;
  401.  
  402.             }
  403.             while(bFoundMatch);
  404.         }
  405.  
  406.         // what do we do if we find an operator.
  407.         // We to a pre-check because we don't want to place some operators, such
  408.         // as comment delimitters in the final token list
  409.         if(bFoundOperator)
  410.         {
  411.             // special exclusions for . and - operators (they can be part of
  412.             // a number)
  413.  
  414.             // If a period or minus is the operator, we need to verify that it isn't part
  415.             // of a number.  If the period isn't the last number in a line
  416.             // and the next character is a digit
  417.             if((sLastMatch == g_pszDecimalPoint) || (sLastMatch == g_pszMinusSign))
  418.             {
  419.                 // make sure we don't go out of bounds
  420.                 if(iLastMatchPosition + 1 < nLineLength)
  421.                 {
  422.                     // Looks like this is part of a real number instead of
  423.                     // a period or minus operator
  424.                     if(IsDigit(pLineBuffer[iLastMatchPosition + 1]))
  425.                     {
  426.                         sLastMatch = "";
  427.                         bFoundOperator = false;
  428.                     }
  429.                 }
  430.             }
  431.             else if(sLastMatch == g_pszStringDelimiter)
  432.             {
  433.                 // toggle the string flag
  434.                 bStringOpened = true;
  435.                 sLastMatch = "";
  436.                 bFoundOperator = false;
  437.             }
  438.             else if(m_bEnableComments)
  439.             {            
  440.                 if(sLastMatch == g_pszOpeningComment)
  441.                 {
  442.                     m_bCStyleCommentActive = true;
  443.                 }
  444.                 else if(sLastMatch == g_pszClosingComment)
  445.                 {
  446.                     bCommentEnded = true;
  447.                 }
  448.             }
  449.         }
  450.  
  451.         // we've found an operator (possibly combined with another token)
  452.         if(bFoundOperator)
  453.         {
  454.             // the operator needs to be split apart from the previous token
  455.             if(iCurrentPosition != iTokenStart)
  456.             {
  457.                 // for the first token, the number of characters should be the
  458.                 // starting position of the second token minus the starting
  459.                 // position of the original token.
  460.                 int iNumToCopy = iCurrentPosition - iTokenStart;
  461.                 //sLineBuffer.copy(cTempBuffer, iNumToCopy, iTokenStart);
  462.                 memcpy(cTempBuffer, pLineBuffer + iTokenStart, iNumToCopy);
  463.                 cTempBuffer[iNumToCopy] = NULL;
  464.                 sTokenBuffer = cTempBuffer;
  465.                 
  466.                 // create the first token
  467.                 MakeToken(sTokenBuffer);
  468.             }
  469.  
  470.             // If the latest token is the single-line comment operator, don't bother
  471.             // storing the token.
  472.             if(sLastMatch == g_pszSingleLineComment)
  473.             {
  474.                 // simply return out of this function to stop processing any more lines.
  475.                 // Remember to add an end of line token if it's required.
  476.                 if(m_bMarkEndOfLine)
  477.                     MakeToken(string(g_pszNewLine), Token::OPERATOR);
  478.                 return true;
  479.             }
  480.  
  481.             // create the second token
  482.             MakeToken(sLastMatch, Token::OPERATOR);
  483.  
  484.             // set the new starting token position
  485.             iTokenStart = iCurrentPosition + sLastMatch.length();
  486.         }
  487.         // we're at the end of a single non-operator token
  488.         else if((IsWhitespace(pLineBuffer[iCurrentPosition]) || bEndOfLine) && !bStringOpened)
  489.         {
  490.             int iNumToCopy = iCurrentPosition - iTokenStart;
  491.  
  492.             // ignore all "tokens" which are really only empty whitespace
  493.             if(iNumToCopy > 0)
  494.             {
  495.                 //sLineBuffer.copy(cTempBuffer, iNumToCopy, iTokenStart);
  496.                 memcpy(cTempBuffer, pLineBuffer + iTokenStart, iNumToCopy);
  497.                 cTempBuffer[iNumToCopy] = NULL;
  498.                 sTokenBuffer = cTempBuffer;
  499.                 
  500.                 // create the first token
  501.                 MakeToken(sTokenBuffer);
  502.             }
  503.  
  504.             iTokenStart = iCurrentPosition + 1;
  505.         }
  506.         else if(bStringClosed)
  507.         {
  508.             bStringClosed = false;
  509.  
  510.             // we remove 1 from the number of characters to copy because we
  511.             // don't want to copy the last quote mark along with the string
  512.             int iNumToCopy = iCurrentPosition - iTokenStart - 1;
  513.  
  514.             // we also start from iTokenStart + 1 to avoid copying the first
  515.             // quote mark as well
  516.             //sLineBuffer.copy(cTempBuffer, iNumToCopy, iTokenStart + 1);
  517.             memcpy(cTempBuffer, pLineBuffer + iTokenStart + 1, iNumToCopy);
  518.             cTempBuffer[iNumToCopy] = NULL;
  519.             sTokenBuffer = cTempBuffer;
  520.             
  521.             // create the first token
  522.             MakeToken(sTokenBuffer, Token::STRING);
  523.  
  524.             // move the token position ahead one character to avoid
  525.             // reparsing the last quote mark
  526.             iTokenStart = iCurrentPosition + 1;
  527.         }
  528.  
  529.         // a C style comment has ended, so reset all flags and resume
  530.         // normal parsing
  531.         if(bCommentEnded)
  532.         {
  533.             m_bCStyleCommentActive = false;
  534.             bCommentEnded = false;
  535.         }
  536.  
  537.         // increment the start position based on how many characters were copied
  538.         if(bFoundOperator)
  539.             iCurrentPosition += sLastMatch.length();
  540.         else
  541.             iCurrentPosition++;
  542.  
  543.  
  544.         // set the number of copied character back to one.
  545.         iCopiedCharacters = 1;
  546.  
  547.         // reset the found operator flag
  548.         bFoundOperator = false;
  549.     }
  550.  
  551.  
  552.     return true;
  553. }
  554.  
  555.  
  556. //------------------------------------------------------------------------//
  557. // Inserts the tokenized contents of header files into
  558. // a token list.
  559. bool Lexer::ProcessHeaders(TokenList& tokenlist)
  560. {
  561.     TokenList IncludeTokenList;
  562.     bool bPreProcessorSymbolFound = false;
  563.     bool bIncludeFound = false;
  564.  
  565.     Token CurrentToken;
  566.  
  567.     // reset the class tokenlist to null, since we will be using another
  568.     // token list if any include directives are found.
  569.     m_pTokenList = NULL;
  570.  
  571.     // store the previous end of line settings
  572.     bool bPreviousEOLSetting = m_bMarkEndOfLine;
  573.     
  574.     // we want to see the end of the line for macro parsing
  575.     m_bMarkEndOfLine = true;
  576.  
  577.     for(TokenList::iterator itor = tokenlist.begin(); itor != tokenlist.end(); ++itor)
  578.     {
  579.         CurrentToken = (*itor);
  580.  
  581.         switch(itor->GetType())
  582.         {
  583.         case Token::OPERATOR:
  584.             if(string(g_pszPoundSign) == itor->GetOperator())
  585.                 bPreProcessorSymbolFound = true;
  586.             else if(string(g_pszNewLine) == itor->GetOperator())
  587.                 bPreProcessorSymbolFound = false;
  588.             break;
  589.         case Token::KEYWORD:
  590.             if(string(g_pszInclude) == itor->GetKeyword())
  591.                 bIncludeFound = true;
  592.             break;
  593.         case Token::STRING:
  594.             if(bPreProcessorSymbolFound)
  595.             {
  596.                 if(bIncludeFound)
  597.                 {
  598.                     // After finding a file to include, we then proceed to parse it
  599.                     // and search for includes in that file.  This is a recursive
  600.                     // process which ends up calling this same function again.
  601.  
  602.                     // reset the include and preprocessor flags for use in this
  603.                     // include file parsing loop.
  604.                     bIncludeFound = false;
  605.                     bPreProcessorSymbolFound = false;
  606.  
  607.                     // If the file successfully parsed, insert
  608.                     if(!Process(itor->GetString(), IncludeTokenList))
  609.                         return Error::Handle("Could not parse include file %s.", itor->GetString());
  610.  
  611.                     // Find and include other files recursively if needed
  612.                     if(!ProcessHeaders(IncludeTokenList))
  613.                         return Error::Handle("Was unable to process header files."); 
  614.  
  615.                     // Replace the #include "someheader.h" tokens with the actual
  616.                     // content of the files.
  617.                     TokenList::iterator bitor = itor;
  618.                     --bitor;  --bitor;
  619.                     ++itor;
  620.                     itor = tokenlist.erase(bitor, itor);
  621.  
  622. #ifdef TOKEN_DEBUGGING_INFO
  623.                     // Create a file to index map for merging the file references
  624.                     vector<int> filemap;
  625.                     filemap.reserve(IncludeTokenList.GetNumFileRefs());
  626.  
  627.                     // Add the file references to the base token list and retrieve the indices
  628.                     for(int i = 0; i < IncludeTokenList.GetNumFileRefs(); i++)
  629.                         filemap.push_back(tokenlist.GetFileIndex(IncludeTokenList.GetFileName(i)));
  630.  
  631.                     // Replace the file in the include token list with new indices
  632.                     for(TokenListItor itr = IncludeTokenList.begin(); itr != IncludeTokenList.end(); ++itr)
  633.                         itr->SetFileIndex(filemap[itr->GetFileIndex()]);
  634. #endif
  635.                     // splice the new parsed list into the existing list
  636.                     tokenlist.splice(itor, IncludeTokenList);
  637.  
  638.                     --itor;
  639.                     // Make sure the include and preprocessor flags are cleared at the
  640.                     // end of this cycle.
  641.                     bIncludeFound = false;
  642.                     bPreProcessorSymbolFound = false;
  643.                 }
  644.             }
  645.             break;
  646.         };
  647.     }
  648.     // restore original end of line settings
  649.     m_bMarkEndOfLine = bPreviousEOLSetting;
  650.     return true;
  651. }
  652.  
  653.  
  654. //------------------------------------------------------------------------//
  655. bool Lexer::ProcessMacros(TokenList& tokenlist)
  656. {
  657.     TokenList TokList;
  658.     TokenList MacroList;
  659.  
  660.     // iterators and flag use for erasing any line
  661.     // beginning with a preprocessor symbol
  662.     TokenListItor PreProcBegin;
  663.     TokenListItor PreProcEnd;
  664.     bool bFoundPreprocessorLine = false;
  665.     bool bErasePreprocessorLine = false;
  666.  
  667.     // A ton of state flags used to find and process any macro
  668.     bool bPreProcessorSymbolFound = false;
  669.     bool bDefineSymbolFound = false;
  670.     bool bDefineMacro = false;
  671.     bool bContinueLineFound = false;
  672.     bool bMacroName = false;
  673.     bool bFirstMacroToken = false;
  674.     bool bMacroArguments = false;
  675.     bool bMacroArgVar = false;
  676.     bool bMacroBody = false;
  677.     bool bMacroArgEnd = false;
  678.  
  679.     Token CurrentToken;
  680.     Macro CurrentMacro;
  681.  
  682.     // reset the class tokenlist to null, since we will be using another
  683.     // token list if any include directives are found.
  684.     m_pTokenList = NULL;
  685.  
  686.     for(TokenList::iterator itor = tokenlist.begin(); itor != tokenlist.end(); ++itor)
  687.     {
  688.         CurrentToken = (*itor);
  689.  
  690.         switch(itor->GetType())
  691.         {
  692.         case Token::OPERATOR:
  693.             if(strcmp(g_pszPoundSign, itor->GetOperator()) == 0)
  694.             {
  695.                 bPreProcessorSymbolFound = true;
  696.                 bFoundPreprocessorLine = true;
  697.                 // mark this entire line for removal from the token list
  698.                 PreProcBegin = itor;
  699.             }
  700.             else if(strcmp(g_pszBackSlash, itor->GetOperator()) == 0)
  701.                 bContinueLineFound = true;
  702.             else if(strcmp(g_pszNewLine, itor->GetOperator()) == 0)
  703.             {
  704.                 if(bContinueLineFound)
  705.                     bContinueLineFound = false;
  706.                 else
  707.                 {
  708.                     if(bFoundPreprocessorLine)
  709.                     {
  710.                         bErasePreprocessorLine = true;
  711.                         // mark the end of the tokens to be removed
  712.                         PreProcEnd = itor;
  713.                         ++PreProcEnd;
  714.                     }
  715.  
  716.                     bDefineSymbolFound = false;
  717.                     bDefineMacro = false;
  718.                     bPreProcessorSymbolFound = false;
  719.                     bMacroBody = false;
  720.                     if(!CurrentMacro.empty())
  721.                     {
  722.                         m_MacroSet.insert(CurrentMacro);
  723.                         CurrentMacro.Clear();
  724.                     }
  725.  
  726.                     // We've hit the end of the macro and haven't found the closing
  727.                     // right paren.  Obviously an error.
  728.                     if(bMacroArguments)
  729.                     {
  730.                         return Error::Handle("Syntax error in header macro.");
  731.                     }
  732.                 }
  733.             }
  734.             break;
  735.  
  736.         case Token::KEYWORD:
  737.             if(bPreProcessorSymbolFound && (strcmp(itor->GetKeyword(), g_pszDefine) == 0))
  738.             {
  739.                 bDefineSymbolFound = true;
  740.             }
  741.             // Check for vector definitions: vector(x,y,z)
  742.             else if(strcmp(itor->GetKeyword(), g_pszVector) == 0)
  743.             {
  744.                 if(!ParseVector(tokenlist, itor))
  745.                     return Error::Handle("Unable to parse Vector definition");
  746.             }
  747.             // GUID recognition is a special case for us to check for
  748.             else if(strcmp(itor->GetKeyword(), g_pszDefineGUID) == 0)
  749.             {
  750.                 if(!ParseGUID(tokenlist, itor))
  751.                     return Error::Handle("Unable to parse GUID definition");
  752.             }
  753.             break;
  754.  
  755.         case Token::VARIABLE:
  756.             // we don't want to expand macros when we're in the middle of defining
  757.             // another macro
  758.             if(!bDefineMacro)
  759.             {
  760.                 Macro TmpMacro;
  761.                 TmpMacro.m_sName = (*itor).GetVariable();
  762.                 MacroSetItor itr = m_MacroSet.find(TmpMacro);
  763.                 if(itr != m_MacroSet.end())
  764.                 {
  765.                     if(!ExpandMacro(tokenlist, itor, itr))
  766.                         return Error::Handle("Could not expand macro");
  767.                 }
  768.             }
  769.             break;
  770.         };
  771.  
  772.         // Here's where we define the macro
  773.         if(bDefineMacro)
  774.         {
  775.             bDefineSymbolFound = false;
  776.  
  777.             // First time through we define the macro name
  778.             if(bMacroName)
  779.             {
  780.                 bMacroName = false;
  781.                 CurrentMacro.Clear();
  782.                 if(itor->GetType() != Token::VARIABLE)
  783.                 {
  784.                     return Error::Handle("Illegal syntax in macro.");
  785.                 }
  786.                 CurrentMacro.m_sName = itor->GetVariable();
  787.                 bFirstMacroToken = true;
  788.             }
  789.             // this indicates that it is the first macro token found after the name, so we
  790.             // check for a left paren to see if the macro takes arguments
  791.             else if(bFirstMacroToken)
  792.             {
  793.                 bFirstMacroToken = false;
  794.                 if((itor->GetType() == Token::OPERATOR) && (strcmp(itor->GetOperator(), "(") == 0))
  795.                 {
  796.                     bMacroArguments = true;
  797.                     bMacroArgVar = true;
  798.                 }
  799.                 else
  800.                 {
  801.                     bMacroBody = true;
  802.                 }
  803.             }
  804.             else if(bMacroArgEnd)
  805.             {
  806.                 bMacroBody = true;
  807.                 bMacroArgEnd = false;
  808.             }
  809.             // This case process all the macro arguments
  810.             else if(bMacroArguments)
  811.             {
  812.                 // stop processing macro arguments if we find the right paren
  813.                 if((itor->GetType() == Token::OPERATOR) && (strcmp(itor->GetOperator(), ")") == 0))
  814.                 {
  815.                     // if we've already parsed a comma and are expecting another variable, then
  816.                     // flag an error when the closing paren is reached.
  817.                     if(bMacroArgVar)
  818.                     {
  819.                         return Error::Handle("Missing argument in macro.");
  820.                     }
  821.                     // Indicate that we're no longer processing arguments
  822.                     bMacroArguments = false;
  823.                     // and we're ready to start processing the macro body
  824.                     bMacroArgEnd = true;
  825.                 }
  826.                 // We know that what we're processing in this case either has to be
  827.                 // argument variables or separating commas
  828.                 else
  829.                 {
  830.                     // If this flag is set, we know to expect a variable (the arg name)
  831.                     if(bMacroArgVar)
  832.                     {
  833.                         bMacroArgVar = false;
  834.                         if(itor->GetType() != Token::VARIABLE)
  835.                         {
  836.                             return Error::Handle("Incorrect syntax for macro variable.");
  837.                         }
  838.                         // push the argument onto the back of the argument vector and
  839.                         // increment the argument count
  840.                         CurrentMacro.m_ArgumentVector.push_back(itor->GetVariable());
  841.                         CurrentMacro.m_SubstitutionVector.push_back(Token());
  842.                         CurrentMacro.m_iTotalArguments++;
  843.                     }
  844.                     // Otherwise we know this has to be a comma separating the arguments
  845.                     else
  846.                     {
  847.                         bMacroArgVar = true;
  848.                         // signal an error on anything but a comma operator
  849.                         if(!((itor->GetType() == Token::OPERATOR) && (strcmp(itor->GetOperator(), ",") == 0)))
  850.                         {
  851.                             return Error::Handle("Missing comma operator between macro arguments.");
  852.                         }
  853.                     }
  854.                 }
  855.             }
  856.             // here's where we actually process the macro body
  857.             if(bMacroBody)
  858.             {
  859.                 // Ignore backslashes and end of line markers
  860.                 if(!((itor->GetType() == Token::OPERATOR) && 
  861.                     ((strcmp(itor->GetOperator(), g_pszBackSlash) == 0) || 
  862.                     ((strcmp(itor->GetOperator(), g_pszNewLine) == 0)))))
  863.                 {
  864.                     CurrentMacro.m_MacroList.push_back(*itor);
  865.                 }
  866.             }
  867.         }
  868.  
  869.         if(bDefineSymbolFound)
  870.         {
  871.             // we're now defining a new macro
  872.             bDefineMacro = true;
  873.             // for the first symbol we're defining the name of the macro
  874.             bMacroName = true;
  875.         }
  876.  
  877.         // erase any line of tokens beginning with a preprocessor symbol
  878.         if(bErasePreprocessorLine && bFoundPreprocessorLine)
  879.         {
  880.             bErasePreprocessorLine = false;
  881.             bFoundPreprocessorLine = false;
  882.  
  883.             CurrentToken = (*PreProcBegin);
  884.             CurrentToken = (*PreProcEnd);
  885.             itor = tokenlist.erase(PreProcBegin, PreProcEnd);
  886.             --itor;
  887.             PreProcBegin = itor;
  888.             PreProcEnd = itor;
  889.         }
  890.         // otherwise clean out any newline symbols
  891.         else
  892.         {
  893.             if((itor->GetType() == Token::OPERATOR) &&
  894.                 (strcmp(itor->GetOperator(), g_pszNewLine) == 0))
  895.             {
  896.                 itor = tokenlist.erase(itor);
  897.                 --itor;
  898.             }
  899.         }
  900.  
  901.     }
  902.  
  903.     MacroList.clear();
  904.  
  905.     return true;
  906. }
  907.  
  908.  
  909. //------------------------------------------------------------------------//
  910. bool Lexer::ExpandMacro(TokenList& tokenlist, TokenListItor& itor, MacroSetItor itr)
  911. {
  912.     // watch variables.  remove when done debugging
  913.     Macro CurrentMacro = (*itr);
  914.     Token CurrentToken = (*itor);
  915.  
  916.     TokenList InsertionList;
  917.  
  918.     int iCodeTokens = 0;
  919.     TokenListItor BeginningItor = itor;
  920.     TokenListItor CurrentItor = itor;
  921.  
  922.     // first, we need to figure out how many arguments the macro definition has
  923.     // and if the macro has the proper format.  If we have a macro with arguments,
  924.     // we store the arguments in the macro for later substitution when we insert
  925.     // the macro tokens into the main token list.
  926.     if(CurrentMacro.m_iTotalArguments > 0)
  927.     {
  928.         // Calculate the number of code tokens needed to call this macro
  929.         iCodeTokens = (CurrentMacro.m_iTotalArguments * 2) + 2;
  930.  
  931.         // advance to where the opening parentheses should be
  932.         ++CurrentItor;
  933.         // error check to make sure the opening parentheses
  934.         // are in the correct spot
  935.         if(((*CurrentItor).GetType() != Token::OPERATOR) || 
  936.             (string((*CurrentItor).GetOperator()) != g_pszLeftParen))
  937.         {
  938.             return Error::Handle("Unable to find opening paren in macro definition");
  939.         }
  940.  
  941.         ++CurrentItor;
  942.         for(int i = 0; i < CurrentMacro.m_iTotalArguments; i++)
  943.         {
  944.             CurrentMacro.m_SubstitutionVector[i] = (*CurrentItor);
  945.             ++CurrentItor;
  946.  
  947.             // error check to make sure that commas and ending
  948.             // parentheses are in the right place
  949.             if(i == (CurrentMacro.m_iTotalArguments - 1))
  950.             {
  951.                 // fail if a right paren is missing
  952.                 if(((*CurrentItor).GetType() != Token::OPERATOR) || 
  953.                 (string((*CurrentItor).GetOperator()) != g_pszRightParen))
  954.                 {
  955.                     return Error::Handle("Unable to find closing paren in macro definition");
  956.                 }
  957.             }
  958.             else
  959.             {
  960.                 // fail if a comma is missing
  961.                 if(((*CurrentItor).GetType() != Token::OPERATOR) || 
  962.                 (string((*CurrentItor).GetOperator()) != ","))
  963.                 {
  964.                     return Error::Handle("Missing comma in macro definition");
  965.                 }
  966.                 ++CurrentItor;
  967.             }
  968.         }
  969.     }
  970.     else
  971.     {
  972.         iCodeTokens = 1;
  973.     }
  974.  
  975.     // Now that we've set up the macro structure, we're ready to proceed with
  976.     // removal of the tokens which make up the macro in the script, then
  977.     // substitute the macro tokens in its place.
  978.  
  979.     // remove the macro code tokens first.  CurrentItor should be pointing
  980.     // to the last token in the macro (it may be the same as the first).  We
  981.     // need to push it forward one token so we can just erase this from 
  982.     // the token stream.
  983.  
  984.     ++CurrentItor;
  985.  
  986.     CurrentItor = tokenlist.erase(BeginningItor, CurrentItor);
  987.     itor = CurrentItor;
  988.     --itor;
  989.  
  990.     // Let's us know whether we're substituting argument text on this cycle
  991.     bool bArgSubst = false;
  992.  
  993.     // Cycle through the list of tokens stored in the macro an insert them into
  994.     // the token list.  If the token is found to be an argument, then find the
  995.     // text that needs to be substituted and insert that token instead of the
  996.     // argument token.
  997.     for(TokenListItor TItor = CurrentMacro.m_MacroList.begin(); 
  998.         TItor != CurrentMacro.m_MacroList.end(); ++TItor)
  999.     {
  1000.         bArgSubst = false;
  1001.         if((*TItor).GetType() == Token::VARIABLE)
  1002.         {
  1003.             for(int iArgIndex = 0; iArgIndex < CurrentMacro.m_iTotalArguments; iArgIndex++)
  1004.             {
  1005.                 if(CurrentMacro.m_ArgumentVector[iArgIndex] == (*TItor).GetVariable())
  1006.                 {
  1007.                     bArgSubst = true;
  1008.                     CurrentMacro.m_iCurrentArgument = iArgIndex;
  1009.                 }
  1010.             }
  1011.         }
  1012.         // Here we either insert the actual macro token or the argument which is
  1013.         // to be substituted for the token.
  1014.         if(bArgSubst)
  1015.             CurrentItor = tokenlist.insert(CurrentItor, CurrentMacro.m_SubstitutionVector[CurrentMacro.m_iCurrentArgument]);
  1016.         else
  1017.             CurrentItor = tokenlist.insert(CurrentItor, (*TItor));
  1018.         // Next!
  1019.         ++CurrentItor;
  1020.     }
  1021.  
  1022.     return true;
  1023. }
  1024.  
  1025. //------------------------------------------------------------------------//
  1026. // ParseVector is a specialized class that substitutes a vector for individual
  1027. // tokens using the built-in definition vector(a, b, c), technically not stored as
  1028. // a macro but parsed during the macro processing phase.  Thus, a client must
  1029. // turn on macro processing in order to have built-in vector support.
  1030. bool Lexer::ParseVector(TokenList& tokenlist, TokenListItor& itor)
  1031. {
  1032.     TokenListItor CurrentItor = itor;
  1033.     TokenListItor BeginningItor = itor;
  1034.     Token CurrentToken = (*CurrentItor);
  1035.     TokenVector3D vVector;
  1036.     vVector.x = 0;
  1037.     vVector.y = 0;
  1038.     vVector.z = 0;
  1039.  
  1040. #ifdef TOKEN_DEBUGGING_INFO
  1041.     int iFileIndex = CurrentToken.GetFileIndex();
  1042.     int iLineNumber = CurrentToken.GetLineNumber();
  1043.     string sFileName = tokenlist.GetFileName(iFileIndex);
  1044. #endif
  1045.  
  1046.  
  1047.     // Look for opening paren
  1048.     CurrentItor++;
  1049.     if((*CurrentItor).IsNewline())
  1050.         CurrentItor++;
  1051.     if((CurrentItor == tokenlist.end()) || 
  1052.         ((*CurrentItor).GetType() != Token::OPERATOR) ||
  1053.         (string((*CurrentItor).GetOperator()) != "("))
  1054.     {
  1055.         return Error::Handle("Missing opening paren in vector definition.");
  1056.     }
  1057.     
  1058.     // check for first vector value (real)
  1059.     CurrentItor++;
  1060.     if((*CurrentItor).IsNewline())
  1061.         CurrentItor++;
  1062.     CurrentToken = (*CurrentItor);
  1063.     if((CurrentItor == tokenlist.end()) || 
  1064.         (CurrentItor->GetType() != Token::REAL) ||
  1065.         (CurrentItor->GetType() != Token::INTEGER))
  1066.     {
  1067.         return Error::Handle("Error in first vector value.");
  1068.     }
  1069.     if(CurrentItor->GetType() == Token::REAL)
  1070.         vVector.x = CurrentItor->GetReal();
  1071.     else
  1072.         vVector.x = CurrentItor->GetInteger();
  1073.  
  1074.     // check for comma
  1075.     CurrentItor++;
  1076.     CurrentToken = (*CurrentItor);
  1077.     if((CurrentItor == tokenlist.end()) || 
  1078.         ((*CurrentItor).GetType() != Token::OPERATOR) ||
  1079.         (string((*CurrentItor).GetOperator()) != ","))
  1080.     {
  1081.         return Error::Handle("Missing comma in vector definition.");
  1082.     }
  1083.         
  1084.     // check for second vector value (real)
  1085.     CurrentItor++;
  1086.     if((*CurrentItor).IsNewline())
  1087.         CurrentItor++;
  1088.     CurrentToken = (*CurrentItor);
  1089.     if((CurrentItor == tokenlist.end()) || 
  1090.         (CurrentItor->GetType() != Token::REAL) ||
  1091.         (CurrentItor->GetType() != Token::INTEGER))
  1092.     {
  1093.         return Error::Handle("Error in first vector value.");
  1094.     }
  1095.     if(CurrentItor->GetType() == Token::REAL)
  1096.         vVector.y = CurrentItor->GetReal();
  1097.     else
  1098.         vVector.y = CurrentItor->GetInteger();
  1099.  
  1100.     // check for comma
  1101.     CurrentItor++;
  1102.     CurrentToken = (*CurrentItor);
  1103.     if((CurrentItor == tokenlist.end()) || 
  1104.         ((*CurrentItor).GetType() != Token::OPERATOR) ||
  1105.         (string((*CurrentItor).GetOperator()) != ","))
  1106.     {
  1107.         return Error::Handle("Missing comma in vector definition.");
  1108.     }
  1109.         
  1110.     // check for third vector value (real)
  1111.     CurrentItor++;
  1112.     if((*CurrentItor).IsNewline())
  1113.         CurrentItor++;
  1114.     CurrentToken = (*CurrentItor);
  1115.     if((CurrentItor == tokenlist.end()) || 
  1116.         (CurrentItor->GetType() != Token::REAL) ||
  1117.         (CurrentItor->GetType() != Token::INTEGER))
  1118.     {
  1119.         return Error::Handle("Error in first vector value.");
  1120.     }
  1121.     if(CurrentItor->GetType() == Token::REAL)
  1122.         vVector.z = CurrentItor->GetReal();
  1123.     else
  1124.         vVector.z = CurrentItor->GetInteger();
  1125.  
  1126.     // Look for closing paren
  1127.     CurrentItor++;
  1128.     if((*CurrentItor).IsNewline())
  1129.         CurrentItor++;
  1130.     if((CurrentItor == tokenlist.end()) || 
  1131.         ((*CurrentItor).GetType() != Token::OPERATOR) ||
  1132.         (string((*CurrentItor).GetOperator()) != ")"))
  1133.     {
  1134.         return Error::Handle("Missing closing paren in vector definition.");
  1135.     }
  1136.         
  1137.     // erase the definition from the token list
  1138.     CurrentItor++;
  1139.     CurrentItor = tokenlist.erase(BeginningItor, CurrentItor);
  1140.     CurrentToken = (*CurrentItor);
  1141.  
  1142.     // create a token from the Vector and insert it into the list
  1143.     Token VectorTok;
  1144.     VectorTok.InitVector(vVector);
  1145.     CurrentItor = tokenlist.insert(CurrentItor, VectorTok);
  1146.  
  1147.     itor = CurrentItor;
  1148.  
  1149. #ifdef TOKEN_DEBUGGING_INFO
  1150.     VectorTok.SetFileIndex(iFileIndex);
  1151.     VectorTok.SetLineNumber(iLineNumber);
  1152. #endif
  1153.  
  1154.     return true;
  1155. }
  1156.  
  1157.  
  1158. //------------------------------------------------------------------------//
  1159. // ParseGUID is a specialized function which turns the DEFINE_GUID() macro
  1160. // into a Lexer class macro to be used for later substitution.
  1161.  
  1162. // Sample format:
  1163. // DEFINE_GUID(SomeIdentifier, 
  1164. // 0xf9f5c237, 0x45e0, 0x11d3, 0x94, 0x56, 0x0, 0xa0, 0xc9, 0x69, 0x6b, 0x73);
  1165.  
  1166. // Note that there is a semi-colon needed at the end of the macro.  Also, the
  1167. // parser can handle whitespace anywhere in the definition as well, so the above
  1168. // example would be parsed correctly.
  1169.  
  1170. // NOTE!!! Fix so whitespace can be anywhere in the definition!!!
  1171.  
  1172. bool Lexer::ParseGUID(TokenList& tokenlist, TokenListItor& itor)
  1173. {
  1174.     TokenListItor CurrentItor = itor;
  1175.     TokenListItor BeginningItor = itor;
  1176.     Token CurrentToken = (*CurrentItor);
  1177.     GUID guidCurrent;
  1178.     Macro CurrentMacro;
  1179.  
  1180. #ifdef TOKEN_DEBUGGING_INFO
  1181.     int iFileIndex = CurrentToken.GetFileIndex();
  1182.     int iLineNumber = CurrentToken.GetLineNumber();
  1183.     string sFileName = tokenlist.GetFileName(iFileIndex);
  1184. #endif
  1185.  
  1186.     // Look for opening paren
  1187.     CurrentItor++;
  1188.     if((*CurrentItor).IsNewline())
  1189.         CurrentItor++;
  1190.     if((CurrentItor == tokenlist.end()) || 
  1191.         ((*CurrentItor).GetType() != Token::OPERATOR) ||
  1192.         (string((*CurrentItor).GetOperator()) != "("))
  1193.     {
  1194.         return Error::Handle("Missing opening paren in GUID definition.");
  1195.     }
  1196.     
  1197.     // check for macro name
  1198.     CurrentItor++;
  1199.     if((*CurrentItor).IsNewline())
  1200.         CurrentItor++;
  1201.     CurrentToken = (*CurrentItor);
  1202.     if((CurrentItor == tokenlist.end()) || 
  1203.         ((*CurrentItor).GetType() != Token::VARIABLE))
  1204.     {
  1205.         return Error::Handle("Invalid GUID name in GUID definition.");
  1206.     }
  1207.     CurrentMacro.m_sName = (*CurrentItor).GetVariable();
  1208.  
  1209.     // check for comma
  1210.     CurrentItor++;
  1211.     if((*CurrentItor).IsNewline())
  1212.         CurrentItor++;
  1213.     CurrentToken = (*CurrentItor);
  1214.     if((CurrentItor == tokenlist.end()) || 
  1215.         ((*CurrentItor).GetType() != Token::OPERATOR) ||
  1216.         (string((*CurrentItor).GetOperator()) != ","))
  1217.     {
  1218.         return Error::Handle("Missing comma in GUID definition.");
  1219.     }
  1220.     
  1221.     // check for first GUID value (DWORD)
  1222.     CurrentItor++;
  1223.     if((*CurrentItor).IsNewline())
  1224.         CurrentItor++;
  1225.     CurrentToken = (*CurrentItor);
  1226.     if((CurrentItor == tokenlist.end()) || 
  1227.         ((*CurrentItor).GetType() != Token::INTEGER))
  1228.     {
  1229.         return Error::Handle("Error in first GUID value.");
  1230.     }
  1231.     guidCurrent.Data1 = (*CurrentItor).GetInteger();
  1232.  
  1233.     // check for comma
  1234.     CurrentItor++;
  1235.     CurrentToken = (*CurrentItor);
  1236.     if((CurrentItor == tokenlist.end()) || 
  1237.         ((*CurrentItor).GetType() != Token::OPERATOR) ||
  1238.         (string((*CurrentItor).GetOperator()) != ","))
  1239.     {
  1240.         return Error::Handle("Missing comma in GUID definition.");
  1241.     }
  1242.     
  1243.     // get the next two word values
  1244.     for(int i = 0; i < 2; i++)
  1245.     {
  1246.         // check for next GUID values (WORD)
  1247.         CurrentItor++;
  1248.         if((*CurrentItor).IsNewline())
  1249.             CurrentItor++;
  1250.         CurrentToken = (*CurrentItor);
  1251.         if((CurrentItor == tokenlist.end()) || 
  1252.             ((*CurrentItor).GetType() != Token::INTEGER))
  1253.         {
  1254.             return Error::Handle("Error in GUID value.");
  1255.         }
  1256.         if(i)
  1257.             guidCurrent.Data3 = (*CurrentItor).GetInteger();
  1258.         else
  1259.             guidCurrent.Data2 = (*CurrentItor).GetInteger();
  1260.  
  1261.         // check for comma
  1262.         CurrentItor++;
  1263.         if((*CurrentItor).IsNewline())
  1264.             CurrentItor++;
  1265.         CurrentToken = (*CurrentItor);
  1266.         if((CurrentItor == tokenlist.end()) || 
  1267.             ((*CurrentItor).GetType() != Token::OPERATOR) ||
  1268.             (string((*CurrentItor).GetOperator()) != ","))
  1269.         {
  1270.             return Error::Handle("Missing comma in GUID definition.");
  1271.         }
  1272.     }
  1273.     
  1274.     // get the next 8 byte values
  1275.     for(i = 0; i < 8; i++)
  1276.     {
  1277.         // check for next GUID values (BYTE)
  1278.         CurrentItor++;
  1279.         if((*CurrentItor).IsNewline())
  1280.             CurrentItor++;
  1281.         CurrentToken = (*CurrentItor);
  1282.         if((CurrentItor == tokenlist.end()) || 
  1283.             ((*CurrentItor).GetType() != Token::INTEGER))
  1284.         {
  1285.             return Error::Handle("Error in GUID value.");
  1286.         }
  1287.         guidCurrent.Data4[i] = (*CurrentItor).GetInteger();
  1288.  
  1289.         if(i == 7)
  1290.         {
  1291.             // check for ending paren
  1292.             CurrentItor++;
  1293.             if((*CurrentItor).IsNewline())
  1294.                 CurrentItor++;
  1295.             CurrentToken = (*CurrentItor);
  1296.             if((CurrentItor == tokenlist.end()) || 
  1297.                 ((*CurrentItor).GetType() != Token::OPERATOR) ||
  1298.                 (string((*CurrentItor).GetOperator()) != ")"))
  1299.             {
  1300.                 return Error::Handle("Missing ending paren in GUID definition.");
  1301.             }
  1302.         }
  1303.         else
  1304.         {
  1305.             // check for comma
  1306.             CurrentItor++;
  1307.             if((*CurrentItor).IsNewline())
  1308.                 CurrentItor++;
  1309.             CurrentToken = (*CurrentItor);
  1310.             if((CurrentItor == tokenlist.end()) || 
  1311.                 ((*CurrentItor).GetType() != Token::OPERATOR) ||
  1312.                 (string((*CurrentItor).GetOperator()) != ","))
  1313.             {
  1314.                 return Error::Handle("Missing comma in GUID definition.");
  1315.             }
  1316.         }
  1317.     }
  1318.     
  1319.     // check for ending semicolon
  1320.     CurrentItor++;
  1321.     if((*CurrentItor).IsNewline())
  1322.         CurrentItor++;
  1323.     CurrentToken = (*CurrentItor);
  1324.     if((CurrentItor == tokenlist.end()) || 
  1325.         ((*CurrentItor).GetType() != Token::OPERATOR) ||
  1326.         (string((*CurrentItor).GetOperator()) != g_pszSemiColon))
  1327.     {
  1328.         return Error::Handle("Missing semicolon at end of GUID definition.");
  1329.     }
  1330.     
  1331.  
  1332.     // erase the definition from the token list
  1333.     CurrentItor++;
  1334.     CurrentItor = tokenlist.erase(BeginningItor, CurrentItor);
  1335.     CurrentToken = (*CurrentItor);
  1336.     itor = CurrentItor;
  1337.  
  1338.     // create a token from the GUID, add it to a macro definition, and 
  1339.     // insert it into the Lexer's macro set
  1340.     Token GuidTok;
  1341.     GuidTok.InitGuid(guidCurrent);
  1342.  
  1343. #ifdef TOKEN_DEBUGGING_INFO
  1344.     GuidTok.SetFileIndex(iFileIndex);
  1345.     GuidTok.SetLineNumber(iLineNumber);
  1346. #endif
  1347.     CurrentMacro.m_MacroList.push_back(GuidTok);
  1348.     m_MacroSet.insert(CurrentMacro);
  1349.     
  1350.     return true;
  1351. }
  1352.  
  1353.  
  1354. //------------------------------------------------------------------------//
  1355. void Lexer::ClearMacros()
  1356. {
  1357.     m_MacroSet.clear();
  1358. }
  1359.  
  1360.  
  1361. //------------------------------------------------------------------------//
  1362. bool Lexer::MakeToken(const string& sToken, Token::TOKEN_TYPE Type)
  1363. {
  1364.     bool bSuccess = false;
  1365.     if(m_bEnableComments && m_bCStyleCommentActive)
  1366.         return true;
  1367.  
  1368.     Token token;
  1369.  
  1370.     switch(Type)
  1371.     {
  1372.     case Token::UNKNOWN_TOKEN:
  1373.         if(IsOperator(sToken))
  1374.             bSuccess = token.InitOperator(sToken.c_str());
  1375.         else if(IsInteger(sToken))
  1376.             bSuccess = token.InitInteger(GetInteger(sToken));
  1377.         else if(IsReal(sToken))
  1378.             bSuccess = token.InitReal(GetReal(sToken));
  1379.         else if(IsBoolean(sToken))
  1380.             bSuccess = token.InitBoolean(GetBoolean(sToken));
  1381.         else if(IsHex(sToken))
  1382.             bSuccess = token.InitInteger(GetHex(sToken));
  1383.         else if(IsKeyword(sToken))
  1384.             bSuccess = token.InitKeyword(sToken.c_str());
  1385.         else
  1386.             bSuccess = token.InitVariable(sToken.c_str());
  1387.         break;
  1388.  
  1389.     case Token::OPERATOR:
  1390.         if(IsOperator(sToken))
  1391.             bSuccess = token.InitOperator(sToken.c_str());
  1392.         break;
  1393.  
  1394.     case Token::KEYWORD:
  1395.         if(IsKeyword(sToken))
  1396.             bSuccess = token.InitKeyword(sToken.c_str());
  1397.         break;
  1398.  
  1399.     case Token::VARIABLE:
  1400.         bSuccess = token.InitVariable(sToken.c_str());
  1401.         break;
  1402.  
  1403.     case Token::STRING:
  1404.         bSuccess = token.InitString(sToken.c_str());
  1405.         break;
  1406.  
  1407.     case Token::INTEGER:
  1408.         if(IsInteger(sToken))
  1409.             bSuccess = token.InitInteger(GetInteger(sToken));
  1410.         break;
  1411.  
  1412.     case Token::REAL:
  1413.         if(IsReal(sToken))
  1414.             bSuccess = token.InitReal(GetReal(sToken));
  1415.         break;
  1416.  
  1417.     case Token::BOOLEAN:
  1418.         if(IsBoolean(sToken))
  1419.             bSuccess = token.InitBoolean(GetBoolean(sToken));
  1420.         break;
  1421.     default:
  1422.         bSuccess = false;
  1423.     };
  1424.  
  1425.     if(bSuccess)
  1426.     {    
  1427. #ifdef TOKEN_DEBUGGING_INFO
  1428.         token.SetLineNumber(m_iCurrentLineNumber);
  1429. #endif
  1430.         m_pTokenList->push_back(token);
  1431.         int index = m_pTokenList->GetFileIndex(m_CurrentFileStack.top());
  1432.     }
  1433.     return bSuccess;
  1434. }
  1435.  
  1436.  
  1437. //------------------------------------------------------------------------//
  1438. bool Lexer::IsReal(const string& sToken) const
  1439. {
  1440.     for(int i = 0; i < sToken.length(); ++i)
  1441.         if(!IsDigit(sToken[i]))
  1442.             if(!((i == 0) && (sToken[i] == '-')) && (sToken[i] != '.'))
  1443.                 return false;
  1444.     return true;
  1445. }
  1446.  
  1447.  
  1448. //------------------------------------------------------------------------//
  1449. bool Lexer::IsInteger(const string& sToken) const
  1450. {
  1451.     for(int i = 0; i < sToken.length(); ++i)
  1452.         if(!IsDigit(sToken[i]))
  1453.             if(!((i == 0) && (sToken[i] == '-')))
  1454.                 return false;
  1455.     return true;
  1456. }
  1457.  
  1458. //------------------------------------------------------------------------//
  1459. bool Lexer::IsHex(const string& sToken) const
  1460. {
  1461.     if(sToken.length() < 3)
  1462.         return false;
  1463.     if(!((sToken[0] == '0') && ((sToken[1] == 'x') || (sToken[1] == 'X'))))
  1464.         return false;
  1465.     for(int i = 2; i < sToken.length(); ++i)
  1466.         if(!IsHexDigit(sToken[i]))
  1467.             return false;
  1468.     return true;
  1469. }
  1470.  
  1471. //------------------------------------------------------------------------//
  1472. bool Lexer::IsKeyword(const string& sToken) const
  1473. {
  1474.     if(find(m_KeywordVector.begin(), m_KeywordVector.end(), sToken) 
  1475.         != m_KeywordVector.end())
  1476.         return true;
  1477.     else
  1478.         return false;
  1479. }
  1480.  
  1481. //------------------------------------------------------------------------//
  1482. bool Lexer::IsOperator(const string& sToken) const
  1483. {
  1484.     if(find(m_OperatorVector.begin(), m_OperatorVector.end(), sToken) 
  1485.         != m_OperatorVector.end())
  1486.         return true;
  1487.     else
  1488.         return false;
  1489. }
  1490.  
  1491. //------------------------------------------------------------------------//
  1492. bool Lexer::IsBoolean(const string& sToken) const
  1493. {
  1494.     if(sToken == g_pszTrue || sToken == g_pszFalse)
  1495.         return true;
  1496.     else
  1497.         return false;
  1498. }
  1499.  
  1500. //------------------------------------------------------------------------//
  1501. bool Lexer::GetBoolean(const string& sToken)
  1502. {
  1503.     if(sToken == g_pszTrue)
  1504.         return true;
  1505.     else
  1506.         return false;
  1507. }
  1508.  
  1509.  
  1510. //------------------------------------------------------------------------//
  1511. DWORD Lexer::GetHex(const std::string& sToken)    
  1512. {
  1513.     DWORD i = 0;
  1514.     sscanf(sToken.c_str(), "%x", &i);  
  1515.     return i;
  1516. }
  1517.  
  1518.  
  1519.