version 1.58, 2009/01/30 22:35:10 |
version 1.59, 2009/01/30 23:07:17 |
Line 124 __RCSID("$NetBSD$"); |
|
Line 124 __RCSID("$NetBSD$"); |
|
* is applied. |
* is applied. |
* |
* |
* Tokens are scanned from the 'condExpr' string. The scanner (CondToken) |
* Tokens are scanned from the 'condExpr' string. The scanner (CondToken) |
* will return And for '&' and '&&', Or for '|' and '||', Not for '!', |
* will return TOK_AND for '&' and '&&', TOK_OR for '|' and '||', TOK_NOT for '!', |
* LParen for '(', RParen for ')' and will evaluate the other terminal |
* TOK_LPAREN for '(', TOK_RPAREN for ')' and will evaluate the other terminal |
* symbols, using either the default function or the function given in the |
* symbols, using either the default function or the function given in the |
* terminal, and return the result as either True or False. |
* terminal, and return the result as either TOK_TRUE or TOK_FALSE. |
* |
* |
* All Non-Terminal functions (CondE, CondF and CondT) return Err on error. |
* All Non-Terminal functions (CondE, CondF and CondT) return TOK_ERROR on error. |
*/ |
*/ |
typedef enum { |
typedef enum { |
And, Or, Not, True, False, LParen, RParen, EndOfFile, None, Err |
TOK_AND, TOK_OR, TOK_NOT, TOK_TRUE, TOK_FALSE, TOK_LPAREN, TOK_RPAREN, |
|
TOK_EOF, TOK_NONE, TOK_ERROR |
} Token; |
} Token; |
|
|
/*- |
/*- |
Line 170 static const struct If { |
|
Line 171 static const struct If { |
|
|
|
static const struct If *if_info; /* Info for current statement */ |
static const struct If *if_info; /* Info for current statement */ |
static char *condExpr; /* The expression to parse */ |
static char *condExpr; /* The expression to parse */ |
static Token condPushBack=None; /* Single push-back token used in |
static Token condPushBack=TOK_NONE; /* Single push-back token used in |
* parsing */ |
* parsing */ |
|
|
static unsigned int cond_depth = 0; /* current .if nesting level */ |
static unsigned int cond_depth = 0; /* current .if nesting level */ |
Line 617 CondGetString(Boolean doEval, Boolean *q |
|
Line 618 CondGetString(Boolean doEval, Boolean *q |
|
* A Token for the next lexical token in the stream. |
* A Token for the next lexical token in the stream. |
* |
* |
* Side Effects: |
* Side Effects: |
* condPushback will be set back to None if it is used. |
* condPushback will be set back to TOK_NONE if it is used. |
* |
* |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
Line 634 compare_expression(Boolean doEval) |
|
Line 635 compare_expression(Boolean doEval) |
|
Boolean rhsQuoted; |
Boolean rhsQuoted; |
double left, right; |
double left, right; |
|
|
t = Err; |
t = TOK_ERROR; |
rhs = NULL; |
rhs = NULL; |
lhsFree = rhsFree = FALSE; |
lhsFree = rhsFree = FALSE; |
lhsQuoted = rhsQuoted = FALSE; |
lhsQuoted = rhsQuoted = FALSE; |
Line 672 compare_expression(Boolean doEval) |
|
Line 673 compare_expression(Boolean doEval) |
|
break; |
break; |
default: |
default: |
if (!doEval) { |
if (!doEval) { |
t = False; |
t = TOK_FALSE; |
goto done; |
goto done; |
} |
} |
/* For .ifxxx "..." check for non-empty string. */ |
/* For .ifxxx "..." check for non-empty string. */ |
if (lhsQuoted) { |
if (lhsQuoted) { |
t = lhs[0] != 0 ? True : False; |
t = lhs[0] != 0 ? TOK_TRUE : TOK_FALSE; |
goto done; |
goto done; |
} |
} |
/* For .ifxxx <number> compare against zero */ |
/* For .ifxxx <number> compare against zero */ |
if (CondCvtArg(lhs, &left)) { |
if (CondCvtArg(lhs, &left)) { |
t = left != 0.0 ? True : False; |
t = left != 0.0 ? TOK_TRUE : TOK_FALSE; |
goto done; |
goto done; |
} |
} |
/* For .if ${...} check for non-empty string (defProc is ifdef). */ |
/* For .if ${...} check for non-empty string (defProc is ifdef). */ |
if (if_info->form[0] == 0) { |
if (if_info->form[0] == 0) { |
t = lhs[0] != 0 ? True : False; |
t = lhs[0] != 0 ? TOK_TRUE : TOK_FALSE; |
goto done; |
goto done; |
} |
} |
/* Otherwise action default test ... */ |
/* Otherwise action default test ... */ |
t = if_info->defProc(strlen(lhs), lhs) != if_info->doNot ? True : False; |
t = if_info->defProc(strlen(lhs), lhs) != if_info->doNot ? TOK_TRUE : TOK_FALSE; |
goto done; |
goto done; |
} |
} |
|
|
Line 725 do_string_compare: |
|
Line 726 do_string_compare: |
|
* t is set to the result. |
* t is set to the result. |
*/ |
*/ |
if (*op == '=') { |
if (*op == '=') { |
t = strcmp(lhs, rhs) ? False : True; |
t = strcmp(lhs, rhs) ? TOK_FALSE : TOK_TRUE; |
} else { |
} else { |
t = strcmp(lhs, rhs) ? True : False; |
t = strcmp(lhs, rhs) ? TOK_TRUE : TOK_FALSE; |
} |
} |
} else { |
} else { |
/* |
/* |
Line 749 do_string_compare: |
|
Line 750 do_string_compare: |
|
"Unknown operator"); |
"Unknown operator"); |
goto done; |
goto done; |
} |
} |
t = (left != right ? True : False); |
t = (left != right ? TOK_TRUE : TOK_FALSE); |
break; |
break; |
case '=': |
case '=': |
if (op[1] != '=') { |
if (op[1] != '=') { |
Line 757 do_string_compare: |
|
Line 758 do_string_compare: |
|
"Unknown operator"); |
"Unknown operator"); |
goto done; |
goto done; |
} |
} |
t = (left == right ? True : False); |
t = (left == right ? TOK_TRUE : TOK_FALSE); |
break; |
break; |
case '<': |
case '<': |
if (op[1] == '=') { |
if (op[1] == '=') { |
t = (left <= right ? True : False); |
t = (left <= right ? TOK_TRUE : TOK_FALSE); |
} else { |
} else { |
t = (left < right ? True : False); |
t = (left < right ? TOK_TRUE : TOK_FALSE); |
} |
} |
break; |
break; |
case '>': |
case '>': |
if (op[1] == '=') { |
if (op[1] == '=') { |
t = (left >= right ? True : False); |
t = (left >= right ? TOK_TRUE : TOK_FALSE); |
} else { |
} else { |
t = (left > right ? True : False); |
t = (left > right ? TOK_TRUE : TOK_FALSE); |
} |
} |
break; |
break; |
} |
} |
Line 789 get_mpt_arg(char **linePtr, char **argPt |
|
Line 790 get_mpt_arg(char **linePtr, char **argPt |
|
{ |
{ |
/* |
/* |
* Use Var_Parse to parse the spec in parens and return |
* Use Var_Parse to parse the spec in parens and return |
* True if the resulting string is empty. |
* TOK_TRUE if the resulting string is empty. |
*/ |
*/ |
int length; |
int length; |
void *freeIt; |
void *freeIt; |
Line 868 compare_function(Boolean doEval) |
|
Line 869 compare_function(Boolean doEval) |
|
arglen = fn_def->fn_getarg(&cp, &arg, fn_def->fn_name); |
arglen = fn_def->fn_getarg(&cp, &arg, fn_def->fn_name); |
if (arglen <= 0) { |
if (arglen <= 0) { |
condExpr = cp; |
condExpr = cp; |
return arglen < 0 ? Err : False; |
return arglen < 0 ? TOK_ERROR : TOK_FALSE; |
} |
} |
/* Evaluate the argument using the required function. */ |
/* Evaluate the argument using the required function. */ |
t = !doEval || fn_def->fn_proc(arglen, arg) ? True : False; |
t = !doEval || fn_def->fn_proc(arglen, arg) ? TOK_TRUE : TOK_FALSE; |
if (arg) |
if (arg) |
free(arg); |
free(arg); |
condExpr = cp; |
condExpr = cp; |
Line 904 compare_function(Boolean doEval) |
|
Line 905 compare_function(Boolean doEval) |
|
* after .if must have been taken literally, so the argument cannot |
* after .if must have been taken literally, so the argument cannot |
* be empty - even if it contained a variable expansion. |
* be empty - even if it contained a variable expansion. |
*/ |
*/ |
t = !doEval || if_info->defProc(arglen, arg) != if_info->doNot ? True : False; |
t = !doEval || if_info->defProc(arglen, arg) != if_info->doNot ? TOK_TRUE : TOK_FALSE; |
if (arg) |
if (arg) |
free(arg); |
free(arg); |
return t; |
return t; |
Line 916 CondToken(Boolean doEval) |
|
Line 917 CondToken(Boolean doEval) |
|
Token t; |
Token t; |
|
|
t = condPushBack; |
t = condPushBack; |
if (t != None) { |
if (t != TOK_NONE) { |
condPushBack = None; |
condPushBack = TOK_NONE; |
return t; |
return t; |
} |
} |
|
|
Line 929 CondToken(Boolean doEval) |
|
Line 930 CondToken(Boolean doEval) |
|
|
|
case '(': |
case '(': |
condExpr++; |
condExpr++; |
return LParen; |
return TOK_LPAREN; |
|
|
case ')': |
case ')': |
condExpr++; |
condExpr++; |
return RParen; |
return TOK_RPAREN; |
|
|
case '|': |
case '|': |
if (condExpr[1] == '|') { |
if (condExpr[1] == '|') { |
condExpr++; |
condExpr++; |
} |
} |
condExpr++; |
condExpr++; |
return Or; |
return TOK_OR; |
|
|
case '&': |
case '&': |
if (condExpr[1] == '&') { |
if (condExpr[1] == '&') { |
condExpr++; |
condExpr++; |
} |
} |
condExpr++; |
condExpr++; |
return And; |
return TOK_AND; |
|
|
case '!': |
case '!': |
condExpr++; |
condExpr++; |
return Not; |
return TOK_NOT; |
|
|
case '#': |
case '#': |
case '\n': |
case '\n': |
case '\0': |
case '\0': |
return EndOfFile; |
return TOK_EOF; |
|
|
case '"': |
case '"': |
case '$': |
case '$': |
Line 971 CondToken(Boolean doEval) |
|
Line 972 CondToken(Boolean doEval) |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* CondT -- |
* CondT -- |
* Parse a single term in the expression. This consists of a terminal |
* Parse a single term in the expression. This consists of a terminal |
* symbol or Not and a terminal symbol (not including the binary |
* symbol or TOK_NOT and a terminal symbol (not including the binary |
* operators): |
* operators): |
* T -> defined(variable) | make(target) | exists(file) | symbol |
* T -> defined(variable) | make(target) | exists(file) | symbol |
* T -> ! T | ( E ) |
* T -> ! T | ( E ) |
* |
* |
* Results: |
* Results: |
* True, False or Err. |
* TOK_TRUE, TOK_FALSE or TOK_ERROR. |
* |
* |
* Side Effects: |
* Side Effects: |
* Tokens are consumed. |
* Tokens are consumed. |
Line 991 CondT(Boolean doEval) |
|
Line 992 CondT(Boolean doEval) |
|
|
|
t = CondToken(doEval); |
t = CondToken(doEval); |
|
|
if (t == EndOfFile) { |
if (t == TOK_EOF) { |
/* |
/* |
* If we reached the end of the expression, the expression |
* If we reached the end of the expression, the expression |
* is malformed... |
* is malformed... |
*/ |
*/ |
t = Err; |
t = TOK_ERROR; |
} else if (t == LParen) { |
} else if (t == TOK_LPAREN) { |
/* |
/* |
* T -> ( E ) |
* T -> ( E ) |
*/ |
*/ |
t = CondE(doEval); |
t = CondE(doEval); |
if (t != Err) { |
if (t != TOK_ERROR) { |
if (CondToken(doEval) != RParen) { |
if (CondToken(doEval) != TOK_RPAREN) { |
t = Err; |
t = TOK_ERROR; |
} |
} |
} |
} |
} else if (t == Not) { |
} else if (t == TOK_NOT) { |
t = CondT(doEval); |
t = CondT(doEval); |
if (t == True) { |
if (t == TOK_TRUE) { |
t = False; |
t = TOK_FALSE; |
} else if (t == False) { |
} else if (t == TOK_FALSE) { |
t = True; |
t = TOK_TRUE; |
} |
} |
} |
} |
return (t); |
return (t); |
Line 1025 CondT(Boolean doEval) |
|
Line 1026 CondT(Boolean doEval) |
|
* F -> T && F | T |
* F -> T && F | T |
* |
* |
* Results: |
* Results: |
* True, False or Err |
* TOK_TRUE, TOK_FALSE or TOK_ERROR |
* |
* |
* Side Effects: |
* Side Effects: |
* Tokens are consumed. |
* Tokens are consumed. |
Line 1038 CondF(Boolean doEval) |
|
Line 1039 CondF(Boolean doEval) |
|
Token l, o; |
Token l, o; |
|
|
l = CondT(doEval); |
l = CondT(doEval); |
if (l != Err) { |
if (l != TOK_ERROR) { |
o = CondToken(doEval); |
o = CondToken(doEval); |
|
|
if (o == And) { |
if (o == TOK_AND) { |
/* |
/* |
* F -> T && F |
* F -> T && F |
* |
* |
* If T is False, the whole thing will be False, but we have to |
* 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). |
* 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 T is TOK_TRUE, the result is the r.h.s., be it an TOK_ERROR or no. |
*/ |
*/ |
if (l == True) { |
if (l == TOK_TRUE) { |
l = CondF(doEval); |
l = CondF(doEval); |
} else { |
} else { |
(void)CondF(FALSE); |
(void)CondF(FALSE); |
Line 1071 CondF(Boolean doEval) |
|
Line 1072 CondF(Boolean doEval) |
|
* E -> F || E | F |
* E -> F || E | F |
* |
* |
* Results: |
* Results: |
* True, False or Err. |
* TOK_TRUE, TOK_FALSE or TOK_ERROR. |
* |
* |
* Side Effects: |
* Side Effects: |
* Tokens are, of course, consumed. |
* Tokens are, of course, consumed. |
Line 1084 CondE(Boolean doEval) |
|
Line 1085 CondE(Boolean doEval) |
|
Token l, o; |
Token l, o; |
|
|
l = CondF(doEval); |
l = CondF(doEval); |
if (l != Err) { |
if (l != TOK_ERROR) { |
o = CondToken(doEval); |
o = CondToken(doEval); |
|
|
if (o == Or) { |
if (o == TOK_OR) { |
/* |
/* |
* E -> F || E |
* E -> F || E |
* |
* |
* A similar thing occurs for ||, except that here we make sure |
* 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. |
* the l.h.s. is TOK_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 |
* Once again, if l is TOK_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. |
* again if l is TOK_TRUE, we parse the r.h.s. to throw it away. |
*/ |
*/ |
if (l == False) { |
if (l == TOK_FALSE) { |
l = CondE(doEval); |
l = CondE(doEval); |
} else { |
} else { |
(void)CondE(FALSE); |
(void)CondE(FALSE); |
Line 1151 Cond_EvalExpression(const struct If *inf |
|
Line 1152 Cond_EvalExpression(const struct If *inf |
|
|
|
if_info = info != NULL ? info : ifs + 4; |
if_info = info != NULL ? info : ifs + 4; |
condExpr = line; |
condExpr = line; |
condPushBack = None; |
condPushBack = TOK_NONE; |
|
|
rval = do_Cond_EvalExpression(value); |
rval = do_Cond_EvalExpression(value); |
|
|
Line 1170 do_Cond_EvalExpression(Boolean *value) |
|
Line 1171 do_Cond_EvalExpression(Boolean *value) |
|
{ |
{ |
|
|
switch (CondE(TRUE)) { |
switch (CondE(TRUE)) { |
case True: |
case TOK_TRUE: |
if (CondToken(TRUE) == EndOfFile) { |
if (CondToken(TRUE) == TOK_EOF) { |
*value = TRUE; |
*value = TRUE; |
return COND_PARSE; |
return COND_PARSE; |
} |
} |
break; |
break; |
case False: |
case TOK_FALSE: |
if (CondToken(TRUE) == EndOfFile) { |
if (CondToken(TRUE) == TOK_EOF) { |
*value = FALSE; |
*value = FALSE; |
return COND_PARSE; |
return COND_PARSE; |
} |
} |
break; |
break; |
default: |
default: |
case Err: |
case TOK_ERROR: |
break; |
break; |
} |
} |
|
|