feisty meow concerns codebase  2.140
ifparser.cpp
Go to the documentation of this file.
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 
60 #ifdef __WIN32__
61  #pragma warning(disable : 4996)
62 #endif
63 
64 #include "ifparser.h"
65 
66 #include <ctype.h>
67 #include <stdlib.h>
68 #include <string.h>
69 
70 /****************************************************************************
71  Internal Macros and Utilities for Parser
72  ****************************************************************************/
73 
74 #define DO(val) if (!(val)) return NULL
75 #define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff))
76 #define SKIPSPACE(ccc) while (isspace(*ccc)) ccc++
77 #define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_')
78 
79 
80 static const char *parse_variable(IfParser *g, const char *cp,
81  const char **varp)
82 {
83  SKIPSPACE (cp);
84 
85  if (!isvarfirstletter (*cp))
86  return CALLFUNC(g, handle_error) (g, cp, "variable name");
87 
88  *varp = cp;
89  /* EMPTY */
90  for (cp++; isalnum(*cp) || *cp == '_'; cp++) ;
91  return cp;
92 }
93 
94 
95 static const char *parse_number(IfParser *g, const char *cp, int *valp)
96 {
97  SKIPSPACE (cp);
98 
99  if (!isdigit(*cp))
100  return CALLFUNC(g, handle_error) (g, cp, "number");
101 
102 #ifdef WIN32
103  char *hold_result;
104  *valp = strtol(cp, &hold_result, 0);
105  cp = hold_result;
106 #else
107  *valp = atoi (cp);
108  /* EMPTY */
109  for (cp++; isdigit(*cp); cp++) ;
110 #endif
111  return cp;
112 }
113 
114 
115 static const char *parse_value(IfParser *g, const char *cp, int *valp)
116 {
117  const char *var;
118 
119  *valp = 0;
120 
121  SKIPSPACE (cp);
122  if (!*cp)
123  return cp;
124 
125  switch (*cp) {
126  case '(':
127  DO (cp = ParseIfExpression (g, cp + 1, valp));
128  SKIPSPACE (cp);
129  if (*cp != ')')
130  return CALLFUNC(g, handle_error) (g, cp, ")");
131 
132  return cp + 1; /* skip the right paren */
133 
134  case '!':
135  DO (cp = parse_value (g, cp + 1, valp));
136  *valp = !(*valp);
137  return cp;
138 
139  case '-':
140  DO (cp = parse_value (g, cp + 1, valp));
141  *valp = -(*valp);
142  return cp;
143 
144  case '#':
145  DO (cp = parse_variable (g, cp + 1, &var));
146  SKIPSPACE (cp);
147  if (*cp != '(')
148  return CALLFUNC(g, handle_error) (g, cp, "(");
149  do {
150  DO (cp = parse_variable (g, cp + 1, &var));
151  SKIPSPACE (cp);
152  } while (*cp && *cp != ')');
153  if (*cp != ')')
154  return CALLFUNC(g, handle_error) (g, cp, ")");
155  *valp = 1; /* XXX */
156  return cp + 1;
157 
158  case 'd':
159  if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) {
160  int paren = 0;
161  cp += 7;
162  SKIPSPACE (cp);
163  if (*cp == '(') {
164  paren = 1;
165  cp++;
166  }
167  DO (cp = parse_variable (g, cp, &var));
168  SKIPSPACE (cp);
169  if (paren && *cp != ')')
170  return CALLFUNC(g, handle_error) (g, cp, ")");
171  *valp = (*(g->funcs.eval_defined)) (g, var, int(cp - var));
172  return cp + paren; /* skip the right paren */
173  }
174  break;
175  /* fall out */
176  }
177 
178  if (isdigit(*cp)) {
179  DO (cp = parse_number (g, cp, valp));
180  } else if (!isvarfirstletter(*cp))
181  return CALLFUNC(g, handle_error) (g, cp, "variable or number");
182  else {
183  DO (cp = parse_variable (g, cp, &var));
184  *valp = (*(g->funcs.eval_variable)) (g, var, int(cp - var));
185  }
186 
187  return cp;
188 }
189 
190 static const char *parse_product(IfParser *g, const char *cp, int *valp)
191 {
192  int rightval;
193 
194  DO (cp = parse_value (g, cp, valp));
195  SKIPSPACE (cp);
196 
197  switch (*cp) {
198  case '*':
199  DO (cp = parse_product (g, cp + 1, &rightval));
200  *valp = (*valp * rightval);
201  break;
202 
203  case '/':
204  DO (cp = parse_product (g, cp + 1, &rightval));
205  *valp = (*valp / rightval);
206  break;
207 
208  case '%':
209  DO (cp = parse_product (g, cp + 1, &rightval));
210  *valp = (*valp % rightval);
211  break;
212  }
213  return cp;
214 }
215 
216 static const char *parse_sum(IfParser *g, const char *cp, int *valp)
217 {
218  int rightval;
219 
220  DO (cp = parse_product (g, cp, valp));
221  SKIPSPACE (cp);
222 
223  switch (*cp) {
224  case '+':
225  DO (cp = parse_sum (g, cp + 1, &rightval));
226  *valp = (*valp + rightval);
227  break;
228 
229  case '-':
230  DO (cp = parse_sum (g, cp + 1, &rightval));
231  *valp = (*valp - rightval);
232  break;
233  }
234  return cp;
235 }
236 
237 
238 static const char *parse_shift(IfParser *g, const char *cp, int *valp)
239 {
240  int rightval;
241 
242  DO (cp = parse_sum (g, cp, valp));
243  SKIPSPACE (cp);
244 
245  switch (*cp) {
246  case '<':
247  if (cp[1] == '<') {
248  DO (cp = parse_shift (g, cp + 2, &rightval));
249  *valp = (*valp << rightval);
250  }
251  break;
252 
253  case '>':
254  if (cp[1] == '>') {
255  DO (cp = parse_shift (g, cp + 2, &rightval));
256  *valp = (*valp >> rightval);
257  }
258  break;
259  }
260  return cp;
261 }
262 
263 static const char *parse_inequality(IfParser *g, const char *cp, int *valp)
264 {
265  int rightval;
266 
267  DO (cp = parse_shift (g, cp, valp));
268  SKIPSPACE (cp);
269 
270  switch (*cp) {
271  case '<':
272  if (cp[1] == '=') {
273  DO (cp = parse_inequality (g, cp + 2, &rightval));
274  *valp = (*valp <= rightval);
275  } else {
276  DO (cp = parse_inequality (g, cp + 1, &rightval));
277  *valp = (*valp < rightval);
278  }
279  break;
280 
281  case '>':
282  if (cp[1] == '=') {
283  DO (cp = parse_inequality (g, cp + 2, &rightval));
284  *valp = (*valp >= rightval);
285  } else {
286  DO (cp = parse_inequality (g, cp + 1, &rightval));
287  *valp = (*valp > rightval);
288  }
289  break;
290  }
291  return cp;
292 }
293 
294 static const char *parse_equality(IfParser *g, const char *cp, int *valp)
295 {
296  int rightval;
297 
298  DO (cp = parse_inequality (g, cp, valp));
299  SKIPSPACE (cp);
300 
301  switch (*cp) {
302  case '=':
303  if (cp[1] == '=')
304  cp++;
305  DO (cp = parse_equality (g, cp + 1, &rightval));
306  *valp = (*valp == rightval);
307  break;
308 
309  case '!':
310  if (cp[1] != '=')
311  break;
312  DO (cp = parse_equality (g, cp + 2, &rightval));
313  *valp = (*valp != rightval);
314  break;
315  }
316  return cp;
317 }
318 
319 static const char *parse_band(IfParser *g, const char *cp, int *valp)
320 {
321  int rightval;
322 
323  DO (cp = parse_equality (g, cp, valp));
324  SKIPSPACE (cp);
325 
326  switch (*cp) {
327  case '&':
328  if (cp[1] != '&') {
329  DO (cp = parse_band (g, cp + 1, &rightval));
330  *valp = (*valp & rightval);
331  }
332  break;
333  }
334  return cp;
335 }
336 
337 
338 static const char *parse_bor(IfParser *g, const char *cp, int *valp)
339 {
340  int rightval;
341 
342  DO (cp = parse_band (g, cp, valp));
343  SKIPSPACE (cp);
344 
345  switch (*cp) {
346  case '|':
347  if (cp[1] != '|') {
348  DO (cp = parse_bor (g, cp + 1, &rightval));
349  *valp = (*valp | rightval);
350  }
351  break;
352  }
353  return cp;
354 }
355 
356 static const char *parse_land(IfParser *g, const char *cp, int *valp)
357 {
358  int rightval;
359 
360  DO (cp = parse_bor (g, cp, valp));
361  SKIPSPACE (cp);
362 
363  switch (*cp) {
364  case '&':
365  if (cp[1] != '&')
366  return CALLFUNC(g, handle_error) (g, cp, "&&");
367  DO (cp = parse_land (g, cp + 2, &rightval));
368  *valp = (*valp && rightval);
369  break;
370  }
371  return cp;
372 }
373 
374 static const char *parse_lor(IfParser *g, const char *cp, int *valp)
375 {
376  int rightval;
377 
378  DO (cp = parse_land (g, cp, valp));
379  SKIPSPACE (cp);
380 
381  switch (*cp) {
382  case '|':
383  if (cp[1] != '|')
384  return CALLFUNC(g, handle_error) (g, cp, "||");
385  DO (cp = parse_lor (g, cp + 2, &rightval));
386  *valp = (*valp || rightval);
387  break;
388  }
389  return cp;
390 }
391 
392 
393 /****************************************************************************
394  External Entry Points
395  ****************************************************************************/
396 
397 const char *ParseIfExpression(IfParser *g, const char *cp, int *valp)
398 {
399  return parse_lor (g, cp, valp);
400 }
401 
402 
#define DO(val)
Definition: ifparser.cpp:74
#define isvarfirstletter(ccc)
Definition: ifparser.cpp:77
#define CALLFUNC(ggg, fff)
Definition: ifparser.cpp:75
const char * ParseIfExpression(IfParser *g, const char *cp, int *valp)
Definition: ifparser.cpp:397
#define SKIPSPACE(ccc)
Definition: ifparser.cpp:76
int(* eval_variable)(IfParser *, const char *, int)
Definition: ifparser.h:63
int(* eval_defined)(IfParser *, const char *, int)
Definition: ifparser.h:64
struct IfParser::@0 funcs