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.

1379 lines
40 KiB

  1. /****************************************************************************/
  2. /* */
  3. /* RCL.C - */
  4. /* */
  5. /* Windows 3.0 Resource Compiler - Lexical analyzer */
  6. /* */
  7. /* */
  8. /****************************************************************************/
  9. #include "rc.h"
  10. #define EOLCHAR L';'
  11. #define STRCHAR L'"'
  12. #define CHRCHAR L'\''
  13. #define SGNCHAR L'-'
  14. #define iswhite( c ) ((c != SYMUSESTART) && (c != SYMDEFSTART) &&\
  15. ((WCHAR)c <= L' ') ? TRUE : FALSE)
  16. static WCHAR curChar;
  17. static WCHAR curCharFTB; /* Cur char From Token Buf */
  18. static PWCHAR CurPtrTB;
  19. static PFILE inpfh;
  20. static int curLin, curCol;
  21. extern BOOL bExternParse;
  22. /* Must be sorted */
  23. KEY keyList[] =
  24. {
  25. { L"ALT", TKALT },
  26. { L"ASCII", TKASCII },
  27. { L"AUTO3STATE", TKAUTO3 },
  28. { L"AUTOCHECKBOX", TKAUTOCHECK },
  29. { L"AUTORADIOBUTTON", TKAUTORADIO },
  30. { L"BEGIN", BEGIN },
  31. { L"BEDIT", TKBEDIT },
  32. { L"BITMAP", TKBITMAP },
  33. { L"BLOCK", TKBLOCK },
  34. { L"BUTTON", TKBUTTON },
  35. { L"CAPTION", TKCAPTION },
  36. { L"CHARACTERISTICS", TKCHARACTERISTICS },
  37. { L"CHECKBOX", TKCHECKBOX },
  38. { L"CHECKED", TKCHECKED },
  39. { L"CLASS", TKCLASS },
  40. { L"COMBOBOX", TKCOMBOBOX },
  41. { L"CONTROL", TKCONTROL },
  42. { L"CTEXT", TKCTEXT },
  43. { L"DEFPUSHBUTTON", TKDEFPUSHBUTTON },
  44. { L"DISCARDABLE", TKDISCARD },
  45. { L"DLGINCLUDE", TKDLGINCLUDE },
  46. { L"DLGINIT", TKDLGINIT },
  47. { L"EDIT", TKEDIT },
  48. { L"EDITTEXT", TKEDITTEXT },
  49. { L"END", END },
  50. { L"EXSTYLE", TKEXSTYLE },
  51. { L"FILEFLAGS", TKFILEFLAGS },
  52. { L"FILEFLAGSMASK", TKFILEFLAGSMASK },
  53. { L"FILEOS", TKFILEOS },
  54. { L"FILESUBTYPE", TKFILESUBTYPE },
  55. { L"FILETYPE", TKFILETYPE },
  56. { L"FILEVERSION", TKFILEVERSION },
  57. { L"FIXED", TKFIXED },
  58. { L"FONT", TKFONT },
  59. { L"GRAYED", TKGRAYED },
  60. { L"GROUPBOX", TKGROUPBOX },
  61. { L"HEDIT", TKHEDIT },
  62. { L"HELP", TKHELP },
  63. { L"ICON", TKICON },
  64. { L"IEDIT", TKIEDIT },
  65. { L"IMPURE", TKIMPURE },
  66. { L"INACTIVE", TKINACTIVE },
  67. { L"LANGUAGE", TKLANGUAGE },
  68. { L"LISTBOX", TKLISTBOX },
  69. { L"LOADONCALL", TKLOADONCALL },
  70. { L"LTEXT", TKLTEXT },
  71. { L"MENU", TKMENU },
  72. { L"MENUBARBREAK", TKBREAKWBAR },
  73. { L"MENUBREAK", TKBREAK },
  74. { L"MENUITEM", TKMENUITEM },
  75. { L"MESAGETABLE", TKMESSAGETABLE },
  76. { L"MOVEABLE", TKMOVEABLE },
  77. { L"NOINVERT", TKNOINVERT },
  78. { L"NONSHARED", TKIMPURE },
  79. { L"NOT", TKNOT },
  80. { L"OWNERDRAW", TKOWNERDRAW },
  81. { L"POPUP", TKPOPUP },
  82. { L"PRELOAD", TKPRELOAD },
  83. { L"PRODUCTVERSION", TKPRODUCTVERSION },
  84. { L"PURE", TKPURE },
  85. { L"PUSHBOX", TKPUSHBOX },
  86. { L"PUSHBUTTON", TKPUSHBUTTON },
  87. { L"RADIOBUTTON", TKRADIOBUTTON },
  88. { L"RCDATA", TKRCDATA },
  89. { L"RTEXT", TKRTEXT },
  90. { L"SCROLLBAR", TKSCROLLBAR },
  91. { L"SEPARATOR", TKSEPARATOR },
  92. { L"SHARED", TKPURE },
  93. { L"SHIFT", TKSHIFT },
  94. { L"STATE3", TK3STATE },
  95. { L"STATIC", TKSTATIC },
  96. { L"STYLE", TKSTYLE },
  97. { L"USERBUTTON", TKUSERBUTTON },
  98. { L"VALUE", TKVALUE },
  99. { L"VERSION", TKVERSION },
  100. { L"VIRTKEY", TKVIRTKEY },
  101. { NULL, 0 }
  102. };
  103. SKEY skeyList[] =
  104. {
  105. { L',', COMMA },
  106. { L'|', OR },
  107. { L'(', LPAREN },
  108. { L')', RPAREN },
  109. { L'{', BEGIN },
  110. { L'}', END },
  111. { L'~', TILDE },
  112. { L'+', TKPLUS },
  113. { L'-', TKMINUS },
  114. { L'&', AND },
  115. { L'=', EQUAL },
  116. { EOFMARK, EOFMARK },
  117. { L'\000', 0 }
  118. };
  119. /*---------------------------------------------------------------------------*/
  120. /* */
  121. /* LexInit() - */
  122. /* */
  123. /*---------------------------------------------------------------------------*/
  124. int
  125. LexInit(
  126. PFILE fh
  127. )
  128. {
  129. /* zero errors so far */
  130. errorCount = 0;
  131. curLin = 1;
  132. curCol = 0;
  133. inpfh = fh;
  134. /* Read initial character */
  135. OurGetChar();
  136. return TRUE;
  137. }
  138. /*---------------------------------------------------------------------------*/
  139. /* */
  140. /* GetCharFTB() - */
  141. /* */
  142. /*---------------------------------------------------------------------------*/
  143. WCHAR
  144. GetCharFTB(
  145. void
  146. )
  147. {
  148. return(curCharFTB = *CurPtrTB++);
  149. }
  150. /*---------------------------------------------------------------------------*/
  151. /* */
  152. /* OurGetChar() - */
  153. /* */
  154. /* Read a character, treating semicolon as an end of line comment char */
  155. /* */
  156. /*---------------------------------------------------------------------------*/
  157. WCHAR
  158. OurGetChar(
  159. void
  160. )
  161. {
  162. if ((LitChar() != EOFMARK) && (curChar == CHCOMMENT))
  163. // if comment, HARD LOOP until EOLN
  164. while ((LitChar() != EOFMARK) && (curChar != CHNEWLINE));
  165. return(curChar);
  166. }
  167. /*---------------------------------------------------------------------------*/
  168. /* */
  169. /* FileChar() - */
  170. /* */
  171. /*---------------------------------------------------------------------------*/
  172. int
  173. FileChar(
  174. void
  175. )
  176. {
  177. static WCHAR rgchLine[MAXSTR];
  178. static int ibNext = MAXSTR;
  179. int cch, ch;
  180. if (ibNext >= MAXSTR) {
  181. ibNext = 0;
  182. cch = MyRead (inpfh, rgchLine, MAXSTR * sizeof(WCHAR));
  183. if (cch < (MAXSTR * sizeof(WCHAR))) {
  184. fclose(inpfh);
  185. // NULL terminate the input buffer
  186. *(rgchLine + (cch / sizeof(WCHAR))) = L'\0';
  187. }
  188. }
  189. if ((ch = rgchLine[ibNext]) != 0)
  190. ibNext++;
  191. return(ch);
  192. }
  193. /*---------------------------------------------------------------------------*/
  194. /* */
  195. /* CopyToken() - */
  196. /* */
  197. /*---------------------------------------------------------------------------*/
  198. void
  199. CopyToken(
  200. PTOKEN ptgt_token,
  201. PTOKEN psrc_token
  202. )
  203. {
  204. ptgt_token->longval = psrc_token->longval;
  205. ptgt_token->row = psrc_token->row;
  206. ptgt_token->col = psrc_token->col;
  207. ptgt_token->flongval = psrc_token->flongval;
  208. ptgt_token->val = psrc_token->val;
  209. ptgt_token->type = psrc_token->type;
  210. ptgt_token->realtype = psrc_token->realtype;
  211. wcscpy(ptgt_token->sym.name, psrc_token->sym.name);
  212. wcscpy(ptgt_token->sym.file, psrc_token->sym.file);
  213. ptgt_token->sym.line = psrc_token->sym.line;
  214. ptgt_token->sym.nID = psrc_token->sym.nID;
  215. }
  216. /*---------------------------------------------------------------------------*/
  217. /* */
  218. /* LitChar() - */
  219. /* */
  220. /*---------------------------------------------------------------------------*/
  221. /* Read a literal character, without interpreting EOL comments */
  222. WCHAR
  223. LitChar(
  224. void
  225. )
  226. {
  227. static int fNewLine = TRUE;
  228. int fIgnore = FALSE;
  229. int fBackSlash = FALSE;
  230. int fDot;
  231. PWCHAR pch;
  232. WCHAR buf[ _MAX_PATH ];
  233. TOKEN token_save;
  234. for (; ; ) {
  235. switch (curChar = (WCHAR)FileChar()) {
  236. case 0:
  237. curChar = EOFMARK;
  238. goto char_return;
  239. case 0xFEFF: // skip Byte Order Mark
  240. continue;
  241. case SYMDEFSTART:
  242. {
  243. int fNewLineSave = fNewLine;
  244. GetSymbolDef(TRUE, curChar);
  245. fNewLine = fNewLineSave;
  246. break;
  247. }
  248. case CHCARRIAGE:
  249. curChar = CHSPACE;
  250. if (!fIgnore)
  251. goto char_return;
  252. break;
  253. case CHNEWLINE:
  254. fNewLine = TRUE;
  255. curLin++;
  256. {
  257. static long lTotalLin = 0;
  258. if ((lTotalLin++ & RC_COMPILE_UPDATE) == 0)
  259. UpdateStatus(2, lTotalLin);
  260. }
  261. if (!fIgnore)
  262. goto char_return;
  263. break;
  264. /* skip whitespace before #line - don't clear fNewLine */
  265. case CHSPACE:
  266. case CHTAB:
  267. if (!fIgnore)
  268. goto char_return;
  269. break;
  270. case CHDIRECTIVE:
  271. if (fNewLine) {
  272. WCHAR tch;
  273. fDot = FALSE;
  274. /* also, leave fNewLine set, since we read thru \n */
  275. /* read the 'line' part */
  276. if ((tch = (WCHAR)FileChar()) != L'l') {
  277. if (tch == L'p') {
  278. if (FileChar() != L'r')
  279. goto DirectiveError;
  280. if (FileChar() != L'a')
  281. goto DirectiveError;
  282. if (FileChar() != L'g')
  283. goto DirectiveError;
  284. if (FileChar() != L'm')
  285. goto DirectiveError;
  286. if (FileChar() != L'a')
  287. goto DirectiveError;
  288. /*
  289. ** This is very specific, as any #pragma will
  290. ** be a code_page pragma written by p0prepro.c.
  291. */
  292. CopyToken( &token_save, &token );
  293. GetToken(FALSE); /* get #pragma and ignore */
  294. GetToken(FALSE); /* get code_page and ignore */
  295. GetToken(TOKEN_NOEXPRESSION); /* get codepage value only*/
  296. /* don't check return value */
  297. uiCodePage = token.val; /* assume ok */
  298. /* read through end of line */
  299. while (curChar != CHNEWLINE) {
  300. curChar = (WCHAR)FileChar();
  301. }
  302. CopyToken( &token, &token_save );
  303. continue;
  304. } else {
  305. goto DirectiveError;
  306. }
  307. }
  308. if (FileChar() != L'i')
  309. goto DirectiveError;
  310. if (FileChar() != L'n')
  311. goto DirectiveError;
  312. if (FileChar() != L'e')
  313. goto DirectiveError;
  314. /* up to filename, grabbing line number as we go */
  315. /* note that curChar first contains '#', because */
  316. /* we don't read a new character into curChar */
  317. curLin = 0;
  318. do {
  319. if (curChar >= L'0' && curChar <= L'9') {
  320. curLin *= 10;
  321. curLin += curChar - L'0';
  322. }
  323. curChar = (WCHAR)FileChar();
  324. } while (curChar != CHQUOTE && curChar != CHNEWLINE);
  325. /* don't change curFile or fIgnore if this is just a
  326. * #line <lineno>
  327. */
  328. if (curChar == CHNEWLINE)
  329. break;
  330. /* read the filename. detect the presence of .c or .h */
  331. pch = buf;
  332. do {
  333. curChar = (WCHAR)FileChar();
  334. switch (towlower(curChar)) {
  335. /* treat backslash like normal char, set flag. */
  336. case L'\\':
  337. if (fBackSlash) {
  338. fBackSlash = FALSE;
  339. } else {
  340. fBackSlash = TRUE;
  341. fIgnore = FALSE;
  342. fDot = FALSE;
  343. *pch++ = curChar;
  344. }
  345. break;
  346. /* line format sanity check: no embedded newlines */
  347. case CHNEWLINE:
  348. case 0:
  349. DirectiveError:
  350. LexError1(2101);
  351. /* stop reading filename when we hit a quote */
  352. case CHQUOTE:
  353. break;
  354. /* if we see a ., prepare to find extension */
  355. case CHEXTENSION:
  356. fBackSlash = FALSE;
  357. fDot = TRUE;
  358. *pch++ = curChar;
  359. break;
  360. /* if there's a C or H after a '.', its not RCINCLUDE'd */
  361. case CHCSOURCE:
  362. case CHCHEADER:
  363. fBackSlash = FALSE;
  364. fIgnore = fDot;
  365. fDot = FALSE;
  366. *pch++ = curChar;
  367. break;
  368. /* any other character in a file means the next character
  369. won't be after a dot, and the last char up to now
  370. wasn't C or H.
  371. */
  372. default:
  373. fIgnore = FALSE;
  374. fDot = FALSE;
  375. *pch++ = curChar;
  376. break;
  377. }
  378. } while (curChar != CHQUOTE);
  379. *pch = 0;
  380. WideCharToMultiByte(uiCodePage, 0, buf, -1, (LPSTR) curFile, _MAX_PATH, NULL, NULL);
  381. /* read through end of line */
  382. do {
  383. curChar = (WCHAR)FileChar();
  384. } while (curChar != CHNEWLINE);
  385. break;
  386. }
  387. /* else, fall through, treat like normal char */
  388. default:
  389. fNewLine = FALSE;
  390. if (!fIgnore)
  391. goto char_return;
  392. }
  393. }
  394. char_return:
  395. if (bExternParse)
  396. *((WCHAR*) GetSpace(sizeof(WCHAR))) = curChar;
  397. return curChar;
  398. }
  399. /*---------------------------------------------------------------------------*/
  400. /* */
  401. /* GetStr() - */
  402. /* */
  403. /*---------------------------------------------------------------------------*/
  404. VOID
  405. GetStr(
  406. void
  407. )
  408. {
  409. PWCHAR s;
  410. WCHAR ch;
  411. WCHAR temptok[ MAXSTR ];
  412. SHORT i = 0;
  413. int inc;
  414. UCHAR Octal_Num;
  415. UCHAR HexNum;
  416. /* token type is string literal */
  417. token.realtype = STRLIT;
  418. /*
  419. ** NB: FloydR
  420. ** The use of token.realtype is a hack for RCDATA.
  421. **
  422. ** When we converted RC to be Unicode-based, all the
  423. ** separate "case STRLIT:" code was removed, and the LSTRLIT
  424. ** cases took over for them. Alternatively, we could have
  425. ** left the STRLIT case, but removed the code it accessed
  426. ** and move the STRLIT case prior/after the LSTRLIT case,
  427. ** since they were now identical. They were removed in favor
  428. ** of smaller/faster code.
  429. **
  430. ** However, RCDATA still had a need to discern the difference,
  431. ** so I added token.realtype, set it to STRLIT in GetStr(),
  432. ** set it to LSTRLIT in GetLStr() (below), and check it in
  433. ** GetRCData() in rctg.c.
  434. **
  435. */
  436. token.type = LSTRLIT;
  437. token.val = 0;
  438. s = tokenbuf;
  439. /* read string until " or EOF */
  440. while (LitChar() != EOFMARK) {
  441. if (curChar == STRCHAR)
  442. if (OurGetChar() != STRCHAR)
  443. goto gotstr;
  444. if (token.val++ == MAXSTR)
  445. LexError1(2102); //"string literal too long"
  446. else
  447. *s++ = curChar;
  448. }
  449. if (curChar == EOFMARK)
  450. LexError1(2103); //"unexpected end of file in string literal"
  451. gotstr:
  452. *s++ = 0;
  453. s = tokenbuf;
  454. /* process escape characters in the string */
  455. while (*s != 0) {
  456. if (*s == L'\\') {
  457. s++;
  458. if (*s == L'\\')
  459. temptok[i++] = L'\\';
  460. else if (*s == L'T' || *s == L't')
  461. temptok[i++] = L'\011'; /* Tab */
  462. else if (*s == 0x0a) /* continuation slash */
  463. ; /* ignore and let it go trough the s++ at the end so we skip the 0x0a char*/
  464. else if (*s == L'A' || *s == L'a')
  465. temptok[i++] = L'\010'; /* Right Align */
  466. else if (*s == L'n')
  467. temptok[i++] = fMacRsrcs ? 13 : 10; /* linefeed */
  468. else if (*s == L'r')
  469. temptok[i++] = fMacRsrcs ? 10 : 13; /* carriage return */
  470. else if (*s == L'"')
  471. temptok[i++] = L'"'; /* quote character */
  472. else if (*s == L'X' || *s == L'x') { /* Hexidecimal digit */
  473. USHORT wCount;
  474. HexNum = 0;
  475. ++s;
  476. for (wCount = 2 ;
  477. wCount && iswxdigit((ch=(WCHAR)towupper(*s)));
  478. --wCount) {
  479. if (ch >= L'A')
  480. inc = ch - L'A' + 10;
  481. else
  482. inc = ch - L'0';
  483. HexNum = HexNum * 16 + inc;
  484. s++;
  485. }
  486. MultiByteToWideChar(uiCodePage, MB_PRECOMPOSED, (LPCSTR) &HexNum, 1, &temptok[i], 1);
  487. i++;
  488. s--;
  489. } else if (*s >= L'0' && *s <= L'7') { /* octal character */
  490. USHORT wCount;
  491. Octal_Num = 0;
  492. for (wCount = 3; wCount && *s >= L'0' && *s <= L'7'; --wCount) {
  493. Octal_Num = (Octal_Num * 8 + (*s - L'0'));
  494. s++;
  495. }
  496. MultiByteToWideChar(uiCodePage, MB_PRECOMPOSED, (LPCSTR) &Octal_Num, 1, &temptok[i], 1);
  497. i++;
  498. s--;
  499. }
  500. else {
  501. temptok[i++] = L'\\';
  502. s--;
  503. }
  504. } else
  505. temptok[i++] = *s;
  506. s++;
  507. }
  508. /* zero terminate */
  509. temptok[i] = L'\0';
  510. memcpy ( tokenbuf, temptok, sizeof(WCHAR)*(i + 1));
  511. token.val = (USHORT)i;
  512. }
  513. /*---------------------------------------------------------------------------*/
  514. /* */
  515. /* GetLStr() - */
  516. /* */
  517. /*---------------------------------------------------------------------------*/
  518. VOID
  519. GetLStr(
  520. void
  521. )
  522. {
  523. PWCHAR s;
  524. WCHAR ch;
  525. WCHAR temptok[ MAXSTR ];
  526. SHORT i = 0;
  527. int inc;
  528. int Octal_Num;
  529. int HexNum;
  530. /* token type is string literal */
  531. token.realtype = token.type = LSTRLIT;
  532. token.val = 0;
  533. s = tokenbuf;
  534. /* read string until " or EOF */
  535. while (LitChar() != EOFMARK) {
  536. if (curChar == STRCHAR)
  537. if (OurGetChar() != STRCHAR)
  538. goto gotstr;
  539. if (token.val++ == MAXSTR)
  540. LexError1(2102); //"string literal too long"
  541. else
  542. *s++ = curChar;
  543. }
  544. if (curChar == EOFMARK)
  545. LexError1(2103); //"unexpected end of file in string literal"
  546. if (token.val >= 256) {
  547. SendError("\n");
  548. SET_MSG(Msg_Text, sizeof(Msg_Text), GET_MSG(4205), curFile, token.row);
  549. SendError(Msg_Text);
  550. }
  551. gotstr:
  552. *s++ = 0;
  553. s = tokenbuf;
  554. /* process escape characters in the string */
  555. while (*s != 0) {
  556. if (*s == L'\\') {
  557. s++;
  558. if (*s == L'\\')
  559. temptok[i++] = L'\\';
  560. else if (*s == L'T' || *s == L't')
  561. temptok[i++] = L'\011'; /* Tab */
  562. else if (*s == L'A' || *s == L'a')
  563. temptok[i++] = L'\010'; /* Right Align */
  564. else if (*s == L'n')
  565. temptok[i++] = fMacRsrcs ? 13 : 10; /* linefeed */
  566. else if (*s == L'r')
  567. temptok[i++] = fMacRsrcs ? 10 : 13; /* carriage return */
  568. else if (*s == L'"')
  569. temptok[i++] = L'"'; /* quote character */
  570. else if (*s == L'X' || *s == L'x') { /* Hexidecimal digit */
  571. USHORT wCount;
  572. HexNum = 0;
  573. ++s;
  574. for (wCount = 4 ;
  575. wCount && iswxdigit((ch=(WCHAR)towupper(*s)));
  576. --wCount) {
  577. if (ch >= L'A')
  578. inc = ch - L'A' + 10;
  579. else
  580. inc = ch - L'0';
  581. HexNum = HexNum * 16 + inc;
  582. s++;
  583. }
  584. temptok[i++] = (WCHAR)HexNum;
  585. s--;
  586. }
  587. else if (*s >= L'0' && *s <= L'7') { /* octal character */
  588. USHORT wCount;
  589. Octal_Num = 0;
  590. for (wCount = 7; wCount && *s >= L'0' && *s <= L'7'; --wCount) {
  591. Octal_Num = (Octal_Num * 8 + (*s - L'0'));
  592. s++;
  593. }
  594. temptok[i++] = (WCHAR)Octal_Num;
  595. s--;
  596. }
  597. }
  598. else
  599. temptok[i++] = *s;
  600. s++;
  601. }
  602. /* zero terminate */
  603. temptok[i] = L'\0';
  604. token.val = (USHORT)i;
  605. memcpy ( tokenbuf, temptok, sizeof(WCHAR)*(i + 1));
  606. }
  607. /*---------------------------------------------------------------------------*/
  608. /* */
  609. /* GetToken() - */
  610. /* */
  611. /*---------------------------------------------------------------------------*/
  612. int
  613. GetToken(
  614. int fReportError
  615. )
  616. {
  617. for (; ; ) {
  618. /* skip whitespace */
  619. while (iswhite( curChar))
  620. OurGetChar();
  621. /* take care of 'random' symbols use */
  622. if (curChar == SYMUSESTART)
  623. GetSymbol(fReportError, curChar);
  624. token.sym.name[0] = L'\0';
  625. /* remember location of token */
  626. token.row = curLin;
  627. token.col = curCol;
  628. /* determine if token is EOF, number, string, or keyword */
  629. token.type = EOFMARK;
  630. switch (curChar) {
  631. case EOFMARK:
  632. break;
  633. case SGNCHAR:
  634. case L'~':
  635. if (fReportError & TOKEN_NOEXPRESSION)
  636. GetNumNoExpression();
  637. else
  638. GetNum();
  639. break;
  640. case STRCHAR:
  641. GetStr();
  642. break;
  643. default:
  644. if (curChar == L'(' && !(fReportError & TOKEN_NOEXPRESSION))
  645. GetNum();
  646. else if (iswdigit( curChar)) {
  647. if (fReportError & TOKEN_NOEXPRESSION)
  648. GetNumNoExpression();
  649. else
  650. GetNum();
  651. if (curChar == SYMUSESTART)
  652. GetSymbol(fReportError, curChar);
  653. } else {
  654. if (!GetKwd( fReportError))
  655. continue;
  656. if (token.type == TKLSTR) {
  657. GetLStr();
  658. break;
  659. }
  660. }
  661. }
  662. break;
  663. }
  664. return token.type;
  665. }
  666. /*---------------------------------------------------------------------------*/
  667. /* */
  668. /* GetXNum() - */
  669. /* */
  670. /*---------------------------------------------------------------------------*/
  671. /* get hexadecimal number */
  672. LONG
  673. GetXNum(
  674. void
  675. )
  676. {
  677. LONG n = 0;
  678. while (iswxdigit (GetCharFTB()))
  679. n = n * 16 + ( ((curCharFTB = (WCHAR)towupper(curCharFTB)) >= L'A') ?
  680. (WCHAR)(curCharFTB - L'A' + 10) :
  681. (WCHAR)(curCharFTB - L'0'));
  682. return (n);
  683. }
  684. /*---------------------------------------------------------------------------*/
  685. /* */
  686. /* GetONum() - */
  687. /* */
  688. /*---------------------------------------------------------------------------*/
  689. /* get octal number */
  690. LONG
  691. GetONum(
  692. void
  693. )
  694. {
  695. LONG n = 0;
  696. while (GetCharFTB() >= L'0' && curCharFTB <= L'7')
  697. n = n * 8 + (curCharFTB - L'0');
  698. return (n);
  699. }
  700. /*---------------------------------------------------------------------------*/
  701. /* */
  702. /* GetDNum() - */
  703. /* */
  704. /*---------------------------------------------------------------------------*/
  705. /* get decimal number */
  706. LONG
  707. GetDNum(
  708. void
  709. )
  710. {
  711. LONG n = 0;
  712. while (iswdigit(curCharFTB)) {
  713. n = n * 10 + (curCharFTB - L'0');
  714. GetCharFTB();
  715. }
  716. return (n);
  717. }
  718. PWSTR
  719. GetWord(
  720. PWSTR pStr
  721. )
  722. {
  723. WCHAR ch;
  724. PSKEY pskey;
  725. *pStr++ = curCharFTB = curChar;
  726. while (TRUE) {
  727. ch = OurGetChar();
  728. if (ch <= L' ')
  729. goto FoundBreak;
  730. switch (ch) {
  731. case EOFMARK:
  732. case EOLCHAR:
  733. case STRCHAR:
  734. case CHRCHAR:
  735. goto FoundBreak;
  736. default:
  737. for (pskey = skeyList; pskey->skwd; pskey++)
  738. if (pskey->skwd == ch)
  739. goto FoundBreak;
  740. }
  741. *pStr++ = ch;
  742. }
  743. FoundBreak:
  744. *pStr = 0;
  745. return(pStr);
  746. }
  747. /* GetNumFTB
  748. * This function was previously added as a hack to handle converting
  749. * radices. I'm treating this as a (ugly) black box to read a number.
  750. */
  751. VOID
  752. GetNumFTB(
  753. void
  754. )
  755. {
  756. int signFlag;
  757. USHORT wNotFlag;
  758. LONG n;
  759. /* Small hack to support NOT: If we have a tilde, skip whitespace
  760. * before the number.
  761. */
  762. if (curChar == L'~')
  763. while (iswhite(curChar))
  764. OurGetChar();
  765. /* Get the entire number in tokenbuf before computing radix */
  766. GetWord(tokenbuf);
  767. /* Skip the first char. It is already in curCharFTB */
  768. CurPtrTB = tokenbuf + 1;
  769. /* mark token type as numeric literal */
  770. token.type = NUMLIT;
  771. /* find sign of number */
  772. if (curCharFTB == SGNCHAR) {
  773. signFlag = TRUE;
  774. GetCharFTB();
  775. } else {
  776. signFlag = FALSE;
  777. }
  778. /* Check for a NOT (~) */
  779. if (curCharFTB == L'~') {
  780. wNotFlag = TRUE;
  781. GetCharFTB();
  782. } else {
  783. wNotFlag = FALSE;
  784. }
  785. /* determine radix of number */
  786. if (curCharFTB == L'0') {
  787. GetCharFTB();
  788. if (curCharFTB == L'x')
  789. n = GetXNum();
  790. else if (curCharFTB == L'o')
  791. n = GetONum();
  792. else
  793. n = GetDNum();
  794. } else {
  795. n = GetDNum();
  796. }
  797. /* find size of number */
  798. if ((curCharFTB == L'L') || (curCharFTB == L'l')) {
  799. token.flongval = TRUE;
  800. GetCharFTB();
  801. } else {
  802. token.flongval = FALSE;
  803. }
  804. /* account for sign */
  805. if (signFlag)
  806. n = -n;
  807. /* Account for the NOT */
  808. if (wNotFlag)
  809. n = ~n;
  810. /* Set longval regardless of flongval because Dialog Styles
  811. * always have to be be long
  812. */
  813. token.longval = n;
  814. token.val = (USHORT)n;
  815. }
  816. /* ----- Static information needed for parsing ----- */
  817. static int wLongFlag;
  818. static int nParenCount;
  819. /*---------------------------------------------------------------------------*/
  820. /* */
  821. /* GetNum() - */
  822. /* */
  823. /*---------------------------------------------------------------------------*/
  824. VOID
  825. GetNum(
  826. void
  827. )
  828. {
  829. LONG lValue;
  830. /* Initialize */
  831. wLongFlag = 0;
  832. nParenCount = 0;
  833. /* Return the number */
  834. lValue = GetExpression();
  835. /* Make sure we had matched parens */
  836. if (nParenCount)
  837. ParseError1(1013); //"Mismatched parentheses"
  838. /* Return as the proper token */
  839. if (wLongFlag)
  840. token.flongval = TRUE;
  841. token.type = NUMLIT;
  842. token.longval = lValue;
  843. token.val = (USHORT)lValue;
  844. }
  845. /* GetNumNoExpression
  846. * Gets a number without doing expression parsing on it.
  847. */
  848. VOID
  849. GetNumNoExpression(
  850. VOID
  851. )
  852. {
  853. /* Call the single number parser */
  854. GetNumFTB();
  855. }
  856. /* GetExpression
  857. * Gets an expression, which is defined as any number of
  858. * operators and operands inside one set of parens.
  859. */
  860. LONG
  861. GetExpression(
  862. VOID
  863. )
  864. {
  865. LONG op1;
  866. LONG op2;
  867. WCHAR byOperator;
  868. UINT wFlags;
  869. /* Get the first operand */
  870. op1 = GetOperand();
  871. /* take care of symbol use */
  872. if (curChar == SYMUSESTART) {
  873. GetSymbol(TRUE, curChar);
  874. token.sym.nID = token.val;
  875. }
  876. /* Loop until end of expression */
  877. for (; ; ) {
  878. /* Get the operator */
  879. wFlags = GetOperator(&byOperator);
  880. /* If this is a right paren, dec the count */
  881. if (byOperator == L')') {
  882. /* Bring the paren count back down */
  883. --nParenCount;
  884. /* Skip the paren and any trailing whitespace */
  885. OurGetChar();
  886. SkipWhitespace();
  887. }
  888. /* If this isn't an operator, we're done with the expression */
  889. if (!wFlags) {
  890. token.sym.nID = (unsigned)op1;
  891. return op1;
  892. }
  893. token.sym.name[0] = L'\0';
  894. /* Get the second operand */
  895. op2 = GetOperand();
  896. /* Compute the value of the expression */
  897. switch (byOperator) {
  898. case L'+':
  899. op1 += op2;
  900. break;
  901. case L'-':
  902. op1 -= op2;
  903. break;
  904. case L'&':
  905. op1 &= op2;
  906. break;
  907. case L'|':
  908. op1 |= op2;
  909. break;
  910. }
  911. }
  912. }
  913. /* GetOperand
  914. * Gets an operand, which may either be a single number or may
  915. * be an entire expression.
  916. */
  917. LONG
  918. GetOperand(
  919. VOID
  920. )
  921. {
  922. /* Check to see if we need to descend a level */
  923. if (curChar == L'(') {
  924. /* Bump paren count so we can match them up */
  925. ++nParenCount;
  926. /* Skip past the paren char */
  927. OurGetChar();
  928. SkipWhitespace();
  929. /* Return the value of the computed expression for the operand */
  930. return GetExpression();
  931. }
  932. /* If this isn't a number, return an error */
  933. if (curChar != L'-' && curChar != L'~' && !iswdigit(curChar)) {
  934. GetKwd(FALSE);
  935. ParseError2(2237, tokenbuf);
  936. return 0;
  937. }
  938. /* Get the number in the token structure */
  939. GetNumFTB();
  940. /* See if we need to force the result long */
  941. if (token.flongval)
  942. wLongFlag = TRUE;
  943. /* Skip trailing whitespace */
  944. SkipWhitespace();
  945. /* Return the value */
  946. return token.longval;
  947. }
  948. /* GetOperator
  949. * Gets the next character and decides if it should be an operator.
  950. * If it should, it returns TRUE, which causes the expression
  951. * parser to continue. Otherwise, it returns FALSE which causes
  952. * the expression parser to pop up a level.
  953. */
  954. int
  955. GetOperator(
  956. PWCHAR pOperator
  957. )
  958. {
  959. static WCHAR byOps[] = L"+-|&";
  960. PWCHAR pOp;
  961. /* take care of symbol use */
  962. if (curChar == SYMUSESTART)
  963. GetSymbol(TRUE, curChar);
  964. /* See if this character is an operator */
  965. pOp = wcschr(byOps, curChar);
  966. *pOperator = curChar;
  967. /* If we didn't find it, get out */
  968. if (!pOp)
  969. return FALSE;
  970. /* Otherwise, read trailing whitespace */
  971. OurGetChar();
  972. SkipWhitespace();
  973. /* Return the operator */
  974. return TRUE;
  975. }
  976. /* SkipWhitespace
  977. * Skips past whitespace in the current stream.
  978. */
  979. VOID
  980. SkipWhitespace(
  981. VOID
  982. )
  983. {
  984. while (iswhite(curChar))
  985. OurGetChar();
  986. }
  987. /*---------------------------------------------------------------------------*/
  988. /* */
  989. /* GetKwd() - */
  990. /* */
  991. /*---------------------------------------------------------------------------*/
  992. int
  993. GetKwd(
  994. int fReportError
  995. )
  996. {
  997. PSKEY sk;
  998. /* see if a special character */
  999. for (sk = &skeyList[ 0 ]; sk->skwd; sk++) {
  1000. if (curChar == sk->skwd) {
  1001. token.type = (UCHAR)sk->skwdval;
  1002. token.val = 0;
  1003. OurGetChar();
  1004. return (token.type >= FIRSTKWD);
  1005. }
  1006. }
  1007. /* else read characters up to the next seperator */
  1008. GetWord(tokenbuf);
  1009. // Check for TKLSTR -- new for NT
  1010. if (!tokenbuf[1] && (towupper(tokenbuf[0]) == L'L') && (curChar == STRCHAR)) {
  1011. token.type = TKLSTR;
  1012. return TRUE;
  1013. }
  1014. /* look up keyword in table */
  1015. if ((token.val = FindKwd( tokenbuf)) != (USHORT)-1) {
  1016. token.type = (UCHAR)token.val;
  1017. } else if (fReportError) {
  1018. LexError2(2104, (PCHAR)tokenbuf); //"undefined keyword or key name: %ws"
  1019. return FALSE;
  1020. }
  1021. else
  1022. token.type = 0;
  1023. return TRUE;
  1024. }
  1025. /*---------------------------------------------------------------------------*/
  1026. /* */
  1027. /* FindKwd() - */
  1028. /* */
  1029. /*---------------------------------------------------------------------------*/
  1030. USHORT
  1031. FindKwd(
  1032. PWCHAR str
  1033. )
  1034. {
  1035. PKEY k;
  1036. int t;
  1037. /* linear search the keyword table for the key */
  1038. for (k = &keyList[0]; k->kwd; k++)
  1039. if (!(t = _wcsicmp( str, k->kwd)))
  1040. return k->kwdval;
  1041. else if (t < 0)
  1042. break;
  1043. /* if not found, return -1 as keyword id */
  1044. return (USHORT)-1;
  1045. }
  1046. /*---------------------------------------------------------------------------*/
  1047. /* */
  1048. /* LexError1() - */
  1049. /* */
  1050. /*---------------------------------------------------------------------------*/
  1051. void
  1052. LexError1(
  1053. int iMsg
  1054. )
  1055. {
  1056. SET_MSG(Msg_Text, sizeof(Msg_Text), GET_MSG(iMsg), curFile, curLin);
  1057. SendError(Msg_Text);
  1058. quit("\n");
  1059. }
  1060. /*---------------------------------------------------------------------------*/
  1061. /* */
  1062. /* LexError2() - */
  1063. /* */
  1064. /*---------------------------------------------------------------------------*/
  1065. void
  1066. LexError2(
  1067. int iMsg,
  1068. PCHAR str
  1069. )
  1070. {
  1071. SET_MSG(Msg_Text, sizeof(Msg_Text), GET_MSG(iMsg), curFile, curLin, str);
  1072. SendError(Msg_Text);
  1073. quit("\n");
  1074. }
  1075. /*---------------------------------------------------------------------------*/
  1076. /* */
  1077. /* GetNameOrd() - */
  1078. /* */
  1079. /*---------------------------------------------------------------------------*/
  1080. /* For reading in resource names and types. */
  1081. int
  1082. GetNameOrd(
  1083. void
  1084. )
  1085. {
  1086. PWCHAR pch;
  1087. int fString;
  1088. /* get space delimited string */
  1089. if (!GetGenText())
  1090. return FALSE;
  1091. /* convert to upper case */
  1092. _wcsupr(tokenbuf);
  1093. /* is it a string or number */
  1094. for (pch=tokenbuf,fString=0 ; *pch ; pch++ )
  1095. if (!iswdigit(*pch))
  1096. fString = 1;
  1097. /* determine if ordinal */
  1098. if (tokenbuf[0] == L'0' && tokenbuf[1] == L'X') {
  1099. int HexNum;
  1100. int inc;
  1101. USHORT wCount;
  1102. PWCHAR s;
  1103. HexNum = 0;
  1104. s = &tokenbuf[2];
  1105. for (wCount = 4 ; wCount && iswxdigit(*s) ; --wCount) {
  1106. if (*s >= L'A')
  1107. inc = *s - L'A' + 10;
  1108. else
  1109. inc = *s - L'0';
  1110. HexNum = HexNum * 16 + inc;
  1111. s++;
  1112. }
  1113. token.val = (USHORT)HexNum;
  1114. } else if (fString) {
  1115. token.val = 0;
  1116. } else {
  1117. token.val = (USHORT)wcsatoi(tokenbuf);
  1118. }
  1119. return TRUE;
  1120. }
  1121. /*---------------------------------------------------------------------------*/
  1122. /* */
  1123. /* GetGenText() - */
  1124. /* */
  1125. /*---------------------------------------------------------------------------*/
  1126. /* returns a pointer to a string of generic text */
  1127. PWCHAR
  1128. GetGenText(
  1129. void
  1130. )
  1131. {
  1132. PWCHAR s;
  1133. s = tokenbuf;
  1134. /* skip white space */
  1135. while (iswhite(curChar))
  1136. OurGetChar();
  1137. if (curChar == EOFMARK) {
  1138. token.type = EOFMARK;
  1139. return NULL;
  1140. }
  1141. /* random symbol */
  1142. if (curChar == SYMUSESTART)
  1143. GetSymbol(TRUE, curChar);
  1144. token.sym.name[0] = L'\0';
  1145. /* read space delimited string */
  1146. *s++ = curChar;
  1147. while (( LitChar() != EOFMARK) && ( !iswhite(curChar)))
  1148. *s++ = curChar;
  1149. *s++ = 0; /* put a \0 on the end of the string */
  1150. OurGetChar(); /* read in the next character */
  1151. if (curChar == EOFMARK)
  1152. token.type = EOFMARK;
  1153. if (curChar == SYMUSESTART) {
  1154. GetSymbol(TRUE, curChar);
  1155. token.sym.nID = token.val;
  1156. }
  1157. return (tokenbuf);
  1158. }