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.

ifparser.c 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. /*
  2. * $XConsortium: ifparser.c,v 1.7 94/01/18 21:30:50 rws Exp $
  3. *
  4. * Copyright 1992 Network Computing Devices, Inc.
  5. *
  6. * Permission to use, copy, modify, and distribute this software and its
  7. * documentation for any purpose and without fee is hereby granted, provided
  8. * that the above copyright notice appear in all copies and that both that
  9. * copyright notice and this permission notice appear in supporting
  10. * documentation, and that the name of Network Computing Devices may not be
  11. * used in advertising or publicity pertaining to distribution of the software
  12. * without specific, written prior permission. Network Computing Devices makes
  13. * no representations about the suitability of this software for any purpose.
  14. * It is provided ``as is'' without express or implied warranty.
  15. *
  16. * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
  17. * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  18. * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL,
  19. * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  20. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  21. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  22. * PERFORMANCE OF THIS SOFTWARE.
  23. *
  24. * Author: Jim Fulton
  25. * Network Computing Devices, Inc.
  26. *
  27. * Simple if statement processor
  28. *
  29. * This module can be used to evaluate string representations of C language
  30. * if constructs. It accepts the following grammar:
  31. *
  32. * EXPRESSION := VALUE
  33. * | VALUE BINOP EXPRESSION
  34. *
  35. * VALUE := '(' EXPRESSION ')'
  36. * | '!' VALUE
  37. * | '-' VALUE
  38. * | 'defined' '(' variable ')'
  39. * | 'defined' variable
  40. * | # variable '(' variable-list ')'
  41. * | variable
  42. * | number
  43. *
  44. * BINOP := '*' | '/' | '%'
  45. * | '+' | '-'
  46. * | '<<' | '>>'
  47. * | '<' | '>' | '<=' | '>='
  48. * | '==' | '!='
  49. * | '&' | '|'
  50. * | '&&' | '||'
  51. *
  52. * The normal C order of precidence is supported.
  53. *
  54. *
  55. * External Entry Points:
  56. *
  57. * ParseIfExpression parse a string for #if
  58. */
  59. #include "ifparser.h"
  60. #include <ctype.h>
  61. /****************************************************************************
  62. Internal Macros and Utilities for Parser
  63. ****************************************************************************/
  64. #define DO(val) if (!(val)) return NULL
  65. #define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff))
  66. #define SKIPSPACE(ccc) while (isspace(*ccc)) ccc++
  67. #define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_')
  68. static const char *
  69. parse_variable (g, cp, varp)
  70. IfParser *g;
  71. const char *cp;
  72. const char **varp;
  73. {
  74. SKIPSPACE (cp);
  75. if (!isvarfirstletter (*cp))
  76. return CALLFUNC(g, handle_error) (g, cp, "variable name");
  77. *varp = cp;
  78. /* EMPTY */
  79. for (cp++; isalnum(*cp) || *cp == '_'; cp++) ;
  80. return cp;
  81. }
  82. static const char *
  83. parse_number (g, cp, valp)
  84. IfParser *g;
  85. const char *cp;
  86. int *valp;
  87. {
  88. SKIPSPACE (cp);
  89. if (!isdigit(*cp))
  90. return CALLFUNC(g, handle_error) (g, cp, "number");
  91. *valp = strtol(cp, &cp, 0);
  92. return cp;
  93. }
  94. static const char *
  95. parse_value (g, cp, valp)
  96. IfParser *g;
  97. const char *cp;
  98. int *valp;
  99. {
  100. const char *var;
  101. *valp = 0;
  102. SKIPSPACE (cp);
  103. if (!*cp)
  104. return cp;
  105. switch (*cp) {
  106. case '(':
  107. DO (cp = ParseIfExpression (g, cp + 1, valp));
  108. SKIPSPACE (cp);
  109. if (*cp != ')')
  110. return CALLFUNC(g, handle_error) (g, cp, ")");
  111. return cp + 1; /* skip the right paren */
  112. case '!':
  113. DO (cp = parse_value (g, cp + 1, valp));
  114. *valp = !(*valp);
  115. return cp;
  116. case '-':
  117. DO (cp = parse_value (g, cp + 1, valp));
  118. *valp = -(*valp);
  119. return cp;
  120. case '#':
  121. DO (cp = parse_variable (g, cp + 1, &var));
  122. SKIPSPACE (cp);
  123. if (*cp != '(')
  124. return CALLFUNC(g, handle_error) (g, cp, "(");
  125. do {
  126. DO (cp = parse_variable (g, cp + 1, &var));
  127. SKIPSPACE (cp);
  128. } while (*cp && *cp != ')');
  129. if (*cp != ')')
  130. return CALLFUNC(g, handle_error) (g, cp, ")");
  131. *valp = 1; /* XXX */
  132. return cp + 1;
  133. case 'd':
  134. if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) {
  135. int paren = 0;
  136. cp += 7;
  137. SKIPSPACE (cp);
  138. if (*cp == '(') {
  139. paren = 1;
  140. cp++;
  141. }
  142. DO (cp = parse_variable (g, cp, &var));
  143. SKIPSPACE (cp);
  144. if (paren && *cp != ')')
  145. return CALLFUNC(g, handle_error) (g, cp, ")");
  146. *valp = (*(g->funcs.eval_defined)) (g, var, cp - var);
  147. return cp + paren; /* skip the right paren */
  148. }
  149. /* fall out */
  150. }
  151. if (isdigit(*cp)) {
  152. DO (cp = parse_number (g, cp, valp));
  153. } else if (!isvarfirstletter(*cp))
  154. return CALLFUNC(g, handle_error) (g, cp, "variable or number");
  155. else {
  156. DO (cp = parse_variable (g, cp, &var));
  157. *valp = (*(g->funcs.eval_variable)) (g, var, cp - var);
  158. }
  159. return cp;
  160. }
  161. static const char *
  162. parse_product (g, cp, valp)
  163. IfParser *g;
  164. const char *cp;
  165. int *valp;
  166. {
  167. int rightval;
  168. DO (cp = parse_value (g, cp, valp));
  169. SKIPSPACE (cp);
  170. switch (*cp) {
  171. case '*':
  172. DO (cp = parse_product (g, cp + 1, &rightval));
  173. *valp = (*valp * rightval);
  174. break;
  175. case '/':
  176. DO (cp = parse_product (g, cp + 1, &rightval));
  177. *valp = (*valp / rightval);
  178. break;
  179. case '%':
  180. DO (cp = parse_product (g, cp + 1, &rightval));
  181. *valp = (*valp % rightval);
  182. break;
  183. }
  184. return cp;
  185. }
  186. static const char *
  187. parse_sum (g, cp, valp)
  188. IfParser *g;
  189. const char *cp;
  190. int *valp;
  191. {
  192. int rightval;
  193. DO (cp = parse_product (g, cp, valp));
  194. SKIPSPACE (cp);
  195. switch (*cp) {
  196. case '+':
  197. DO (cp = parse_sum (g, cp + 1, &rightval));
  198. *valp = (*valp + rightval);
  199. break;
  200. case '-':
  201. DO (cp = parse_sum (g, cp + 1, &rightval));
  202. *valp = (*valp - rightval);
  203. break;
  204. }
  205. return cp;
  206. }
  207. static const char *
  208. parse_shift (g, cp, valp)
  209. IfParser *g;
  210. const char *cp;
  211. int *valp;
  212. {
  213. int rightval;
  214. DO (cp = parse_sum (g, cp, valp));
  215. SKIPSPACE (cp);
  216. switch (*cp) {
  217. case '<':
  218. if (cp[1] == '<') {
  219. DO (cp = parse_shift (g, cp + 2, &rightval));
  220. *valp = (*valp << rightval);
  221. }
  222. break;
  223. case '>':
  224. if (cp[1] == '>') {
  225. DO (cp = parse_shift (g, cp + 2, &rightval));
  226. *valp = (*valp >> rightval);
  227. }
  228. break;
  229. }
  230. return cp;
  231. }
  232. static const char *
  233. parse_inequality (g, cp, valp)
  234. IfParser *g;
  235. const char *cp;
  236. int *valp;
  237. {
  238. int rightval;
  239. DO (cp = parse_shift (g, cp, valp));
  240. SKIPSPACE (cp);
  241. switch (*cp) {
  242. case '<':
  243. if (cp[1] == '=') {
  244. DO (cp = parse_inequality (g, cp + 2, &rightval));
  245. *valp = (*valp <= rightval);
  246. } else {
  247. DO (cp = parse_inequality (g, cp + 1, &rightval));
  248. *valp = (*valp < rightval);
  249. }
  250. break;
  251. case '>':
  252. if (cp[1] == '=') {
  253. DO (cp = parse_inequality (g, cp + 2, &rightval));
  254. *valp = (*valp >= rightval);
  255. } else {
  256. DO (cp = parse_inequality (g, cp + 1, &rightval));
  257. *valp = (*valp > rightval);
  258. }
  259. break;
  260. }
  261. return cp;
  262. }
  263. static const char *
  264. parse_equality (g, cp, valp)
  265. IfParser *g;
  266. const char *cp;
  267. int *valp;
  268. {
  269. int rightval;
  270. DO (cp = parse_inequality (g, cp, valp));
  271. SKIPSPACE (cp);
  272. switch (*cp) {
  273. case '=':
  274. if (cp[1] == '=')
  275. cp++;
  276. DO (cp = parse_equality (g, cp + 1, &rightval));
  277. *valp = (*valp == rightval);
  278. break;
  279. case '!':
  280. if (cp[1] != '=')
  281. break;
  282. DO (cp = parse_equality (g, cp + 2, &rightval));
  283. *valp = (*valp != rightval);
  284. break;
  285. }
  286. return cp;
  287. }
  288. static const char *
  289. parse_band (g, cp, valp)
  290. IfParser *g;
  291. const char *cp;
  292. int *valp;
  293. {
  294. int rightval;
  295. DO (cp = parse_equality (g, cp, valp));
  296. SKIPSPACE (cp);
  297. switch (*cp) {
  298. case '&':
  299. if (cp[1] != '&') {
  300. DO (cp = parse_band (g, cp + 1, &rightval));
  301. *valp = (*valp & rightval);
  302. }
  303. break;
  304. }
  305. return cp;
  306. }
  307. static const char *
  308. parse_bor (g, cp, valp)
  309. IfParser *g;
  310. const char *cp;
  311. int *valp;
  312. {
  313. int rightval;
  314. DO (cp = parse_band (g, cp, valp));
  315. SKIPSPACE (cp);
  316. switch (*cp) {
  317. case '|':
  318. if (cp[1] != '|') {
  319. DO (cp = parse_bor (g, cp + 1, &rightval));
  320. *valp = (*valp | rightval);
  321. }
  322. break;
  323. }
  324. return cp;
  325. }
  326. static const char *
  327. parse_land (g, cp, valp)
  328. IfParser *g;
  329. const char *cp;
  330. int *valp;
  331. {
  332. int rightval;
  333. DO (cp = parse_bor (g, cp, valp));
  334. SKIPSPACE (cp);
  335. switch (*cp) {
  336. case '&':
  337. if (cp[1] != '&')
  338. return CALLFUNC(g, handle_error) (g, cp, "&&");
  339. DO (cp = parse_land (g, cp + 2, &rightval));
  340. *valp = (*valp && rightval);
  341. break;
  342. }
  343. return cp;
  344. }
  345. static const char *
  346. parse_lor (g, cp, valp)
  347. IfParser *g;
  348. const char *cp;
  349. int *valp;
  350. {
  351. int rightval;
  352. DO (cp = parse_land (g, cp, valp));
  353. SKIPSPACE (cp);
  354. switch (*cp) {
  355. case '|':
  356. if (cp[1] != '|')
  357. return CALLFUNC(g, handle_error) (g, cp, "||");
  358. DO (cp = parse_lor (g, cp + 2, &rightval));
  359. *valp = (*valp || rightval);
  360. break;
  361. }
  362. return cp;
  363. }
  364. /****************************************************************************
  365. External Entry Points
  366. ****************************************************************************/
  367. const char *
  368. ParseIfExpression (g, cp, valp)
  369. IfParser *g;
  370. const char *cp;
  371. int *valp;
  372. {
  373. return parse_lor (g, cp, valp);
  374. }