Leaked source code of windows server 2003
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.

1600 lines
44 KiB

  1. /*++
  2. Copyright (C) 1995-2001 Microsoft Corporation
  3. Module Name:
  4. MOFLEX.CPP
  5. Abstract:
  6. Implementation for class CMofLexer, which tokenizes MOF files.
  7. ANSI, DBCS and UNICODE are supported.
  8. History:
  9. a-raymcc 11-Oct-95 Created.
  10. a-raymcc 27-Jan-96 Update for aliasing.
  11. a-davj 6-June-96 Added support for octal, hex and binary constants
  12. and line stitching, comment concatenation, escape
  13. characters and old style comments.
  14. --*/
  15. #include "precomp.h"
  16. #include <bmof.h>
  17. #include <stdio.h>
  18. #include <errno.h>
  19. #include <arrtempl.h>
  20. #include "mrciclass.h"
  21. #include "datasrc.h"
  22. #include "moflex.h"
  23. #include "preproc.h"
  24. #include "trace.h"
  25. #include "strings.h"
  26. #include "wbemcli.h"
  27. #define INIT_ALLOC 512
  28. #define ADDITIONAL_ALLOC 10000
  29. #define MAX_ALLOC 1000000
  30. #define UUIDLEN 36
  31. // The following is the table of tokens consisting of a
  32. // single character.
  33. // =====================================================
  34. typedef struct
  35. {
  36. wchar_t cToken;
  37. int nSymbol;
  38. } SingleTok;
  39. SingleTok SingleTokenMap[] =
  40. {
  41. L'{', TOK_OPEN_BRACE,
  42. L'}', TOK_CLOSE_BRACE,
  43. L'[', TOK_OPEN_BRACKET,
  44. L']', TOK_CLOSE_BRACKET,
  45. L'(', TOK_OPEN_PAREN,
  46. L')', TOK_CLOSE_PAREN,
  47. L',', TOK_COMMA,
  48. L'=', TOK_EQUALS,
  49. L';', TOK_SEMI,
  50. L'&', TOK_AMPERSAND,
  51. L':', TOK_COLON,
  52. L'#', TOK_POUND,
  53. L'$', TOK_DOLLAR_SIGN,
  54. L'+', TOK_PLUS
  55. };
  56. #define NUM_SINGLE_TOKENS (sizeof(SingleTokenMap)/sizeof(SingleTok))
  57. // The following is the table of keywords which look like normal
  58. // identifiers.
  59. // =============================================================
  60. typedef struct
  61. {
  62. OLECHAR *pKeyword;
  63. int nToken;
  64. } Keyword;
  65. static Keyword MofKeywords[] =
  66. {
  67. L"class", TOK_CLASS,
  68. L"instance", TOK_INSTANCE,
  69. L"null", TOK_KEYWORD_NULL,
  70. L"external", TOK_EXTERNAL,
  71. L"as", TOK_AS,
  72. L"ref", TOK_REF,
  73. L"of", TOK_OF,
  74. // L"object", TOK_OBJECT,
  75. L"typedef", TOK_TYPEDEF,
  76. L"subrange", TOK_SUBRANGE,
  77. L"pragma", TOK_PRAGMA,
  78. L"define", TOK_DEFINE,
  79. L"ifdef", TOK_IFDEF,
  80. L"include", TOK_INCLUDE,
  81. L"endif", TOK_ENDIF,
  82. L"ifndef", TOK_IFNDEF,
  83. L"enum", TOK_ENUM,
  84. L"AUTORECOVER", TOK_AUTORECOVER,
  85. L"true", TOK_TRUE,
  86. L"false", TOK_FALSE,
  87. L"interface", TOK_INTERFACE,
  88. L"ToInstance", TOK_TOINSTANCE,
  89. L"ToSubClass", TOK_TOSUBCLASS,
  90. L"EnableOverride", TOK_ENABLEOVERRIDE,
  91. L"DisableOverride", TOK_DISABLEOVERRIDE,
  92. L"NotToInstance", TOK_NOTTOINSTANCE,
  93. L"Amended", TOK_AMENDED,
  94. L"NotToSubClass", TOK_NOTTOSUBCLASS,
  95. L"Restricted", TOK_RESTRICTED,
  96. L"qualifier", TOK_QUALIFIER,
  97. L"ClassFlags", TOK_CLASSFLAGS,
  98. L"InstanceFlags", TOK_INSTANCEFLAGS,
  99. L"Amendment", TOK_AMENDMENT,
  100. L"void", TOK_VOID,
  101. L"deleteclass", TOK_DELETECLASS,
  102. L"FAIL", TOK_FAIL,
  103. L"NOFAIL", TOK_NOFAIL
  104. };
  105. #define NUM_KEYWORDS (sizeof(MofKeywords)/sizeof(Keyword))
  106. BOOL iswodigit(wchar_t wcTest);
  107. //***************************************************************************
  108. //
  109. // SingleCharToken()
  110. //
  111. // This examines a single character of input and scans the table to
  112. // determine if it is one of the single-character tokens.
  113. //
  114. // Parameters:
  115. // c = The character being tested.
  116. // Return value:
  117. // Zero if no match, otherwise the TOK_ constant which identifies
  118. // the token.
  119. //
  120. //***************************************************************************
  121. static int SingleCharToken(wchar_t c)
  122. {
  123. for (int i = 0; i < NUM_SINGLE_TOKENS; i++)
  124. if (SingleTokenMap[i].cToken == c)
  125. return SingleTokenMap[i].nSymbol;
  126. return 0;
  127. }
  128. //***************************************************************************
  129. //
  130. // BOOL iswwbemalpha
  131. //
  132. // Used to test if a wide character is suitable for identifiers.
  133. //
  134. // Parameters:
  135. // c = The character being tested.
  136. // Return value:
  137. // TRUE if OK.
  138. //
  139. //***************************************************************************
  140. BOOL iswwbemalpha(wchar_t c)
  141. {
  142. if(c == 0x5f || (0x41 <= c && c <= 0x5a) ||
  143. (0x61 <= c && c <= 0x7a) || (0x80 <= c && c <= 0xfffd))
  144. return TRUE;
  145. else
  146. return FALSE;
  147. }
  148. //***************************************************************************
  149. //
  150. // KeywordFilter()
  151. //
  152. // This function examines an identifier string to determine if it is
  153. // in fact a keyword.
  154. //
  155. // Parameters:
  156. // pTokStr = a pointer to the string to be examined.
  157. //
  158. // Return value:
  159. // TOK_SIMPLE_IDENT if no match and no '_', or else the correct TOK_ value
  160. // for the keyword.
  161. //
  162. //***************************************************************************
  163. static int KeywordFilter(wchar_t *pTokStr)
  164. {
  165. for (int i = 0; i < NUM_KEYWORDS; i++)
  166. if (wbem_wcsicmp(MofKeywords[i].pKeyword, pTokStr) == 0)
  167. return MofKeywords[i].nToken;
  168. wchar_t * pEnd;
  169. pEnd = pTokStr + wcslen(pTokStr) -1;
  170. if(*pTokStr != L'_' && *pEnd != L'_')
  171. return TOK_SIMPLE_IDENT;
  172. else
  173. return TOK_SYSTEM_IDENT;
  174. }
  175. //***************************************************************************
  176. //
  177. // ValidGuid()
  178. //
  179. // Examines a character string to determine if it constitutes a valid
  180. // GUID.
  181. //
  182. // Return value:
  183. // TRUE if the string is a GUID, FALSE if not.
  184. //
  185. //***************************************************************************
  186. BOOL CMofLexer::ValidGuid()
  187. {
  188. int i;
  189. int iSoFar = 0;
  190. #define HEXCHECK(n) \
  191. for (i = 0; i < n; i++) \
  192. if (!iswxdigit(GetChar(iSoFar++))) \
  193. return FALSE;
  194. #define HYPHENCHECK() \
  195. if (GetChar(iSoFar++) != L'-') \
  196. return FALSE;
  197. HEXCHECK(8);
  198. HYPHENCHECK();
  199. HEXCHECK(4);
  200. HYPHENCHECK();
  201. HEXCHECK(4);
  202. HYPHENCHECK();
  203. HEXCHECK(4);
  204. HYPHENCHECK();
  205. HEXCHECK(12);
  206. return TRUE;
  207. }
  208. //***************************************************************************
  209. //
  210. // CMofLexer::Init()
  211. //
  212. // Helper for first state of construction; inializing variables.
  213. //
  214. //***************************************************************************
  215. void CMofLexer::Init()
  216. {
  217. m_nLine = 1;
  218. m_nStartOfLinePos = 0;
  219. m_bBMOF = false;
  220. m_wFile[0] = 0;
  221. m_nWorkBufSize = INIT_ALLOC;
  222. m_pWorkBuf = new wchar_t[m_nWorkBufSize];
  223. m_pDataSrc = NULL;
  224. m_pBuff = NULL; // set in the constructors
  225. m_pToFar = NULL;
  226. m_nErrorCode = (m_pWorkBuf) ? no_error : memory_failure ;
  227. }
  228. //***************************************************************************
  229. //
  230. // CMofLexer::BuildBuffer()
  231. //
  232. // Helper for last stage of construction; build the unicode buffer. Note
  233. // that this can be used by either the file or memory based constructor.
  234. //
  235. //***************************************************************************
  236. void CMofLexer::BuildBuffer(long lSize, TCHAR * pFileName, char * pMemSrc, char * pMemToFar)
  237. {
  238. if(m_nErrorCode != no_error)
  239. return; // already failed!
  240. if(pFileName)
  241. #ifdef USE_MMF_APPROACH
  242. m_pDataSrc = new FileDataSrc1(pFileName);
  243. #else
  244. m_pDataSrc = new FileDataSrc(pFileName);
  245. #endif
  246. else
  247. m_pDataSrc = new BufferDataSrc(lSize, pMemSrc);
  248. if(m_pDataSrc == NULL)
  249. m_nErrorCode = memory_failure;
  250. else if(m_pDataSrc->GetStatus() != 0)
  251. m_nErrorCode = file_io_error;
  252. return;
  253. }
  254. //***************************************************************************
  255. //
  256. // Constructor for in-memory parsing.
  257. //
  258. //***************************************************************************
  259. CMofLexer::CMofLexer(PDBG pDbg)
  260. {
  261. m_bUnicode = false;
  262. m_pDbg = pDbg;
  263. Init();
  264. }
  265. HRESULT CMofLexer::SetBuffer(char *pMemory, DWORD dwMemSize)
  266. {
  267. DWORD dwCompressedSize, dwExpandedSize;
  268. if(IsBMOFBuffer((BYTE *)pMemory, dwCompressedSize, dwExpandedSize))
  269. {
  270. bool bRet = CreateBufferFromBMOF((BYTE *)pMemory + 16, dwCompressedSize, dwExpandedSize);
  271. if(bRet == false)
  272. m_nErrorCode = invalid_source_buffer;
  273. }
  274. else
  275. {
  276. m_bUnicode = false;
  277. BuildBuffer(dwMemSize+4, NULL, pMemory, pMemory+dwMemSize);
  278. }
  279. if(m_nErrorCode == no_error)
  280. return S_OK;
  281. else
  282. return WBEM_E_FAILED;
  283. }
  284. //***************************************************************************
  285. //
  286. // Checks if the file contains a binarary mof and if it does, decompresses
  287. // the binary data.
  288. //
  289. //***************************************************************************
  290. bool CMofLexer::ProcessBMOFFile(FILE *fp,TCHAR * szFilename)
  291. {
  292. // read the first 20 bytes
  293. BYTE Test[TEST_SIZE];
  294. int iRet = fread(Test, 1, TEST_SIZE, fp);
  295. if(iRet != TEST_SIZE)
  296. {
  297. // if we cant read even the header, it must not be a BMOF
  298. return false;
  299. }
  300. DWORD dwCompressedSize, dwExpandedSize;
  301. // Test if the mof is binary
  302. if(!IsBMOFBuffer(Test, dwCompressedSize, dwExpandedSize))
  303. {
  304. // not a binary mof. This is the typical case
  305. return false;
  306. }
  307. // get the compression type, and the sizes
  308. if( 0 != fseek(fp, 0, SEEK_SET)) return false;
  309. DWORD dwSig, dwCompType;
  310. iRet = fread(&dwSig, sizeof(DWORD), 1, fp);
  311. iRet = fread(&dwCompType, sizeof(DWORD), 1, fp);
  312. iRet = fread(&dwCompressedSize, sizeof(DWORD), 1, fp);
  313. iRet = fread(&dwExpandedSize, sizeof(DWORD), 1, fp);
  314. // Make sure the compression type is one we understand!
  315. if(dwCompType != 0 && dwCompType != 1)
  316. {
  317. return FALSE;
  318. }
  319. m_pDataSrc = new BMOFDataSrc(szFilename);
  320. if (NULL == m_pDataSrc) return false;
  321. // If there was no compression, just read the data
  322. if(dwCompType == 0)
  323. {
  324. m_pBuff = (WCHAR *)new BYTE[dwExpandedSize];
  325. if(m_pBuff == NULL)
  326. {
  327. return false;
  328. }
  329. iRet = fread(m_pBuff, dwExpandedSize, 1, fp);
  330. m_bBMOF = true;
  331. m_pToFar = (BYTE *)m_pBuff + dwExpandedSize;
  332. return true;
  333. }
  334. // Allocate storage for the compressed data
  335. BYTE * pCompressed = new BYTE[dwCompressedSize];
  336. if(pCompressed == NULL)
  337. {
  338. return false;
  339. }
  340. // Read the compressed data.
  341. iRet = fread(pCompressed, 1, dwCompressedSize,fp);
  342. if((DWORD)iRet != dwCompressedSize)
  343. {
  344. delete pCompressed;
  345. return false;
  346. }
  347. // Convert from compress into something we can use later
  348. bool bRet = CreateBufferFromBMOF(pCompressed, dwCompressedSize, dwExpandedSize);
  349. delete pCompressed;
  350. return bRet;
  351. }
  352. //***************************************************************************
  353. //
  354. // Creates the working buffer from a compressed binary mof buffer.
  355. //
  356. //***************************************************************************
  357. bool CMofLexer::CreateBufferFromBMOF(byte * pCompressed, DWORD dwCompressedSize, DWORD dwExpandedSize)
  358. {
  359. if(m_pBuff)
  360. delete m_pBuff;
  361. m_pBuff = (WCHAR *)new BYTE[dwExpandedSize];
  362. if(m_pBuff == NULL)
  363. {
  364. return false;
  365. }
  366. m_pToFar = (BYTE *)m_pBuff + dwExpandedSize;
  367. // Decompress the data
  368. CMRCICompression * pCompress = new CMRCICompression;
  369. if(pCompress == NULL)
  370. return FALSE;
  371. CDeleteMe<CMRCICompression> dm(pCompress);
  372. DWORD dwResSize = pCompress->Mrci1Decompress(pCompressed, dwCompressedSize,
  373. (BYTE *)m_pBuff, dwExpandedSize);
  374. bool bRet = dwResSize == dwExpandedSize;
  375. if(bRet)
  376. m_bBMOF = true;
  377. return bRet;
  378. }
  379. //***************************************************************************
  380. //
  381. // Constructor for file-based parsing.
  382. //
  383. //***************************************************************************
  384. CMofLexer::CMofLexer(const TCHAR *pFilePath, PDBG pDbg)
  385. {
  386. m_bUnicode = FALSE;
  387. m_pDbg = pDbg;
  388. Init();
  389. FILE *fp;
  390. BOOL bBigEndian = FALSE;
  391. if(pFilePath == NULL)
  392. {
  393. m_nErrorCode = file_not_found;
  394. return;
  395. }
  396. TCHAR szExpandedFilename[MAX_PATH+1];
  397. DWORD nRes = ExpandEnvironmentStrings(pFilePath,
  398. szExpandedFilename,
  399. FILENAME_MAX);
  400. if(nRes == 0)
  401. StringCchCopyW(szExpandedFilename, MAX_PATH+1, pFilePath);
  402. // Make sure the file exists and can be opened
  403. if(pFilePath && lstrlen(szExpandedFilename))
  404. {
  405. Trace(true, pDbg, PARSING_MSG, szExpandedFilename);
  406. }
  407. #ifdef UNICODE
  408. fp = _wfopen(szExpandedFilename, L"rb");
  409. #else
  410. fp = fopen(szExpandedFilename, "rb");
  411. #endif
  412. if (!fp)
  413. {
  414. if (errno == ENOENT)
  415. m_nErrorCode = file_not_found;
  416. if (errno == EACCES)
  417. m_nErrorCode = access_denied;
  418. else
  419. m_nErrorCode = file_io_error;
  420. return;
  421. }
  422. else
  423. {
  424. CfcloseMe cm(fp);
  425. // If the file contains a binary mof, handle it here
  426. if(ProcessBMOFFile(fp,szExpandedFilename))
  427. {
  428. return;
  429. }
  430. }
  431. // Create a temp file name
  432. TCHAR cTempFileName[MAX_PATH+1];
  433. TCHAR cTempPath[MAX_PATH+1];
  434. if( 0 == GetTempPath(MAX_PATH+1, cTempPath))
  435. {
  436. m_nErrorCode = problem_creating_temp_file;
  437. return ;
  438. }
  439. if( 0 == GetTempFileName(cTempPath, TEXT("tmp"), 0, cTempFileName))
  440. {
  441. m_nErrorCode = problem_creating_temp_file;
  442. return ;
  443. }
  444. // Create the temp file
  445. FILE *fpTemp;
  446. #ifdef UNICODE
  447. fpTemp = _wfopen(cTempFileName, L"wb+");
  448. #else
  449. fpTemp = fopen(cTempFileName, "wb+");
  450. #endif
  451. if(fpTemp == 0)
  452. {
  453. m_nErrorCode = problem_creating_temp_file;
  454. return;
  455. }
  456. else
  457. {
  458. CFlexArray sofar; // used to make sure we dont get into an infinite loop
  459. SCODE sc = WriteFileToTemp(szExpandedFilename, fpTemp, sofar, pDbg, this);
  460. fclose(fpTemp);
  461. for(int iCnt = 0; iCnt < sofar.Size(); iCnt++)
  462. {
  463. char * pTemp = (char * )sofar.GetAt(iCnt);
  464. delete pTemp;
  465. }
  466. if(sc != S_OK)
  467. {
  468. if(m_nErrorCode == no_error)
  469. m_nErrorCode = preprocessor_error;
  470. DeleteFile(cTempFileName);
  471. return;
  472. }
  473. // Determine the size of the file
  474. // ==============================
  475. fseek(fpTemp, 0, SEEK_END);
  476. long lSize = ftell(fpTemp) + 6; // add a bit extra for ending space and null NULL
  477. fseek(fpTemp, 0, SEEK_SET);
  478. // The temp file will be little endian unicode
  479. lSize /= 2;
  480. m_bUnicode = TRUE;
  481. bBigEndian = FALSE;
  482. // This will create a DataSrc object which will clean up the temp file
  483. BuildBuffer(lSize,cTempFileName ,NULL,NULL);
  484. }
  485. }
  486. //***************************************************************************
  487. //
  488. // Destructor.
  489. //
  490. //***************************************************************************
  491. CMofLexer::~CMofLexer()
  492. {
  493. if (m_pBuff)
  494. delete m_pBuff;
  495. if (m_pWorkBuf)
  496. delete m_pWorkBuf;
  497. delete m_pDataSrc;
  498. }
  499. //***************************************************************************
  500. //
  501. // iswodigit
  502. //
  503. // Returns TRUE if it is a valid octal character. '0' to '7'.
  504. //
  505. //***************************************************************************
  506. BOOL iswodigit(wchar_t wcTest)
  507. {
  508. if(wbem_iswdigit(wcTest) && wcTest != L'8' && wcTest != L'9')
  509. return TRUE;
  510. else
  511. return FALSE;
  512. }
  513. //***************************************************************************
  514. //
  515. // CMofLexer::OctalConvert
  516. //
  517. // Converts an octal escape sequence into a character and returns the number
  518. // of digits converted. Only a max of 3 digits is converted and if it isnt
  519. // a wchar, the digits cant add up to more that 0377
  520. //
  521. //***************************************************************************
  522. int CMofLexer::OctalConvert(wchar_t *pResult, LexState lsCurr)
  523. {
  524. int iNum = 0;
  525. wchar_t wcTest;
  526. *pResult = 0;
  527. for(wcTest = GetChar(iNum+1); iswodigit(wcTest) && iNum < 3;
  528. iNum++, wcTest = GetChar(iNum+1))
  529. {
  530. *pResult *= 8;
  531. *pResult += wcTest - L'0';
  532. }
  533. if((lsCurr == wstring || lsCurr == wcharacter) && *pResult >0xff)
  534. m_bBadString = TRUE;
  535. return iNum;
  536. }
  537. //***************************************************************************
  538. //
  539. // CMofLexer::HexConvert
  540. //
  541. // Converts a hex escape sequence into a character and returns the number
  542. // of digits converted.
  543. //
  544. //***************************************************************************
  545. int CMofLexer::HexConvert(wchar_t *pResult, LexState lsCurr)
  546. {
  547. int iNum = 0;
  548. wchar_t wcTest;
  549. *pResult = 0;
  550. int iMax = (lsCurr == wstring||lsCurr == wcharacter) ? 4 : 2;
  551. for(wcTest = GetChar(iNum+2); iswxdigit(wcTest) && iNum < iMax;
  552. iNum++, wcTest = GetChar(iNum+2))
  553. {
  554. *pResult *= 16;
  555. if(wbem_iswdigit(wcTest)) // sscanf(xx,"%1x",int) also works!
  556. *pResult += wcTest - L'0';
  557. else
  558. *pResult += towupper(wcTest) - L'A' + 10;
  559. }
  560. if(iNum == 0)
  561. return -1; // error, nothing was converted!
  562. return iNum+1; // num converted plus the 'x' char!
  563. }
  564. //***************************************************************************
  565. //
  566. // CMofLexer::ConvertEsc
  567. //
  568. // Processes escape characters. Returns size of sequence, a -1 indicates an
  569. // error. Also, the *pResult is set upon success.
  570. //
  571. //***************************************************************************
  572. int CMofLexer::ConvertEsc(wchar_t * pResult, LexState lsCurr)
  573. {
  574. // like C, case sensitive
  575. switch(GetChar(1)) {
  576. case L'n':
  577. *pResult = 0xa;
  578. break;
  579. case L't':
  580. *pResult = 0x9;
  581. break;
  582. case L'v':
  583. *pResult = 0xb;
  584. break;
  585. case L'b':
  586. *pResult = 0x8;
  587. break;
  588. case L'r':
  589. *pResult = 0xd;
  590. break;
  591. case L'f':
  592. *pResult = 0xc;
  593. break;
  594. case L'a':
  595. *pResult = 0x7;
  596. break;
  597. case L'\\':
  598. *pResult = L'\\';
  599. break;
  600. case L'?':
  601. *pResult = L'?';
  602. break;
  603. case L'\'':
  604. *pResult = L'\'';
  605. break;
  606. case L'\"':
  607. *pResult = L'\"';
  608. break;
  609. case L'x':
  610. return HexConvert(pResult,lsCurr);
  611. break;
  612. default:
  613. if(iswodigit(GetChar(1)))
  614. return OctalConvert(pResult,lsCurr);
  615. return -1; // error!
  616. break;
  617. }
  618. return 1;
  619. }
  620. //***************************************************************************
  621. //
  622. // ProcessStr
  623. //
  624. // Processes new characters once we are in the string state.
  625. //
  626. // Return "stop" if end of string.
  627. //
  628. //***************************************************************************
  629. LexState CMofLexer::ProcessStr(wchar_t * pNewChar, LexState lsCurr, int * piRet)
  630. {
  631. // Check for end of string if we are a wstring state
  632. if (GetChar() == L'"' && lsCurr == wstring)
  633. {
  634. // search for the next non white space character. If it is another
  635. // string then these strings need to be combined.
  636. int iCnt = 1;
  637. int iMinMove = 0;
  638. wchar_t wcTest;
  639. for(wcTest = GetChar(iCnt); wcTest != NULL; iCnt++, wcTest=GetChar(iCnt))
  640. {
  641. if(m_pDataSrc->WouldBePastEnd(iCnt))
  642. {
  643. // dont go past eof!!
  644. *piRet = (m_bBadString) ? TOK_ERROR : TOK_LPWSTR;
  645. return stop; // last string in the file
  646. }
  647. if(wcTest == L'"' && GetChar(iCnt+1) == L'"')
  648. {
  649. iCnt++;
  650. iMinMove = iCnt;
  651. continue;
  652. }
  653. if(!iswspace(wcTest))
  654. break;
  655. }
  656. // a-levn: no ascii strings are supported. "abc" means unicode.
  657. if(lsCurr == wstring)
  658. {
  659. if(wcTest == L'/')
  660. {
  661. // might be an intervening comment
  662. // ===============================
  663. if (GetChar(iCnt+1) == L'/')
  664. {
  665. m_bInString = TRUE;
  666. MovePtr(iCnt+1);
  667. return new_style_comment;
  668. }
  669. else if (GetChar(iCnt+1) == L'*')
  670. {
  671. m_bInString = TRUE;
  672. MovePtr(iCnt+1); // skip an extra so not to be fooled by
  673. return old_style_comment;
  674. }
  675. }
  676. if(wcTest != L'"')
  677. {
  678. *piRet = (m_bBadString) ? TOK_ERROR : TOK_LPWSTR;
  679. MovePtr(iMinMove); // skip over '"'
  680. return stop; // normal way for string to end
  681. }
  682. else
  683. MovePtr(iCnt + 1); // skip over '"'
  684. }
  685. }
  686. // If we are in character state, check for end
  687. if (GetChar(0) == L'\'' && lsCurr == wcharacter)
  688. {
  689. if(m_bBadString || m_pDataSrc->PastEnd() ||
  690. (m_pDataSrc->GetAt(-1) == L'\'') && m_pDataSrc->GetAt(-2) != L'\\')
  691. *piRet = TOK_ERROR;
  692. else
  693. *piRet = TOK_WCHAR;
  694. return stop;
  695. }
  696. // Not at end, get the character, possibly converting escape sequences
  697. if(GetChar(0) == L'\\')
  698. {
  699. int iSize = ConvertEsc(pNewChar,lsCurr);
  700. m_i8 = *pNewChar;
  701. if(iSize < 1)
  702. m_bBadString = TRUE;
  703. else
  704. {
  705. MovePtr(iSize);
  706. if(lsCurr == wcharacter && GetChar(1) != L'\'')
  707. {
  708. *piRet = TOK_ERROR;
  709. return stop;
  710. }
  711. }
  712. }
  713. else if(GetChar(0) == '\n')
  714. {
  715. m_bBadString = TRUE;
  716. MovePtr(-1);
  717. return stop;
  718. }
  719. else
  720. {
  721. *pNewChar = GetChar(0);
  722. m_i8 = *pNewChar;
  723. if(*pNewChar == 0 || *pNewChar > 0xfffeu || (GetChar(1) != L'\'' && lsCurr == wcharacter))
  724. {
  725. *piRet = TOK_ERROR;
  726. return stop;
  727. }
  728. }
  729. return lsCurr;
  730. }
  731. //***************************************************************************
  732. //
  733. // BinaryToInt
  734. //
  735. // Converts a character representation of a binary, such as "101b" into
  736. // an integer.
  737. //
  738. //***************************************************************************
  739. BOOL BinaryToInt(wchar_t * pConvert, __int64& i64Res)
  740. {
  741. BOOL bNeg = FALSE;
  742. __int64 iRet = 0;
  743. WCHAR * pStart;
  744. if(*pConvert == L'-' || *pConvert == L'+')
  745. {
  746. if(*pConvert == L'-')
  747. bNeg = TRUE;
  748. pConvert++;
  749. }
  750. for(pStart = pConvert;*pConvert && (*pConvert == L'0' || *pConvert == L'1'); pConvert++)
  751. {
  752. if(pConvert - pStart > 63)
  753. return FALSE; // Its too long
  754. iRet *= 2;
  755. if(*pConvert == L'1')
  756. iRet += 1;
  757. }
  758. if(towupper(*pConvert) != L'B')
  759. return FALSE;
  760. if(bNeg)
  761. iRet = -iRet;
  762. i64Res = iRet;
  763. return TRUE;
  764. }
  765. BOOL GetInt(WCHAR *pData, WCHAR * pFormat, __int64 * p64)
  766. {
  767. static WCHAR wTemp[100];
  768. if(swscanf(pData, pFormat, p64) != 1)
  769. return FALSE;
  770. // Make sure the data is ok. When comparing, make sure that leading 0's are skipped
  771. StringCchPrintfW(wTemp, 100, pFormat, *p64);
  772. WCHAR * pTemp;
  773. for(pTemp = pData; *pTemp == L'0' && pTemp[1]; pTemp++);
  774. if(wbem_wcsicmp(wTemp, pTemp))
  775. return FALSE;
  776. return TRUE;
  777. }
  778. //***************************************************************************
  779. //
  780. // CMofLexer::iGetNumericType()
  781. //
  782. // Return value:
  783. // What type of numeric constant the current pointer is pointing to.
  784. //
  785. //***************************************************************************
  786. int CMofLexer::iGetNumericType(void)
  787. {
  788. #define isuorl(x) (towupper(x) == L'U' || towupper(x) == L'L')
  789. wchar_t * pTemp;
  790. BOOL bBinary = FALSE;
  791. wchar_t * pStart; // first charcter not including leading - or +
  792. int iNumBinaryDigit = 0;
  793. int iNumDigit = 0;
  794. int iNumOctalDigit = 0;
  795. int iNumDot = 0;
  796. int iNumE = 0;
  797. wchar_t * pEnd = m_pWorkBuf + wcslen(m_pWorkBuf) - 1;
  798. if(*m_pWorkBuf == L'-' || *m_pWorkBuf == L'+')
  799. pStart = m_pWorkBuf+1;
  800. else
  801. pStart = m_pWorkBuf;
  802. int iLen = wcslen(pStart); // length not including leading '-' or '+'
  803. BOOL bHex = (pStart[0] == L'0' && towupper(pStart[1]) == L'X');
  804. // loop through and count the number of various digit types, decimal points, etc.
  805. // ==============================================================================
  806. for(pTemp = pStart; *pTemp; pTemp++)
  807. {
  808. // Check for 'U' or 'l' characters at the end. They are an error
  809. // if the number is a float, or not in the last two characters, or
  810. // if a 'u' is present along with a '-' in the first character
  811. // ===============================================================
  812. if (isuorl(*pTemp))
  813. {
  814. if(pTemp < pEnd -1 || !isuorl(*pEnd) || iNumDot || iNumE)
  815. return TOK_ERROR;
  816. if(towupper(*pTemp) == L'U' && *m_pWorkBuf == L'-')
  817. return TOK_ERROR;
  818. iLen--;
  819. continue;
  820. }
  821. // If we previously hit the binary indicator, the only thing that
  822. // should be after the b is U or L characters.
  823. // ==============================================================
  824. if(bBinary)
  825. return TOK_ERROR;
  826. // If in hex mode, only allow for x in second digit and hex numbers.
  827. // anything else is an error.
  828. // =================================================================
  829. if(bHex)
  830. {
  831. if(pTemp < pStart+2) // ignore the 0X
  832. continue;
  833. if(!iswxdigit(*pTemp))
  834. return TOK_ERROR;
  835. iNumDigit++;
  836. continue;
  837. }
  838. // Number is either a non hex integer or a float.
  839. // Do a count of various special digit types, decimal points, etc.
  840. // ===============================================================
  841. if(*pTemp == L'0' || *pTemp == L'1')
  842. iNumBinaryDigit++;
  843. if(iswodigit(*pTemp))
  844. iNumOctalDigit++;
  845. // each character should fall into one of the following catagories
  846. if(wbem_iswdigit(*pTemp))
  847. iNumDigit++;
  848. else if(*pTemp == L'.')
  849. {
  850. iNumDot++;
  851. if(iNumDot > 1 || iNumE > 0)
  852. return TOK_ERROR;
  853. }
  854. else if(towupper(*pTemp) == L'E')
  855. {
  856. if(iNumDigit == 0 || iNumE > 0)
  857. return TOK_ERROR;
  858. iNumDigit=0; // to ensure at least one digit after the 'e'
  859. iNumE++;
  860. }
  861. else if(*pTemp == L'-' || *pTemp == L'+') // ok if after 'E'
  862. {
  863. if(pTemp > pStart && towupper(pTemp[-1]) == L'E')
  864. continue;
  865. else
  866. return TOK_ERROR;
  867. }
  868. else if (towupper(*pTemp) == L'B')
  869. bBinary = TRUE;
  870. else
  871. return TOK_ERROR;
  872. }
  873. // Make sure there are enough digits
  874. // =================================
  875. if(iNumDigit < 1)
  876. return TOK_ERROR;
  877. // take care of integer case.
  878. // ==========================
  879. if(bHex || bBinary || iNumDigit == iLen)
  880. {
  881. __int64 i8 = 0;
  882. if(bHex)
  883. {
  884. if(!GetInt(m_pWorkBuf+2, L"%I64x", &i8))
  885. return TOK_ERROR;
  886. }
  887. else if(bBinary)
  888. {
  889. if(!BinaryToInt(m_pWorkBuf, i8))
  890. return TOK_ERROR;
  891. }
  892. else if(pStart[0] != L'0' || wcslen(pStart) == 1)
  893. {
  894. if(*m_pWorkBuf == '-')
  895. {
  896. if(!GetInt(m_pWorkBuf, L"%I64i", &i8))
  897. return TOK_ERROR;
  898. }
  899. else
  900. {
  901. if(!GetInt(m_pWorkBuf, L"%I64u", &i8))
  902. return TOK_ERROR;
  903. }
  904. }
  905. else if(iNumDigit == iNumOctalDigit)
  906. {
  907. if(!GetInt(m_pWorkBuf+1, L"%I64o", &i8))
  908. return TOK_ERROR;
  909. }
  910. else return TOK_ERROR;
  911. // Make sure the number isnt too large
  912. // ===================================
  913. m_i8 = i8;
  914. if(*m_pWorkBuf == L'-')
  915. return TOK_SIGNED64_NUMERIC_CONST;
  916. else
  917. return TOK_UNSIGNED64_NUMERIC_CONST;
  918. }
  919. // must be a floating point, no conversion needed.
  920. return TOK_FLOAT_VALUE;
  921. }
  922. //***************************************************************************
  923. //
  924. // CMofLexer::MovePtr
  925. //
  926. // Moves pointer farther into the buffer. Note that the farthest it will go
  927. // is one past the last valid WCHAR which is the location of an extra NULL
  928. //
  929. //***************************************************************************
  930. void CMofLexer::MovePtr(int iNum)
  931. {
  932. int iSoFar = 0;
  933. int iChange = (iNum > 0) ? 1 : -1;
  934. int iNumToDo = (iNum > 0) ? iNum : -iNum;
  935. while(iSoFar < iNumToDo)
  936. {
  937. if(iChange == 1)
  938. {
  939. // going forward, update the pointer and make sure it
  940. // is still in an acceptable range.
  941. // ==================================================
  942. m_pDataSrc->Move(iChange);
  943. if(m_pDataSrc->PastEnd()) // points to the NULL
  944. return;
  945. // If going forward and a slash cr is hit, do an extra skip.
  946. WCHAR wCurr = m_pDataSrc->GetAt(0);
  947. if(wCurr == L'\\' && m_pDataSrc->GetAt(1) == L'\n')
  948. {
  949. m_nLine++;
  950. m_pDataSrc->Move(1); // extra increment
  951. m_nStartOfLinePos = m_pDataSrc->GetPos();
  952. continue;
  953. }
  954. else if(wCurr == L'\\' && m_pDataSrc->GetAt(1) == L'\r'
  955. && m_pDataSrc->GetAt(2) == L'\n')
  956. {
  957. m_nLine++;
  958. m_pDataSrc->Move(2); // extra increment
  959. m_nStartOfLinePos = m_pDataSrc->GetPos();
  960. continue;
  961. }
  962. else if (wCurr == L'\n')
  963. {
  964. m_nLine++;
  965. m_nStartOfLinePos = m_pDataSrc->GetPos();
  966. }
  967. }
  968. else
  969. {
  970. // If going backward and a cr is left, then decrement the line
  971. if (m_pDataSrc->GetAt(0) == L'\n' &&
  972. m_pDataSrc->GetPos() > 0 )
  973. {
  974. m_nLine--;
  975. m_nStartOfLinePos = m_pDataSrc->GetPos();
  976. }
  977. // Update the pointer and make sure it is still in an
  978. // acceptable range.
  979. // ==================================================
  980. m_pDataSrc->Move(iChange);
  981. if(m_pDataSrc->GetPos() < 0)
  982. {
  983. m_pDataSrc->MoveToStart();
  984. return;
  985. }
  986. // If going backward and a slash cr is hit, do an extra skip.
  987. WCHAR wCurr = m_pDataSrc->GetAt(0);
  988. if( wCurr == L'\n' && m_pDataSrc->GetAt(-1) == L'\\')
  989. {
  990. m_nLine--;
  991. m_nStartOfLinePos = m_pDataSrc->GetPos();
  992. m_pDataSrc->Move(-1); // extra decrement
  993. continue;
  994. }
  995. else if( wCurr == L'\n' && m_pDataSrc->GetAt(-1) == L'\r' &&
  996. m_pDataSrc->GetAt(-2) == L'\\')
  997. {
  998. m_nLine--;
  999. m_nStartOfLinePos = m_pDataSrc->GetPos();
  1000. m_pDataSrc->Move(-2); // extra decrement
  1001. continue;
  1002. }
  1003. }
  1004. iSoFar++;
  1005. }
  1006. }
  1007. //***************************************************************************
  1008. //
  1009. // CMofLexer::GetChar()
  1010. //
  1011. // Returns a character at an offset from the current character pointer.
  1012. //
  1013. //***************************************************************************
  1014. wchar_t CMofLexer::GetChar(int iNum)
  1015. {
  1016. if(iNum == 0)
  1017. return m_pDataSrc->GetAt(0);
  1018. else if(iNum == 1)
  1019. {
  1020. wchar_t tRet = m_pDataSrc->GetAt(1);
  1021. if(tRet != L'\\' && tRet != '\n')
  1022. return tRet;
  1023. }
  1024. MovePtr(iNum);
  1025. wchar_t wcRet = m_pDataSrc->GetAt(0);
  1026. MovePtr(-iNum);
  1027. return wcRet;
  1028. }
  1029. //***************************************************************************
  1030. //
  1031. // CMofLexer::iGetColumn()
  1032. //
  1033. // Gets the current column value. Counts back to the previous Cr or the
  1034. // start of buffer.
  1035. //
  1036. //***************************************************************************
  1037. int CMofLexer::iGetColumn()
  1038. {
  1039. return m_pDataSrc->GetPos() - m_nStartOfLinePos;
  1040. }
  1041. //***************************************************************************
  1042. //
  1043. // CMofLexer::bOKNumericAddition()
  1044. //
  1045. // Returns true if the test character could be added to numeric buffer.
  1046. // Note that it returns true if an alphanumeric, or a + or - and the last
  1047. // character in the working buffer is an 'E'
  1048. //
  1049. //***************************************************************************
  1050. BOOL CMofLexer::bOKNumericAddition(wchar_t cTest)
  1051. {
  1052. if(wbem_iswalnum(cTest) || cTest == L'.')
  1053. return TRUE;
  1054. int iLen = wcslen(m_pWorkBuf);
  1055. if(iLen > 0)
  1056. if(towupper(m_pWorkBuf[iLen-1]) == L'E' &&
  1057. (cTest == L'+' || cTest == L'-') &&
  1058. towupper(m_pWorkBuf[1]) != L'X')
  1059. return TRUE;
  1060. return FALSE;
  1061. }
  1062. //***************************************************************************
  1063. //
  1064. // CMofLexer::SpaceAvailable()
  1065. //
  1066. // Returns TRUE if there is enuough space in the working buffer to add.
  1067. // another character. It will expand the buffer if need be.
  1068. //
  1069. //***************************************************************************
  1070. BOOL CMofLexer::SpaceAvailable()
  1071. {
  1072. // most common case is that there is already space available
  1073. int iNumWChar = m_pEndOfText-m_pWorkBuf+1;
  1074. if(iNumWChar < m_nWorkBufSize)
  1075. return TRUE;
  1076. if(m_nWorkBufSize > MAX_ALLOC) // programs need limits!
  1077. return FALSE;
  1078. // Allocate a bigger buffer and copy the old stuff into it
  1079. // =======================================================
  1080. long nNewSize = m_nWorkBufSize + ADDITIONAL_ALLOC;
  1081. wchar_t * pNew = new wchar_t[nNewSize];
  1082. if(pNew == FALSE)
  1083. return FALSE;
  1084. memcpy(pNew, m_pWorkBuf, m_nWorkBufSize*2);
  1085. delete m_pWorkBuf;
  1086. m_nWorkBufSize = nNewSize;
  1087. m_pWorkBuf = pNew;
  1088. m_pEndOfText = m_pWorkBuf + iNumWChar - 1;
  1089. return TRUE;
  1090. }
  1091. //***************************************************************************
  1092. //
  1093. // NextToken()
  1094. //
  1095. // This function contains the DFA recognizer for MOF tokens. It works
  1096. // entirely in UNICODE characters, so the NextChar() function is expected
  1097. // to pretranslate ANSI or DBCS source streams into wide characters.
  1098. //
  1099. // Return value:
  1100. // One of the TOK_ constants, or TOK_EOF when the end of the input
  1101. // stream has been reached. If the user calls PushBack(), then
  1102. // this will return the symbol which was pushed back onto the input
  1103. // stream. Only one level of push back is supported.
  1104. //
  1105. //***************************************************************************
  1106. int CMofLexer::NextToken(bool bDontAllowWhitespace)
  1107. {
  1108. int nToken = TOK_ERROR;
  1109. LexState eState = start;
  1110. m_bBadString = FALSE;
  1111. *m_pWorkBuf = 0;
  1112. m_pEndOfText = m_pWorkBuf;
  1113. m_bInString = FALSE;
  1114. #define CONSUME(c) \
  1115. if (!SpaceAvailable()) return TOK_ERROR;\
  1116. *m_pEndOfText++ = (c), *m_pEndOfText = 0;
  1117. wchar_t c;
  1118. for (MovePtr(1); m_nErrorCode == no_error && !m_pDataSrc->PastEnd(); MovePtr(1))
  1119. {
  1120. c = GetChar();
  1121. // *************************************************************************
  1122. // General 'start' state entry.
  1123. // ============================
  1124. if (eState == start)
  1125. {
  1126. m_nTokCol = iGetColumn();
  1127. m_nTokLine = m_nLine;
  1128. // If a non-newline whitespace and we are in 'start', then just strip it.
  1129. // =======================================================================
  1130. if (iswspace(c) || c == L'\n')
  1131. if(bDontAllowWhitespace)
  1132. return TOK_ERROR;
  1133. else
  1134. continue;
  1135. // Check for string continuation
  1136. // =============================
  1137. if(m_bInString)
  1138. {
  1139. if(c == '"')
  1140. {
  1141. eState = wstring;
  1142. continue;
  1143. }
  1144. else
  1145. {
  1146. // string ended after all
  1147. MovePtr(-1);
  1148. return TOK_LPWSTR;
  1149. }
  1150. }
  1151. // Handle all single character tokens.
  1152. // ===================================
  1153. if (nToken = SingleCharToken(c))
  1154. return nToken;
  1155. // Start of comment, we have to get either another / or a *.
  1156. // The style of comment depends on what you get. To get
  1157. // neither is an error
  1158. // ======================================================
  1159. if (c == L'/')
  1160. {
  1161. if (GetChar(1) == L'/')
  1162. {
  1163. eState = new_style_comment;
  1164. continue;
  1165. }
  1166. else if (GetChar(1) == L'*')
  1167. {
  1168. eState = old_style_comment;
  1169. MovePtr(1); // skip an extra so not to be fooled by /*/
  1170. continue;
  1171. }
  1172. else
  1173. return TOK_ERROR;
  1174. }
  1175. // Check for strings or characters. Like C, 'L' is case sensitive
  1176. // ================================
  1177. if (c == L'"' || c == L'\'')
  1178. {
  1179. eState = (c == L'"') ? wstring : wcharacter;
  1180. continue;
  1181. }
  1182. // Tokens beginning with these letters might be a uuid.
  1183. // ====================================================
  1184. if (iswxdigit(c) && ValidGuid())
  1185. {
  1186. eState = uuid;
  1187. CONSUME(c);
  1188. continue;
  1189. }
  1190. // Check for identifiers which start with either a letter or _
  1191. // ===========================================================
  1192. if (iswwbemalpha(c) || c == L'_')
  1193. {
  1194. eState = ident;
  1195. CONSUME(c);
  1196. continue;
  1197. }
  1198. // Check for a leading minus sign or digits. Either indicates
  1199. // a numeric constant
  1200. // ===========================================================
  1201. if (wbem_iswdigit(c) || c == L'-')
  1202. {
  1203. eState = numeric;
  1204. CONSUME(c);
  1205. continue;
  1206. }
  1207. // If the first character was a '.', then it might be a
  1208. // float or a single byte token.
  1209. // ====================================================
  1210. if (c == L'.')
  1211. {
  1212. if (wbem_iswdigit(GetChar(1)))
  1213. {
  1214. eState = numeric;
  1215. CONSUME(c);
  1216. continue;
  1217. }
  1218. return TOK_DOT;
  1219. }
  1220. // If here, an unknown token.
  1221. // ==========================
  1222. break;
  1223. } // end of if (eState == start)
  1224. // ************************************************************
  1225. // Some state other than start
  1226. // If we are in a quoted string or character.
  1227. // ==========================================
  1228. if (eState == wstring || eState == wcharacter)
  1229. {
  1230. wchar_t wTemp; // might be converted esc sequence
  1231. int iRet;
  1232. LexState lsNew = ProcessStr(&wTemp,eState,&iRet);
  1233. if(stop == lsNew)
  1234. {
  1235. return iRet;
  1236. }
  1237. else
  1238. {
  1239. eState = lsNew;
  1240. }
  1241. if(eState == wstring || eState == wcharacter)
  1242. {
  1243. CONSUME(wTemp);
  1244. }
  1245. // else we stepped out of the string and into a comment.
  1246. continue;
  1247. }
  1248. // numeric state, undetermined numeric constant.
  1249. // =============================================
  1250. if (eState == numeric)
  1251. {
  1252. if(bOKNumericAddition(c))
  1253. {
  1254. CONSUME(c);
  1255. continue;
  1256. }
  1257. MovePtr(-1);
  1258. return iGetNumericType();
  1259. }
  1260. // If we are getting an identifer, we continue
  1261. // until a nonident char is hit.
  1262. // ============================================
  1263. if (eState == ident)
  1264. {
  1265. if (wbem_iswdigit(c) || iswwbemalpha(c) || c == L'_')
  1266. {
  1267. CONSUME(c);
  1268. continue;
  1269. }
  1270. MovePtr(-1);
  1271. return KeywordFilter(m_pWorkBuf);
  1272. }
  1273. // GUIDs are already verified, just load up the proper length
  1274. // ==========================================================
  1275. if (eState == uuid)
  1276. {
  1277. CONSUME(c);
  1278. if(wcslen(m_pWorkBuf) >= UUIDLEN)
  1279. return TOK_UUID;
  1280. else
  1281. continue;
  1282. }
  1283. // Take care of comment states. New style comments "//" are
  1284. // terminated by a new line while old style end with "*/"
  1285. // =========================================================
  1286. if (eState == new_style_comment)
  1287. {
  1288. if (c == L'\n')
  1289. {
  1290. eState = start;
  1291. }
  1292. continue;
  1293. }
  1294. if (eState == old_style_comment)
  1295. {
  1296. if (c == L'*')
  1297. if(GetChar(1) == L'/')
  1298. {
  1299. MovePtr(1);
  1300. eState = start;
  1301. }
  1302. continue;
  1303. }
  1304. break; // this is bad, got into strange state
  1305. }
  1306. // If we ended and the last thing was a string, the we are ok. This takes care
  1307. // of the case where the last token in a file is a string.
  1308. if ((eState == start || eState == new_style_comment) && m_bInString)
  1309. {
  1310. return TOK_LPWSTR;
  1311. }
  1312. // return eof if we never got started, ex, bad file name
  1313. if(m_nErrorCode != no_error)
  1314. return 0;
  1315. if(m_pDataSrc->PastEnd() &&
  1316. (eState == start || eState == new_style_comment))
  1317. return 0;
  1318. else
  1319. {
  1320. if(eState == old_style_comment)
  1321. Trace(true, m_pDbg, UNEXPECTED_EOF, m_nTokLine);
  1322. if(c == L'*' && GetChar(1) == L'/')
  1323. Trace(true, m_pDbg, COMMENT_ERROR, m_nTokLine);
  1324. return TOK_ERROR;
  1325. }
  1326. }
  1327. //***************************************************************************
  1328. //
  1329. // GetText
  1330. //
  1331. //***************************************************************************
  1332. const OLECHAR *CMofLexer::GetText(int *pLineDeclared)
  1333. {
  1334. if (pLineDeclared)
  1335. *pLineDeclared = m_nTokLine;
  1336. return m_pWorkBuf;
  1337. }
  1338. void CMofLexer::SetLexPosition(ParseState * pPos)
  1339. {
  1340. m_pDataSrc->MoveToPos(pPos->m_iPos);
  1341. }
  1342. void CMofLexer::GetLexPosition(ParseState * pPos)
  1343. {
  1344. pPos->m_iPos = m_pDataSrc->GetPos();
  1345. }