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.

933 lines
30 KiB

  1. /************************************************************************/
  2. /* */
  3. /* RCPP - Resource Compiler Pre-Processor for NT system */
  4. /* */
  5. /* P0PREPRO.C - Main Preprocessor */
  6. /* */
  7. /* 27-Nov-90 w-BrianM Update for NT from PM SDK RCPP */
  8. /* */
  9. /************************************************************************/
  10. #include "rc.h"
  11. #include <ddeml.h>
  12. /************************************************************************/
  13. /* Internal constants */
  14. /************************************************************************/
  15. #define GOT_IF 1 /* last nesting command was an if.. */
  16. #define GOT_ELIF 2 /* last nesting command was an if.. */
  17. #define GOT_ELSE 3 /* last nesting command was an else */
  18. #define GOT_ENDIF 4 /* found endif */
  19. #define ELSE_OR_ENDIF 5 /* skip to either #else or #endif */
  20. #define ENDIF_ONLY 6 /* skip to #endif -- #else is an error*/
  21. int ifstack[IFSTACK_SIZE];
  22. /************************************************************************/
  23. /* Local Function Prototypes */
  24. /************************************************************************/
  25. void chk_newline(PWCHAR);
  26. void in_standard(void);
  27. int incr_ifstack(void);
  28. token_t next_control(void);
  29. unsigned long int pragma(void);
  30. int skipto(int);
  31. void skip_quoted(int);
  32. PWCHAR sysinclude(void);
  33. /************************************************************************/
  34. /* incr_ifstack - Increment the IF nesting stack */
  35. /************************************************************************/
  36. int
  37. incr_ifstack(
  38. void
  39. )
  40. {
  41. if(++Prep_ifstack >= IFSTACK_SIZE) {
  42. strcpy (Msg_Text, GET_MSG (1052));
  43. fatal (1052);
  44. }
  45. return(Prep_ifstack);
  46. }
  47. /************************************************************************
  48. * SYSINCLUDE - process a system include : #include <foo>
  49. *
  50. * ARGUMENTS - none
  51. *
  52. * RETURNS - none
  53. *
  54. * SIDE EFFECTS - none
  55. *
  56. * DESCRIPTION
  57. * Get the system include file name. Since the name is not a "string",
  58. * the name must be built much the same as the -E option rebuilds the text
  59. * by using the Tokstring expansion for tokens with no expansion already
  60. *
  61. * NOTE : IS THIS ANSI? note we're just reading chars, and not expanding
  62. * any macros. NO, it's not. it must expand the macros.
  63. * TODO : have it call yylex() unless and until it finds a '>' or a newline.
  64. * (probably have to set On_pound_line to have yylex return the newline.)
  65. *
  66. * AUTHOR
  67. * Ralph Ryan Sep. 1982
  68. *
  69. * MODIFICATIONS - none
  70. *
  71. *
  72. ************************************************************************/
  73. PWCHAR
  74. sysinclude(
  75. void
  76. )
  77. {
  78. REG int c;
  79. REG WCHAR *p_fname;
  80. p_fname = Reuse_W;
  81. c = skip_cwhite();
  82. if( c == L'\n' ) {
  83. UNGETCH();
  84. strcpy (Msg_Text, GET_MSG (2012));
  85. error(2012); /* missing name after '<' */
  86. return(NULL);
  87. }
  88. while( c != L'>' && c != L'\n' ) {
  89. *p_fname++ = (WCHAR)c; /* check for buffer overflow ??? */
  90. c = get_non_eof();
  91. }
  92. if( c == L'\n' ) {
  93. UNGETCH();
  94. strcpy (Msg_Text, GET_MSG (2013));
  95. error(2013); /* missing '>' */
  96. return(NULL);
  97. }
  98. if(p_fname != Reuse_W) {
  99. p_fname--;
  100. while((p_fname >= Reuse_W) && iswspace(*p_fname)) {
  101. p_fname--;
  102. }
  103. p_fname++;
  104. }
  105. *p_fname = L'\0';
  106. return(Reuse_W);
  107. }
  108. /************************************************************************
  109. ** preprocess : the scanner found a # which was the first non-white char
  110. ** on a line.
  111. ************************************************************************/
  112. void
  113. preprocess(
  114. void
  115. )
  116. {
  117. REG WCHAR c;
  118. long eval;
  119. int condition;
  120. token_t deftok;
  121. hln_t identifier;
  122. unsigned long int cp;
  123. if(Macro_depth != 0) { /* # only when not in a macro */
  124. return;
  125. }
  126. switch(CHARMAP(c = skip_cwhite())) {
  127. case LX_ID:
  128. getid(c);
  129. HLN_NAME(identifier) = Reuse_W;
  130. HLN_LENGTH(identifier) = (UINT)Reuse_W_length;
  131. HLN_HASH(identifier) = Reuse_W_hash;
  132. break;
  133. case LX_NL:
  134. UNGETCH();
  135. return;
  136. default:
  137. Msg_Temp = GET_MSG (2019);
  138. SET_MSG (Msg_Text, sizeof(Msg_Text), Msg_Temp, c);
  139. error(2019); /* unknown preprocessor command */
  140. skip_cnew(); /* finds a newline */
  141. return;
  142. }
  143. On_pound_line = TRUE;
  144. start:
  145. switch(deftok = is_pkeyword(HLN_IDENTP_NAME(&identifier))) {
  146. int old_prep;
  147. case P0_DEFINE :
  148. define();
  149. break;
  150. case P0_LINE :
  151. old_prep = Prep;
  152. Prep = FALSE;
  153. yylex();
  154. if(Basic_token != L_CINTEGER) { /* #line needs line number */
  155. Msg_Temp = GET_MSG (2005);
  156. SET_MSG (Msg_Text, sizeof(Msg_Text), Msg_Temp, TS_STR(Basic_token));
  157. error(2005); /* unknown preprocessor command */
  158. Prep = old_prep;
  159. skip_cnew();
  160. On_pound_line = FALSE;
  161. return;
  162. }
  163. /*
  164. ** -1 because there's a newline at the end of this line
  165. ** which will be counted later when we find it.
  166. ** the #line says the next line is the number we've given
  167. */
  168. Linenumber = TR_LVALUE(yylval.yy_tree) - 1;
  169. yylex();
  170. Prep = old_prep;
  171. switch(Basic_token) {
  172. case L_STRING:
  173. if( wcscmp(Filename, yylval.yy_string.str_ptr) != 0) {
  174. wcsncpy(Filename,
  175. yylval.yy_string.str_ptr,
  176. sizeof(Filebuff) / sizeof(WCHAR)
  177. );
  178. }
  179. case L_NOTOKEN:
  180. break;
  181. default:
  182. Msg_Temp = GET_MSG (2130);
  183. SET_MSG (Msg_Text, sizeof(Msg_Text), Msg_Temp, TS_STR(Basic_token));
  184. error(2130); /* #line needs a string */
  185. skip_cnew();
  186. On_pound_line = FALSE;
  187. return;
  188. break;
  189. }
  190. emit_line();
  191. chk_newline(L"#line");
  192. break;
  193. case P0_INCLUDE :
  194. old_prep = Prep;
  195. Prep = FALSE;
  196. InInclude = TRUE;
  197. yylex();
  198. InInclude = FALSE;
  199. Prep = old_prep;
  200. switch(Basic_token) {
  201. case L_LT:
  202. if((sysinclude()) == NULL) {
  203. skip_cnew();
  204. On_pound_line = FALSE;
  205. return;
  206. break; /* error already emitted */
  207. }
  208. yylval.yy_string.str_ptr = Reuse_W;
  209. break;
  210. case L_STRING:
  211. break;
  212. default:
  213. Msg_Temp = GET_MSG (2006);
  214. SET_MSG (Msg_Text, sizeof(Msg_Text), Msg_Temp, TS_STR(Basic_token));
  215. error(2006); /* needs file name */
  216. skip_cnew();
  217. On_pound_line = FALSE;
  218. return;
  219. break;
  220. }
  221. wcscpy(Reuse_Include, yylval.yy_string.str_ptr);
  222. chk_newline(L"#include");
  223. if( wcschr(Path_chars, *yylval.yy_string.str_ptr) ||
  224. (wcschr(Path_chars, L':') && (yylval.yy_string.str_ptr[1] == L':'))) {
  225. /*
  226. ** we have a string which either has a 1st char which is a path
  227. ** delimiter or, if ':' is a path delimiter (DOS), which has
  228. ** "<drive letter>:" as the first two characters. Such names
  229. ** specify a fully qualified pathnames. Do not append the search
  230. ** list, just look it up.
  231. */
  232. if( ! newinput(yylval.yy_string.str_ptr, MAY_OPEN)) {
  233. Msg_Temp = GET_MSG (1015);
  234. SET_MSG (Msg_Text, sizeof(Msg_Text), Msg_Temp, Reuse_W);
  235. fatal (1015); /* can't find include file */
  236. }
  237. }
  238. else if( (Basic_token != L_STRING) || (! nested_include())) {
  239. in_standard();
  240. }
  241. break;
  242. case P0_IFDEF :
  243. case P0_IFNDEF :
  244. if(CHARMAP(c = skip_cwhite()) != LX_ID) {
  245. strcpy (Msg_Text, GET_MSG (1016));
  246. fatal (1016);
  247. }
  248. getid(c);
  249. eval = (get_defined()) ? TRUE : FALSE;
  250. chk_newline((deftok == P0_IFDEF) ? L"#ifdef" : L"#ifndef");
  251. if(deftok == P0_IFNDEF) {
  252. eval = ( ! eval );
  253. }
  254. if( eval || ((condition = skipto(ELSE_OR_ENDIF)) == GOT_ELSE) ) {
  255. /*
  256. ** expression is TRUE or when we skipped the false part
  257. ** we found a #else that will be expanded.
  258. */
  259. ifstack[incr_ifstack()] = GOT_IF;
  260. } else if(condition == GOT_ELIF) {
  261. /* hash is wrong, but it won't be used */
  262. HLN_NAME(identifier) = L"if"; /* sleazy HACK */
  263. goto start;
  264. }
  265. break;
  266. case P0_IF :
  267. old_prep = Prep;
  268. Prep = FALSE;
  269. InIf = TRUE;
  270. eval = do_constexpr();
  271. InIf = FALSE;
  272. Prep = old_prep;
  273. chk_newline(PPifel_str /* "#if/#elif" */);
  274. if((eval) || ((condition = skipto(ELSE_OR_ENDIF)) == GOT_ELSE) ) {
  275. /*
  276. ** expression is TRUE or when we skipped the false part
  277. ** we found a #else that will be expanded.
  278. */
  279. ifstack[incr_ifstack()] = GOT_IF;
  280. if(Eflag && !eval)
  281. emit_line();
  282. } else {
  283. /*
  284. ** here the #if's expression was false, so we skipped until we found
  285. ** an #elif. we'll restart and fake that we're processing a #if
  286. */
  287. if(Eflag)
  288. emit_line();
  289. if(condition == GOT_ELIF) {
  290. /* hash is wrong, but it won't be needed */
  291. HLN_NAME(identifier) = L"if"; /* sleazy HACK */
  292. goto start;
  293. }
  294. }
  295. break;
  296. case P0_ELIF :
  297. /*
  298. ** here, we have found a #elif. first check to make sure that
  299. ** this is not an occurrance of a #elif with no preceding #if.
  300. ** (if Prep_ifstack < 0) then there is no preceding #if.
  301. */
  302. if(Prep_ifstack-- < 0) {
  303. strcpy (Msg_Text, GET_MSG (1018));
  304. fatal (1018);
  305. }
  306. /*
  307. ** now, the preceding #if/#elif was true, and we've
  308. ** just found the next #elif. we want to skip all #else's
  309. ** and #elif's from here until we find the enclosing #endif
  310. */
  311. while(skipto(ELSE_OR_ENDIF) != GOT_ENDIF) {
  312. ;
  313. }
  314. if(Eflag)
  315. emit_line();
  316. break;
  317. case P0_ELSE : /* the preceding #if/#elif was true */
  318. if((Prep_ifstack < 0) || (ifstack[Prep_ifstack--] != GOT_IF)) {
  319. strcpy (Msg_Text, GET_MSG (1019));
  320. fatal (1019); /* make sure there was one */
  321. }
  322. chk_newline(PPelse_str /* "#else" */);
  323. skipto(ENDIF_ONLY);
  324. if(Eflag)
  325. emit_line();
  326. break;
  327. case P0_ENDIF : /* only way here is a lonely #endif */
  328. if(Prep_ifstack-- < 0) {
  329. strcpy (Msg_Text, GET_MSG (1020));
  330. fatal (1020);
  331. }
  332. if(Eflag)
  333. emit_line();
  334. chk_newline(PPendif_str /* "#endif" */);
  335. break;
  336. case P0_PRAGMA :
  337. cp = pragma();
  338. if (cp != 0) {
  339. if (cp == CP_WINUNICODE) {
  340. strcpy (Msg_Text, GET_MSG (4213));
  341. if (fWarnInvalidCodePage) {
  342. warning(4213);
  343. } else {
  344. fatal(4213);
  345. }
  346. break;
  347. }
  348. if (!IsValidCodePage(cp)) {
  349. strcpy (Msg_Text, GET_MSG (4214));
  350. if (fWarnInvalidCodePage) {
  351. warning(4214);
  352. } else {
  353. fatal(4214);
  354. }
  355. break;
  356. }
  357. if (cp != uiCodePage) {
  358. if (!io_restart(cp)) {
  359. strcpy (Msg_Text, GET_MSG (1121));
  360. fatal(1121);
  361. }
  362. uiCodePage = cp; // can't be set until now!
  363. }
  364. }
  365. break;
  366. case P0_UNDEF :
  367. if(CHARMAP(c = skip_cwhite()) != LX_ID) {
  368. strcpy (Msg_Text, GET_MSG (4006));
  369. warning(4006); /* missing identifier on #undef */
  370. } else {
  371. getid(c);
  372. undefine();
  373. }
  374. chk_newline(L"#undef");
  375. break;
  376. case P0_ERROR:
  377. {
  378. PWCHAR p;
  379. p = Reuse_W;
  380. while((c = get_non_eof()) != LX_EOS) {
  381. if(c == L'\n') {
  382. UNGETCH();
  383. break;
  384. }
  385. *p++ = c;
  386. }
  387. *p = L'\0';
  388. }
  389. Msg_Temp = GET_MSG (2189);
  390. SET_MSG (Msg_Text, sizeof(Msg_Text), Msg_Temp, Reuse_W);
  391. error(2188);
  392. chk_newline(L"#error");
  393. break;
  394. case P0_IDENT:
  395. old_prep = Prep ;
  396. Prep = FALSE;
  397. yylex();
  398. Prep = old_prep;
  399. if(Basic_token != L_STRING) {
  400. Msg_Temp = GET_MSG (4079);
  401. SET_MSG (Msg_Text, sizeof(Msg_Text), Msg_Temp, TS_STR(Basic_token));
  402. warning(4079);
  403. }
  404. chk_newline(L"#error");
  405. break;
  406. case P0_NOTOKEN:
  407. Msg_Temp = GET_MSG (1021);
  408. SET_MSG (Msg_Text, sizeof(Msg_Text), Msg_Temp, HLN_IDENTP_NAME(&identifier));
  409. fatal (1021);
  410. break;
  411. }
  412. On_pound_line = FALSE;
  413. }
  414. /************************************************************************
  415. * SKIPTO - skip code until the end of an undefined block is reached.
  416. *
  417. * ARGUMENTS
  418. * short key - skip to an ELSE or ENDIF or just an ENDIF
  419. *
  420. * RETURNS - none
  421. *
  422. * SIDE EFFECTS
  423. * - throws away input
  424. *
  425. * DESCRIPTION
  426. * The preprocessor is skipping code between failed ifdef, etc. and
  427. * the corresponding ELSE or ENDIF (when key == ELSE_OR_ENDIF).
  428. * Or it is skipping code between a failed ELSE and the ENDIF (when
  429. * key == ENDIF_ONLY).
  430. *
  431. * AUTHOR - Ralph Ryan, Sept. 16, 1982
  432. *
  433. * MODIFICATIONS - none
  434. *
  435. ************************************************************************/
  436. int
  437. skipto(
  438. int key
  439. )
  440. {
  441. REG int level;
  442. REG token_t tok;
  443. level = 0;
  444. tok = P0_NOTOKEN;
  445. for(;;) {
  446. /* make sure that IF [ELSE] ENDIF s are balanced */
  447. switch(next_control()) {
  448. case P0_IFDEF:
  449. case P0_IFNDEF:
  450. case P0_IF:
  451. level++;
  452. break;
  453. case P0_ELSE:
  454. tok = P0_ELSE;
  455. /*
  456. ** FALLTHROUGH
  457. */
  458. case P0_ELIF:
  459. /*
  460. ** we found a #else or a #elif. these have their only chance
  461. ** at being valid if they're at level 0.
  462. ** if we're at any other level,
  463. ** then this else/elif belongs to some other #if and we skip them.
  464. ** if we were looking for an endif, the we have an error.
  465. */
  466. if(level != 0) {
  467. tok = P0_NOTOKEN;
  468. break;
  469. }
  470. if(key == ENDIF_ONLY) {
  471. strcpy (Msg_Text, GET_MSG (1022));
  472. fatal (1022); /* expected #endif */
  473. } else if(tok == P0_ELSE) {
  474. chk_newline(PPelse_str /* "#else" */);
  475. return(GOT_ELSE);
  476. } else {
  477. return(GOT_ELIF);
  478. }
  479. break;
  480. case P0_ENDIF:
  481. if(level == 0) {
  482. chk_newline(PPendif_str /* "#endif" */);
  483. return(GOT_ENDIF);
  484. } else {
  485. level--;
  486. }
  487. break;
  488. }
  489. }
  490. }
  491. /*************************************************************************
  492. ** in_standard : search for the given file name in the directory list.
  493. ** Input : ptr to include file name.
  494. ** Output : fatal error if not found.
  495. *************************************************************************/
  496. void
  497. in_standard(
  498. void
  499. )
  500. {
  501. int i;
  502. int stop;
  503. WCHAR *p_dir;
  504. WCHAR *p_file;
  505. WCHAR *p_tmp;
  506. stop = Includes.li_top;
  507. for(i = MAXLIST-1; i >= stop; i--) {
  508. p_file = yylval.yy_string.str_ptr;
  509. if( ((p_dir = Includes.li_defns[i])!=0) &&(wcscmp(p_dir, L"./") != 0) ) {
  510. /*
  511. ** there is a directory to prepend and it's not './'
  512. */
  513. p_tmp = Exp_ptr;
  514. while((*p_tmp++ = *p_dir++) != 0)
  515. ;
  516. /*
  517. ** above loop increments p_tmp past null.
  518. ** this replaces that null with a '/' if needed. Not needed if the
  519. ** last character of the directory spec is a path delimiter.
  520. ** we then point to the char after the '/'
  521. */
  522. if(wcschr(Path_chars, p_dir[-2]) == 0) {
  523. p_tmp[-1] = L'/';
  524. } else {
  525. --p_tmp;
  526. }
  527. while((*p_tmp++ = *p_file++) != 0)
  528. ;
  529. p_file = Exp_ptr;
  530. }
  531. if(newinput(p_file,MAY_OPEN)) { /* this is the non-error way out */
  532. return;
  533. }
  534. }
  535. Msg_Temp = GET_MSG (1015);
  536. SET_MSG (Msg_Text, sizeof(Msg_Text), Msg_Temp, yylval.yy_string.str_ptr);
  537. fatal (1015); /* can't find include file */
  538. }
  539. /*************************************************************************
  540. ** chk_newline : check for whitespace only before a newline.
  541. ** eat the newline.
  542. *************************************************************************/
  543. void
  544. chk_newline(
  545. PWCHAR cmd
  546. )
  547. {
  548. if(skip_cwhite() != L'\n') {
  549. Msg_Temp = GET_MSG (4067);
  550. SET_MSG (Msg_Text, sizeof(Msg_Text), Msg_Temp, cmd);
  551. warning(4067); /* cmd expected newline */
  552. skip_cnew();
  553. } else {
  554. UNGETCH();
  555. }
  556. }
  557. /*************************************************************************
  558. ** skip_quoted : skips chars until it finds a char which matches its arg.
  559. *************************************************************************/
  560. void
  561. skip_quoted(
  562. int sc
  563. )
  564. {
  565. REG WCHAR c;
  566. for(;;) {
  567. switch(CHARMAP(c = GETCH())) {
  568. case LX_NL:
  569. strcpy (Msg_Text, GET_MSG (4093));
  570. warning(4093);
  571. UNGETCH();
  572. return;
  573. break;
  574. case LX_DQUOTE:
  575. case LX_SQUOTE:
  576. if(c == (WCHAR)sc)
  577. return;
  578. break;
  579. case LX_EOS:
  580. if(handle_eos() == BACKSLASH_EOS) {
  581. SKIPCH(); /* might be /" !! */
  582. }
  583. break;
  584. case LX_LEADBYTE:
  585. get_non_eof();
  586. break;
  587. }
  588. }
  589. }
  590. /*************************************************************************
  591. ** next_control : find a newline. find a pound sign as the first non-white.
  592. ** find an id start char, build an id look it up and return the token.
  593. ** this knows about strings/char const and such.
  594. *************************************************************************/
  595. token_t
  596. next_control(
  597. void
  598. )
  599. {
  600. REG WCHAR c;
  601. for(;;) {
  602. c = skip_cwhite();
  603. first_switch:
  604. switch(CHARMAP(c)) {
  605. case LX_NL:
  606. Linenumber++;
  607. // must manually write '\r' with '\n' when writing 16-bit strings
  608. if(Prep) {
  609. myfwrite(L"\r\n", 2 * sizeof(WCHAR), 1, OUTPUTFILE);
  610. }
  611. if((c = skip_cwhite()) == L'#') {
  612. if(LX_IS_IDENT(c = skip_cwhite())) {
  613. /*
  614. ** this is the only way to return to the caller.
  615. */
  616. getid(c);
  617. return(is_pkeyword(Reuse_W)); /* if its predefined */
  618. }
  619. }
  620. goto first_switch;
  621. break;
  622. case LX_DQUOTE:
  623. case LX_SQUOTE:
  624. skip_quoted(c);
  625. break;
  626. case LX_EOS:
  627. if(handle_eos() == BACKSLASH_EOS) {
  628. SKIPCH(); /* might be \" !! */
  629. }
  630. break;
  631. }
  632. }
  633. }
  634. /*************************************************************************
  635. ** do_defined : does the work for the defined(id)
  636. ** should parens be counted, or just be used as delimiters (ie the
  637. ** first open paren matches the first close paren)? If this is ever
  638. ** an issue, it really means that there is not a legal identifier
  639. ** between the parens, causing an error anyway, but consider:
  640. ** #if (defined(2*(x-1))) || 1
  641. ** #endif
  642. ** It is friendlier to allow compilation to continue
  643. *************************************************************************/
  644. int
  645. do_defined(
  646. PWCHAR p_tmp
  647. )
  648. {
  649. REG UINT c;
  650. REG int value=0;
  651. int paren_level = 0;
  652. /*
  653. ** we want to allow:
  654. ** #define FOO defined
  655. ** #define BAR(a,b) a FOO | b
  656. ** #define SNAFOO 0
  657. ** #if FOO BAR
  658. ** print("BAR is defined");
  659. ** #endif
  660. ** #if BAR(defined, SNAFOO)
  661. ** print("FOO is defined");
  662. ** #endif
  663. */
  664. if(wcscmp(p_tmp,L"defined") != 0) {
  665. return(0);
  666. }
  667. if((!can_get_non_white()) && (Tiny_lexer_nesting == 0)) {
  668. /* NL encountered */
  669. return(value);
  670. }
  671. if((c = CHECKCH())== L'(') { /* assumes no other CHARMAP form of OPAREN */
  672. *Exp_ptr++ = (WCHAR)c;
  673. SKIPCH();
  674. paren_level++;
  675. if((!can_get_non_white()) && (Tiny_lexer_nesting == 0)) {
  676. /* NL encountered */
  677. return(value);
  678. }
  679. }
  680. if(Tiny_lexer_nesting>0) {
  681. if((CHARMAP((WCHAR)(c=CHECKCH()))==LX_MACFORMAL) || (CHARMAP((WCHAR)c)==LX_ID)) {
  682. SKIPCH();
  683. tl_getid((UCHAR)c);
  684. }
  685. } else {
  686. if(LX_IS_IDENT(((WCHAR)(c = CHECKCH())))) {
  687. SKIPCH();
  688. if(Macro_depth >0) {
  689. lex_getid((WCHAR)c);
  690. } else {
  691. getid((WCHAR)c);
  692. }
  693. value = (get_defined()) ? TRUE : FALSE;
  694. } else {
  695. if(paren_level==0) {
  696. strcpy (Msg_Text, GET_MSG (2003));
  697. error(2003);
  698. } else {
  699. strcpy (Msg_Text, GET_MSG (2004));
  700. error(2004);
  701. }
  702. }
  703. }
  704. if((CHARMAP(((WCHAR)(c = CHECKCH()))) == LX_WHITE) || (CHARMAP((WCHAR)c) == LX_EOS)) {
  705. if( ! can_get_non_white()) {
  706. return(value);
  707. }
  708. }
  709. if(paren_level) {
  710. if((CHARMAP(((WCHAR)(c = CHECKCH()))) == LX_CPAREN)) {
  711. SKIPCH();
  712. paren_level--;
  713. *Exp_ptr++ = (WCHAR)c;
  714. }
  715. }
  716. if((paren_level > 0) && (Tiny_lexer_nesting == 0)) {
  717. strcpy (Msg_Text, GET_MSG (4004));
  718. warning(4004);
  719. }
  720. return(value);
  721. }
  722. /*************************************************************************
  723. * NEXTIS - The lexical interface for #if expression parsing.
  724. * If the next token does not match what is wanted, return FALSE.
  725. * otherwise Set Currtok to L_NOTOKEN to force scanning on the next call.
  726. * Return TRUE.
  727. * will leave a newline as next char if it finds one.
  728. *************************************************************************/
  729. int
  730. nextis(
  731. register token_t tok
  732. )
  733. {
  734. if(Currtok != L_NOTOKEN) {
  735. if(tok == Currtok) {
  736. Currtok = L_NOTOKEN; /* use up the token */
  737. return(TRUE);
  738. } else {
  739. return(FALSE);
  740. }
  741. }
  742. switch(yylex()) { /* acquire a new token */
  743. case 0:
  744. break;
  745. case L_CONSTANT:
  746. if( ! IS_INTEGRAL(TR_BTYPE(yylval.yy_tree))) {
  747. strcpy (Msg_Text, GET_MSG (1017));
  748. fatal (1017);
  749. } else {
  750. Currval = TR_LVALUE(yylval.yy_tree);
  751. }
  752. if(tok == L_CINTEGER) {
  753. return(TRUE);
  754. }
  755. Currtok = L_CINTEGER;
  756. break;
  757. case L_IDENT:
  758. Currval = do_defined(HLN_IDENTP_NAME(&yylval.yy_ident));
  759. if(tok == L_CINTEGER) {
  760. return(TRUE);
  761. }
  762. Currtok = L_CINTEGER;
  763. break;
  764. default:
  765. if(tok == Basic_token) {
  766. return(TRUE);
  767. }
  768. Currtok = Basic_token;
  769. break;
  770. }
  771. return(FALSE);
  772. }
  773. /************************************************************************
  774. ** skip_cnew : reads up to and including the next newline.
  775. ************************************************************************/
  776. void
  777. skip_cnew(
  778. void
  779. )
  780. {
  781. for(;;) {
  782. switch(CHARMAP(GETCH())) {
  783. case LX_NL:
  784. UNGETCH();
  785. return;
  786. case LX_SLASH:
  787. skip_comment();
  788. break;
  789. case LX_EOS:
  790. handle_eos();
  791. break;
  792. }
  793. }
  794. }
  795. /************************************************************************
  796. ** skip_NLonly : reads up to the next newline, disallowing comments
  797. ************************************************************************/
  798. void
  799. skip_NLonly(
  800. void
  801. )
  802. {
  803. for(;;) {
  804. switch(CHARMAP(GETCH())) {
  805. case LX_NL:
  806. UNGETCH();
  807. return;
  808. case LX_EOS:
  809. handle_eos();
  810. break;
  811. }
  812. }
  813. }
  814. /************************************************************************
  815. ** pragma : handle processing the pragma directive
  816. ** called by preprocess() after we have seen the #pragma
  817. ** and are ready to handle the keyword which follows.
  818. ************************************************************************/
  819. unsigned long
  820. pragma(
  821. void
  822. )
  823. {
  824. WCHAR c;
  825. unsigned long int cp=0;
  826. c = skip_cwhite();
  827. if (c != L'\n') {
  828. getid(c);
  829. _wcsupr(Reuse_W);
  830. if (wcscmp(L"CODE_PAGE", Reuse_W) == 0) {
  831. if ((c = skip_cwhite()) == L'(') {
  832. c = skip_cwhite(); // peek token
  833. if (iswdigit(c)) {
  834. token_t tok;
  835. int old_prep = Prep;
  836. Prep = FALSE;
  837. tok = getnum(c);
  838. Prep = old_prep;
  839. switch(tok) {
  840. default:
  841. case L_CFLOAT:
  842. case L_CDOUBLE:
  843. case L_CLDOUBLE:
  844. case L_FLOAT:
  845. case L_DOUBLE:
  846. break;
  847. case L_CINTEGER:
  848. case L_LONGINT:
  849. case L_CUNSIGNED:
  850. case L_LONGUNSIGNED:
  851. case L_SHORT:
  852. case L_LONG:
  853. case L_SIGNED:
  854. case L_UNSIGNED:
  855. cp = TR_LVALUE(yylval.yy_tree);
  856. break;
  857. }
  858. }
  859. if (cp == 0) {
  860. getid(c);
  861. _wcsupr(Reuse_W);
  862. if (wcscmp(L"DEFAULT", Reuse_W) == 0) {
  863. cp = uiDefaultCodePage;
  864. } else {
  865. wsprintfA(Msg_Text, "%s%ws", GET_MSG(4212), Reuse_W);
  866. error(4212);
  867. }
  868. }
  869. if ((c = skip_cwhite()) != L')') {
  870. UNGETCH();
  871. strcpy (Msg_Text, GET_MSG (4211));
  872. error(4211);
  873. }
  874. } else {
  875. UNGETCH();
  876. strcpy (Msg_Text, GET_MSG (4210));
  877. error(4210);
  878. }
  879. swprintf(Reuse_W, L"#pragma code_page %d\r\n", cp);
  880. myfwrite(Reuse_W, wcslen(Reuse_W) * sizeof(WCHAR), 1, OUTPUTFILE);
  881. }
  882. }
  883. // Skip #pragma statements
  884. while((c = get_non_eof()) != L'\n');
  885. UNGETCH();
  886. return cp;
  887. }