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.

191 lines
5.2 KiB

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