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.

1084 lines
30 KiB

  1. /***********************************************************************
  2. * Microsoft (R) Windows (R) Resource Compiler
  3. *
  4. * Copyright (c) Microsoft Corporation. All rights reserved.
  5. *
  6. * File Comments:
  7. *
  8. *
  9. ***********************************************************************/
  10. #include "rc.h"
  11. #define ABS(x) ((x > 0) ? x : -1 * x)
  12. #define ALERT_CHAR L'\007' /* ANSI alert character is ASCII BEL */
  13. ULONG lCPPTotalLinenumber = 0;
  14. extern int vfCurrFileType; //- Added for 16-bit file support.
  15. /************************************************************************/
  16. /* Local Function Prototypes */
  17. /************************************************************************/
  18. token_t c_size(long);
  19. int ctoi(int);
  20. int escape(int);
  21. token_t get_real(PWCHAR);
  22. token_t l_size(long);
  23. long matol(PWCHAR, int);
  24. token_t uc_size(long);
  25. token_t ul_size(long);
  26. void skip_1comment(void);
  27. /************************************************************************/
  28. /* local_c_hash */
  29. /************************************************************************/
  30. hash_t
  31. local_c_hash(
  32. REG WCHAR *name
  33. )
  34. {
  35. REG hash_t i;
  36. i = 0;
  37. while(*name) {
  38. i += (*name & HASH_MASK);
  39. name++;
  40. }
  41. return(i);
  42. }
  43. /************************************************************************
  44. * GETID - Get an identifier or keyword.
  45. * (we know that we're given at least 1 id char)
  46. * in addition, we'll hash the value using 'c'.
  47. ************************************************************************/
  48. void
  49. getid(
  50. REG UINT c
  51. )
  52. {
  53. REG WCHAR *p;
  54. p = Reuse_W;
  55. *p++ = (WCHAR)c;
  56. c &= HASH_MASK;
  57. repeat:
  58. while(LXC_IS_IDENT(*p = GETCH())) { /* while it's an id char . . . */
  59. c += (*p & HASH_MASK); /* hash it */
  60. p++;
  61. }
  62. if(*p != EOS_CHAR) {
  63. if((*p == L'\\') && (checknl())) {
  64. goto repeat;
  65. }
  66. UNGETCH();
  67. if(p >= LIMIT(Reuse_W)) {
  68. fatal(1067);
  69. }
  70. if( ((p - Reuse_W) > LIMIT_ID_LENGTH) && ( ! Prep )) {
  71. p = Reuse_W + LIMIT_ID_LENGTH;
  72. *p++ = L'\0';
  73. c = local_c_hash(Reuse_W);
  74. warning(4011, Reuse_W); /* id truncated */
  75. } else {
  76. *p++ = L'\0';
  77. }
  78. Reuse_W_hash = (hash_t)c;
  79. Reuse_W_length = (UINT)(p - Reuse_W);
  80. return;
  81. }
  82. if(io_eob()) { /* end of file in middle of id */
  83. fatal(1004);
  84. }
  85. goto repeat;
  86. }
  87. /************************************************************************
  88. ** prep_string : outputs char/string constants when preprocessing only
  89. ************************************************************************/
  90. void
  91. prep_string(
  92. REG WCHAR c
  93. )
  94. {
  95. REG WCHAR *p_buf;
  96. int term_char;
  97. p_buf = Reuse_W;
  98. term_char = c;
  99. *p_buf++ = c; /* save the open quote */
  100. for(;;) {
  101. switch(CHARMAP(c = GETCH())) {
  102. case LX_DQUOTE:
  103. case LX_SQUOTE:
  104. if(c == (WCHAR)term_char) {
  105. *p_buf++ = (WCHAR)term_char;/* save the terminating quote */
  106. goto out_of_loop;
  107. }
  108. break;
  109. case LX_BACKSLASH:
  110. *p_buf++ = c;
  111. break;
  112. case LX_CR:
  113. continue;
  114. case LX_NL:
  115. UNGETCH();
  116. goto out_of_loop;
  117. case LX_EOS:
  118. if(c == L'\\') {
  119. *p_buf++ = c;
  120. c = get_non_eof();
  121. break;
  122. }
  123. handle_eos();
  124. continue;
  125. }
  126. *p_buf++ = c;
  127. if(p_buf >= &Reuse_W[MED_BUFFER - 1]) {
  128. *p_buf = L'\0';
  129. myfwrite(Reuse_W, (size_t)(p_buf - Reuse_W) * sizeof(WCHAR), 1, OUTPUTFILE);
  130. p_buf = Reuse_W;
  131. }
  132. }
  133. out_of_loop:
  134. *p_buf = L'\0';
  135. myfwrite(Reuse_W, (size_t)(p_buf - Reuse_W) * sizeof(WCHAR), 1, OUTPUTFILE);
  136. }
  137. /************************************************************************
  138. ** char_const : gather up a character constant
  139. ** we're called after finding the openning single quote.
  140. ************************************************************************/
  141. token_t
  142. char_const(
  143. void
  144. )
  145. {
  146. REG WCHAR c;
  147. value_t value;
  148. token_t tok;
  149. tok = (token_t)(Jflag ? L_CUNSIGNED : L_CINTEGER);
  150. first_switch:
  151. switch(CHARMAP(c = GETCH())) {
  152. case LX_BACKSLASH:
  153. break;
  154. case LX_SQUOTE:
  155. error(2137); //"empty character constant"
  156. value.v_long = 0;
  157. UNGETCH();
  158. break;
  159. case LX_EOS: /* ??? assumes i/o buffering > 1 char */
  160. if(handle_eos() != BACKSLASH_EOS) {
  161. goto first_switch;
  162. }
  163. value.v_long = escape(get_non_eof());
  164. if( tok == L_CUNSIGNED ) { /* don't sign extend */
  165. value.v_long &= 0xff;
  166. }
  167. break;
  168. case LX_NL:
  169. /* newline in character constant */
  170. error(2001);
  171. UNGETCH();
  172. /*
  173. ** FALLTHROUGH
  174. */
  175. default:
  176. value.v_long = c;
  177. break;
  178. }
  179. if((c = get_non_eof()) != L'\'') {
  180. error(2015); /* too many chars in constant */
  181. do {
  182. if(c == L'\n') {
  183. error(2016); /* missing closing ' */
  184. break;
  185. }
  186. } while((c = get_non_eof()) != L'\'');
  187. }
  188. yylval.yy_tree = build_const(tok, &value);
  189. return(tok);
  190. }
  191. /************************************************************************
  192. ** str_const : gather up a string constant
  193. ************************************************************************/
  194. void
  195. str_const(
  196. VOID
  197. )
  198. {
  199. REG WCHAR c;
  200. REG PWCHAR p_buf;
  201. int not_warned_yet = TRUE;
  202. p_buf = yylval.yy_string.str_ptr = Macro_buffer;
  203. /*
  204. ** Is it possible that reading this string during a rescan will
  205. ** overwrite the expansion being rescanned? No, because a macro
  206. ** expansion is limited to the top half of Macro_buffer.
  207. ** For Macro_depth > 0, this is like copying the string from
  208. ** somewhere in the top half of Macro_buffer to the bottom half
  209. ** of Macro_buffer.
  210. ** Note that the restriction on the size of an expanded macro is
  211. ** stricter than the limit on an L_STRING length. An expanded
  212. ** macro is limited to around 1019 bytes, but an L_STRING is
  213. ** limited to 2043 bytes.
  214. */
  215. for(;;) {
  216. switch(CHARMAP(c = GETCH())) {
  217. case LX_NL:
  218. UNGETCH();
  219. error(2001);
  220. /*
  221. ** FALLTHROUGH
  222. */
  223. case LX_DQUOTE:
  224. *p_buf++ = L'\0';
  225. yylval.yy_string.str_len = (USHORT)(p_buf-yylval.yy_string.str_ptr);
  226. return;
  227. break;
  228. case LX_EOS:
  229. if(handle_eos() != BACKSLASH_EOS) {
  230. continue;
  231. }
  232. if(InInclude) {
  233. break;
  234. }
  235. else {
  236. c = (WCHAR)escape(get_non_eof()); /* process escaped char */
  237. }
  238. break;
  239. }
  240. if(p_buf - Macro_buffer > LIMIT_STRING_LENGTH) {
  241. if( not_warned_yet ) {
  242. warning(4009); /* string too big, truncating */
  243. not_warned_yet = FALSE;
  244. }
  245. } else {
  246. *p_buf++ = c;
  247. }
  248. }
  249. }
  250. /************************************************************************
  251. ** do_newline : does work after a newline has been found.
  252. ************************************************************************/
  253. void
  254. do_newline(
  255. void
  256. )
  257. {
  258. ++Linenumber;
  259. for(;;) {
  260. switch(CHARMAP(GETCH())) {
  261. case LX_BOM: // ignore Byte Order Mark
  262. break;
  263. case LX_CR:
  264. break;
  265. case LX_POUND:
  266. preprocess();
  267. break;
  268. case LX_SLASH:
  269. if( ! skip_comment()) {
  270. goto leave_do_newline;
  271. }
  272. break;
  273. case LX_NL:
  274. if ((lCPPTotalLinenumber++ & RC_PREPROCESS_UPDATE) == 0)
  275. UpdateStatus(1, lCPPTotalLinenumber);
  276. Linenumber++;
  277. // must manually write '\r' with '\n' when writing 16-bit strings
  278. if( Prep ) { /* preprocessing only */
  279. myfwrite(L"\r", sizeof(WCHAR), 1, OUTPUTFILE);
  280. }
  281. /*
  282. ** FALLTHROUGH
  283. */
  284. case LX_WHITE:
  285. if( Prep ) { /* preprocessing only, output whitespace */
  286. myfwrite(&(PREVCH()), sizeof(WCHAR), 1, OUTPUTFILE);
  287. } else {
  288. do {
  289. ;
  290. } while(LXC_IS_WHITE(GETCH()));
  291. UNGETCH();
  292. }
  293. break;
  294. case LX_EOS:
  295. if(PREVCH() == EOS_CHAR || PREVCH() == CONTROL_Z) {
  296. if(io_eob()) { /* leaves us pointing at a valid char */
  297. return;
  298. }
  299. break;
  300. }
  301. if(checknl()) {
  302. continue;
  303. }
  304. /* it's a backslash */
  305. /*
  306. ** FALLTHROUGH
  307. */
  308. default: /* first non-white is not a '#', leave */
  309. leave_do_newline:
  310. UNGETCH();
  311. return;
  312. }
  313. }
  314. }
  315. /************************************************************************
  316. * GETNUM - Get a number from the input stream.
  317. *
  318. * ARGUMENTS
  319. * radix - the radix of the number to be accumulated. Can only be 8, 10,
  320. * or 16
  321. * pval - a pointer to a VALUE union to be filled in with the value
  322. *
  323. * RETURNS - type of the token (L_CINTEGER or L_CFLOAT)
  324. *
  325. * SIDE EFFECTS -
  326. * does push back on the input stream.
  327. * writes into pval by reference
  328. * uses buffer Reuse_W
  329. *
  330. * DESCRIPTION -
  331. * Accumulate the number according to the rules for each radix.
  332. * Set up the format string according to the radix (or distinguish
  333. * integer from float if radix is 10) and convert to binary.
  334. *
  335. * AUTHOR - Ralph Ryan, Sept. 8, 1982
  336. *
  337. * MODIFICATIONS - none
  338. *
  339. ************************************************************************/
  340. token_t
  341. getnum(
  342. REG WCHAR c
  343. )
  344. {
  345. REG WCHAR *p;
  346. WCHAR *start;
  347. int radix;
  348. token_t tok;
  349. value_t value;
  350. tok = L_CINTEGER;
  351. start = (Tiny_lexer_nesting ? Exp_ptr : Reuse_W);
  352. p = start;
  353. if( c == L'0' ) {
  354. c = get_non_eof();
  355. if( IS_X(c) ) {
  356. radix = 16;
  357. if( Prep ) {
  358. *p++ = L'0';
  359. *p++ = L'x';
  360. }
  361. for(c = get_non_eof(); LXC_IS_XDIGIT(c); c = get_non_eof()) {
  362. /* no check for overflow? */
  363. *p++ = c;
  364. }
  365. if((p == Reuse_W) && (Tiny_lexer_nesting == 0)) {
  366. error(2153);
  367. }
  368. goto check_suffix;
  369. } else {
  370. radix = 8;
  371. *p++ = L'0'; /* for preprocessing or 0.xxx case */
  372. }
  373. } else {
  374. radix = 10;
  375. }
  376. while( LXC_IS_DIGIT((WCHAR)c) ) {
  377. *p++ = c;
  378. c = get_non_eof();
  379. }
  380. if( IS_DOT(c) || IS_E(c) ) {
  381. UNGETCH();
  382. return(get_real(p));
  383. }
  384. check_suffix:
  385. if( IS_EL(c) ) {
  386. if( Prep ) {
  387. *p++ = c;
  388. }
  389. c = get_non_eof();
  390. if( IS_U(c) ) {
  391. if(Prep) {
  392. *p++ = c;
  393. }
  394. tok = L_LONGUNSIGNED;
  395. } else {
  396. tok = L_LONGINT;
  397. UNGETCH();
  398. }
  399. } else if( IS_U(c) ) {
  400. if( Prep ) {
  401. *p++ = c;
  402. }
  403. c = get_non_eof();
  404. if( IS_EL(c) ) {
  405. if( Prep ) {
  406. *p++ = c;
  407. }
  408. tok = L_LONGUNSIGNED;
  409. } else {
  410. tok = L_CUNSIGNED;
  411. UNGETCH();
  412. }
  413. } else {
  414. UNGETCH();
  415. }
  416. *p = L'\0';
  417. if( start == Exp_ptr ) {
  418. Exp_ptr = p;
  419. return(L_NOTOKEN);
  420. } else if( Prep ) {
  421. myfwrite( Reuse_W, (size_t)(p - Reuse_W) * sizeof(WCHAR), 1, OUTPUTFILE);
  422. return(L_NOTOKEN);
  423. }
  424. value.v_long = matol(Reuse_W,radix);
  425. switch(tok) {
  426. case L_CINTEGER:
  427. tok = (radix == 10)
  428. ? c_size(value.v_long)
  429. : uc_size(value.v_long)
  430. ;
  431. break;
  432. case L_LONGINT:
  433. tok = l_size(value.v_long);
  434. break;
  435. case L_CUNSIGNED:
  436. tok = ul_size(value.v_long);
  437. break;
  438. }
  439. yylval.yy_tree = build_const(tok, &value);
  440. return(tok);
  441. }
  442. /************************************************************************
  443. ** get_real : gathers the real part/exponent of a real number.
  444. ** Input : ptr to the null terminator of the whole part
  445. ** pointer to receive value.
  446. ** Output : L_CFLOAT
  447. **
  448. ** ASSUMES whole part is either at Exp_ptr or Reuse_W.
  449. ************************************************************************/
  450. token_t
  451. get_real(
  452. REG PWCHAR p
  453. )
  454. {
  455. REG int c;
  456. token_t tok;
  457. c = get_non_eof();
  458. if(Cross_compile && (Tiny_lexer_nesting == 0)) {
  459. warning(4012); /* float constant in cross compilation */
  460. Cross_compile = FALSE; /* only one msg per file */
  461. }
  462. /*
  463. ** if the next char is a digit, then we've been called after
  464. ** finding a '.'. if this is true, then
  465. ** we want to find the fractional part of the number.
  466. ** if it's a '.', then we've been called after finding
  467. ** a whole part, and we want the fraction.
  468. */
  469. if( LXC_IS_DIGIT((WCHAR)c) || IS_DOT(c) ) {
  470. do {
  471. *p++ = (WCHAR)c;
  472. c = (int)get_non_eof();
  473. } while( LXC_IS_DIGIT((WCHAR)c) );
  474. }
  475. if( IS_E((WCHAR)c) ) { /* now have found the exponent */
  476. *p++ = (WCHAR)c; /* save the 'e' */
  477. c = (WCHAR)get_non_eof(); /* skip it */
  478. if( IS_SIGN(c) ) { /* optional sign */
  479. *p++ = (WCHAR)c; /* save the sign */
  480. c = (int)get_non_eof();
  481. }
  482. if( ! LXC_IS_DIGIT((WCHAR)c)) {
  483. if( ! Rflag ) {
  484. if(Tiny_lexer_nesting == 0) {
  485. error(2021, c); /* missing or malformed exponent */
  486. }
  487. *p++ = L'0';
  488. }
  489. } else {
  490. do { /* gather the exponent */
  491. *p++ = (WCHAR)c;
  492. c = (int)get_non_eof();
  493. } while( LXC_IS_DIGIT((WCHAR)c) );
  494. }
  495. }
  496. if( IS_F((WCHAR)c) ) {
  497. tok = L_CFLOAT;
  498. if( Prep ) {
  499. *p++ = (WCHAR)c;
  500. }
  501. } else if( IS_EL((WCHAR)c) ) {
  502. tok = L_CLDOUBLE;
  503. if( Prep ) {
  504. *p++ = (WCHAR)c;
  505. }
  506. } else {
  507. UNGETCH();
  508. tok = L_CDOUBLE;
  509. }
  510. *p = L'\0';
  511. if( Tiny_lexer_nesting > 0 ) {
  512. Exp_ptr = p;
  513. return(L_NOTOKEN);
  514. }
  515. else if( Prep ) {
  516. myfwrite( Reuse_W, (size_t)(p - Reuse_W) * sizeof(WCHAR), 1, OUTPUTFILE);
  517. return(L_NOTOKEN);
  518. }
  519. /*
  520. ** reals aren't used during preprocessing
  521. */
  522. return(tok);
  523. }
  524. /************************************************************************
  525. ** matol : ascii to long, given a radix.
  526. ************************************************************************/
  527. long
  528. matol(
  529. REG PWCHAR p_start,
  530. REG int radix
  531. )
  532. {
  533. long result, old_result;
  534. unsigned int i;
  535. old_result = result = 0;
  536. while(*p_start) {
  537. result *= radix;
  538. i = ctoi(*p_start);
  539. if( ((int)i >= radix) && (! Prep) ) {
  540. error(2020, *p_start, radix); /* illegal digit % for base % */
  541. }
  542. result += i;
  543. p_start++;
  544. if(radix == 10) {
  545. if(result < old_result) {
  546. p_start--; /* fix the string ptr since we have overflowed */
  547. break;
  548. }
  549. } else if(*p_start) {
  550. /*
  551. ** the loop is not finished.
  552. ** we will multiply by the radix again
  553. ** check the upper bits. if they're on, then
  554. ** that mult will overflow the value
  555. */
  556. if(radix == 8) {
  557. if(result & 0xe0000000) {
  558. break;
  559. }
  560. } else if(result & 0xf0000000) {
  561. break;
  562. }
  563. }
  564. old_result = result;
  565. }
  566. if(*p_start) {
  567. error(2177); /* constant too big */
  568. result = 0;
  569. }
  570. return(result);
  571. }
  572. /************************************************************************
  573. ** uc_size : returns 'int' or 'long' (virtual unsigned).
  574. ** if their are no bits in the upper part of the value,
  575. ** then it's an int. otherwise, it's a long.
  576. ** this is valid too if target sizeof(int) != sizeof(long).
  577. ** then L_CINTEGER and L_LONGINT are synonymous.
  578. ************************************************************************/
  579. token_t
  580. uc_size(
  581. long value
  582. )
  583. {
  584. return((token_t)((value > INT_MAX) ? L_CUNSIGNED : L_CINTEGER));
  585. }
  586. /************************************************************************
  587. ** c_size : returns 'int' or 'long' for signed numbers.
  588. ** if the sign bit of the lower word is on or any bits
  589. ** in the upper word are on, then we must use 'long'.
  590. ************************************************************************/
  591. token_t
  592. c_size(
  593. long value
  594. )
  595. {
  596. return((token_t)((ABS(value) > INT_MAX) ? L_LONGINT : L_CINTEGER));
  597. }
  598. /************************************************************************
  599. ** l_size : returns 'longint' or 'longunsigned' for long numbers.
  600. ** if the sign bit of the high word is on this is 'longunsigned';
  601. ************************************************************************/
  602. token_t
  603. l_size(
  604. long value
  605. )
  606. {
  607. return((token_t)((value > LONG_MAX) ? L_LONGUNSIGNED : L_LONGINT));
  608. }
  609. /************************************************************************
  610. ** ul_size : returns 'unsigned' or 'longunsigned' for unsigned numbers.
  611. ** if the number can't be represented as unsigned, it is promoted to
  612. ** unsignedlong.
  613. ************************************************************************/
  614. token_t
  615. ul_size(
  616. long value
  617. )
  618. {
  619. return((token_t)((ABS(value) > UINT_MAX-1) ? L_LONGUNSIGNED : L_CUNSIGNED));
  620. }
  621. /************************************************************************
  622. ** ctoi : character to int.
  623. ************************************************************************/
  624. int
  625. ctoi(
  626. int c
  627. )
  628. {
  629. if(LXC_IS_DIGIT((WCHAR)c)) {
  630. return(c - L'0');
  631. } else {
  632. return(towupper((WCHAR)c) - towupper(L'A') + 10);
  633. }
  634. }
  635. /************************************************************************
  636. * ESCAPE - get an escaped character
  637. *
  638. * ARGUMENTS - none
  639. *
  640. * RETURNS - value of escaped character
  641. *
  642. * SIDE EFFECTS - may push back input
  643. *
  644. * DESCRIPTION - An escape ( '\' ) was discovered in the input. Translate
  645. * the next symbol or symbols into an escape sequence.
  646. *
  647. * AUTHOR - Ralph Ryan, Sept. 7, 1982
  648. *
  649. * MODIFICATIONS - none
  650. *
  651. ************************************************************************/
  652. int
  653. escape(
  654. REG int c
  655. )
  656. {
  657. REG int value;
  658. int cnt;
  659. escape_again:
  660. if( LXC_IS_ODIGIT((WCHAR)c) ) {/* \ooo is an octal number, must fit into a byte */
  661. cnt = 1;
  662. for(value = ctoi(c), c = get_non_eof();
  663. (cnt < 3) && LXC_IS_ODIGIT((WCHAR)c);
  664. cnt++, c = get_non_eof()
  665. ) {
  666. value *= 8;
  667. value += ctoi(c);
  668. }
  669. if( ! Prep ) {
  670. if(value > 255) {
  671. error(2022, value);
  672. }
  673. }
  674. UNGETCH();
  675. return((char)value);
  676. }
  677. switch( c ) {
  678. case L'a':
  679. return(ALERT_CHAR);
  680. break;
  681. case L'b':
  682. return(L'\b');
  683. break;
  684. case L'f':
  685. return(L'\f');
  686. break;
  687. case L'n':
  688. return fMacRsrcs ? (L'\r') : (L'\n');
  689. break;
  690. case L'r':
  691. return fMacRsrcs ? (L'\n') : (L'\r');
  692. break;
  693. case L't':
  694. return(L'\t');
  695. break;
  696. case L'v':
  697. return(L'\v');
  698. break;
  699. case L'x':
  700. cnt = 0;
  701. value = 0;
  702. c = get_non_eof();
  703. while((cnt < 3) && LXC_IS_XDIGIT((WCHAR)c)) {
  704. value *= 16;
  705. value += ctoi(c);
  706. c = get_non_eof();
  707. cnt++;
  708. }
  709. if(cnt == 0) {
  710. error(2153);
  711. }
  712. UNGETCH();
  713. return((char)value); /* cast to get sign extend */
  714. default:
  715. if(c != L'\\') {
  716. return(c);
  717. } else {
  718. if(checknl()) {
  719. c = get_non_eof();
  720. goto escape_again;
  721. } else {
  722. return(c);
  723. }
  724. }
  725. }
  726. }
  727. /************************************************************************
  728. * CHECKOP - Check whether the next input character matches the argument.
  729. *
  730. * ARGUMENTS
  731. * short op - the character to be checked against
  732. *
  733. * RETURNS
  734. * TRUE or FALSE
  735. *
  736. * SIDE EFFECTS
  737. * Will push character back onto the input if there is no match.
  738. *
  739. * DESCRIPTION
  740. * If the next input character matches op, return TRUE. Otherwise
  741. * push it back onto the input.
  742. *
  743. * AUTHOR - Ralph Ryan, Sept. 9, 1982
  744. *
  745. * MODIFICATIONS - none
  746. *
  747. ************************************************************************/
  748. int
  749. checkop(
  750. int op
  751. )
  752. {
  753. if(op == (int)get_non_eof()) {
  754. return(TRUE);
  755. }
  756. UNGETCH();
  757. return(FALSE);
  758. }
  759. /************************************************************************
  760. ** DumpSlashComment : while skipping a comment, output it.
  761. ************************************************************************/
  762. void
  763. DumpSlashComment(
  764. VOID
  765. )
  766. {
  767. if( ! Cflag ) {
  768. skip_NLonly();
  769. return;
  770. }
  771. myfwrite(L"//", 2 * sizeof(WCHAR), 1, OUTPUTFILE);
  772. for(;;) {
  773. WCHAR c;
  774. switch(CHARMAP(c = GETCH())) {
  775. // must manually write '\r' with '\n' when writing 16-bit strings
  776. //case LX_CR:
  777. // continue;
  778. case LX_EOS:
  779. handle_eos();
  780. continue;
  781. case LX_NL:
  782. UNGETCH();
  783. return;
  784. }
  785. myfwrite(&c, sizeof(WCHAR), 1, OUTPUTFILE);
  786. }
  787. }
  788. /************************************************************************
  789. ** dump_comment : while skipping a comment, output it.
  790. ************************************************************************/
  791. void
  792. dump_comment(
  793. void
  794. )
  795. {
  796. if( ! Cflag ) {
  797. skip_1comment();
  798. return;
  799. }
  800. myfwrite(L"/*", 2 * sizeof(WCHAR), 1, OUTPUTFILE);
  801. for(;;) {
  802. WCHAR c;
  803. switch(CHARMAP(c = GETCH())) {
  804. case LX_STAR:
  805. if(checkop(L'/')) {
  806. myfwrite(L"*/", 2 * sizeof(WCHAR), 1, OUTPUTFILE);
  807. return;
  808. }
  809. break;
  810. case LX_EOS:
  811. handle_eos();
  812. continue;
  813. case LX_NL:
  814. Linenumber++;
  815. break; /* output below */
  816. // must manually write '\r' with '\n' when writing 16-bit strings
  817. //case LX_CR:
  818. // continue;
  819. }
  820. myfwrite(&c, sizeof(WCHAR), 1, OUTPUTFILE);
  821. }
  822. }
  823. /************************************************************************/
  824. /* skip_comment() */
  825. /************************************************************************/
  826. int
  827. skip_comment(
  828. void
  829. )
  830. {
  831. if(checkop(L'*')) {
  832. skip_1comment();
  833. return(TRUE);
  834. } else if(checkop(L'/')) {
  835. skip_NLonly();
  836. return(TRUE);
  837. } else {
  838. return(FALSE);
  839. }
  840. }
  841. /************************************************************************
  842. ** skip_1comment : we're called when we're already in a comment.
  843. ** we're looking for the comment close. we also count newlines
  844. ** and output them if we're preprocessing.
  845. ************************************************************************/
  846. void
  847. skip_1comment(
  848. void
  849. )
  850. {
  851. UINT c;
  852. for(;;) {
  853. c = GETCH();
  854. if(c == L'*') {
  855. recheck:
  856. c = GETCH();
  857. if(c == L'/') { /* end of comment */
  858. return;
  859. } else if(c == L'*') {
  860. /*
  861. ** if we get another '*' go back and check for a slash
  862. */
  863. goto recheck;
  864. } else if(c == EOS_CHAR) {
  865. handle_eos();
  866. goto recheck;
  867. }
  868. }
  869. /*
  870. ** note we fall through here. we know this baby is not a '*'
  871. ** we used to unget the char and continue. since we check for
  872. ** another '*' inside the above test, we can fall through here
  873. ** without ungetting/getting and checking again.
  874. */
  875. if(c <= L'\n') {
  876. /*
  877. ** hopefully, the above test is less expensive than doing two tests
  878. */
  879. if(c == L'\n') {
  880. Linenumber++;
  881. if(Prep) {
  882. myfwrite(L"\r\n", 2 * sizeof(WCHAR), 1, OUTPUTFILE);
  883. }
  884. } else if(c == EOS_CHAR) {
  885. handle_eos();
  886. }
  887. }
  888. }
  889. }
  890. /************************************************************************
  891. ** skip_cwhite : while the current character is whitespace or a comment.
  892. ** a newline is NOT whitespace.
  893. ************************************************************************/
  894. WCHAR
  895. skip_cwhite(
  896. void
  897. )
  898. {
  899. REG WCHAR c;
  900. skip_cwhite_again:
  901. while((c = GETCH()) <= L'/') { /* many chars are above this */
  902. if(c == L'/') {
  903. if( ! skip_comment()) {
  904. return(L'/');
  905. }
  906. } else if(c > L' ') { /* char is between '!' and '.' */
  907. return(c);
  908. } else {
  909. switch(CHARMAP(c)) {
  910. case LX_EOS:
  911. handle_eos();
  912. break;
  913. case LX_WHITE:
  914. continue;
  915. break;
  916. case LX_CR:
  917. continue;
  918. break;
  919. default:
  920. return(c);
  921. break;
  922. }
  923. }
  924. }
  925. if((c == L'\\') && (checknl())) {
  926. goto skip_cwhite_again;
  927. }
  928. return(c);
  929. }
  930. /************************************************************************
  931. ** checknl : check for newline, skipping carriage return if there is one.
  932. ** also increments Linenumber, so this should be used by routines which
  933. ** will not push the newline back in such a way that rawtok() will be invoked,
  934. ** find the newline and do another increment.
  935. ************************************************************************/
  936. int
  937. checknl(
  938. void
  939. )
  940. {
  941. REG WCHAR c;
  942. for(;;) {
  943. c = GETCH();
  944. if(c > L'\r') {
  945. UNGETCH();
  946. return(FALSE);
  947. }
  948. switch(c) {
  949. case L'\n':
  950. Linenumber++;
  951. // must manually write '\r' with '\n' when writing 16-bit strings
  952. if( Prep ) {
  953. myfwrite(L"\r\n", 2 * sizeof(WCHAR), 1, OUTPUTFILE);
  954. }
  955. return(TRUE);
  956. break;
  957. case L'\r':
  958. continue;
  959. break;
  960. case EOS_CHAR:
  961. handle_eos();
  962. PREVCH() = L'\\'; /* M00HACK - needs pushback */
  963. continue;
  964. break;
  965. default:
  966. UNGETCH();
  967. return(FALSE);
  968. break;
  969. }
  970. }
  971. }
  972. /************************************************************************
  973. ** get_non_eof : get a real char.
  974. ************************************************************************/
  975. WCHAR
  976. get_non_eof(
  977. void
  978. )
  979. {
  980. WCHAR c;
  981. get_non_eof_again:
  982. while((c = GETCH()) <= L'\r') {
  983. if(c == L'\r') {
  984. continue;
  985. } else if(c != EOS_CHAR) {
  986. break;
  987. }
  988. if(Tiny_lexer_nesting > 0) {
  989. break;
  990. }
  991. handle_eos();
  992. }
  993. if((c == L'\\') && (checknl())) {
  994. goto get_non_eof_again;
  995. }
  996. return(c);
  997. }