Edit

IABSD.fr/xenocara/util/makedepend/ifparser.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2012-03-12 20:27:35
    Hash : 8a1e57d1
    Message : Update to makedepend 1.0.4. Tested by naddy@ on a bulk ports build

  • util/makedepend/ifparser.c
  • /*
     *
     * 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 ':'	EXPRESSION
     *
     *     VALUE		:=	'('  EXPRESSION  ')'
     * 			 |	'!'  VALUE
     * 			 |	'-'  VALUE
     * 			 |	'+'  VALUE
     *			 |	'~'  VALUE
     * 			 |	'defined'  '('  variable  ')'
     * 			 |	'defined'  variable
     *			 |	# variable '(' variable-list ')'
     * 			 |	variable
     * 			 |	number
     *
     *     BINOP		:=	'*'	|  '/'	|  '%'
     * 			 |	'+'	|  '-'
     * 			 |	'<<'	|  '>>'
     * 			 |	'<'	|  '>'	|  '<='  |  '>='
     * 			 |	'=='	|  '!='
     * 			 |	'&'	|  '^'  |  '|'
     * 			 |	'&&'	|  '||'
     *
     * The normal C order of precedence is supported.
     *
     *
     * External Entry Points:
     *
     *     ParseIfExpression		parse a string for #if
     */
    
    #include "ifparser.h"
    #include <ctype.h>
    #include <stdlib.h>
    #include <string.h>
    #include <limits.h>
    
    /****************************************************************************
    		   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 (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 (IfParser *g, const char *cp, long *valp)
    {
        long base = 10;
        SKIPSPACE (cp);
    
        if (!isdigit(*cp))
    	return CALLFUNC(g, handle_error) (g, cp, "number");
    
        *valp = 0;
    
        if (*cp == '0') {
    	cp++;
    	if ((*cp == 'x') || (*cp == 'X')) {
    	    base = 16;
    	    cp++;
    	} else {
    	    base = 8;
    	}
        }
    
        /* Ignore overflows and assume ASCII, what source is usually written in */
        while (1) {
    	int increment = -1;
    	if (base == 8) {
    	    if ((*cp >= '0') && (*cp <= '7'))
    		increment = *cp++ - '0';
    	} else if (base == 16) {
    	    if ((*cp >= '0') && (*cp <= '9'))
    		increment = *cp++ - '0';
    	    else if ((*cp >= 'A') &&  (*cp <= 'F'))
    		increment = *cp++ - ('A' - 10);
    	    else if ((*cp >= 'a') && (*cp <= 'f'))
    		increment = *cp++ - ('a' - 10);
    	} else {	/* Decimal */
    	    if ((*cp >= '0') && (*cp <= '9'))
    		increment = *cp++ - '0';
    	}
    	if (increment < 0)
    	    break;
    	*valp = (*valp * base) + increment;
        }
    
        /* Skip trailing qualifiers */
        while (*cp == 'U' || *cp == 'u' || *cp == 'L' || *cp == 'l') cp++;
        return cp;
    }
    
    static const char *
    parse_character (IfParser *g, const char *cp, long *valp)
    {
        char val;
    
        SKIPSPACE (cp);
        if (*cp == '\\')
    	switch (cp[1]) {
    	case 'n': val = '\n'; break;
    	case 't': val = '\t'; break;
    	case 'v': val = '\v'; break;
    	case 'b': val = '\b'; break;
    	case 'r': val = '\r'; break;
    	case 'f': val = '\f'; break;
    	case 'a': val = '\a'; break;
    	case '\\': val = '\\'; break;
    	case '?': val = '\?'; break;
    	case '\'': val = '\''; break;
    	case '\"': val = '\"'; break;
    	case 'x': val = (char) strtol (cp + 2, NULL, 16); break;
    	default: val = (char) strtol (cp + 1, NULL, 8); break;
    	}
        else
    	val = *cp;
        while (*cp != '\'') cp++;
        *valp = (long) val;
        return cp;
    }
    
    static const char *
    parse_value (IfParser *g, const char *cp, long *valp)
    {
        const char *var, *varend;
    
        *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_value (g, cp + 1, 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 '\'':
    	DO (cp = parse_character (g, cp + 1, valp));
    	if (*cp != '\'')
    	    return CALLFUNC(g, handle_error) (g, cp, "'");
    	return cp + 1;
    
          case 'd':
    	if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) {
    	    int paren = 0;
    	    int len;
    
    	    cp += 7;
    	    SKIPSPACE (cp);
    	    if (*cp == '(') {
    		paren = 1;
    		cp++;
    	    }
    	    DO (cp = parse_variable (g, cp, &var));
    	    len = cp - var;
    	    SKIPSPACE (cp);
    	    if (paren && *cp != ')')
    		return CALLFUNC(g, handle_error) (g, cp, ")");
    	    *valp = (*(g->funcs.eval_defined)) (g, var, len);
    	    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));
    	varend = cp;
    	SKIPSPACE(cp);
    	if (*cp != '(') {
    	    *valp = (*(g->funcs.eval_variable)) (g, var, varend - var);
    	} else {
    	    do {
    		long dummy;
    		DO (cp = ParseIfExpression (g, cp + 1, &dummy));
    		SKIPSPACE(cp);
    		if (*cp == ')')
    		    break;
    		if (*cp != ',')
    		    return CALLFUNC(g, handle_error) (g, cp, ",");
    	    } while (1);
    
    	    *valp = 1;	/* XXX */
    	    cp++;
    	}
        }
    
        return cp;
    }
    
    
    
    static const char *
    parse_product (IfParser *g, const char *cp, long *valp)
    {
        long 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));
        if (rightval)
    	    *valp = (*valp / rightval);
        else
            *valp = LONG_MAX;
    	break;
    
          case '%':
    	DO (cp = parse_product (g, cp + 1, &rightval));
    	*valp = (*valp % rightval);
    	break;
        }
        return cp;
    }
    
    
    static const char *
    parse_sum (IfParser *g, const char *cp, long *valp)
    {
        long 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 (IfParser *g, const char *cp, long *valp)
    {
        long 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 (IfParser *g, const char *cp, long *valp)
    {
        long 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 (IfParser *g, const char *cp, long *valp)
    {
        long 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 (IfParser *g, const char *cp, long *valp)
    {
        long 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_bxor (IfParser *g, const char *cp, long *valp)
    {
        long rightval;
    
        DO (cp = parse_band (g, cp, valp));
        SKIPSPACE (cp);
    
        switch (*cp) {
          case '^':
    	DO (cp = parse_bxor (g, cp + 1, &rightval));
    	*valp = (*valp ^ rightval);
    	break;
        }
        return cp;
    }
    
    
    static const char *
    parse_bor (IfParser *g, const char *cp, long *valp)
    {
        long rightval;
    
        DO (cp = parse_bxor (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 (IfParser *g, const char *cp, long *valp)
    {
        long 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 (IfParser *g, const char *cp, long *valp)
    {
        long 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;
    }
    
    
    static const char *
    parse_cond(IfParser *g, const char *cp, long *valp)
    {
        long trueval, falseval;
    
        DO (cp = parse_lor (g, cp, valp));
        SKIPSPACE (cp);
    
        switch (*cp) {
          case '?':
    	DO (cp = parse_cond (g, cp + 1, &trueval));
    	SKIPSPACE (cp);
    	if (*cp != ':')
    	    return CALLFUNC(g, handle_error) (g, cp, ":");
    	DO (cp = parse_cond (g, cp + 1, &falseval));
    	*valp = (*valp ? trueval : falseval);
    	break;
        }
        return cp;
    }
    
    
    /****************************************************************************
    			     External Entry Points
     ****************************************************************************/
    
    const char *
    ParseIfExpression (IfParser *g, const char *cp, long *valp)
    {
        return parse_cond (g, cp, valp);
    }