/*- *----------------------------------------------------------------------- * 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; }
/*- *----------------------------------------------------------------------- * 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); }
/*- *----------------------------------------------------------------------- * 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; }
/*- *----------------------------------------------------------------------- * 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; }
/*- *----------------------------------------------------------------------- * 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); }
/*- *----------------------------------------------------------------------- * 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); }
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; }
/* 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; }