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