📄 tclexpr.c
字号:
case '?':
infoPtr->token = QUESTY;
return TCL_OK;
case ':':
infoPtr->token = COLON;
return TCL_OK;
case '<':
switch (p[1]) {
case '<':
infoPtr->expr = p+2;
infoPtr->token = LEFT_SHIFT;
break;
case '=':
infoPtr->expr = p+2;
infoPtr->token = LEQ;
break;
default:
infoPtr->token = LESS;
break;
}
return TCL_OK;
case '>':
switch (p[1]) {
case '>':
infoPtr->expr = p+2;
infoPtr->token = RIGHT_SHIFT;
break;
case '=':
infoPtr->expr = p+2;
infoPtr->token = GEQ;
break;
default:
infoPtr->token = GREATER;
break;
}
return TCL_OK;
case '=':
if (p[1] == '=') {
infoPtr->expr = p+2;
infoPtr->token = EQUAL;
} else {
infoPtr->token = UNKNOWN;
}
return TCL_OK;
case '!':
if (p[1] == '=') {
infoPtr->expr = p+2;
infoPtr->token = NEQ;
} else {
infoPtr->token = NOT;
}
return TCL_OK;
case '&':
if (p[1] == '&') {
infoPtr->expr = p+2;
infoPtr->token = AND;
} else {
infoPtr->token = BIT_AND;
}
return TCL_OK;
case '^':
infoPtr->token = BIT_XOR;
return TCL_OK;
case '|':
if (p[1] == '|') {
infoPtr->expr = p+2;
infoPtr->token = OR;
} else {
infoPtr->token = BIT_OR;
}
return TCL_OK;
case '~':
infoPtr->token = BIT_NOT;
return TCL_OK;
case 0:
infoPtr->token = END;
infoPtr->expr = p;
return TCL_OK;
default:
infoPtr->expr = p+1;
infoPtr->token = UNKNOWN;
return TCL_OK;
}
}
/*
*----------------------------------------------------------------------
*
* ExprGetValue --
*
* Parse a "value" from the remainder of the expression in infoPtr.
*
* Results:
* Normally TCL_OK is returned. The value of the expression is
* returned in *valuePtr. If an error occurred, then interp->result
* contains an error message and TCL_ERROR is returned.
* InfoPtr->token will be left pointing to the token AFTER the
* expression, and infoPtr->expr will point to the character just
* after the terminating token.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
ExprGetValue(interp, infoPtr, prec, valuePtr)
Tcl_Interp *interp; /* Interpreter to use for error
* reporting. */
register ExprInfo *infoPtr; /* Describes the state of the parse
* just before the value (i.e. ExprLex
* will be called to get first token
* of value). */
int prec; /* Treat any un-parenthesized operator
* with precedence <= this as the end
* of the expression. */
Value *valuePtr; /* Where to store the value of the
* expression. Caller must have
* initialized pv field. */
{
Interp *iPtr = (Interp *) interp;
Value value2; /* Second operand for current
* operator. */
int operator; /* Current operator (either unary
* or binary). */
int badType; /* Type of offending argument; used
* for error messages. */
int gotOp; /* Non-zero means already lexed the
* operator (while picking up value
* for unary operator). Don't lex
* again. */
int result;
/*
* There are two phases to this procedure. First, pick off an initial
* value. Then, parse (binary operator, value) pairs until done.
*/
gotOp = 0;
value2.pv.buffer = value2.pv.next = value2.staticSpace;
value2.pv.end = value2.pv.buffer + STATIC_STRING_SPACE - 1;
value2.pv.expandProc = TclExpandParseValue;
value2.pv.clientData = (ClientData) NULL;
result = ExprLex(interp, infoPtr, valuePtr);
if (result != TCL_OK) {
goto done;
}
if (infoPtr->token == OPEN_PAREN) {
/*
* Parenthesized sub-expression.
*/
result = ExprGetValue(interp, infoPtr, -1, valuePtr);
if (result != TCL_OK) {
goto done;
}
if (infoPtr->token != CLOSE_PAREN) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp,
"unmatched parentheses in expression \"",
infoPtr->originalExpr, "\"", (char *) NULL);
result = TCL_ERROR;
goto done;
}
} else {
if (infoPtr->token == MINUS) {
infoPtr->token = UNARY_MINUS;
}
if (infoPtr->token >= UNARY_MINUS) {
/*
* Process unary operators.
*/
operator = infoPtr->token;
result = ExprGetValue(interp, infoPtr, precTable[infoPtr->token],
valuePtr);
if (result != TCL_OK) {
goto done;
}
switch (operator) {
case UNARY_MINUS:
if (valuePtr->type == TYPE_INT) {
valuePtr->intValue = -valuePtr->intValue;
} else if (valuePtr->type == TYPE_DOUBLE){
valuePtr->doubleValue = -valuePtr->doubleValue;
} else {
badType = valuePtr->type;
goto illegalType;
}
break;
case NOT:
if (valuePtr->type == TYPE_INT) {
valuePtr->intValue = !valuePtr->intValue;
} else if (valuePtr->type == TYPE_DOUBLE) {
/*
* Theoretically, should be able to use
* "!valuePtr->intValue", but apparently some
* compilers can't handle it.
*/
if (valuePtr->doubleValue == 0.0) {
valuePtr->intValue = 1;
} else {
valuePtr->intValue = 0;
}
valuePtr->type = TYPE_INT;
} else {
badType = valuePtr->type;
goto illegalType;
}
break;
case BIT_NOT:
if (valuePtr->type == TYPE_INT) {
valuePtr->intValue = ~valuePtr->intValue;
} else {
badType = valuePtr->type;
goto illegalType;
}
break;
}
gotOp = 1;
} else if (infoPtr->token != VALUE) {
goto syntaxError;
}
}
/*
* Got the first operand. Now fetch (operator, operand) pairs.
*/
if (!gotOp) {
result = ExprLex(interp, infoPtr, &value2);
if (result != TCL_OK) {
goto done;
}
}
while (1) {
operator = infoPtr->token;
value2.pv.next = value2.pv.buffer;
if ((operator < MULT) || (operator >= UNARY_MINUS)) {
if ((operator == END) || (operator == CLOSE_PAREN)) {
result = TCL_OK;
goto done;
} else {
goto syntaxError;
}
}
if (precTable[operator] <= prec) {
result = TCL_OK;
goto done;
}
/*
* If we're doing an AND or OR and the first operand already
* determines the result, don't execute anything in the
* second operand: just parse. Same style for ?: pairs.
*/
if ((operator == AND) || (operator == OR) || (operator == QUESTY)) {
if (valuePtr->type == TYPE_DOUBLE) {
valuePtr->intValue = valuePtr->doubleValue != 0;
valuePtr->type = TYPE_INT;
} else if (valuePtr->type == TYPE_STRING) {
badType = TYPE_STRING;
goto illegalType;
}
if (((operator == AND) && !valuePtr->intValue)
|| ((operator == OR) && valuePtr->intValue)) {
iPtr->noEval++;
result = ExprGetValue(interp, infoPtr, precTable[operator],
&value2);
iPtr->noEval--;
} else if (operator == QUESTY) {
if (valuePtr->intValue != 0) {
valuePtr->pv.next = valuePtr->pv.buffer;
result = ExprGetValue(interp, infoPtr, precTable[operator],
valuePtr);
if (result != TCL_OK) {
goto done;
}
if (infoPtr->token != COLON) {
goto syntaxError;
}
value2.pv.next = value2.pv.buffer;
iPtr->noEval++;
result = ExprGetValue(interp, infoPtr, precTable[operator],
&value2);
iPtr->noEval--;
} else {
iPtr->noEval++;
result = ExprGetValue(interp, infoPtr, precTable[operator],
&value2);
iPtr->noEval--;
if (result != TCL_OK) {
goto done;
}
if (infoPtr->token != COLON) {
goto syntaxError;
}
valuePtr->pv.next = valuePtr->pv.buffer;
result = ExprGetValue(interp, infoPtr, precTable[operator],
valuePtr);
}
} else {
result = ExprGetValue(interp, infoPtr, precTable[operator],
&value2);
}
} else {
result = ExprGetValue(interp, infoPtr, precTable[operator],
&value2);
}
if (result != TCL_OK) {
goto done;
}
if ((infoPtr->token < MULT) && (infoPtr->token != VALUE)
&& (infoPtr->token != END)
&& (infoPtr->token != CLOSE_PAREN)) {
goto syntaxError;
}
/*
* At this point we've got two values and an operator. Check
* to make sure that the particular data types are appropriate
* for the particular operator, and perform type conversion
* if necessary.
*/
switch (operator) {
/*
* For the operators below, no strings are allowed and
* ints get converted to floats if necessary.
*/
case MULT: case DIVIDE: case PLUS: case MINUS:
if ((valuePtr->type == TYPE_STRING)
|| (value2.type == TYPE_STRING)) {
badType = TYPE_STRING;
goto illegalType;
}
if (valuePtr->type == TYPE_DOUBLE) {
if (value2.type == TYPE_INT) {
value2.doubleValue = value2.intValue;
value2.type = TYPE_DOUBLE;
}
} else if (value2.type == TYPE_DOUBLE) {
if (valuePtr->type == TYPE_INT) {
valuePtr->doubleValue = valuePtr->intValue;
valuePtr->type = TYPE_DOUBLE;
}
}
break;
/*
* For the operators below, only integers are allowed.
*/
case MOD: case LEFT_SHIFT: case RIGHT_SHIFT:
case BIT_AND: case BIT_XOR: case BIT_OR:
if (valuePtr->type != TYPE_INT) {
badType = valuePtr->type;
goto illegalType;
} else if (value2.type != TYPE_INT) {
badType = value2.type;
goto illegalType;
}
break;
/*
* For the operators below, any type is allowed but the
* two operands must have the same type. Convert integers
* to floats and either to strings, if necessary.
*/
case LESS: case GREATER: case LEQ: case GEQ:
case EQUAL: case NEQ:
if (valuePtr->type == TYPE_STRING) {
if (value2.type != TYPE_STRING) {
ExprMakeString(&value2);
}
} else if (value2.type == TYPE_STRING) {
if (valuePtr->type != TYPE_STRING) {
ExprMakeString(valuePtr);
}
} else if (valuePtr->type == TYPE_DOUBLE) {
if (value2.type == TYPE_INT) {
value2.doubleValue = value2.intValue;
value2.type = TYPE_DOUBLE;
}
} else if (value2.type == TYPE_DOUBLE) {
if (valuePtr->type == TYPE_INT) {
valuePtr->doubleValue = valuePtr->intValue;
valuePtr->type = TYPE_DOUBLE;
}
}
break;
/*
* For the operators below, no strings are allowed, but
* no int->double conversions are performed.
*/
case AND: case OR:
if (valuePtr->type == TYPE_STRING) {
badType = valuePtr->type;
goto illegalType;
}
if (value2.type == TYPE_STRING) {
badType = value2.type;
goto illegalType;
}
break;
/*
* For the operators below, type and conversions are
* irrelevant: they're handled elsewhere.
*/
case QUESTY: case COLON:
break;
/*
* Any other operator is an error.
*/
default:
interp->result = "unknown operator in expression";
result = TCL_ERROR;
goto done;
}
/*
* If necessary, convert one of the operands to the type
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -