示例#1
0
/*-
 *-----------------------------------------------------------------------
 * CondT --
 *	Parse a single term in the expression. This consists of a terminal
 *	symbol or Not and a terminal symbol (not including the binary
 *	operators):
 *	    T -> defined(variable) | make(target) | exists(file) | symbol
 *	    T -> ! T | ( E )
 *
 * Results:
 *	True, False or Err.
 *
 * Side Effects:
 *	Tokens are consumed.
 *-----------------------------------------------------------------------
 */
static Token
CondT(bool doEval)
{
	Token t;

	t = CondToken(doEval);

	if (t == EndOfFile)
		/* If we reached the end of the expression, the expression
		 * is malformed...  */
		t = Err;
	else if (t == LParen) {
		/* T -> ( E ).	*/
		t = CondE(doEval);
		if (t != Err)
			if (CondToken(doEval) != RParen)
				t = Err;
	} else if (t == Not) {
		t = CondT(doEval);
		if (t == True)
			t = False;
		else if (t == False)
			t = True;
	}
	return t;
}
示例#2
0
/*-
 *-----------------------------------------------------------------------
 * CondT --
 *	Parse a single term in the expression. This consists of a terminal
 *	symbol or TOK_NOT and a terminal symbol (not including the binary
 *	operators):
 *	    T -> defined(variable) | make(target) | exists(file) | symbol
 *	    T -> ! T | ( E )
 *
 * Results:
 *	TOK_TRUE, TOK_FALSE or TOK_ERROR.
 *
 * Side Effects:
 *	Tokens are consumed.
 *
 *-----------------------------------------------------------------------
 */
static Token
CondT(Boolean doEval)
{
    Token   t;

    t = CondToken(doEval);

    if (t == TOK_EOF) {
	/*
	 * If we reached the end of the expression, the expression
	 * is malformed...
	 */
	t = TOK_ERROR;
    } else if (t == TOK_LPAREN) {
	/*
	 * T -> ( E )
	 */
	t = CondE(doEval);
	if (t != TOK_ERROR) {
	    if (CondToken(doEval) != TOK_RPAREN) {
		t = TOK_ERROR;
	    }
	}
    } else if (t == TOK_NOT) {
	t = CondT(doEval);
	if (t == TOK_TRUE) {
	    t = TOK_FALSE;
	} else if (t == TOK_FALSE) {
	    t = TOK_TRUE;
	}
    }
    return (t);
}
示例#3
0
/*-
 *-----------------------------------------------------------------------
 * CondE --
 *	Main expression production.
 *	    E -> F || E | F
 *
 * Results:
 *	True, False or Err.
 *
 * Side Effects:
 *	Tokens are, of course, consumed.
 *-----------------------------------------------------------------------
 */
static Token
CondE(bool doEval)
{
	Token l, o;

	l = CondF(doEval);
	if (l != Err) {
		o = CondToken(doEval);

		if (o == Or) {
			/* E -> F || E
			 *
			 * A similar thing occurs for ||, except that here we
			 * make sure the l.h.s. is False before we bother to
			 * evaluate the r.h.s.  Once again, if l is False, the
			 * result is the r.h.s. and once again if l is True, we
			 * parse the r.h.s. to throw it away.  */
			if (l == False)
				l = CondE(doEval);
			else
				(void)CondE(false);
		} else
			/* E -> F.	*/
			condPushBack = o;
	}
	return l;
}
示例#4
0
/*-
 *-----------------------------------------------------------------------
 * CondF --
 *	Parse a conjunctive factor (nice name, wot?)
 *	    F -> T && F | T
 *
 * Results:
 *	True, False or Err
 *
 * Side Effects:
 *	Tokens are consumed.
 *-----------------------------------------------------------------------
 */
static Token
CondF(bool doEval)
{
	Token l, o;

	l = CondT(doEval);
	if (l != Err) {
		o = CondToken(doEval);

		if (o == And) {
		    /* F -> T && F
		     *
		     * If T is False, the whole thing will be False, but we
		     * have to parse the r.h.s. anyway (to throw it away).  If
		     * T is True, the result is the r.h.s., be it an Err or no.
		     * */
		    if (l == True)
			    l = CondF(doEval);
		    else
			    (void)CondF(false);
		} else
			/* F -> T.	*/
			condPushBack = o;
	}
	return l;
}
示例#5
0
/*-
 *-----------------------------------------------------------------------
 * CondE --
 *	Main expression production.
 *	    E -> F || E | F
 *
 * Results:
 *	TOK_TRUE, TOK_FALSE or TOK_ERROR.
 *
 * Side Effects:
 *	Tokens are, of course, consumed.
 *
 *-----------------------------------------------------------------------
 */
static Token
CondE(Boolean doEval)
{
    Token   l, o;

    l = CondF(doEval);
    if (l != TOK_ERROR) {
	o = CondToken(doEval);

	if (o == TOK_OR) {
	    /*
	     * E -> F || E
	     *
	     * A similar thing occurs for ||, except that here we make sure
	     * the l.h.s. is TOK_FALSE before we bother to evaluate the r.h.s.
	     * Once again, if l is TOK_FALSE, the result is the r.h.s. and once
	     * again if l is TOK_TRUE, we parse the r.h.s. to throw it away.
	     */
	    if (l == TOK_FALSE) {
		l = CondE(doEval);
	    } else {
		(void)CondE(FALSE);
	    }
	} else {
	    /*
	     * E -> F
	     */
	    CondPushBack(o);
	}
    }
    return (l);
}
示例#6
0
/*-
 *-----------------------------------------------------------------------
 * CondF --
 *	Parse a conjunctive factor (nice name, wot?)
 *	    F -> T && F | T
 *
 * Results:
 *	TOK_TRUE, TOK_FALSE or TOK_ERROR
 *
 * Side Effects:
 *	Tokens are consumed.
 *
 *-----------------------------------------------------------------------
 */
static Token
CondF(Boolean doEval)
{
    Token   l, o;

    l = CondT(doEval);
    if (l != TOK_ERROR) {
	o = CondToken(doEval);

	if (o == TOK_AND) {
	    /*
	     * F -> T && F
	     *
	     * If T is TOK_FALSE, the whole thing will be TOK_FALSE, but we have to
	     * parse the r.h.s. anyway (to throw it away).
	     * If T is TOK_TRUE, the result is the r.h.s., be it an TOK_ERROR or no.
	     */
	    if (l == TOK_TRUE) {
		l = CondF(doEval);
	    } else {
		(void)CondF(FALSE);
	    }
	} else {
	    /*
	     * F -> T
	     */
	    CondPushBack(o);
	}
    }
    return (l);
}
示例#7
0
static int
do_Cond_EvalExpression(Boolean *value)
{

    switch (CondE(TRUE)) {
    case TOK_TRUE:
	if (CondToken(TRUE) == TOK_EOF) {
	    *value = TRUE;
	    return COND_PARSE;
	}
	break;
    case TOK_FALSE:
	if (CondToken(TRUE) == TOK_EOF) {
	    *value = FALSE;
	    return COND_PARSE;
	}
	break;
    default:
    case TOK_ERROR:
	break;
    }

    return COND_INVALID;
}
示例#8
0
/* Evaluate conditional in line.
 * returns COND_SKIP, COND_PARSE, COND_INVALID, COND_ISFOR, COND_ISINCLUDE,
 * COND_ISUNDEF.
 * A conditional line looks like this:
 *	<cond-type> <expr>
 *	where <cond-type> is any of if, ifmake, ifnmake, ifdef,
 *	ifndef, elif, elifmake, elifnmake, elifdef, elifndef
 *	and <expr> consists of &&, ||, !, make(target), defined(variable)
 *	and parenthetical groupings thereof.
 */
int
Cond_Eval(const char *line)
{
	/* find end of keyword */
	const char *end;
	uint32_t k;
	size_t len;
	struct If *ifp;
	bool value = false;
	int level;	/* Level at which to report errors. */

	level = PARSE_FATAL;

	for (end = line; islower(*end); end++)
		;
	/* quick path: recognize special targets early on */
	if (*end == '.' || *end == ':')
		return COND_INVALID;
	len = end - line;
	k = ohash_interval(line, &end);
	switch(k % MAGICSLOTS2) {
	case K_COND_IF % MAGICSLOTS2:
		if (k == K_COND_IF && len == strlen(COND_IF) &&
		    strncmp(line, COND_IF, len) == 0) {
			ifp = ifs + COND_IF_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_IFDEF % MAGICSLOTS2:
		if (k == K_COND_IFDEF && len == strlen(COND_IFDEF) &&
		    strncmp(line, COND_IFDEF, len) == 0) {
			ifp = ifs + COND_IFDEF_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_IFNDEF % MAGICSLOTS2:
		if (k == K_COND_IFNDEF && len == strlen(COND_IFNDEF) &&
		    strncmp(line, COND_IFNDEF, len) == 0) {
			ifp = ifs + COND_IFNDEF_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_IFMAKE % MAGICSLOTS2:
		if (k == K_COND_IFMAKE && len == strlen(COND_IFMAKE) &&
		    strncmp(line, COND_IFMAKE, len) == 0) {
			ifp = ifs + COND_IFMAKE_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_IFNMAKE % MAGICSLOTS2:
		if (k == K_COND_IFNMAKE && len == strlen(COND_IFNMAKE) &&
		    strncmp(line, COND_IFNMAKE, len) == 0) {
			ifp = ifs + COND_IFNMAKE_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_ELIF % MAGICSLOTS2:
		if (k == K_COND_ELIF && len == strlen(COND_ELIF) &&
		    strncmp(line, COND_ELIF, len) == 0) {
			ifp = ifs + COND_ELIF_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_ELIFDEF % MAGICSLOTS2:
		if (k == K_COND_ELIFDEF && len == strlen(COND_ELIFDEF) &&
		    strncmp(line, COND_ELIFDEF, len) == 0) {
			ifp = ifs + COND_ELIFDEF_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_ELIFNDEF % MAGICSLOTS2:
		if (k == K_COND_ELIFNDEF && len == strlen(COND_ELIFNDEF) &&
		    strncmp(line, COND_ELIFNDEF, len) == 0) {
			ifp = ifs + COND_ELIFNDEF_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_ELIFMAKE % MAGICSLOTS2:
		if (k == K_COND_ELIFMAKE && len == strlen(COND_ELIFMAKE) &&
		    strncmp(line, COND_ELIFMAKE, len) == 0) {
			ifp = ifs + COND_ELIFMAKE_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_ELIFNMAKE % MAGICSLOTS2:
		if (k == K_COND_ELIFNMAKE && len == strlen(COND_ELIFNMAKE) &&
		    strncmp(line, COND_ELIFNMAKE, len) == 0) {
			ifp = ifs + COND_ELIFNMAKE_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_ELSE % MAGICSLOTS2:
		/* valid conditional whose value is the inverse
		 * of the previous if we parsed.  */
		if (k == K_COND_ELSE && len == strlen(COND_ELSE) &&
		    strncmp(line, COND_ELSE, len) == 0) {
			if (condTop == MAXIF) {
				Parse_Error(level, "if-less else");
				return COND_INVALID;
			} else if (skipIfLevel == 0) {
				value = !condStack[condTop].value;
				ifp = ifs + COND_ELSE_INDEX;
			} else
				return COND_SKIP;
		} else
			return COND_INVALID;
		break;
	case K_COND_ENDIF % MAGICSLOTS2:
		if (k == K_COND_ENDIF && len == strlen(COND_ENDIF) &&
		    strncmp(line, COND_ENDIF, len) == 0) {
			/* End of a conditional section. If skipIfLevel is
			 * non-zero, that conditional was skipped, so lines
			 * following it should also be skipped. Hence, we
			 * return COND_SKIP. Otherwise, the conditional was
			 * read so succeeding lines should be parsed (think
			 * about it...) so we return COND_PARSE, unless this
			 * endif isn't paired with a decent if.  */
			if (skipIfLevel != 0) {
				skipIfLevel--;
				return COND_SKIP;
			} else {
				if (condTop == MAXIF) {
					Parse_Error(level, "if-less endif");
					return COND_INVALID;
				} else {
					skipLine = false;
					condTop++;
					return COND_PARSE;
				}
			}
		} else
			return COND_INVALID;
		break;

	/* Recognize other keywords there, to simplify parser's task */
	case K_COND_FOR % MAGICSLOTS2:
		if (k == K_COND_FOR && len == strlen(COND_FOR) &&
		    strncmp(line, COND_FOR, len) == 0)
			return COND_ISFOR;
		else
			return COND_INVALID;
	case K_COND_UNDEF % MAGICSLOTS2:
		if (k == K_COND_UNDEF && len == strlen(COND_UNDEF) &&
		    strncmp(line, COND_UNDEF, len) == 0)
			return COND_ISUNDEF;
		else
			return COND_INVALID;
	case K_COND_POISON % MAGICSLOTS2:
		if (k == K_COND_POISON && len == strlen(COND_POISON) &&
		    strncmp(line, COND_POISON, len) == 0)
			return COND_ISPOISON;
		else
			return COND_INVALID;
	case K_COND_INCLUDE % MAGICSLOTS2:
		if (k == K_COND_INCLUDE && len == strlen(COND_INCLUDE) &&
		    strncmp(line, COND_INCLUDE, len) == 0)
			return COND_ISINCLUDE;
		else
			return COND_INVALID;
	default:
		/* Not a valid conditional type. No error...  */
		return COND_INVALID;
	}

	if (ifp->isElse) {
		if (condTop == MAXIF) {
			Parse_Error(level, "if-less elif");
			return COND_INVALID;
		} else if (skipIfLevel != 0 || condStack[condTop].value) {
			/*
			 * Skip if we're meant to or is an else-type
			 * conditional and previous corresponding one was
			 * evaluated to true.
			 */
			skipLine = true;
			return COND_SKIP;
		}
	} else if (skipLine) {
		/* Don't even try to evaluate a conditional that's not an else
		 * if we're skipping things...  */
		skipIfLevel++;
		return COND_SKIP;
	} else
		condTop--;

	if (condTop < 0) {
		/* This is the one case where we can definitely proclaim a fatal
		 * error. If we don't, we're hosed.  */
		Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.",
		    MAXIF);
		condTop = 0;
		return COND_INVALID;
	}

	if (ifp->defProc) {
		/* Initialize file-global variables for parsing.  */
		condDefProc = ifp->defProc;
		condInvert = ifp->doNot;

		line += len;

		while (*line == ' ' || *line == '\t')
			line++;

		condExpr = line;
		condPushBack = None;

		switch (CondE(true)) {
		case True:
			if (CondToken(true) == EndOfFile) {
				value = true;
				break;
			}
			goto err;
			/* FALLTHROUGH */
		case False:
			if (CondToken(true) == EndOfFile) {
				value = false;
				break;
			}
			/* FALLTHROUGH */
		case Err:
err:
			Parse_Error(level, "Malformed conditional (%s)", line);
			return COND_INVALID;
		default:
			break;
		}
	}

	condStack[condTop].value = value;
	Parse_FillLocation(&condStack[condTop].origin);
	skipLine = !value;
	return value ? COND_PARSE : COND_SKIP;
}