/* Partially preprocesses a #if expression. ifexp points to the text * immediately following the #if. The function seeks to the end of the * expression and evaluates it. The return value points to the text * immediately following the expression. If the expression has a * defined state, status receives either statDefined or statUndefined. * If the expression's contents are disjoint from the defined and * undefined symbols, status receives statUnaffected. Otherwise the * expression is in a partial state, in which case status receives * statPartDefined, and the original string is modified so as to * remove the parts of the expression that have a defined state. */ static char const *seqif(struct ppproc *ppp, char *ifexp, enum status *status) { struct exptree *tree; char const *ret; char *str; int defined, n; tree = initexptree(); *status = statUnaffected; n = geterrormark(); ret = parseexptree(tree, ppp->cl, ifexp); if (errorsincemark(n)) { *status = statError; goto quit; } n = markdefined(tree, ppp->defs, TRUE) + markdefined(tree, ppp->undefs, FALSE); if (n) { *status = evaltree(tree, &defined) ? statDefined : statUndefined; if (!defined) { *status = statPartDefined; str = allocate(strlen(ifexp) + 1); n = unparseevaluated(tree, str); strcpy(str + n, ifexp + getexplength(tree)); strcpy(ifexp, str); deallocate(str); } } quit: freeexptree(tree); return ret; }
/* Creates and returns a new subtree, with pos being the index of * which child branch to insert the new subtree at. */ static struct exptree *addnewchild(struct exptree *t, int pos) { struct exptree *child; child = initexptree(); if (!addchild(t, child, pos)) { deallocate(child); return NULL; } return child; }
/* Parses a C preprocessor expression from the C source code pointed * to by input, via the given lexer, and creates a expression tree * representing it. prec gives the precedence of the operator this * expression is attached to, or zero if there is no such operator. * The return value points to the source immediately following the * parsed expression. */ static char const *parseexp(struct exptree *t, struct clexer *cl, char const *input, int prec) { struct exptree *x; char const *tmp; int found, n; if (t->exp != expNone) return input; if (*input == '(') { tmp = input; input = skipwhite(cl, nextchar(cl, input)); input = parseexp(t, cl, input, 0); if (t->exp == expNone) { error(errSyntax); goto failure; } else if (*input != ')') { error(errOpenParenthesis); goto failure; } t->begin = tmp; input = nextchar(cl, input); t->end = input; input = skipwhite(cl, input); } else { found = FALSE; for (n = 0 ; n < sizearray(prefixops) ; ++n) { if (!memcmp(input, prefixops[n].symbol, prefixops[n].size)) { found = TRUE; break; } } if (found) { if (prefixops[n].prec < prec) { error(errMissingOperand); goto failure; } t->exp = expOperator; t->op = prefixops[n].op; t->begin = input; input = nextchars(cl, input, prefixops[n].size); input = skipwhite(cl, input); x = addnewchild(t, -1); input = parseexp(x, cl, input, prefixops[n].prec); if (x->exp == expNone) { error(errSyntax); goto failure; } t->end = x->end; } else { input = parseconstant(t, cl, input); if (t->exp == expNone) { error(errSyntax); goto failure; } } } for (;;) { found = FALSE; for (n = 0 ; n < sizearray(infixops) ; ++n) { if (!memcmp(input, infixops[n].symbol, infixops[n].size)) { found = TRUE; break; } } if (!found || infixops[n].prec < prec || (infixops[n].prec == prec && infixops[n].l2r)) break; input = nextchars(cl, input, infixops[n].size); input = skipwhite(cl, input); x = initexptree(); tmp = t->begin; *x = *t; clearexptree(t); t->exp = expOperator; t->op = infixops[n].op; t->begin = tmp; addchild(t, x, -1); x = addnewchild(t, -1); if (t->op == opConditional) { input = parseexp(x, cl, input, infixops[n].prec); if (x->exp == expNone) { error(errSyntax); goto failure; } if (*input != ':') { error(errSyntax); goto failure; } input = skipwhite(cl, nextchar(cl, input)); x = addnewchild(t, -1); } input = parseexp(x, cl, input, infixops[n].prec); if (x->exp == expNone) { error(errSyntax); goto failure; } t->end = x->end; } return input; failure: t->exp = expNone; return input; }