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
80static 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
95static 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
115static 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
190static 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
216static 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
238static 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
263static 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
294static 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
319static 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
338static 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
356static 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
374static 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
397const 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