Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

192 lines
5.2 KiB

  1. /*++
  2. Copyright (c) 1999-2001 Microsoft Corporation, All Rights Reserved
  3. Module Name:
  4. GENLEX.CPP
  5. Abstract:
  6. Generic lexer framework classes.
  7. History:
  8. --*/
  9. #include "precomp.h"
  10. #include <genlex.h>
  11. //***************************************************************************
  12. //
  13. //***************************************************************************
  14. CGenLexer::CGenLexer(LexEl *pTbl, CGenLexSource *pSrc)
  15. {
  16. m_nCurBufSize = 256;
  17. m_pTokenBuf = (wchar_t *) HeapAlloc(GetProcessHeap(), 0,
  18. m_nCurBufSize * 2);
  19. m_nCurrentLine = 1;
  20. m_pTable = pTbl;
  21. m_pSrc = pSrc;
  22. }
  23. //***************************************************************************
  24. //
  25. //***************************************************************************
  26. void CGenLexer::Reset()
  27. {
  28. m_pSrc->Reset();
  29. m_nCurrentLine = 1;
  30. }
  31. //***************************************************************************
  32. //
  33. //***************************************************************************
  34. CGenLexer::~CGenLexer()
  35. {
  36. HeapFree(GetProcessHeap(), 0, m_pTokenBuf);
  37. }
  38. //***************************************************************************
  39. //
  40. //***************************************************************************
  41. int CGenLexer::NextToken()
  42. {
  43. int nState = 0;
  44. int nCurBufEnd = 0;
  45. BOOL bRead = TRUE;
  46. wchar_t cCurrent = 0;
  47. BOOL bEOF = FALSE;
  48. if (m_pTokenBuf == 0)
  49. return 0;
  50. *m_pTokenBuf = 0;
  51. // Generic DFA driver based on the table specified
  52. // in the constructor.
  53. // ===============================================
  54. while (1)
  55. {
  56. BOOL bMatch = FALSE;
  57. WORD wInstructions = m_pTable[nState].wInstructions;
  58. if (bRead)
  59. {
  60. if(bEOF)
  61. {
  62. // The lexer table allowed us to go past end of string!!!
  63. return 1;
  64. }
  65. cCurrent = m_pSrc->NextChar();
  66. if(cCurrent == 0)
  67. bEOF = TRUE;
  68. }
  69. bRead = FALSE;
  70. // Check here if only the first character is present.
  71. // ==================================================
  72. if (m_pTable[nState].cFirst == GLEX_ANY)
  73. bMatch = TRUE;
  74. else if (m_pTable[nState].cLast == GLEX_EMPTY)
  75. {
  76. if (cCurrent == m_pTable[nState].cFirst)
  77. bMatch = TRUE;
  78. else if ((wInstructions & GLEX_NOT) &&
  79. !(cCurrent == m_pTable[nState].cFirst))
  80. bMatch = TRUE;
  81. }
  82. // If here, both first/last are present and we
  83. // are testing to see if the input is in between.
  84. // ==============================================
  85. else if (m_pTable[nState].cFirst != GLEX_ANY)
  86. {
  87. if ((wInstructions & GLEX_NOT) &&
  88. !(cCurrent >= m_pTable[nState].cFirst &&
  89. cCurrent <= m_pTable[nState].cLast))
  90. bMatch = TRUE;
  91. else if (cCurrent >= m_pTable[nState].cFirst &&
  92. cCurrent <= m_pTable[nState].cLast)
  93. bMatch = TRUE;
  94. }
  95. // Interpret the instruction field to determine
  96. // whether the character is actually to be included
  97. // in the token text.
  98. // ================================================
  99. if (bMatch)
  100. {
  101. if (wInstructions & GLEX_ACCEPT)
  102. {
  103. // Expand the current buffer, if required.
  104. // =======================================
  105. if (nCurBufEnd == m_nCurBufSize - 1)
  106. {
  107. m_nCurBufSize += 256;
  108. m_pTokenBuf = (wchar_t *) HeapReAlloc(GetProcessHeap(), 0, m_pTokenBuf,
  109. m_nCurBufSize * 2);
  110. if (m_pTokenBuf == 0)
  111. return 0; // out of memory
  112. }
  113. m_pTokenBuf[nCurBufEnd] = cCurrent;
  114. m_pTokenBuf[++nCurBufEnd]= 0;
  115. bRead = TRUE;
  116. }
  117. if (wInstructions & GLEX_CONSUME)
  118. bRead = TRUE;
  119. // else GLEX_CONSUME, which means 'skip'
  120. // If the PUSHBACK instruction is present,
  121. // push the char back.
  122. // ======================================
  123. if (wInstructions & GLEX_PUSHBACK)
  124. {
  125. bRead = TRUE;
  126. m_pSrc->Pushback(cCurrent);
  127. }
  128. // If a linefeed instruction.
  129. // ==========================
  130. if (wInstructions & GLEX_LINEFEED)
  131. m_nCurrentLine++;
  132. // If the return field is present and there was
  133. // a match, then return the specified token. Alternately,
  134. // the GLEX_RETURN instruction will force a return
  135. // match, or no match.
  136. // =======================================================
  137. if (m_pTable[nState].wReturnTok ||
  138. (wInstructions & GLEX_RETURN))
  139. return int(m_pTable[nState].wReturnTok);
  140. nState = int(m_pTable[nState].wGotoState);
  141. }
  142. // If here, there was no match.
  143. // ===================================
  144. else
  145. nState++;
  146. }
  147. return 0; // No path to here
  148. }