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.

778 lines
26 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. lbufPtr = (char *) REALLOC(lbufPtr, lbufSize+1);
  337. if (!lbufPtr)
  338. makeError(line, MACRO_TOO_LONG);
  339. }
  340. }
  341. *(lbufPtr + (index++)) = (char) c;
  342. }
  343. *(lbufPtr + index) = '\0'; // null terminate the string
  344. if (c == '#') {
  345. for(c = GetTxtChr(file); (c != '\n') && (c != EOF); c = GetTxtChr(file))
  346. ;
  347. // newline at end is eaten up
  348. }
  349. if (c == EOF) {
  350. UngetTxtChr(c, file); // this directive is to be processed
  351. }
  352. s = lbufPtr; // start expanding macros here
  353. s = removeMacros(s); // remove and expand macros in string s
  354. return(s);
  355. }
  356. // getDirType()
  357. //
  358. // arguments: s - pointer to buffer that has directive text.
  359. // dirType - pointer to unsigned char that gets set
  360. // with directive type.
  361. //
  362. // actions : goes past directive keyword, sets the type code and
  363. // returns a pointer to rest of test.
  364. char *
  365. getDirType(
  366. char *s,
  367. UCHAR *dirType
  368. )
  369. {
  370. char *t;
  371. int len;
  372. *dirType = 0;
  373. for (t = s; *t && !WHITESPACE(*t); ++t);
  374. len = (int) (t - s); // store len of directive
  375. while (*t && WHITESPACE(*t)) {
  376. ++t; // go past directive keyword
  377. } if (!_tcsnicmp(s, "INCLUDE", 7) && (len == 7)) {
  378. *dirType = INCLUDE;
  379. } else if (!_tcsnicmp(s, "CMDSWITCHES", 11) && (len == 11)) {
  380. *dirType = CMDSWITCHES;
  381. } else if (!_tcsnicmp(s, "ERROR", 5) && (len == 5)) {
  382. *dirType = ERROR;
  383. } else if (!_tcsnicmp(s, "MESSAGE", 7) && (len == 7)) {
  384. *dirType = MESSAGE;
  385. } else if (!_tcsnicmp(s, "UNDEF", 5) && (len == 5)) {
  386. *dirType = UNDEF;
  387. } else {
  388. *dirType = ifsPresent(s, len, &t) ; // directive one of "if"s?
  389. }
  390. if (!*dirType) {
  391. makeError(line, SYNTAX_BAD_DIRECTIVE, lbufPtr);
  392. }
  393. return(t);
  394. }
  395. // processCmdSwitches() -- processes command line switches in makefiles
  396. //
  397. // arguments: t pointer to flag settings specified.
  398. //
  399. // actions : sets or resets global flags as specified in the directive.
  400. // The allowed flags are:
  401. // s - silent mode, d - debug output (dates printed)
  402. // n - no execute mode, i - ignore error returns from commands
  403. // u - dump inline files
  404. // If parsing tools.ini, can also handle epqtbc
  405. // reports a bad directive error for any other flags
  406. // specified
  407. //
  408. // modifies : nothing
  409. //
  410. // returns : nothing
  411. void
  412. processCmdSwitches(
  413. char *t // pointer to switch values
  414. )
  415. {
  416. for (; *t; ++t) { // ignore errors in flags specified
  417. switch (*t) {
  418. case '+':
  419. while (*++t && *t != '-') {
  420. if (_tcschr("DINSU", (unsigned short)_totupper(*t))) {
  421. setFlags(*t, TRUE);
  422. } else if (init && _tcschr("ABCEKLPQRTY", (unsigned short)_totupper(*t))) {
  423. setFlags(*t, TRUE);
  424. } else {
  425. makeError(line, SYNTAX_BAD_CMDSWITCHES);
  426. }
  427. }
  428. if (!*t) {
  429. break;
  430. }
  431. case '-':
  432. while (*++t && *t != '+') {
  433. if (_tcschr("DINSU", (unsigned short)_totupper(*t))) {
  434. setFlags(*t, FALSE);
  435. } else if (init && _tcschr("ABCEKLMPQRTV", (unsigned short)_totupper(*t))) {
  436. setFlags(*t, FALSE);
  437. } else {
  438. makeError(line, SYNTAX_BAD_CMDSWITCHES);
  439. }
  440. }
  441. break;
  442. default:
  443. if (!WHITESPACE(*t)) {
  444. makeError(line, SYNTAX_BAD_CMDSWITCHES);
  445. }
  446. break;
  447. }
  448. if (!*t) {
  449. break;
  450. }
  451. }
  452. }
  453. // ifsPresent() -- checks if current directive is one of the "if"s
  454. //
  455. // arguments: s pointer to buffer with directive name in it
  456. // len length of the directive that was seen
  457. // t pointer to address upto which processed
  458. //
  459. // actions : does a string compare in the buffer for one of the
  460. // directive keywords. If string matches true, it returns
  461. // a non-zero value, the code for the specific directive
  462. //
  463. // modifies : nothing
  464. //
  465. // returns : a zero if no match, or the code for directive found.
  466. UCHAR
  467. ifsPresent(
  468. char *s,
  469. unsigned len,
  470. char **t
  471. )
  472. {
  473. UCHAR ifFlags = 0; // takes non-zero value when one of
  474. // if/else etc is to be processed
  475. if (!_tcsnicmp(s, "IF", 2) && (len == 2)) {
  476. ifFlags = IF_TYPE;
  477. } else if (!_tcsnicmp(s, "IFDEF", 5) && (len == 5)) {
  478. ifFlags = IFDEF_TYPE;
  479. } else if (!_tcsnicmp(s, "IFNDEF", 6) && (len == 6)) {
  480. ifFlags = IFNDEF_TYPE;
  481. } else if (!_tcsnicmp(s, "ELSE", 4) && (len == 4)) {
  482. // 'else' or 'else if' or 'else ifdef' or 'else ifndef'
  483. char *p = *t;
  484. if (!*p) {
  485. ifFlags = ELSE_TYPE;
  486. } else {
  487. for (s = p; *p && !WHITESPACE(*p); p++)
  488. ;
  489. len = (unsigned) (p - s);
  490. while (*p && WHITESPACE(*p)) {
  491. p++;
  492. }
  493. *t = p;
  494. if (!_tcsnicmp(s, "IF", 2) && (len == 2)) {
  495. ifFlags = ELSE_IF_TYPE;
  496. } else if (!_tcsnicmp(s, "IFDEF", 5) && (len == 5)) {
  497. ifFlags = ELSE_IFDEF_TYPE;
  498. } else if (!_tcsnicmp(s, "IFNDEF", 6) && (len == 6)) {
  499. ifFlags = ELSE_IFNDEF_TYPE;
  500. }
  501. }
  502. }
  503. else if (!_tcsnicmp(s, "ELSEIF", 6) && (len == 6)) {
  504. ifFlags = ELSE_IF_TYPE;
  505. }
  506. else if (!_tcsnicmp(s, "ELSEIFDEF", 9) && (len == 9)) {
  507. ifFlags = ELSE_IFDEF_TYPE;
  508. }
  509. else if (!_tcsnicmp(s, "ELSEIFNDEF", 10) && (len == 10)) {
  510. ifFlags = ELSE_IFNDEF_TYPE;
  511. }
  512. else if (!_tcsnicmp(s, "ENDIF", 5) && (len == 5)) {
  513. ifFlags = ENDIF_TYPE;
  514. }
  515. return(ifFlags);
  516. }
  517. // processIfs() -- sets up / changes state information on "if"s
  518. //
  519. // arguments: s pointer to "if" expression ( don't care
  520. // for "endif" )
  521. //
  522. // kind code indicating if processing if/else/ifdef etc.
  523. //
  524. // actions : modifies a stack (ifStack) by pushing/popping or
  525. // sets/resets bits in the top element on the
  526. // stack(examining the previous element pushed if
  527. // required).
  528. // case (kind) of
  529. // IF
  530. // IFDEF
  531. // IFNDEF
  532. // IF defined() : if no more space on ifStack
  533. // (too many nesting levels) abort...
  534. // set IFELSE bit in elt.
  535. // push elt on ifStack.
  536. // if more than one elt on stack
  537. // and outer level "ifelse" false
  538. // set IGNORE bit, skipToNextDirective
  539. // else
  540. // evaluate expression of
  541. // current "if"
  542. // if expr true set CONDITION bit in elt
  543. // else skipToNextDirective.
  544. // ELSE : if no elt on stack or previous
  545. // directive was "else", flag error, abort
  546. // clear IFELSE bit in elt on stack.
  547. // if current ifelse block is to
  548. // be skipped (IGNORE bit is on
  549. // in outer level if/else),skip...
  550. // else FLIP condition bit.
  551. // if "else" part is false
  552. // skipToNextDirective.
  553. // ENDIF : if no elt on stack, flag error,abort
  554. // pop an elt from ifStack.
  555. // if there are elts on stack
  556. // and we are in a "false" block
  557. // skipToNextDirective.
  558. // end case
  559. //
  560. // modifies: ifStack if directives' stack, static to this module
  561. // ifTop index of current element at top of stack
  562. // line lexer's line count (thru calls to
  563. // skipToNextDirective())
  564. //
  565. // returns : nothing
  566. void
  567. processIfs(
  568. char *s,
  569. UCHAR kind
  570. )
  571. {
  572. UCHAR element; // has its bits set and is pushed on the ifStack
  573. switch (kind) {
  574. case IF_TYPE:
  575. case IFDEF_TYPE:
  576. case IFNDEF_TYPE:
  577. if (ifTop == IFSTACKSIZE-1) {
  578. makeError(line, SYNTAX_TOO_MANY_IFS);
  579. }
  580. element = (UCHAR) 0;
  581. SET(element, NMIFELSE);
  582. pushIfStk(element);
  583. if (ifTop && OFF(ifStack[ifTop-1], NMCONDITION)) {
  584. SET(ifStkTop(), NMIGNORE);
  585. skipToNextDirective();
  586. } else if (evalExpr(s, kind)) {
  587. SET(ifStkTop(), NMCONDITION);
  588. } else {
  589. skipToNextDirective();
  590. }
  591. break;
  592. case ELSE_TYPE:
  593. if ((ifTop < 0) || (OFF(ifStkTop(), NMIFELSE) && OFF(ifStkTop(), NMELSEIF))) {
  594. makeError(line, SYNTAX_UNEXPECTED_ELSE);
  595. }
  596. CLEAR(ifStkTop(), NMIFELSE);
  597. CLEAR(ifStkTop(), NMELSEIF);
  598. if (ON(ifStkTop(), NMIGNORE)) {
  599. skipToNextDirective();
  600. } else {
  601. FLIP(ifStkTop(), NMCONDITION);
  602. if (OFF(ifStkTop(), NMCONDITION)) {
  603. skipToNextDirective();
  604. }
  605. }
  606. break;
  607. case ELSE_IF_TYPE:
  608. case ELSE_IFDEF_TYPE:
  609. case ELSE_IFNDEF_TYPE:
  610. if ((ifTop < 0) || (OFF(ifStkTop(), NMIFELSE) && OFF(ifStkTop(), NMELSEIF))) {
  611. makeError(line, SYNTAX_UNEXPECTED_ELSE);
  612. }
  613. CLEAR(ifStkTop(), NMIFELSE);
  614. SET(ifStkTop(), NMELSEIF);
  615. if (ON(ifStkTop(), NMIGNORE)) {
  616. skipToNextDirective();
  617. } else {
  618. if (ON(ifStkTop(), NMCONDITION)) {
  619. SET(ifStkTop(), NMIGNORE);
  620. CLEAR(ifStkTop(), NMCONDITION);
  621. skipToNextDirective();
  622. } else if (evalExpr(s, kind)) {
  623. SET(ifStkTop(), NMCONDITION);
  624. } else {
  625. skipToNextDirective();
  626. }
  627. }
  628. break;
  629. case ENDIF_TYPE:
  630. if (ifTop < 0) {
  631. makeError(line, SYNTAX_UNEXPECTED_ENDIF);
  632. }
  633. popIfStk();
  634. if (ifTop >= 0) {
  635. if (OFF(ifStkTop(), NMCONDITION)) {
  636. skipToNextDirective();
  637. }
  638. }
  639. default:
  640. break; // default should never happen
  641. }
  642. }
  643. // skipToNextDirective() -- skips to next line that has '!' in column zero
  644. //
  645. // actions : gets first char of the line to be skipped if it is
  646. // not a directive ( has no '!' on column zero ).
  647. // a "line" that is skipped may in fact span many
  648. // lines ( by using sp-backslash-nl to continue...)
  649. // comments in colZero are skipped as part of the previous
  650. // line ('#' or ';' in tools.ini)
  651. // comment char '#' elsewhere in line implies the end of
  652. // that line (with the next newline / EOF)
  653. // if a '!' is found in colZero, read in the next directive
  654. // if the directive is NOT one of if/ifdef/ifndef/else/
  655. // endif, keep skipping more lines and look for the
  656. // next directive ( go to top of the routine here ).
  657. // if EOF found before next directive, report error.
  658. //
  659. // modifies : line global lexer line count
  660. //
  661. // returns : nothing
  662. void
  663. skipToNextDirective()
  664. {
  665. register int c;
  666. UCHAR type;
  667. repeat:
  668. for (c = GetTxtChr(file); (c != '!') && (c != EOF) ;c = GetTxtChr(file)) {
  669. ++line; // lexer's line count
  670. do {
  671. if (c == '\\') {
  672. c = skipBackSlash(c, FROMSTREAM);
  673. if (c == '!' && colZero) {
  674. break;
  675. } else {
  676. colZero = FALSE;
  677. }
  678. }
  679. if ((c == '#') || (c == '\n') || (c == EOF)) {
  680. break;
  681. }
  682. c = GetTxtChr(file);
  683. } while (TRUE);
  684. if (c == '#') {
  685. for (c = GetTxtChr(file); (c != '\n') && (c != EOF); c = GetTxtChr(file))
  686. ;
  687. }
  688. if ((c == EOF) || (c == '!')) {
  689. break;
  690. }
  691. }
  692. if (c == '!') {
  693. if (prevDirPtr && (prevDirPtr != lbufPtr)) {
  694. FREE(prevDirPtr);
  695. }
  696. prevDirPtr = readInOneLine();
  697. getDirType(prevDirPtr, &type);
  698. if (type > ENDIF_TYPE) { // type is NOT one of the "if"s
  699. ++line;
  700. goto repeat;
  701. }
  702. } else if (c == EOF) {
  703. makeError(line, SYNTAX_EOF_NO_DIRECTIVE);
  704. }
  705. }