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.

781 lines
27 KiB

  1. // IFEXPR.C -- routines to handle directives
  2. //
  3. // Copyright (c) 1988-1989, Microsoft Corporation. All rights reserved.
  4. //
  5. // Purpose:
  6. // Module contains routines to handle !directives. This module is transparent to
  7. // rest of NMAKE. It also contains lgetc() used by lexer.c
  8. //
  9. // Revision History:
  10. // 15-Oct-1993 HV Use tchar.h instead of mbstring.h directly, change STR*() to _ftcs*()
  11. // 01-Jun-1993 HV Created UngetTxtChr()
  12. // 01-Jun-1993 HV Change #ifdef KANJI to _MBCS.
  13. // Eliminate #include <jctype.h>
  14. // 10-May-1993 HV Add include file mbstring.h
  15. // Change the str* functions to STR*
  16. // 30-Jul-1990 SB Freeing ptr in the middle of a string for 'undef foo' case
  17. // 01-Dec-1989 SB Changed realloc() to REALLOC()
  18. // 22-Nov-1989 SB Changed free() to FREE()
  19. // 05-Apr-1989 SB made all funcs NEAR; Reqd to make all function calls NEAR
  20. // 19-Sep-1988 RB Remove ESCH processing from readInOneLine().
  21. // 15-Sep-1988 RB Move chBuf to GLOBALS.
  22. // 17-Aug-1988 RB Clean up.
  23. // 29-Jun-1988 rj Added support for cmdswitches e,q,p,t,b,c in tools.ini.
  24. // 23-Jun-1988 rj Fixed GP fault when doing directives in tools.ini.
  25. // 23-Jun-1988 rj Add support for ESCH to readInOneLine().
  26. // 25-May-1988 rb Add missing argument to makeError() call.
  27. #include "precomp.h"
  28. #pragma hdrstop
  29. // function prototypes
  30. void skipToNextDirective(void);
  31. void processIfs(char*, UCHAR);
  32. UCHAR ifsPresent(char*, unsigned, char**);
  33. void processCmdSwitches(char*);
  34. char * readInOneLine(void);
  35. char * getDirType(char*, UCHAR*);
  36. // macros that deal w/ the if/else directives' stack
  37. #define ifStkTop() (ifStack[ifTop])
  38. #define popIfStk() (ifStack[ifTop--])
  39. #define pushIfStk(A) (ifStack[++ifTop] = A)
  40. #define INCLUDE 0x09
  41. #define CMDSWITCHES 0x0A
  42. #define ERROR 0x0B
  43. #define MESSAGE 0x0C
  44. #define UNDEF 0x0D
  45. #ifdef _MBCS
  46. // GetTxtChr : get the next character from a text file stream
  47. //
  48. // This routine handles mixed DBCS and ASCII characters as
  49. // follows:
  50. //
  51. // 1. The second byte of a DBCS character is returned in a
  52. // word with the high byte set to the lead byte of the character.
  53. // Thus the return value can be used in comparisions with
  54. // ASCII constants without being mistakenly matched.
  55. //
  56. // 2. A DBCS space character (0x8140) is returned as two
  57. // ASCII spaces (0x20). I.e. return a space the 1st and 2nd
  58. // times we're called.
  59. //
  60. // 3. ASCII characters and lead bytes of DBCS characters
  61. // are returned in the low byte of a word with the high byte
  62. // set to 0.
  63. int GetTxtChr(FILE *bs)
  64. {
  65. extern int chBuf; // Character buffer
  66. int next; // The next byte
  67. int next2; // The one after that
  68. // -1 in chBuf means it doesn't contain a valid character
  69. // If we're not in the middle of a double-byte character,
  70. // get the next byte and process it.
  71. if(chBuf == -1) {
  72. next = getc(bs);
  73. // If this byte is a lead byte, get the following byte
  74. // and store both as a word in chBuf.
  75. if (_ismbblead(next)) {
  76. next2 = getc(bs);
  77. chBuf = (next << 8) | next2;
  78. // If the pair matches a DBCS space, set the return value
  79. // to ASCII space.
  80. if(chBuf == 0x8140)
  81. next = 0x20;
  82. }
  83. } else {
  84. // Else we're in the middle of a double-byte character.
  85. if(chBuf == 0x8140) {
  86. // If this is the 2nd byte of a DBCS space, set the return
  87. // value to ASCII space.
  88. next = 0x20;
  89. } else {
  90. // Else set the return value to the whole DBCS character
  91. next = chBuf;
  92. }
  93. // Reset the character buffer
  94. chBuf = -1;
  95. }
  96. // Return the next character
  97. return(next);
  98. }
  99. #endif // _MBCS
  100. #ifdef _MBCS
  101. // UngetTxtChr -- Unget character fetched by GetTxtChr
  102. //
  103. // Scope:
  104. // Global.
  105. //
  106. // Purpose:
  107. // Since GetTxtChr() sometimes reads ahead one character and saves it in chBuf,
  108. // ungetc() will sometimes put back characters in incorrect sequence.
  109. // UngetTxtChr, on the other hand, understands how GetTxtChr works and will
  110. // correctly put those characers back.
  111. //
  112. // Input:
  113. // c -- The character read by GetTxtChr()
  114. // bs -- The file buffer which c was read from.
  115. //
  116. // Output:
  117. // Returns c if c is put back OK, otherwise returns EOF
  118. //
  119. // Errors/Warnings:
  120. //
  121. // Assumes:
  122. // Assumes that characters are read only by GetTxtChr(), not by getc, etc.
  123. //
  124. // Modifies Globals:
  125. // chBuf -- The composite character, read ahead by GetTxtChr()
  126. //
  127. // Uses Globals:
  128. // chBuf -- The composite character, read ahead by GetTxtChr()
  129. //
  130. // Notes:
  131. // There are three cases to consider:
  132. // 1. Normal character (chBuf == -1 && c == 0x00XX)
  133. // In this case, just put back c is sufficient.
  134. // 2. Trail byte character (chBuf == -1 && c = LB|TB)
  135. // chBuf = c;
  136. // 3. Lead byte character (chBuf == LB|TB && c == LB)
  137. // put back TB
  138. // put back LB
  139. // chBuf = -1
  140. //
  141. // History:
  142. // 01-Jun-1993 HV Created.
  143. int
  144. UngetTxtChr(int c, FILE *bs)
  145. {
  146. extern int chBuf; // Character buffer
  147. int nTrailByte; // The trail byte to put back
  148. if (-1 == chBuf) { // We're not in the middle of a DB character
  149. if (0 == (c >> 8)) { // CASE 1: normal character
  150. c = ungetc(c, bs); // putback normal char
  151. } else { // CASE 2: at trail byte (c=LBTB)
  152. chBuf = c; // change chBuf is sufficient
  153. }
  154. } else { // CASE 3: at lead byte (c=LB, chBuf=LBTB)
  155. nTrailByte = chBuf & (int)0xff; // Figure out the trail byte to putback
  156. ungetc(nTrailByte, bs); // putback trail byte
  157. c = ungetc(c, bs); // putback lead byte
  158. chBuf = -1;
  159. }
  160. return (c);
  161. }
  162. #endif // _MBCS
  163. // lgetc() local getc - handles directives and returns char
  164. //
  165. // arguments: init global boolean value -- TRUE if tools.ini
  166. // is the file being parsed
  167. // colZero global boolean value -- TRUE if at first column
  168. //
  169. // actions:
  170. // gets a character from the currently open file.
  171. // loop
  172. // if it is column zero and the char is '!' or
  173. // there is a previous directive to be processed do
  174. // read in one line into buffer.
  175. // find directive type and get a pointer to rest of
  176. // text.
  177. // case directive of:
  178. //
  179. // CMDSWITCHES : set/reset global flags
  180. // ERROR : set up global error message
  181. // printed by error routine on
  182. // termination. (not implemented yet )
  183. // INCLUDE : calls processInclude
  184. // continues with new file...
  185. // UNDEF : undef the macro in the table
  186. // IF
  187. // IFDEF
  188. // IFNDEF
  189. // ELSE
  190. // ENDIF : change the state information
  191. // on the ifStack
  192. // evaluate expression if required
  193. // skip text if required (and look
  194. // for the next directive)
  195. // ( look at processIfs() )
  196. // free extra buffers used (only one buffer need be
  197. // maintained )
  198. // increment lexer's line count
  199. // we 're now back at column zero
  200. // get next char from current file
  201. // end if
  202. // end loop
  203. // return a char
  204. //
  205. // returns : a character (that is not part of any directive...)
  206. //
  207. // modifies: ifStack if directives' stack, static to this module
  208. // ifTop index of current element at top of stack
  209. // line lexer's line count...
  210. //
  211. // file current file, if !include is found...
  212. // fName if !include is processed...
  213. int
  214. lgetc()
  215. {
  216. UCHAR dirType;
  217. int c;
  218. char *s, *t;
  219. MACRODEF *m;
  220. for (c = GetTxtChr(file); prevDirPtr || (colZero && (c == '!'));
  221. ++line, c = GetTxtChr(file)) {
  222. colZero = FALSE; // we saw a '!' incolZero
  223. if (!prevDirPtr) {
  224. s = readInOneLine(); // might modify lbufPtr -
  225. // if input text causes realloc */
  226. } else {
  227. UngetTxtChr(c, file);
  228. s = prevDirPtr;
  229. prevDirPtr = NULL;
  230. }
  231. t = getDirType(s, &dirType);
  232. if (dirType == INCLUDE) {
  233. if (init) {
  234. makeError(line, SYNTAX_UNEXPECTED_TOKEN, s);
  235. }
  236. // processInclude eats up first char in new file
  237. // if it is space char. we check for that and break out.
  238. if (processIncludeFile(t) == (UCHAR) NEWLINESPACE) {
  239. c = ' '; // space character is returned
  240. break; // colZero is now FALSE
  241. }
  242. }
  243. else if (dirType == CMDSWITCHES) {
  244. processCmdSwitches(t);
  245. }
  246. else if (dirType == ERROR) {
  247. makeError(line, USER_CONTROLLED, t);
  248. }
  249. else if (dirType == MESSAGE) {
  250. if (!_tcsnicmp(t, "\\t", 2)) {
  251. printf("\t");
  252. t+=2;
  253. }
  254. makeMessage(USER_MESSAGE, t);
  255. }
  256. else if (dirType == UNDEF) {
  257. char *tmp;
  258. tmp = _tcstok(t, " \t");
  259. if (_tcstok(NULL, " \t")) {
  260. makeError(line, SYNTAX_UNEXPECTED_TOKEN, tmp);
  261. }
  262. if (NULL != (m = findMacro(tmp))) {
  263. SET(m->flags, M_UNDEFINED);
  264. }
  265. // CONSIDER: why not remove symbol from table? [RB]
  266. }
  267. else processIfs(t, dirType);
  268. colZero = TRUE; // finished with this directive
  269. if (s != lbufPtr) // free buffer if it had expanded macros
  270. FREE(s);
  271. }
  272. return(c); // return a character to the lexer
  273. }
  274. // readInOneLine()
  275. //
  276. // arguments: lbufPtr pointer(static/global to this module) to buffer that
  277. // will hold text of line being read in
  278. // lbufSize size of buffer(static/global to this module), updated
  279. // if buffer is realloc'd
  280. // actions : skip spaces/tabs and look for the directive.
  281. // line continuations allowed in usual way
  282. // if space-backslash-nl keep looking...
  283. // if colZero of next line has comment char
  284. // (#, or ; in tools.ini), look at next line...
  285. // if first non-space char is '\n' or EOF report
  286. // fatal-error and stop.
  287. //
  288. // keep reading in chars and storing in the buffer until
  289. // a newline, EOF or a '#' which is NOT in column
  290. // zero is seen
  291. // if comment char in column zero ('#' or ';' in tools.ini)
  292. // skip the line, continue with text on next line.
  293. // if buffer needs to be realloc'd increase size by
  294. // MAXBUF, a global constant.
  295. // if newline was found, eat up newline.
  296. // null terminate string for return.
  297. // if '#' was found discard chars till the a newline or EOF.
  298. // if EOF was found, push it back on stream for return
  299. // to the lexer the next time.
  300. //
  301. // now expand macros. get a different buffer with clean
  302. // text after expansion of macros.
  303. //
  304. // modifies : colZero global boolean value ( thru' call to
  305. // skipBackSlash())
  306. // lbufPtr buffer pointer, in case of reallocs.
  307. // lbufSize size of buffer, increased if buffer is realloc'd
  308. // Note: the buffer size will grow to be just greater than the size
  309. // of the longest directive in any of the files processed,
  310. // if it calls for any realloc's
  311. // Do NOT process ESCH here. It is processed at a higher level.
  312. //
  313. // returns : pointer to buffer.
  314. //
  315. char *
  316. readInOneLine()
  317. {
  318. extern STRINGLIST *eMacros;
  319. int c;
  320. unsigned index = 0;
  321. register char *s;
  322. if (((c = skipWhiteSpace(FROMSTREAM)) == '\n') || (c == EOF))
  323. makeError(line, SYNTAX_MISSING_DIRECTIVE);
  324. UngetTxtChr(c, file);
  325. for (;;) {
  326. c = GetTxtChr(file);
  327. c = skipBackSlash(c, FROMSTREAM);
  328. if (c == '#' || c == '\n' || c == EOF) {
  329. break;
  330. }
  331. if ((index+2) > lbufSize) {
  332. lbufSize += MAXBUF;
  333. if (!lbufPtr) {
  334. lbufPtr = (char *) allocate(lbufSize+1); // +1 for NULL byte
  335. } else {
  336. void *pv = REALLOC(lbufPtr, lbufSize+1);
  337. if (pv) {
  338. lbufPtr = (char *) pv;
  339. } else {
  340. makeError(line, MACRO_TOO_LONG);
  341. }
  342. }
  343. }
  344. *(lbufPtr + (index++)) = (char) c;
  345. }
  346. *(lbufPtr + index) = '\0'; // null terminate the string
  347. if (c == '#') {
  348. for(c = GetTxtChr(file); (c != '\n') && (c != EOF); c = GetTxtChr(file))
  349. ;
  350. // newline at end is eaten up
  351. }
  352. if (c == EOF) {
  353. UngetTxtChr(c, file); // this directive is to be processed
  354. }
  355. s = lbufPtr; // start expanding macros here
  356. s = removeMacros(s); // remove and expand macros in string s
  357. return(s);
  358. }
  359. // getDirType()
  360. //
  361. // arguments: s - pointer to buffer that has directive text.
  362. // dirType - pointer to unsigned char that gets set
  363. // with directive type.
  364. //
  365. // actions : goes past directive keyword, sets the type code and
  366. // returns a pointer to rest of test.
  367. char *
  368. getDirType(
  369. char *s,
  370. UCHAR *dirType
  371. )
  372. {
  373. char *t;
  374. int len;
  375. *dirType = 0;
  376. for (t = s; *t && !WHITESPACE(*t); ++t);
  377. len = (int) (t - s); // store len of directive
  378. while (*t && WHITESPACE(*t)) {
  379. ++t; // go past directive keyword
  380. } if (!_tcsnicmp(s, "INCLUDE", 7) && (len == 7)) {
  381. *dirType = INCLUDE;
  382. } else if (!_tcsnicmp(s, "CMDSWITCHES", 11) && (len == 11)) {
  383. *dirType = CMDSWITCHES;
  384. } else if (!_tcsnicmp(s, "ERROR", 5) && (len == 5)) {
  385. *dirType = ERROR;
  386. } else if (!_tcsnicmp(s, "MESSAGE", 7) && (len == 7)) {
  387. *dirType = MESSAGE;
  388. } else if (!_tcsnicmp(s, "UNDEF", 5) && (len == 5)) {
  389. *dirType = UNDEF;
  390. } else {
  391. *dirType = ifsPresent(s, len, &t) ; // directive one of "if"s?
  392. }
  393. if (!*dirType) {
  394. makeError(line, SYNTAX_BAD_DIRECTIVE, lbufPtr);
  395. }
  396. return(t);
  397. }
  398. // processCmdSwitches() -- processes command line switches in makefiles
  399. //
  400. // arguments: t pointer to flag settings specified.
  401. //
  402. // actions : sets or resets global flags as specified in the directive.
  403. // The allowed flags are:
  404. // s - silent mode, d - debug output (dates printed)
  405. // n - no execute mode, i - ignore error returns from commands
  406. // u - dump inline files
  407. // If parsing tools.ini, can also handle epqtbc
  408. // reports a bad directive error for any other flags
  409. // specified
  410. //
  411. // modifies : nothing
  412. //
  413. // returns : nothing
  414. void
  415. processCmdSwitches(
  416. char *t // pointer to switch values
  417. )
  418. {
  419. for (; *t; ++t) { // ignore errors in flags specified
  420. switch (*t) {
  421. case '+':
  422. while (*++t && *t != '-') {
  423. if (_tcschr("DINSU", (unsigned short)_totupper(*t))) {
  424. setFlags(*t, TRUE);
  425. } else if (init && _tcschr("ABCEKLPQRTY", (unsigned short)_totupper(*t))) {
  426. setFlags(*t, TRUE);
  427. } else {
  428. makeError(line, SYNTAX_BAD_CMDSWITCHES);
  429. }
  430. }
  431. if (!*t) {
  432. break;
  433. }
  434. case '-':
  435. while (*++t && *t != '+') {
  436. if (_tcschr("DINSU", (unsigned short)_totupper(*t))) {
  437. setFlags(*t, FALSE);
  438. } else if (init && _tcschr("ABCEKLMPQRTV", (unsigned short)_totupper(*t))) {
  439. setFlags(*t, FALSE);
  440. } else {
  441. makeError(line, SYNTAX_BAD_CMDSWITCHES);
  442. }
  443. }
  444. break;
  445. default:
  446. if (!WHITESPACE(*t)) {
  447. makeError(line, SYNTAX_BAD_CMDSWITCHES);
  448. }
  449. break;
  450. }
  451. if (!*t) {
  452. break;
  453. }
  454. }
  455. }
  456. // ifsPresent() -- checks if current directive is one of the "if"s
  457. //
  458. // arguments: s pointer to buffer with directive name in it
  459. // len length of the directive that was seen
  460. // t pointer to address upto which processed
  461. //
  462. // actions : does a string compare in the buffer for one of the
  463. // directive keywords. If string matches true, it returns
  464. // a non-zero value, the code for the specific directive
  465. //
  466. // modifies : nothing
  467. //
  468. // returns : a zero if no match, or the code for directive found.
  469. UCHAR
  470. ifsPresent(
  471. char *s,
  472. unsigned len,
  473. char **t
  474. )
  475. {
  476. UCHAR ifFlags = 0; // takes non-zero value when one of
  477. // if/else etc is to be processed
  478. if (!_tcsnicmp(s, "IF", 2) && (len == 2)) {
  479. ifFlags = IF_TYPE;
  480. } else if (!_tcsnicmp(s, "IFDEF", 5) && (len == 5)) {
  481. ifFlags = IFDEF_TYPE;
  482. } else if (!_tcsnicmp(s, "IFNDEF", 6) && (len == 6)) {
  483. ifFlags = IFNDEF_TYPE;
  484. } else if (!_tcsnicmp(s, "ELSE", 4) && (len == 4)) {
  485. // 'else' or 'else if' or 'else ifdef' or 'else ifndef'
  486. char *p = *t;
  487. if (!*p) {
  488. ifFlags = ELSE_TYPE;
  489. } else {
  490. for (s = p; *p && !WHITESPACE(*p); p++)
  491. ;
  492. len = (unsigned) (p - s);
  493. while (*p && WHITESPACE(*p)) {
  494. p++;
  495. }
  496. *t = p;
  497. if (!_tcsnicmp(s, "IF", 2) && (len == 2)) {
  498. ifFlags = ELSE_IF_TYPE;
  499. } else if (!_tcsnicmp(s, "IFDEF", 5) && (len == 5)) {
  500. ifFlags = ELSE_IFDEF_TYPE;
  501. } else if (!_tcsnicmp(s, "IFNDEF", 6) && (len == 6)) {
  502. ifFlags = ELSE_IFNDEF_TYPE;
  503. }
  504. }
  505. }
  506. else if (!_tcsnicmp(s, "ELSEIF", 6) && (len == 6)) {
  507. ifFlags = ELSE_IF_TYPE;
  508. }
  509. else if (!_tcsnicmp(s, "ELSEIFDEF", 9) && (len == 9)) {
  510. ifFlags = ELSE_IFDEF_TYPE;
  511. }
  512. else if (!_tcsnicmp(s, "ELSEIFNDEF", 10) && (len == 10)) {
  513. ifFlags = ELSE_IFNDEF_TYPE;
  514. }
  515. else if (!_tcsnicmp(s, "ENDIF", 5) && (len == 5)) {
  516. ifFlags = ENDIF_TYPE;
  517. }
  518. return(ifFlags);
  519. }
  520. // processIfs() -- sets up / changes state information on "if"s
  521. //
  522. // arguments: s pointer to "if" expression ( don't care
  523. // for "endif" )
  524. //
  525. // kind code indicating if processing if/else/ifdef etc.
  526. //
  527. // actions : modifies a stack (ifStack) by pushing/popping or
  528. // sets/resets bits in the top element on the
  529. // stack(examining the previous element pushed if
  530. // required).
  531. // case (kind) of
  532. // IF
  533. // IFDEF
  534. // IFNDEF
  535. // IF defined() : if no more space on ifStack
  536. // (too many nesting levels) abort...
  537. // set IFELSE bit in elt.
  538. // push elt on ifStack.
  539. // if more than one elt on stack
  540. // and outer level "ifelse" false
  541. // set IGNORE bit, skipToNextDirective
  542. // else
  543. // evaluate expression of
  544. // current "if"
  545. // if expr true set CONDITION bit in elt
  546. // else skipToNextDirective.
  547. // ELSE : if no elt on stack or previous
  548. // directive was "else", flag error, abort
  549. // clear IFELSE bit in elt on stack.
  550. // if current ifelse block is to
  551. // be skipped (IGNORE bit is on
  552. // in outer level if/else),skip...
  553. // else FLIP condition bit.
  554. // if "else" part is false
  555. // skipToNextDirective.
  556. // ENDIF : if no elt on stack, flag error,abort
  557. // pop an elt from ifStack.
  558. // if there are elts on stack
  559. // and we are in a "false" block
  560. // skipToNextDirective.
  561. // end case
  562. //
  563. // modifies: ifStack if directives' stack, static to this module
  564. // ifTop index of current element at top of stack
  565. // line lexer's line count (thru calls to
  566. // skipToNextDirective())
  567. //
  568. // returns : nothing
  569. void
  570. processIfs(
  571. char *s,
  572. UCHAR kind
  573. )
  574. {
  575. UCHAR element; // has its bits set and is pushed on the ifStack
  576. switch (kind) {
  577. case IF_TYPE:
  578. case IFDEF_TYPE:
  579. case IFNDEF_TYPE:
  580. if (ifTop == IFSTACKSIZE-1) {
  581. makeError(line, SYNTAX_TOO_MANY_IFS);
  582. }
  583. element = (UCHAR) 0;
  584. SET(element, NMIFELSE);
  585. pushIfStk(element);
  586. if (ifTop && OFF(ifStack[ifTop-1], NMCONDITION)) {
  587. SET(ifStkTop(), NMIGNORE);
  588. skipToNextDirective();
  589. } else if (evalExpr(s, kind)) {
  590. SET(ifStkTop(), NMCONDITION);
  591. } else {
  592. skipToNextDirective();
  593. }
  594. break;
  595. case ELSE_TYPE:
  596. if ((ifTop < 0) || (OFF(ifStkTop(), NMIFELSE) && OFF(ifStkTop(), NMELSEIF))) {
  597. makeError(line, SYNTAX_UNEXPECTED_ELSE);
  598. }
  599. CLEAR(ifStkTop(), NMIFELSE);
  600. CLEAR(ifStkTop(), NMELSEIF);
  601. if (ON(ifStkTop(), NMIGNORE)) {
  602. skipToNextDirective();
  603. } else {
  604. FLIP(ifStkTop(), NMCONDITION);
  605. if (OFF(ifStkTop(), NMCONDITION)) {
  606. skipToNextDirective();
  607. }
  608. }
  609. break;
  610. case ELSE_IF_TYPE:
  611. case ELSE_IFDEF_TYPE:
  612. case ELSE_IFNDEF_TYPE:
  613. if ((ifTop < 0) || (OFF(ifStkTop(), NMIFELSE) && OFF(ifStkTop(), NMELSEIF))) {
  614. makeError(line, SYNTAX_UNEXPECTED_ELSE);
  615. }
  616. CLEAR(ifStkTop(), NMIFELSE);
  617. SET(ifStkTop(), NMELSEIF);
  618. if (ON(ifStkTop(), NMIGNORE)) {
  619. skipToNextDirective();
  620. } else {
  621. if (ON(ifStkTop(), NMCONDITION)) {
  622. SET(ifStkTop(), NMIGNORE);
  623. CLEAR(ifStkTop(), NMCONDITION);
  624. skipToNextDirective();
  625. } else if (evalExpr(s, kind)) {
  626. SET(ifStkTop(), NMCONDITION);
  627. } else {
  628. skipToNextDirective();
  629. }
  630. }
  631. break;
  632. case ENDIF_TYPE:
  633. if (ifTop < 0) {
  634. makeError(line, SYNTAX_UNEXPECTED_ENDIF);
  635. }
  636. popIfStk();
  637. if (ifTop >= 0) {
  638. if (OFF(ifStkTop(), NMCONDITION)) {
  639. skipToNextDirective();
  640. }
  641. }
  642. default:
  643. break; // default should never happen
  644. }
  645. }
  646. // skipToNextDirective() -- skips to next line that has '!' in column zero
  647. //
  648. // actions : gets first char of the line to be skipped if it is
  649. // not a directive ( has no '!' on column zero ).
  650. // a "line" that is skipped may in fact span many
  651. // lines ( by using sp-backslash-nl to continue...)
  652. // comments in colZero are skipped as part of the previous
  653. // line ('#' or ';' in tools.ini)
  654. // comment char '#' elsewhere in line implies the end of
  655. // that line (with the next newline / EOF)
  656. // if a '!' is found in colZero, read in the next directive
  657. // if the directive is NOT one of if/ifdef/ifndef/else/
  658. // endif, keep skipping more lines and look for the
  659. // next directive ( go to top of the routine here ).
  660. // if EOF found before next directive, report error.
  661. //
  662. // modifies : line global lexer line count
  663. //
  664. // returns : nothing
  665. void
  666. skipToNextDirective()
  667. {
  668. register int c;
  669. UCHAR type;
  670. repeat:
  671. for (c = GetTxtChr(file); (c != '!') && (c != EOF) ;c = GetTxtChr(file)) {
  672. ++line; // lexer's line count
  673. do {
  674. if (c == '\\') {
  675. c = skipBackSlash(c, FROMSTREAM);
  676. if (c == '!' && colZero) {
  677. break;
  678. } else {
  679. colZero = FALSE;
  680. }
  681. }
  682. if ((c == '#') || (c == '\n') || (c == EOF)) {
  683. break;
  684. }
  685. c = GetTxtChr(file);
  686. } while (TRUE);
  687. if (c == '#') {
  688. for (c = GetTxtChr(file); (c != '\n') && (c != EOF); c = GetTxtChr(file))
  689. ;
  690. }
  691. if ((c == EOF) || (c == '!')) {
  692. break;
  693. }
  694. }
  695. if (c == '!') {
  696. if (prevDirPtr && (prevDirPtr != lbufPtr)) {
  697. FREE(prevDirPtr);
  698. }
  699. prevDirPtr = readInOneLine();
  700. getDirType(prevDirPtr, &type);
  701. if (type > ENDIF_TYPE) { // type is NOT one of the "if"s
  702. ++line;
  703. goto repeat;
  704. }
  705. } else if (c == EOF) {
  706. makeError(line, SYNTAX_EOF_NO_DIRECTIVE);
  707. }
  708. }