📄 tclexpr.c
字号:
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 intExprGetValue(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 * of the other. If the operands are incompatible with * the operator (e.g. "+" on strings) then return an * error. */ switch (operator) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -