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.

538 lines
18 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. /************************************************************************
  12. ** MAP_TOKEN : a token has two representations and additional information.
  13. ** (ex : const, has basic token of L_CONST,
  14. ** mapped token of [L_TYPE | L_MODIFIER]
  15. ** and info based on what the map token is)
  16. ** MAP_AND_FILL : has two representations, but none of the extra info.
  17. ** (ex : '<', has basic of L_LT, and map of L_RELOP)
  18. ** NOMAP_TOKEN : has 1 representation and additional info.
  19. ** (ex: a string, basic and 'map' type L_STRING and ptrs to the actual str)
  20. ** NOMAP_AND_FILL : has 1 representation and no additional info.
  21. ** (ex : 'while', has basic and 'map' of L_WHILE)
  22. ** the FILL versions fill the token with the basic token type.
  23. ************************************************************************/
  24. #define MAP_TOKEN(otok)\
  25. (Basic_token = (otok), TS_VALUE(Basic_token))
  26. #define MAP_AND_FILL(otok)\
  27. (yylval.yy_token = Basic_token = (otok), TS_VALUE(Basic_token))
  28. #define NOMAP_TOKEN(otok)\
  29. (Basic_token = (otok))
  30. #define NOMAP_AND_FILL(otok)\
  31. (yylval.yy_token = Basic_token = (otok))
  32. /************************************************************************/
  33. /* yylex - main tokenization routine */
  34. /************************************************************************/
  35. token_t
  36. yylex(
  37. void
  38. )
  39. {
  40. REG WCHAR last_mapped;
  41. WCHAR mapped_c;
  42. WCHAR buf[5];
  43. REG token_t lex_token;
  44. for(;;) {
  45. last_mapped = mapped_c = CHARMAP(GETCH());
  46. first_switch:
  47. switch(mapped_c) {
  48. case LX_EACH:
  49. case LX_ASCII:
  50. if (fAFXSymbols && PREVCH() == SYMUSESTART || PREVCH() == SYMDEFSTART
  51. || PREVCH() == SYMDELIMIT) {
  52. myfwrite(&(PREVCH()), sizeof(WCHAR), 1, OUTPUTFILE);
  53. continue;
  54. }
  55. error(2018, PREVCH());
  56. continue;
  57. case LX_OBRACE:
  58. return(NOMAP_AND_FILL(L_LCURLY));
  59. case LX_CBRACE:
  60. return(NOMAP_AND_FILL(L_RCURLY));
  61. case LX_OBRACK:
  62. return(NOMAP_AND_FILL(L_LBRACK));
  63. case LX_CBRACK:
  64. return(NOMAP_AND_FILL(L_RBRACK));
  65. case LX_OPAREN:
  66. return(NOMAP_AND_FILL(L_LPAREN));
  67. case LX_CPAREN:
  68. return(NOMAP_AND_FILL(L_RPAREN));
  69. case LX_COMMA:
  70. return(NOMAP_AND_FILL(L_COMMA));
  71. case LX_QUEST:
  72. return(NOMAP_AND_FILL(L_QUEST));
  73. case LX_SEMI:
  74. return(NOMAP_AND_FILL(L_SEMI));
  75. case LX_TILDE:
  76. return(NOMAP_AND_FILL(L_TILDE));
  77. case LX_NUMBER:
  78. return(MAP_TOKEN(getnum(PREVCH())));
  79. case LX_MINUS:
  80. switch(last_mapped = CHARMAP(GETCH())) {
  81. case LX_EQ:
  82. return(MAP_AND_FILL(L_MINUSEQ));
  83. case LX_GT:
  84. return(MAP_AND_FILL(L_POINTSTO));
  85. case LX_MINUS:
  86. return(MAP_AND_FILL(L_DECR));
  87. default:
  88. lex_token = L_MINUS;
  89. break;
  90. }
  91. break;
  92. case LX_PLUS:
  93. switch(last_mapped = CHARMAP(GETCH())) {
  94. case LX_EQ:
  95. return(MAP_AND_FILL(L_PLUSEQ));
  96. case LX_PLUS:
  97. return(MAP_AND_FILL(L_INCR));
  98. default:
  99. lex_token = L_PLUS;
  100. break;
  101. }
  102. break;
  103. case LX_AND:
  104. switch(last_mapped = CHARMAP(GETCH())) {
  105. case LX_EQ:
  106. return(MAP_AND_FILL(L_ANDEQ));
  107. case LX_AND:
  108. return(MAP_AND_FILL(L_ANDAND));
  109. default:
  110. lex_token = L_AND;
  111. break;
  112. }
  113. break;
  114. case LX_OR:
  115. switch(last_mapped = CHARMAP(GETCH())) {
  116. case LX_EQ:
  117. return(MAP_AND_FILL(L_OREQ));
  118. case LX_OR:
  119. return(MAP_AND_FILL(L_OROR));
  120. default:
  121. lex_token = L_OR;
  122. break;
  123. }
  124. break;
  125. case LX_COLON:
  126. return(NOMAP_AND_FILL(L_COLON));
  127. case LX_HAT:
  128. if((last_mapped = CHARMAP(GETCH())) == LX_EQ) {
  129. return(MAP_AND_FILL(L_XOREQ));
  130. }
  131. lex_token = L_XOR;
  132. break;
  133. case LX_PERCENT:
  134. if((last_mapped = CHARMAP(GETCH())) == LX_EQ) {
  135. return(MAP_AND_FILL(L_MODEQ));
  136. }
  137. lex_token = L_MOD;
  138. break;
  139. case LX_EQ:
  140. if((last_mapped = CHARMAP(GETCH())) == LX_EQ) {
  141. return(MAP_AND_FILL(L_EQUALS));
  142. }
  143. lex_token = L_ASSIGN;
  144. break;
  145. case LX_BANG:
  146. if((last_mapped = CHARMAP(GETCH())) == LX_EQ) {
  147. return(MAP_AND_FILL(L_NOTEQ));
  148. }
  149. lex_token = L_EXCLAIM;
  150. break;
  151. case LX_SLASH:
  152. switch(last_mapped = CHARMAP(GETCH())) {
  153. case LX_STAR:
  154. dump_comment();
  155. continue;
  156. case LX_SLASH:
  157. DumpSlashComment();
  158. continue;
  159. case LX_EQ:
  160. return(MAP_AND_FILL(L_DIVEQ));
  161. default:
  162. lex_token = L_DIV;
  163. break;
  164. }
  165. break;
  166. case LX_STAR:
  167. switch(last_mapped = CHARMAP(GETCH())) {
  168. case LX_SLASH:
  169. if( ! Prep ) {
  170. error(2138); /* (nested comments) */
  171. } else {
  172. myfwrite(L"*/", 2 * sizeof(WCHAR), 1, OUTPUTFILE);
  173. }
  174. continue;
  175. case LX_EQ:
  176. return(MAP_AND_FILL(L_MULTEQ));
  177. default:
  178. lex_token = L_MULT;
  179. break;
  180. }
  181. break;
  182. case LX_LT:
  183. switch(last_mapped = CHARMAP(GETCH())) {
  184. case LX_LT:
  185. if((last_mapped = CHARMAP(GETCH())) == LX_EQ) {
  186. return(MAP_AND_FILL(L_LSHFTEQ));
  187. }
  188. mapped_c = LX_LSHIFT;
  189. lex_token = L_LSHIFT;
  190. break;
  191. case LX_EQ:
  192. return(MAP_AND_FILL(L_LTEQ));
  193. default:
  194. lex_token = L_LT;
  195. break;
  196. }
  197. break;
  198. case LX_LSHIFT:
  199. /*
  200. ** if the next char is not an =, then we unget and return,
  201. ** since the only way in here is if we broke on the char
  202. ** following '<<'. since we'll have already worked the handle_eos()
  203. ** code prior to getting here, we'll not see another eos,
  204. ** UNLESS i/o buffering is char by char. ???
  205. ** see also, LX_RSHIFT
  206. */
  207. if((last_mapped = CHARMAP(GETCH())) == LX_EQ) {
  208. return(MAP_AND_FILL(L_LSHFTEQ));
  209. }
  210. UNGETCH();
  211. return(MAP_AND_FILL(L_LSHIFT));
  212. case LX_GT:
  213. switch(last_mapped = CHARMAP(GETCH())) {
  214. case LX_EQ:
  215. return(MAP_AND_FILL(L_GTEQ));
  216. case LX_GT:
  217. if((last_mapped = CHARMAP(GETCH())) == LX_EQ) {
  218. return(MAP_AND_FILL(L_RSHFTEQ));
  219. }
  220. mapped_c = LX_RSHIFT;
  221. lex_token = L_RSHIFT;
  222. break;
  223. default:
  224. lex_token = L_GT;
  225. break;
  226. }
  227. break;
  228. case LX_RSHIFT:
  229. if((last_mapped = CHARMAP(GETCH())) == LX_EQ) {
  230. return(MAP_AND_FILL(L_RSHFTEQ));
  231. }
  232. UNGETCH();
  233. return(MAP_AND_FILL(L_RSHIFT));
  234. case LX_POUND:
  235. if( ! Prep ) {
  236. error(2014);/* # sign must be first non-whitespace */
  237. UNGETCH(); /* replace it */
  238. Linenumber--; /* do_newline counts a newline */
  239. do_newline(); /* may be a 'real' prepro line */
  240. } else {
  241. myfwrite(L"#", sizeof(WCHAR), 1, OUTPUTFILE);
  242. }
  243. continue;
  244. case LX_EOS:
  245. if(PREVCH() == L'\\') {
  246. if( ! Prep ) {
  247. if( ! checknl()) { /* ignore the new line */
  248. error(2017);/* illegal escape sequence */
  249. }
  250. } else {
  251. myfwrite(L"\\", sizeof(WCHAR), 1, OUTPUTFILE);
  252. *buf = get_non_eof();
  253. myfwrite(buf, sizeof(WCHAR), 1, OUTPUTFILE);
  254. }
  255. continue;
  256. }
  257. if(Macro_depth == 0) {
  258. if( ! io_eob()) { /* not the end of the buffer */
  259. continue;
  260. }
  261. if(fpop()) { /* have more files to read */
  262. continue;
  263. }
  264. return(MAP_AND_FILL(L_EOF)); /* all gone . . . */
  265. }
  266. handle_eos(); /* found end of macro */
  267. continue;
  268. case LX_DQUOTE:
  269. if( ! Prep ) {
  270. str_const();
  271. return(NOMAP_TOKEN(L_STRING));
  272. }
  273. prep_string(L'\"');
  274. continue;
  275. case LX_SQUOTE:
  276. if( ! Prep ) {
  277. return(MAP_TOKEN(char_const()));
  278. }
  279. prep_string(L'\'');
  280. continue;
  281. case LX_CR: /* ??? check for nl next */
  282. continue;
  283. case LX_NL:
  284. if(On_pound_line) {
  285. UNGETCH();
  286. return(NOMAP_TOKEN(L_NOTOKEN));
  287. }
  288. if(Prep) {
  289. // must manually write '\r' with '\n' when writing 16-bit strings
  290. myfwrite(L"\r\n", 2 * sizeof(WCHAR), 1, OUTPUTFILE);
  291. }
  292. do_newline();
  293. continue;
  294. case LX_WHITE: /* skip all white space */
  295. if( ! Prep ) { /* check only once */
  296. do {
  297. ;
  298. } while(LXC_IS_WHITE(GETCH()));
  299. }
  300. else {
  301. WCHAR c;
  302. c = PREVCH();
  303. do {
  304. myfwrite(&c, sizeof(WCHAR), 1, OUTPUTFILE);
  305. } while(LXC_IS_WHITE(c = GETCH()));
  306. }
  307. UNGETCH();
  308. continue;
  309. case LX_ILL:
  310. if( ! Prep ) {
  311. error(2018, PREVCH());/* unknown character */
  312. } else {
  313. myfwrite(&(PREVCH()), sizeof(WCHAR), 1, OUTPUTFILE);
  314. }
  315. continue;
  316. case LX_BACKSLASH:
  317. if( ! Prep ) {
  318. if( ! checknl()) { /* ignore the new line */
  319. error(2017);/* illegal escape sequence */
  320. }
  321. }
  322. else {
  323. myfwrite(L"\\", sizeof(WCHAR), 1, OUTPUTFILE);
  324. *buf = get_non_eof();
  325. myfwrite(buf, sizeof(WCHAR), 1, OUTPUTFILE);
  326. }
  327. continue;
  328. case LX_DOT:
  329. dot_switch:
  330. switch(last_mapped = CHARMAP(GETCH())) {
  331. case LX_BACKSLASH:
  332. if(checknl()) {
  333. goto dot_switch;
  334. }
  335. UNGETCH();
  336. break;
  337. case LX_EOS:
  338. if(handle_eos() == BACKSLASH_EOS) {
  339. break;
  340. }
  341. goto dot_switch;
  342. case LX_DOT:
  343. if( ! checkop(L'.') ) {
  344. error(2142);/* ellipsis requires three '.'s */
  345. }
  346. return(NOMAP_AND_FILL(L_ELLIPSIS));
  347. case LX_NUMBER:
  348. /*
  349. ** don't worry about getting correct hash value.
  350. ** The text equivalent of a real number is never
  351. ** hashed
  352. */
  353. Reuse_W[0] = L'.';
  354. Reuse_W[1] = PREVCH();
  355. return(MAP_TOKEN(get_real(&Reuse_W[2])));
  356. }
  357. UNGETCH();
  358. return(MAP_AND_FILL(L_PERIOD));
  359. case LX_NOEXPAND:
  360. SKIPCH(); /* just skip length */
  361. continue;
  362. case LX_ID:
  363. {
  364. pdefn_t pdef;
  365. if(Macro_depth > 0) {
  366. if( ! lex_getid(PREVCH())) {
  367. goto avoid_expand;
  368. }
  369. }
  370. else {
  371. getid(PREVCH());
  372. }
  373. if( ((pdef = get_defined()) != 0)
  374. &&
  375. ( ! DEFN_EXPANDING(pdef))
  376. &&
  377. ( can_expand(pdef))
  378. ) {
  379. continue;
  380. }
  381. avoid_expand:
  382. if( ! Prep ) {
  383. /* M00BUG get near copy of identifier???? */
  384. HLN_NAME(yylval.yy_ident) = Reuse_W;
  385. HLN_HASH(yylval.yy_ident) = Reuse_W_hash;
  386. HLN_LENGTH(yylval.yy_ident) = (UINT)Reuse_W_length;
  387. return(L_IDENT);
  388. } else {
  389. myfwrite(Reuse_W, (Reuse_W_length - 1) * sizeof(WCHAR), 1, OUTPUTFILE);
  390. return(NOMAP_TOKEN(L_NOTOKEN));
  391. }
  392. }
  393. continue;
  394. }
  395. /*
  396. ** all the multichar ( -> -- -= etc ) operands
  397. ** must come through here. we've gotten the next char,
  398. ** and not matched one of the possiblities, but we have to check
  399. ** for the end of the buffer character and act accordingly
  400. ** if it is the eob, then we handle it and go back for another try.
  401. ** otherwise, we unget the char we got, and return the base token.
  402. */
  403. if(last_mapped == LX_EOS) {
  404. if(handle_eos() != BACKSLASH_EOS) {
  405. goto first_switch;
  406. }
  407. }
  408. UNGETCH(); /* cause we got an extra one to check */
  409. return(MAP_AND_FILL(lex_token));
  410. }
  411. }
  412. /************************************************************************
  413. **
  414. ** lex_getid: reads an identifier for the main lexer. The
  415. ** identifier is read into Reuse_W. This function should not handle
  416. ** an end of string if it is rescanning a macro expansion, because
  417. ** this could switch the context with regards to whether the macro
  418. ** is expandable or not. Similarly, the noexpand marker must only be
  419. ** allowed if a macro is being rescanned, otherwise let this character
  420. ** be caught as an illegal character in text
  421. ************************************************************************/
  422. int
  423. lex_getid(
  424. WCHAR c
  425. )
  426. {
  427. REG WCHAR *p;
  428. int length = 0;
  429. p = Reuse_W;
  430. *p++ = c;
  431. c &= HASH_MASK;
  432. for(;;) {
  433. while(LXC_IS_IDENT(*p = GETCH())) { /* collect character */
  434. c += (*p & HASH_MASK); /* hash it */
  435. p++;
  436. }
  437. if(CHARMAP(*p) == LX_NOEXPAND ) {
  438. length = (int)GETCH();
  439. continue;
  440. }
  441. UNGETCH();
  442. break; /* out of for loop - only way out */
  443. }
  444. if(p >= LIMIT(Reuse_W)) { /* is this error # correct? */
  445. fatal(1067);
  446. }
  447. if(((p - Reuse_W) > LIMIT_ID_LENGTH) && ( ! Prep )) {
  448. p = Reuse_W + LIMIT_ID_LENGTH;
  449. *p = L'\0';
  450. c = local_c_hash(Reuse_W);
  451. warning(4011, Reuse_W); /* id truncated */
  452. } else {
  453. *p = L'\0'; /* terminates identifier for expandable check */
  454. }
  455. Reuse_W_hash = (hash_t)c;
  456. Reuse_W_length = (UINT)((p - Reuse_W) + 1);
  457. return(length != (p - Reuse_W));
  458. }