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.

594 lines
18 KiB

  1. /***
  2. *eval.c - if expression evaluator
  3. *
  4. * Copyright (c) 1992-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * produce truth values and simplified conditions from compound if
  8. * statements.
  9. *
  10. *Revision History:
  11. * 09-30-92 MAL Original version
  12. * 10-13-93 SKS Recognize comments of the form /-*IFSTRIP=IGN*-/ to
  13. * override ifstrip behavior.
  14. * 09-01-94 SKS Add support for more operators: == != < > <= >=
  15. * Add terseflag (-t) to suppress mesgs about directives
  16. * 10-04-94 SKS Add support for more operators: EQ NE LT GT LE NE
  17. * @ is an identifier character (e.g., MASM's @Version)
  18. * 01-04-00 GB Add support for internal crt builds
  19. *
  20. *******************************************************************************/
  21. #include <stdio.h>
  22. #include <ctype.h>
  23. #include <string.h>
  24. #include <stdlib.h>
  25. #include "eval.h" /* Header for this module */
  26. #include "symtab.h" /* Symbol table access */
  27. #include "constant.h" /* Constants for tokens etc */
  28. #include "errormes.h" /* Errors and Warning messages */
  29. /* Types */
  30. typedef struct condrec
  31. {
  32. int truth;
  33. char *condition;
  34. } condrec, *cond;
  35. /* Global variables */
  36. extern int terseFlag; /* controls display of forced directives */
  37. extern char **comments; /* Language dependent comment strings */
  38. extern int *commlen; /* Lengths of above strings */
  39. extern int nonumbers; /* allow numeric expressions */
  40. extern enum {NON_CRT = 0, CRT = 1} progtype;
  41. char *operators[] = {
  42. "!", "(", ")", "||", "&&", "defined" ,
  43. "==" , "!=" , "<" , ">" , "<=" , ">=" ,
  44. "EQ" , "NE" , "LT" , "GT" , "LE" , "GE" };
  45. int oplengths[] = {
  46. 1 , 1 , 1 , 2 , 2 , 7 ,
  47. 2 , 2 , 1 , 1 , 2 , 2 ,
  48. 2 , 2 , 2 , 2 , 2 , 2 };
  49. /* # significant chars */
  50. #define numoperators 18
  51. /* These tokens must be in the same order as 'operators' */
  52. #define NOT 0
  53. #define OPENPARENTHESIS 1
  54. #define CLOSEPARENTHESIS 2
  55. #define OR 3
  56. #define AND 4
  57. #define DEFINEDFN 5
  58. #define EQUALS 6
  59. #define NOTEQUALS 7
  60. #define LESSTHAN 8
  61. #define LESSOREQ 9
  62. #define GREATERTHAN 10
  63. #define GREATEROREQ 11
  64. #define EQUALS_ASM 12
  65. #define NOTEQUALS_ASM 13
  66. #define LESSTHAN_ASM 14
  67. #define LESSOREQ_ASM 15
  68. #define GREATERTHAN_ASM 16
  69. #define GREATEROREQ_ASM 17
  70. #define UINT 100
  71. #define ID 101
  72. #define ENDOFLINE 102
  73. #define UNKNOWN 103
  74. /* Global state */
  75. /* String holding input, the current pointer into it, and the current token */
  76. char conditions[MAXLINELEN], *tokenptr, currenttoken[MAXCONDLEN];
  77. int token = -1;
  78. /* Function prototypes */
  79. cond evaluateexpression(void);
  80. cond orexpression(void);
  81. cond andexpression(void);
  82. cond unaryexpression(void);
  83. cond parenthesesexpression(void);
  84. cond atomicexpression(void);
  85. cond createcondition(void);
  86. void destroycondition(cond);
  87. char *createstring(int);
  88. void destroystring(char *);
  89. void gettoken(void);
  90. int issymbolchar(char);
  91. /* CFW - added complex expression warning */
  92. void evalwarn()
  93. {
  94. warning("cannot parse expression - ignoring", conditions);
  95. }
  96. /*
  97. * Comments may be in the input source which contain IFSTRIP Directives:
  98. *
  99. * For C source they should look like:
  100. *
  101. * #if foo>bar !*IFSTRIP=DEF*! '!' here stands for '/'
  102. *
  103. * and for Assembler source they should look like:
  104. *
  105. * if foo ;;IFSTRIP=UND;;
  106. *
  107. * Note that the directive and an optional preceding blank or tab
  108. * are deleted from the input source. The directive can thus be
  109. * followed by a backslash to continue the line, another comment, etc.
  110. */
  111. static char IfStripCStr[] =
  112. "/*IFSTRIP="; /* -*IFSTRIP=IGN*- */
  113. static char IfStripAStr[] =
  114. /*0123456789*- -* 0123456789012345 */
  115. ";;IFSTRIP="; /* ;;IFSTRIP=IGN;; */
  116. /* IGN may also be DEF or UND */
  117. #define IFSTRIPVALOFF 10
  118. #define IFSTRIPVALEND 13
  119. #define IFSTRIPVALLEN 15
  120. void evaluate(char *outputstring, int *value, char *inputstring)
  121. {
  122. int forcevalue = IGNORE;
  123. cond result;
  124. strcpy(conditions, inputstring); /* Prepare the string for tokenising */
  125. tokenptr = conditions;
  126. gettoken(); /* Read in the first token of input */
  127. result = evaluateexpression();
  128. /* check for bad/complex expression */
  129. if (token != ENDOFLINE)
  130. {
  131. char *adir = NULL;
  132. char *cdir = NULL;
  133. if(((cdir = strstr(inputstring, IfStripCStr)) && cdir[IFSTRIPVALEND] == '*' && cdir[IFSTRIPVALEND+1] == '/')
  134. || ((adir = strstr(inputstring, IfStripAStr)) && adir[IFSTRIPVALEND] == ';' && adir[IFSTRIPVALEND+1] == ';'))
  135. {
  136. char *pstr;
  137. char *ifstr;
  138. /* fprintf(stderr,"<< evaluate(): (%s)\n", inputstring); */
  139. pstr = ifstr = ( adir ? adir : cdir ) ;
  140. /*
  141. * Have recognized the /-*-IFSTRIP= directive, interpret its argument
  142. * and remove the directive comment from the input/output text.
  143. * Back up exactly one white space character (blank or tab) if possible.
  144. */
  145. if(pstr > inputstring && (pstr[-1] == '\t' || pstr[-1] == ' '))
  146. -- pstr;
  147. if(!memcmp(ifstr+IFSTRIPVALOFF, "DEF", 3)) /* DEFINED */
  148. forcevalue = DEFINED;
  149. else if(!memcmp(ifstr+IFSTRIPVALOFF, "UND", 3)) /* UNDEFINED */
  150. forcevalue = UNDEFINED;
  151. else if(memcmp(ifstr+IFSTRIPVALOFF, "IGN", 3)) /* IGNORE */
  152. warning("cannot recognize IFSTRIP: directive - ignoring", conditions);
  153. /* else "IGNORE" -- forcevalue is already set by default to IGNORE */
  154. if(!terseFlag)
  155. warning("ifstrip directive forced evaluation", conditions);
  156. /* remove the directive comment (and preceding blank or tab) from the input line */
  157. strcpy(pstr, ifstr + IFSTRIPVALLEN); /* "C" comments have closing -*-/- */
  158. /* fprintf(stderr,">> evaluate(): (%s)\n", inputstring); */
  159. }
  160. else
  161. evalwarn();
  162. if (result)
  163. {
  164. destroycondition(result);
  165. result = NULL;
  166. }
  167. }
  168. /* bad/complex expression, return IGNORE and entire expression */
  169. if (!result)
  170. {
  171. *value = forcevalue;
  172. strcpy(outputstring, inputstring);
  173. return;
  174. }
  175. *value = result -> truth;
  176. if(!result -> condition)
  177. * outputstring = '\0';
  178. else
  179. strcpy(outputstring, result -> condition);
  180. /* Convert from internal to external representation */
  181. destroycondition(result);
  182. }
  183. cond evaluateexpression()
  184. {
  185. return orexpression();
  186. }
  187. cond orexpression()
  188. {
  189. cond condition1, condition2;
  190. char *output;
  191. condition1 = andexpression();
  192. if (!condition1)
  193. return NULL;
  194. while (token == OR)
  195. {
  196. gettoken();
  197. condition2 = andexpression();
  198. if (!condition2)
  199. {
  200. destroycondition(condition1);
  201. return NULL;
  202. }
  203. switch (condition1 -> truth)
  204. {
  205. case DEFINED: /* DEFINED || x == DEFINED */
  206. /* condition1 set up correctly for next pass */
  207. destroycondition(condition2);
  208. break;
  209. case UNDEFINED:
  210. switch (condition2 -> truth)
  211. {
  212. case DEFINED: /* UNDEFINED || DEFINED == DEFINED */
  213. destroycondition(condition1);
  214. condition1 = condition2;
  215. break;
  216. case UNDEFINED: /* UNDEFINED || UNDEFINED == UNDEFINED */
  217. destroycondition(condition2);
  218. /* condition1 set up correctly for next pass */
  219. break;
  220. case IGNORE: /* UNDEFINED || IGNORE == IGNORE */
  221. destroycondition(condition1);
  222. condition1 = condition2;
  223. break;
  224. }
  225. break;
  226. case IGNORE:
  227. switch (condition2 -> truth)
  228. {
  229. case DEFINED: /* IGNORE || DEFINED == DEFINED */
  230. destroycondition(condition1);
  231. condition1 = condition2;
  232. break;
  233. case UNDEFINED: /* IGNORE || UNDEFINED == IGNORE */
  234. /* condition1 set up correctly for next pass */
  235. destroycondition(condition2);
  236. break;
  237. case IGNORE: /* IGNORE || IGNORE == IGNORE */
  238. output = createstring(strlen(condition1 -> condition)
  239. + strlen (condition2 -> condition)
  240. + (sizeof(" || ") - 1));
  241. strcpy(output, condition1 -> condition);
  242. strcat(output, " || ");
  243. strcat(output, condition2 -> condition);
  244. /* Build up the condition string */
  245. destroystring(condition1 -> condition);
  246. condition1 -> condition = output;
  247. /* Place the new string in condition1 */
  248. destroycondition(condition2);
  249. break;
  250. }
  251. break;
  252. }
  253. }
  254. return condition1;
  255. }
  256. cond andexpression()
  257. {
  258. cond condition1, condition2;
  259. char *output;
  260. condition1 = unaryexpression();
  261. if (!condition1)
  262. return NULL;
  263. while (token == AND)
  264. {
  265. gettoken();
  266. condition2 = unaryexpression();
  267. if (!condition2)
  268. {
  269. destroycondition(condition1);
  270. return NULL;
  271. }
  272. switch (condition1 -> truth)
  273. {
  274. case DEFINED:
  275. switch (condition2 -> truth)
  276. {
  277. case DEFINED: /* DEFINED && DEFINED == DEFINED */
  278. destroycondition(condition2);
  279. /* condition1 set up correctly for next pass */
  280. break;
  281. case UNDEFINED: /* DEFINED && UNDEFINED == UNDEFINED */
  282. destroycondition(condition1);
  283. condition1 = condition2;
  284. break;
  285. case IGNORE: /* DEFINED && IGNORE == IGNORE */
  286. destroycondition(condition1);
  287. condition1 = condition2;
  288. break;
  289. }
  290. break;
  291. case UNDEFINED: /* UNDEFINED && x == UNDEFINED */
  292. /* condition1 set up correctly for next pass */
  293. destroycondition(condition2);
  294. break;
  295. case IGNORE:
  296. switch (condition2 -> truth)
  297. {
  298. case DEFINED: /* IGNORE && DEFINED == IGNORE */
  299. /* condition1 set up correctly for next pass */
  300. destroycondition(condition2);
  301. break;
  302. case UNDEFINED: /* IGNORE && UNDEFINED == UNDEFINED */
  303. destroycondition(condition1);
  304. condition1 = condition2;
  305. break;
  306. case IGNORE: /* IGNORE && IGNORE == IGNORE */
  307. output = createstring(strlen(condition1 -> condition)
  308. + strlen (condition2 -> condition)
  309. + (sizeof(" && ") - 1));
  310. strcpy(output, condition1 -> condition);
  311. strcat(output, " && ");
  312. strcat(output, condition2 -> condition);
  313. /* Build up the condition string */
  314. destroystring(condition1 -> condition);
  315. condition1 -> condition = output;
  316. /* Place the new string in condition1 */
  317. destroycondition(condition2);
  318. break;
  319. }
  320. break;
  321. }
  322. }
  323. return condition1;
  324. }
  325. cond unaryexpression()
  326. {
  327. cond condition1;
  328. char *output;
  329. switch (token)
  330. {
  331. case NOT:
  332. gettoken();
  333. condition1 = unaryexpression();
  334. if (!condition1)
  335. return NULL;
  336. if ((condition1 -> truth) == IGNORE)
  337. {
  338. output = createstring(strlen(condition1 -> condition) + 1);
  339. *output = '!';
  340. strcpy(output + 1, condition1 -> condition);
  341. destroystring(condition1 -> condition);
  342. condition1 -> condition = output;
  343. }
  344. else
  345. condition1 -> truth = negatecondition(condition1 -> truth);
  346. break;
  347. case DEFINEDFN:
  348. gettoken();
  349. condition1 = parenthesesexpression();
  350. if (!condition1)
  351. return NULL;
  352. if ((condition1 -> truth) == IGNORE)
  353. {
  354. output = createstring(strlen(condition1 -> condition)
  355. + (sizeof("defined ") - 1));
  356. strcpy(output, "defined ");
  357. strcat(output, condition1 -> condition);
  358. destroystring(condition1 -> condition);
  359. condition1 -> condition = output;
  360. }
  361. break;
  362. default:
  363. condition1 = parenthesesexpression();
  364. if (!condition1)
  365. return NULL;
  366. break;
  367. }
  368. return condition1;
  369. }
  370. cond parenthesesexpression()
  371. {
  372. cond condition1;
  373. char *output;
  374. if (token == OPENPARENTHESIS)
  375. {
  376. gettoken();
  377. condition1 = evaluateexpression();
  378. if (!condition1)
  379. return NULL;
  380. if (token != CLOSEPARENTHESIS)
  381. {
  382. /* check for bad/complex expression */
  383. evalwarn();
  384. destroycondition(condition1);
  385. return NULL;
  386. }
  387. gettoken();
  388. if ((condition1 -> truth) == IGNORE)
  389. {
  390. output = createstring(strlen(condition1 -> condition) + 2);
  391. *output = '(';
  392. strcpy(output + 1, condition1 -> condition);
  393. strcat(output, ")");
  394. destroystring(condition1 -> condition);
  395. condition1 -> condition = output;
  396. }
  397. }
  398. else
  399. condition1 = atomicexpression();
  400. return condition1;
  401. }
  402. cond atomicexpression()
  403. {
  404. cond condition1 = createcondition();
  405. switch (token)
  406. {
  407. case UINT:
  408. if ( progtype == 1)
  409. condition1 -> truth = DEFINED;
  410. else
  411. condition1 -> truth = (atoi(currenttoken) == 0) ? UNDEFINED : DEFINED;
  412. break;
  413. case ID:
  414. condition1 -> truth = lookupsym(currenttoken);
  415. if ((condition1 -> truth) == NOTPRESENT)
  416. {
  417. warning("Switch unlisted - ignoring", currenttoken);
  418. condition1 -> truth = IGNORE;
  419. }
  420. if ((condition1 -> truth) == IGNORE) {
  421. condition1 -> condition = createstring(strlen(currenttoken));
  422. strcpy(condition1 -> condition, currenttoken);
  423. }
  424. break;
  425. default:
  426. /* bad/complex expression */
  427. evalwarn();
  428. destroycondition(condition1);
  429. return NULL;
  430. break;
  431. }
  432. gettoken();
  433. return condition1;
  434. }
  435. /* Negate condition (MAL) */
  436. __inline int negatecondition(int condvalue) /* inline for speed */
  437. {
  438. switch (condvalue)
  439. {
  440. case DEFINED:
  441. return UNDEFINED;
  442. case UNDEFINED:
  443. return DEFINED;
  444. default:
  445. return condvalue;
  446. };
  447. }
  448. /* Allocate the memory for an empty condition structure and return a pointer to it */
  449. __inline cond createcondition()
  450. {
  451. cond retvalue;
  452. retvalue = (cond) malloc(sizeof(condrec));
  453. if (retvalue == NULL)
  454. error("Memory overflow","");
  455. retvalue -> condition = NULL;
  456. return retvalue;
  457. }
  458. /* Destroy a condition structure */
  459. __inline void destroycondition(cond condition1)
  460. {
  461. if (condition1 -> condition)
  462. free(condition1 -> condition);
  463. free(condition1);
  464. }
  465. /* Allocate the memory for a string of given length (not including terminator) and return the pointer */
  466. __inline char *createstring(int length)
  467. {
  468. char *retvalue;
  469. retvalue = (char *) malloc(length + 1);
  470. if (retvalue == NULL)
  471. error("Memory overflow","");
  472. return retvalue;
  473. }
  474. /* Destroy a string */
  475. __inline void destroystring(char *string)
  476. {
  477. free(string);
  478. }
  479. int iscomment(char *tokenptr)
  480. {
  481. int cindex;
  482. for (cindex = 0; cindex < maxcomment; cindex++)
  483. {
  484. if (commlen[cindex] &&
  485. !_strnicmp(tokenptr, comments[cindex], commlen[cindex]))
  486. return TRUE;
  487. }
  488. return FALSE;
  489. }
  490. void gettoken()
  491. {
  492. int numofwhitespace, comparetoken = 0, found = FALSE, isnumber = TRUE;
  493. char *digitcheck;
  494. numofwhitespace = strspn(tokenptr, " \t");
  495. /* CFW - skips comments, assumes comment is last thing on line */
  496. if (numofwhitespace == (int) strlen(tokenptr))
  497. token = ENDOFLINE;
  498. else
  499. {
  500. tokenptr += numofwhitespace;
  501. if (iscomment(tokenptr))
  502. {
  503. token = ENDOFLINE;
  504. }
  505. else
  506. {
  507. do
  508. {
  509. if (!_strnicmp(tokenptr, operators[comparetoken], oplengths[comparetoken]))
  510. found = TRUE;
  511. else
  512. comparetoken++;
  513. } while ( (!found) && (comparetoken < numoperators) );
  514. if (found)
  515. {
  516. tokenptr += oplengths[comparetoken];
  517. token = comparetoken;
  518. /* currenttoken is left blank for all but UINTs and IDs */
  519. }
  520. else
  521. {
  522. digitcheck = tokenptr;
  523. if (!nonumbers && isdigit(*digitcheck))
  524. {
  525. while (isdigit(*digitcheck))
  526. digitcheck++;
  527. strncpy(currenttoken, tokenptr, digitcheck - tokenptr);
  528. tokenptr = digitcheck;
  529. token = UINT;
  530. }
  531. else if (issymbolchar(*digitcheck))
  532. {
  533. while (issymbolchar(*digitcheck))
  534. digitcheck++;
  535. strncpy(currenttoken, tokenptr, digitcheck - tokenptr);
  536. *(currenttoken + (digitcheck - tokenptr)) = '\0';
  537. tokenptr = digitcheck;
  538. token = ID;
  539. }
  540. else
  541. token = UNKNOWN;
  542. }
  543. }
  544. }
  545. }
  546. __inline int issymbolchar(char c)
  547. {
  548. return (iscsym(c) || (c == '$') || (c == '?') || (c == '@'));
  549. }