1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * $XConsortium: ifparser.c,v 1.8 95/06/03 00:01:41 gildea Exp $
5 * Copyright 1992 Network Computing Devices, Inc.
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation for any purpose and without fee is hereby granted, provided
9 * that the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of Network Computing Devices may not be
12 * used in advertising or publicity pertaining to distribution of the software
13 * without specific, written prior permission. Network Computing Devices makes
14 * no representations about the suitability of this software for any purpose.
15 * It is provided ``as is'' without express or implied warranty.
17 * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
18 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
19 * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL,
20 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
21 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23 * PERFORMANCE OF THIS SOFTWARE.
26 * Network Computing Devices, Inc.
28 * Simple if statement processor
30 * This module can be used to evaluate string representations of C language
31 * if constructs. It accepts the following grammar:
34 * | VALUE BINOP EXPRESSION
36 * VALUE := '(' EXPRESSION ')'
39 * | 'defined' '(' variable ')'
40 * | 'defined' variable
41 * | # variable '(' variable-list ')'
45 * BINOP := '*' | '/' | '%'
48 * | '<' | '>' | '<=' | '>='
53 * The normal C order of precedence is supported.
56 * External Entry Points:
58 * ParseIfExpression parse a string for #if
66 /****************************************************************************
67 Internal Macros and Utilities for Parser
68 ****************************************************************************/
70 #define DO(val) if (!(val)) return NULL
71 #define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff))
72 #define SKIPSPACE(ccc) while (isspace((unsigned char)*ccc)) ccc++
73 #define isvarfirstletter(ccc) (isalpha((unsigned char)(ccc)) || (ccc) == '_')
77 parse_variable (IfParser
*g
, const char *cp
, const char **varp
)
81 if (!isvarfirstletter (*cp
))
82 return CALLFUNC(g
, handle_error
) (g
, cp
, "variable name");
86 for (cp
++; isalnum((unsigned char)*cp
) || *cp
== '_'; cp
++) ;
92 parse_number (IfParser
*g
, const char *cp
, int *valp
)
96 if (!isdigit((unsigned char)*cp
))
97 return CALLFUNC(g
, handle_error
) (g
, cp
, "number");
102 *valp
= strtol(cp
, &cp2
, 0);
107 for (cp
++; isdigit((unsigned char)*cp
); cp
++) ;
114 parse_value (IfParser
*g
, const char *cp
, int *valp
)
126 DO (cp
= ParseIfExpression (g
, cp
+ 1, valp
));
129 return CALLFUNC(g
, handle_error
) (g
, cp
, ")");
131 return cp
+ 1; /* skip the right paren */
134 DO (cp
= parse_value (g
, cp
+ 1, valp
));
139 DO (cp
= parse_value (g
, cp
+ 1, valp
));
144 DO (cp
= parse_variable (g
, cp
+ 1, &var
));
147 return CALLFUNC(g
, handle_error
) (g
, cp
, "(");
149 DO (cp
= parse_variable (g
, cp
+ 1, &var
));
151 } while (*cp
&& *cp
!= ')');
153 return CALLFUNC(g
, handle_error
) (g
, cp
, ")");
158 if (strncmp (cp
, "defined", 7) == 0 && !isalnum((unsigned char)cp
[7])) {
168 DO (cp
= parse_variable (g
, cp
, &var
));
169 len
= (size_t)(cp
- var
);
171 if (paren
&& *cp
!= ')')
172 return CALLFUNC(g
, handle_error
) (g
, cp
, ")");
173 *valp
= (*(g
->funcs
.eval_defined
)) (g
, var
, len
);
174 return cp
+ paren
; /* skip the right paren */
179 if (isdigit((unsigned char)*cp
)) {
180 DO (cp
= parse_number (g
, cp
, valp
));
181 } else if (!isvarfirstletter(*cp
))
182 return CALLFUNC(g
, handle_error
) (g
, cp
, "variable or number");
184 DO (cp
= parse_variable (g
, cp
, &var
));
185 *valp
= (*(g
->funcs
.eval_variable
)) (g
, var
, (size_t)(cp
- var
));
194 parse_product (IfParser
*g
, const char *cp
, int *valp
)
198 DO (cp
= parse_value (g
, cp
, valp
));
203 DO (cp
= parse_product (g
, cp
+ 1, &rightval
));
204 *valp
= (*valp
* rightval
);
208 DO (cp
= parse_product (g
, cp
+ 1, &rightval
));
210 /* Do nothing in the divide-by-zero case. */
212 *valp
= (*valp
/ rightval
);
217 DO (cp
= parse_product (g
, cp
+ 1, &rightval
));
218 *valp
= (*valp
% rightval
);
226 parse_sum (IfParser
*g
, const char *cp
, int *valp
)
230 DO (cp
= parse_product (g
, cp
, valp
));
235 DO (cp
= parse_sum (g
, cp
+ 1, &rightval
));
236 *valp
= (*valp
+ rightval
);
240 DO (cp
= parse_sum (g
, cp
+ 1, &rightval
));
241 *valp
= (*valp
- rightval
);
249 parse_shift (IfParser
*g
, const char *cp
, int *valp
)
253 DO (cp
= parse_sum (g
, cp
, valp
));
259 DO (cp
= parse_shift (g
, cp
+ 2, &rightval
));
260 *valp
= (*valp
<< rightval
);
266 DO (cp
= parse_shift (g
, cp
+ 2, &rightval
));
267 *valp
= (*valp
>> rightval
);
276 parse_inequality (IfParser
*g
, const char *cp
, int *valp
)
280 DO (cp
= parse_shift (g
, cp
, valp
));
286 DO (cp
= parse_inequality (g
, cp
+ 2, &rightval
));
287 *valp
= (*valp
<= rightval
);
289 DO (cp
= parse_inequality (g
, cp
+ 1, &rightval
));
290 *valp
= (*valp
< rightval
);
296 DO (cp
= parse_inequality (g
, cp
+ 2, &rightval
));
297 *valp
= (*valp
>= rightval
);
299 DO (cp
= parse_inequality (g
, cp
+ 1, &rightval
));
300 *valp
= (*valp
> rightval
);
309 parse_equality (IfParser
*g
, const char *cp
, int *valp
)
313 DO (cp
= parse_inequality (g
, cp
, valp
));
320 DO (cp
= parse_equality (g
, cp
+ 1, &rightval
));
321 *valp
= (*valp
== rightval
);
327 DO (cp
= parse_equality (g
, cp
+ 2, &rightval
));
328 *valp
= (*valp
!= rightval
);
336 parse_band (IfParser
*g
, const char *cp
, int *valp
)
340 DO (cp
= parse_equality (g
, cp
, valp
));
346 DO (cp
= parse_band (g
, cp
+ 1, &rightval
));
347 *valp
= (*valp
& rightval
);
356 parse_bor (IfParser
*g
, const char *cp
, int *valp
)
360 DO (cp
= parse_band (g
, cp
, valp
));
366 DO (cp
= parse_bor (g
, cp
+ 1, &rightval
));
367 *valp
= (*valp
| rightval
);
376 parse_land (IfParser
*g
, const char *cp
, int *valp
)
380 DO (cp
= parse_bor (g
, cp
, valp
));
386 return CALLFUNC(g
, handle_error
) (g
, cp
, "&&");
387 DO (cp
= parse_land (g
, cp
+ 2, &rightval
));
388 *valp
= (*valp
&& rightval
);
396 parse_lor (IfParser
*g
, const char *cp
, int *valp
)
400 DO (cp
= parse_land (g
, cp
, valp
));
406 return CALLFUNC(g
, handle_error
) (g
, cp
, "||");
407 DO (cp
= parse_lor (g
, cp
+ 2, &rightval
));
408 *valp
= (*valp
|| rightval
);
415 /****************************************************************************
416 External Entry Points
417 ****************************************************************************/
420 ParseIfExpression (IfParser
*g
, const char *cp
, int *valp
)
422 return parse_lor (g
, cp
, valp
);
426 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */