📄 tclexpr.c
字号:
* of the other. If the operands are incompatible with
* the operator (e.g. "+" on strings) then return an
* error.
*/
switch (operator) {
case MULT:
if (valuePtr->type == TYPE_INT) {
valuePtr->intValue *= value2.intValue;
} else {
valuePtr->doubleValue *= value2.doubleValue;
}
break;
case DIVIDE:
if (valuePtr->type == TYPE_INT) {
if (value2.intValue == 0) {
divideByZero:
interp->result = "divide by zero";
result = TCL_ERROR;
goto done;
}
valuePtr->intValue /= value2.intValue;
} else {
if (value2.doubleValue == 0.0) {
goto divideByZero;
}
valuePtr->doubleValue /= value2.doubleValue;
}
break;
case MOD:
if (value2.intValue == 0) {
goto divideByZero;
}
valuePtr->intValue %= value2.intValue;
break;
case PLUS:
if (valuePtr->type == TYPE_INT) {
valuePtr->intValue += value2.intValue;
} else {
valuePtr->doubleValue += value2.doubleValue;
}
break;
case MINUS:
if (valuePtr->type == TYPE_INT) {
valuePtr->intValue -= value2.intValue;
} else {
valuePtr->doubleValue -= value2.doubleValue;
}
break;
case LEFT_SHIFT:
valuePtr->intValue <<= value2.intValue;
break;
case RIGHT_SHIFT:
/*
* The following code is a bit tricky: it ensures that
* right shifts propagate the sign bit even on machines
* where ">>" won't do it by default.
*/
if (valuePtr->intValue < 0) {
valuePtr->intValue =
~((~valuePtr->intValue) >> value2.intValue);
} else {
valuePtr->intValue >>= value2.intValue;
}
break;
case LESS:
if (valuePtr->type == TYPE_INT) {
valuePtr->intValue =
valuePtr->intValue < value2.intValue;
} else if (valuePtr->type == TYPE_DOUBLE) {
valuePtr->intValue =
valuePtr->doubleValue < value2.doubleValue;
} else {
valuePtr->intValue =
strcmp(valuePtr->pv.buffer, value2.pv.buffer) < 0;
}
valuePtr->type = TYPE_INT;
break;
case GREATER:
if (valuePtr->type == TYPE_INT) {
valuePtr->intValue =
valuePtr->intValue > value2.intValue;
} else if (valuePtr->type == TYPE_DOUBLE) {
valuePtr->intValue =
valuePtr->doubleValue > value2.doubleValue;
} else {
valuePtr->intValue =
strcmp(valuePtr->pv.buffer, value2.pv.buffer) > 0;
}
valuePtr->type = TYPE_INT;
break;
case LEQ:
if (valuePtr->type == TYPE_INT) {
valuePtr->intValue =
valuePtr->intValue <= value2.intValue;
} else if (valuePtr->type == TYPE_DOUBLE) {
valuePtr->intValue =
valuePtr->doubleValue <= value2.doubleValue;
} else {
valuePtr->intValue =
strcmp(valuePtr->pv.buffer, value2.pv.buffer) <= 0;
}
valuePtr->type = TYPE_INT;
break;
case GEQ:
if (valuePtr->type == TYPE_INT) {
valuePtr->intValue =
valuePtr->intValue >= value2.intValue;
} else if (valuePtr->type == TYPE_DOUBLE) {
valuePtr->intValue =
valuePtr->doubleValue >= value2.doubleValue;
} else {
valuePtr->intValue =
strcmp(valuePtr->pv.buffer, value2.pv.buffer) >= 0;
}
valuePtr->type = TYPE_INT;
break;
case EQUAL:
if (valuePtr->type == TYPE_INT) {
valuePtr->intValue =
valuePtr->intValue == value2.intValue;
} else if (valuePtr->type == TYPE_DOUBLE) {
valuePtr->intValue =
valuePtr->doubleValue == value2.doubleValue;
} else {
valuePtr->intValue =
strcmp(valuePtr->pv.buffer, value2.pv.buffer) == 0;
}
valuePtr->type = TYPE_INT;
break;
case NEQ:
if (valuePtr->type == TYPE_INT) {
valuePtr->intValue =
valuePtr->intValue != value2.intValue;
} else if (valuePtr->type == TYPE_DOUBLE) {
valuePtr->intValue =
valuePtr->doubleValue != value2.doubleValue;
} else {
valuePtr->intValue =
strcmp(valuePtr->pv.buffer, value2.pv.buffer) != 0;
}
valuePtr->type = TYPE_INT;
break;
case BIT_AND:
valuePtr->intValue &= value2.intValue;
break;
case BIT_XOR:
valuePtr->intValue ^= value2.intValue;
break;
case BIT_OR:
valuePtr->intValue |= value2.intValue;
break;
/*
* For AND and OR, we know that the first value has already
* been converted to an integer. Thus we need only consider
* the possibility of int vs. double for the second value.
*/
case AND:
if (value2.type == TYPE_DOUBLE) {
value2.intValue = value2.doubleValue != 0;
value2.type = TYPE_INT;
}
valuePtr->intValue = valuePtr->intValue && value2.intValue;
break;
case OR:
if (value2.type == TYPE_DOUBLE) {
value2.intValue = value2.doubleValue != 0;
value2.type = TYPE_INT;
}
valuePtr->intValue = valuePtr->intValue || value2.intValue;
break;
case COLON:
interp->result = "can't have : operator without ? first";
result = TCL_ERROR;
goto done;
}
}
done:
if (value2.pv.buffer != value2.staticSpace) {
ckfree(value2.pv.buffer);
}
return result;
syntaxError:
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "syntax error in expression \"",
infoPtr->originalExpr, "\"", (char *) NULL);
result = TCL_ERROR;
goto done;
illegalType:
Tcl_AppendResult(interp, "can't use ", (badType == TYPE_DOUBLE) ?
"floating-point value" : "non-numeric string",
" as operand of \"", operatorStrings[operator], "\"",
(char *) NULL);
result = TCL_ERROR;
goto done;
}
/*
*--------------------------------------------------------------
*
* ExprMakeString --
*
* Convert a value from int or double representation to
* a string.
*
* Results:
* The information at *valuePtr gets converted to string
* format, if it wasn't that way already.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static void
ExprMakeString(valuePtr)
register Value *valuePtr; /* Value to be converted. */
{
int shortfall;
shortfall = 150 - (valuePtr->pv.end - valuePtr->pv.buffer);
if (shortfall > 0) {
(*valuePtr->pv.expandProc)(&valuePtr->pv, shortfall);
}
if (valuePtr->type == TYPE_INT) {
sprintf(valuePtr->pv.buffer, "%ld", valuePtr->intValue);
} else if (valuePtr->type == TYPE_DOUBLE) {
sprintf(valuePtr->pv.buffer, "%g", valuePtr->doubleValue);
}
valuePtr->type = TYPE_STRING;
}
/*
*--------------------------------------------------------------
*
* ExprTopLevel --
*
* This procedure provides top-level functionality shared by
* procedures like Tcl_ExprInt, Tcl_ExprDouble, etc.
*
* Results:
* The result is a standard Tcl return value. If an error
* occurs then an error message is left in interp->result.
* The value of the expression is returned in *valuePtr, in
* whatever form it ends up in (could be string or integer
* or double). Caller may need to convert result. Caller
* is also responsible for freeing string memory in *valuePtr,
* if any was allocated.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static int
ExprTopLevel(interp, string, valuePtr)
Tcl_Interp *interp; /* Context in which to evaluate the
* expression. */
char *string; /* Expression to evaluate. */
Value *valuePtr; /* Where to store result. Should
* not be initialized by caller. */
{
ExprInfo info;
int result;
info.originalExpr = string;
info.expr = string;
valuePtr->pv.buffer = valuePtr->pv.next = valuePtr->staticSpace;
valuePtr->pv.end = valuePtr->pv.buffer + STATIC_STRING_SPACE - 1;
valuePtr->pv.expandProc = TclExpandParseValue;
valuePtr->pv.clientData = (ClientData) NULL;
result = ExprGetValue(interp, &info, -1, valuePtr);
if (result != TCL_OK) {
return result;
}
if (info.token != END) {
Tcl_AppendResult(interp, "syntax error in expression \"",
string, "\"", (char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* Tcl_ExprLong, Tcl_ExprDouble, Tcl_ExprBoolean --
*
* Procedures to evaluate an expression and return its value
* in a particular form.
*
* Results:
* Each of the procedures below returns a standard Tcl result.
* If an error occurs then an error message is left in
* interp->result. Otherwise the value of the expression,
* in the appropriate form, is stored at *resultPtr. If
* the expression had a result that was incompatible with the
* desired form then an error is returned.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
int
Tcl_ExprLong(interp, string, ptr)
Tcl_Interp *interp; /* Context in which to evaluate the
* expression. */
char *string; /* Expression to evaluate. */
long *ptr; /* Where to store result. */
{
Value value;
int result;
result = ExprTopLevel(interp, string, &value);
if (result == TCL_OK) {
if (value.type == TYPE_INT) {
*ptr = value.intValue;
} else if (value.type == TYPE_DOUBLE) {
*ptr = value.doubleValue;
} else {
interp->result = "expression didn't have numeric value";
result = TCL_ERROR;
}
}
if (value.pv.buffer != value.staticSpace) {
ckfree(value.pv.buffer);
}
return result;
}
int
Tcl_ExprDouble(interp, string, ptr)
Tcl_Interp *interp; /* Context in which to evaluate the
* expression. */
char *string; /* Expression to evaluate. */
double *ptr; /* Where to store result. */
{
Value value;
int result;
result = ExprTopLevel(interp, string, &value);
if (result == TCL_OK) {
if (value.type == TYPE_INT) {
*ptr = value.intValue;
} else if (value.type == TYPE_DOUBLE) {
*ptr = value.doubleValue;
} else {
interp->result = "expression didn't have numeric value";
result = TCL_ERROR;
}
}
if (value.pv.buffer != value.staticSpace) {
ckfree(value.pv.buffer);
}
return result;
}
int
Tcl_ExprBoolean(interp, string, ptr)
Tcl_Interp *interp; /* Context in which to evaluate the
* expression. */
char *string; /* Expression to evaluate. */
int *ptr; /* Where to store 0/1 result. */
{
Value value;
int result;
result = ExprTopLevel(interp, string, &value);
if (result == TCL_OK) {
if (value.type == TYPE_INT) {
*ptr = value.intValue != 0;
} else if (value.type == TYPE_DOUBLE) {
*ptr = value.doubleValue != 0.0;
} else {
interp->result = "expression didn't have numeric value";
result = TCL_ERROR;
}
}
if (value.pv.buffer != value.staticSpace) {
ckfree(value.pv.buffer);
}
return result;
}
/*
*--------------------------------------------------------------
*
* Tcl_ExprString --
*
* Evaluate an expression and return its value in string form.
*
* Results:
* A standard Tcl result. If the result is TCL_OK, then the
* interpreter's result is set to the string value of the
* expression. If the result is TCL_OK, then interp->result
* contains an error message.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
int
Tcl_ExprString(interp, string)
Tcl_Interp *interp; /* Context in which to evaluate the
* expression. */
char *string; /* Expression to evaluate. */
{
Value value;
int result;
result = ExprTopLevel(interp, string, &value);
if (result == TCL_OK) {
if (value.type == TYPE_INT) {
sprintf(interp->result, "%ld", value.intValue);
} else if (value.type == TYPE_DOUBLE) {
sprintf(interp->result, "%g", value.doubleValue);
} else {
if (value.pv.buffer != value.staticSpace) {
interp->result = value.pv.buffer;
interp->freeProc = (Tcl_FreeProc *) free;
value.pv.buffer = value.staticSpace;
} else {
Tcl_SetResult(interp, value.pv.buffer, TCL_VOLATILE);
}
}
}
if (value.pv.buffer != value.staticSpace) {
ckfree(value.pv.buffer);
}
return result;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -