/* * $XConsortium: ifparser.c,v 1.7 94/01/18 21:30:50 rws Exp $ * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any other legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * * Copyright 1992 Network Computing Devices, Inc. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Network Computing Devices may not be * used in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. Network Computing Devices makes * no representations about the suitability of this software for any purpose. * It is provided ``as is'' without express or implied warranty. * * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * Author: Jim Fulton * Network Computing Devices, Inc. * * Simple if statement processor * * This module can be used to evaluate string representations of C language * if constructs. It accepts the following grammar: * * EXPRESSION := VALUE * | VALUE BINOP EXPRESSION * * VALUE := '(' EXPRESSION ')' * | '!' VALUE * | '-' VALUE * | 'defined' '(' variable ')' * | 'defined' variable * | # variable '(' variable-list ')' * | variable * | number * * BINOP := '*' | '/' | '%' * | '+' | '-' * | '<<' | '>>' * | '<' | '>' | '<=' | '>=' * | '==' | '!=' * | '&' | '|' * | '&&' | '||' * * The normal C order of precidence is supported. * * * External Entry Points: * * ParseIfExpression parse a string for #if */ #include "ifparser.h" #include /**************************************************************************** Internal Macros and Utilities for Parser ****************************************************************************/ #define DO(val) if (!(val)) return NULL #define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff)) #define SKIPSPACE(ccc) while (isspace(*ccc)) ccc++ #define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_') static const char * parse_variable (g, cp, varp) IfParser *g; const char *cp; const char **varp; { SKIPSPACE (cp); if (!isvarfirstletter (*cp)) return CALLFUNC(g, handle_error) (g, cp, "variable name"); *varp = cp; /* EMPTY */ for (cp++; isalnum(*cp) || *cp == '_'; cp++) ; return cp; } static const char * parse_number (g, cp, valp) IfParser *g; const char *cp; int *valp; { SKIPSPACE (cp); if (!isdigit(*cp)) return CALLFUNC(g, handle_error) (g, cp, "number"); #ifdef WIN32 *valp = strtol(cp, &cp, 0); #else *valp = atoi (cp); /* EMPTY */ for (cp++; isdigit(*cp); cp++) ; #endif return cp; } static const char * parse_value (g, cp, valp) IfParser *g; const char *cp; int *valp; { const char *var; *valp = 0; SKIPSPACE (cp); if (!*cp) return cp; switch (*cp) { case '(': DO (cp = ParseIfExpression (g, cp + 1, valp)); SKIPSPACE (cp); if (*cp != ')') return CALLFUNC(g, handle_error) (g, cp, ")"); return cp + 1; /* skip the right paren */ case '!': DO (cp = parse_value (g, cp + 1, valp)); *valp = !(*valp); return cp; case '-': DO (cp = parse_value (g, cp + 1, valp)); *valp = -(*valp); return cp; case '#': DO (cp = parse_variable (g, cp + 1, &var)); SKIPSPACE (cp); if (*cp != '(') return CALLFUNC(g, handle_error) (g, cp, "("); do { DO (cp = parse_variable (g, cp + 1, &var)); SKIPSPACE (cp); } while (*cp && *cp != ')'); if (*cp != ')') return CALLFUNC(g, handle_error) (g, cp, ")"); *valp = 1; /* XXX */ return cp + 1; case 'd': if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) { int paren = 0; cp += 7; SKIPSPACE (cp); if (*cp == '(') { paren = 1; cp++; } DO (cp = parse_variable (g, cp, &var)); SKIPSPACE (cp); if (paren && *cp != ')') return CALLFUNC(g, handle_error) (g, cp, ")"); *valp = (*(g->funcs.eval_defined)) (g, var, cp - var); return cp + paren; /* skip the right paren */ } /* fall out */ } if (isdigit(*cp)) { DO (cp = parse_number (g, cp, valp)); } else if (!isvarfirstletter(*cp)) return CALLFUNC(g, handle_error) (g, cp, "variable or number"); else { DO (cp = parse_variable (g, cp, &var)); *valp = (*(g->funcs.eval_variable)) (g, var, cp - var); } return cp; } static const char * parse_product (g, cp, valp) IfParser *g; const char *cp; int *valp; { int rightval; DO (cp = parse_value (g, cp, valp)); SKIPSPACE (cp); switch (*cp) { case '*': DO (cp = parse_product (g, cp + 1, &rightval)); *valp = (*valp * rightval); break; case '/': DO (cp = parse_product (g, cp + 1, &rightval)); *valp = (*valp / rightval); break; case '%': DO (cp = parse_product (g, cp + 1, &rightval)); *valp = (*valp % rightval); break; } return cp; } static const char * parse_sum (g, cp, valp) IfParser *g; const char *cp; int *valp; { int rightval; DO (cp = parse_product (g, cp, valp)); SKIPSPACE (cp); switch (*cp) { case '+': DO (cp = parse_sum (g, cp + 1, &rightval)); *valp = (*valp + rightval); break; case '-': DO (cp = parse_sum (g, cp + 1, &rightval)); *valp = (*valp - rightval); break; } return cp; } static const char * parse_shift (g, cp, valp) IfParser *g; const char *cp; int *valp; { int rightval; DO (cp = parse_sum (g, cp, valp)); SKIPSPACE (cp); switch (*cp) { case '<': if (cp[1] == '<') { DO (cp = parse_shift (g, cp + 2, &rightval)); *valp = (*valp << rightval); } break; case '>': if (cp[1] == '>') { DO (cp = parse_shift (g, cp + 2, &rightval)); *valp = (*valp >> rightval); } break; } return cp; } static const char * parse_inequality (g, cp, valp) IfParser *g; const char *cp; int *valp; { int rightval; DO (cp = parse_shift (g, cp, valp)); SKIPSPACE (cp); switch (*cp) { case '<': if (cp[1] == '=') { DO (cp = parse_inequality (g, cp + 2, &rightval)); *valp = (*valp <= rightval); } else { DO (cp = parse_inequality (g, cp + 1, &rightval)); *valp = (*valp < rightval); } break; case '>': if (cp[1] == '=') { DO (cp = parse_inequality (g, cp + 2, &rightval)); *valp = (*valp >= rightval); } else { DO (cp = parse_inequality (g, cp + 1, &rightval)); *valp = (*valp > rightval); } break; } return cp; } static const char * parse_equality (g, cp, valp) IfParser *g; const char *cp; int *valp; { int rightval; DO (cp = parse_inequality (g, cp, valp)); SKIPSPACE (cp); switch (*cp) { case '=': if (cp[1] == '=') cp++; DO (cp = parse_equality (g, cp + 1, &rightval)); *valp = (*valp == rightval); break; case '!': if (cp[1] != '=') break; DO (cp = parse_equality (g, cp + 2, &rightval)); *valp = (*valp != rightval); break; } return cp; } static const char * parse_band (g, cp, valp) IfParser *g; const char *cp; int *valp; { int rightval; DO (cp = parse_equality (g, cp, valp)); SKIPSPACE (cp); switch (*cp) { case '&': if (cp[1] != '&') { DO (cp = parse_band (g, cp + 1, &rightval)); *valp = (*valp & rightval); } break; } return cp; } static const char * parse_bor (g, cp, valp) IfParser *g; const char *cp; int *valp; { int rightval; DO (cp = parse_band (g, cp, valp)); SKIPSPACE (cp); switch (*cp) { case '|': if (cp[1] != '|') { DO (cp = parse_bor (g, cp + 1, &rightval)); *valp = (*valp | rightval); } break; } return cp; } static const char * parse_land (g, cp, valp) IfParser *g; const char *cp; int *valp; { int rightval; DO (cp = parse_bor (g, cp, valp)); SKIPSPACE (cp); switch (*cp) { case '&': if (cp[1] != '&') return CALLFUNC(g, handle_error) (g, cp, "&&"); DO (cp = parse_land (g, cp + 2, &rightval)); *valp = (*valp && rightval); break; } return cp; } static const char * parse_lor (g, cp, valp) IfParser *g; const char *cp; int *valp; { int rightval; DO (cp = parse_land (g, cp, valp)); SKIPSPACE (cp); switch (*cp) { case '|': if (cp[1] != '|') return CALLFUNC(g, handle_error) (g, cp, "||"); DO (cp = parse_lor (g, cp + 2, &rightval)); *valp = (*valp || rightval); break; } return cp; } /**************************************************************************** External Entry Points ****************************************************************************/ const char * ParseIfExpression (g, cp, valp) IfParser *g; const char *cp; int *valp; { return parse_lor (g, cp, valp); }