📄 tclcompexpr.c
字号:
"syntax error in expression \"", infoPtr->originalExpr, "\"", (char *) NULL); result = TCL_ERROR; goto done; } if (!infoPtr->hasOperators) { TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr); } result = GetToken(interp, infoPtr, envPtr); /* skip over the ':' */ if (result != TCL_OK) { goto done; } /* * Emit an unconditional jump around the "else" condExpr. */ TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpAroundElseFixup); /* * Compile the "else" expression. */ infoPtr->hasOperators = 0; elseCodeOffset = TclCurrCodeOffset(); result = CompileCondExpr(interp, infoPtr, flags, envPtr); if (result != TCL_OK) { goto done; } maxDepth = TclMax(envPtr->maxStackDepth, maxDepth); if (!infoPtr->hasOperators) { TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr); } /* * Fix up the second jump: the unconditional jump around the "else" * expression. If the distance is too great (> 127 bytes), replace * it with a four byte instruction and move the instructions after * the jump down. */ currCodeOffset = TclCurrCodeOffset(); jumpDist = (currCodeOffset - jumpAroundElseFixup.codeOffset); if (TclFixupForwardJump(envPtr, &jumpAroundElseFixup, jumpDist, 127)) { /* * Update the else expression's starting code offset since it * moved down 3 bytes too. */ elseCodeOffset += 3; } /* * Now fix up the first branch: the jumpFalse after the test. If the * distance is too great, replace it with a four byte instruction * and update the code offsets for the commands in both the "then" * and "else" expressions. */ jumpDist = (elseCodeOffset - jumpAroundThenFixup.codeOffset); TclFixupForwardJump(envPtr, &jumpAroundThenFixup, jumpDist, 127); infoPtr->hasOperators = 1; /* * A comparison is not the top-level operator in this expression. */ infoPtr->exprIsComparison = 0; } done: envPtr->maxStackDepth = maxDepth; return result;}/* *---------------------------------------------------------------------- * * CompileLorExpr -- * * This procedure compiles a Tcl logical or expression: * lorExpr ::= landExpr {'||' landExpr} * * Results: * The return value is TCL_OK on a successful compilation and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * envPtr->maxStackDepth is updated with the maximum number of stack * elements needed to execute the expression. * * Side effects: * Adds instructions to envPtr to evaluate the expression at runtime. * *---------------------------------------------------------------------- */static intCompileLorExpr(interp, infoPtr, flags, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ ExprInfo *infoPtr; /* Describes the compilation state for the * expression being compiled. */ int flags; /* Flags to control compilation (same as * passed to Tcl_Eval). */ CompileEnv *envPtr; /* Holds resulting instructions. */{ int maxDepth; /* Maximum number of stack elements needed * to execute the expression. */ JumpFixupArray jumpFixupArray; /* Used to fix up the forward "short * circuit" jump after each or-ed * subexpression to just after the last * subexpression. */ JumpFixup jumpTrueFixup, jumpFixup; /* Used to emit the jumps in the code to * convert the first operand to a 0 or 1. */ int fixupIndex, jumpDist, currCodeOffset, objIndex, j, result; Tcl_Obj *objPtr; HERE("lorExpr", 2); result = CompileLandExpr(interp, infoPtr, flags, envPtr); if ((result != TCL_OK) || (infoPtr->token != OR)) { return result; /* envPtr->maxStackDepth is already set */ } infoPtr->hasOperators = 1; infoPtr->exprIsJustVarRef = 0; maxDepth = envPtr->maxStackDepth; TclInitJumpFixupArray(&jumpFixupArray); while (infoPtr->token == OR) { result = GetToken(interp, infoPtr, envPtr); /* skip over the '||' */ if (result != TCL_OK) { goto done; } if (jumpFixupArray.next == 0) { /* * Just the first "lor" operand is on the stack. The following * is slightly ugly: we need to convert that first "lor" operand * to a "0" or "1" to get the correct result if it is nonzero. * Eventually we'll use a new instruction for this. */ TclEmitForwardJump(envPtr, TCL_TRUE_JUMP, &jumpTrueFixup); objIndex = TclObjIndexForString("0", 1, /*allocStrRep*/ 0, /*inHeap*/ 0, envPtr); objPtr = envPtr->objArrayPtr[objIndex]; Tcl_InvalidateStringRep(objPtr); objPtr->internalRep.longValue = 0; objPtr->typePtr = &tclIntType; TclEmitPush(objIndex, envPtr); TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup); jumpDist = (TclCurrCodeOffset() - jumpTrueFixup.codeOffset); if (TclFixupForwardJump(envPtr, &jumpTrueFixup, jumpDist, 127)) { panic("CompileLorExpr: bad jump distance %d\n", jumpDist); } objIndex = TclObjIndexForString("1", 1, /*allocStrRep*/ 0, /*inHeap*/ 0, envPtr); objPtr = envPtr->objArrayPtr[objIndex]; Tcl_InvalidateStringRep(objPtr); objPtr->internalRep.longValue = 1; objPtr->typePtr = &tclIntType; TclEmitPush(objIndex, envPtr); jumpDist = (TclCurrCodeOffset() - jumpFixup.codeOffset); if (TclFixupForwardJump(envPtr, &jumpFixup, jumpDist, 127)) { panic("CompileLorExpr: bad jump distance %d\n", jumpDist); } } /* * Duplicate the value on top of the stack to prevent the jump from * consuming it. */ TclEmitOpcode(INST_DUP, envPtr); /* * Emit the "short circuit" jump around the rest of the lorExp if * the previous expression was true. We emit a one byte (relative) * jump here, and replace it later with a four byte jump if the jump * target is more than 127 bytes away. */ if (jumpFixupArray.next == jumpFixupArray.end) { TclExpandJumpFixupArray(&jumpFixupArray); } fixupIndex = jumpFixupArray.next; jumpFixupArray.next++; TclEmitForwardJump(envPtr, TCL_TRUE_JUMP, &(jumpFixupArray.fixup[fixupIndex])); /* * Compile the subexpression. */ result = CompileLandExpr(interp, infoPtr, flags, envPtr); if (result != TCL_OK) { goto done; } maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth); /* * Emit a "logical or" instruction. This does not try to "short- * circuit" the evaluation of both operands of a Tcl "||" operator, * but instead ensures that we either have a "1" or a "0" result. */ TclEmitOpcode(INST_LOR, envPtr); } /* * Now that we know the target of the forward jumps, update the jumps * with the correct distance. Also, if the distance is too great (> 127 * bytes), replace the jump with a four byte instruction and move the * instructions after the jump down. */ for (j = jumpFixupArray.next; j > 0; j--) { fixupIndex = (j - 1); /* process closest jump first */ currCodeOffset = TclCurrCodeOffset(); jumpDist = (currCodeOffset - jumpFixupArray.fixup[fixupIndex].codeOffset); TclFixupForwardJump(envPtr, &(jumpFixupArray.fixup[fixupIndex]), jumpDist, 127); } /* * We get here only if one or more ||'s appear as top-level operators. */ done: infoPtr->exprIsComparison = 0; TclFreeJumpFixupArray(&jumpFixupArray); envPtr->maxStackDepth = maxDepth; return result;}/* *---------------------------------------------------------------------- * * CompileLandExpr -- * * This procedure compiles a Tcl logical and expression: * landExpr ::= bitOrExpr {'&&' bitOrExpr} * * Results: * The return value is TCL_OK on a successful compilation and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * envPtr->maxStackDepth is updated with the maximum number of stack * elements needed to execute the expression. * * Side effects: * Adds instructions to envPtr to evaluate the expression at runtime. * *---------------------------------------------------------------------- */static intCompileLandExpr(interp, infoPtr, flags, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ ExprInfo *infoPtr; /* Describes the compilation state for the * expression being compiled. */ int flags; /* Flags to control compilation (same as * passed to Tcl_Eval). */ CompileEnv *envPtr; /* Holds resulting instructions. */{ int maxDepth; /* Maximum number of stack elements needed * to execute the expression. */ JumpFixupArray jumpFixupArray; /* Used to fix up the forward "short * circuit" jump after each and-ed * subexpression to just after the last * subexpression. */ JumpFixup jumpTrueFixup, jumpFixup; /* Used to emit the jumps in the code to * convert the first operand to a 0 or 1. */ int fixupIndex, jumpDist, currCodeOffset, objIndex, j, result; Tcl_Obj *objPtr; HERE("landExpr", 3); result = CompileBitOrExpr(interp, infoPtr, flags, envPtr); if ((result != TCL_OK) || (infoPtr->token != AND)) { return result; /* envPtr->maxStackDepth is already set */ } infoPtr->hasOperators = 1; infoPtr->exprIsJustVarRef = 0; maxDepth = envPtr->maxStackDepth; TclInitJumpFixupArray(&jumpFixupArray); while (infoPtr->token == AND) { result = GetToken(interp, infoPtr, envPtr); /* skip over the '&&' */ if (result != TCL_OK) { goto done; } if (jumpFixupArray.next == 0) { /* * Just the first "land" operand is on the stack. The following * is slightly ugly: we need to convert the first "land" operand * to a "0" or "1" to get the correct result if it is * nonzero. Eventually we'll use a new instruction. */ TclEmitForwardJump(envPtr, TCL_TRUE_JUMP, &jumpTrueFixup); objIndex = TclObjIndexForString("0", 1, /*allocStrRep*/ 0, /*inHeap*/ 0, envPtr); objPtr = envPtr->objArrayPtr[objIndex]; Tcl_InvalidateStringRep(objPtr); objPtr->internalRep.longValue = 0; objPtr->typePtr = &tclIntType; TclEmitPush(objIndex, envPtr); TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup); jumpDist = (TclCurrCodeOffset() - jumpTrueFixup.codeOffset); if (TclFixupForwardJump(envPtr, &jumpTrueFixup, jumpDist, 127)) { panic("CompileLandExpr: bad jump distance %d\n", jumpDist); } objIndex = TclObjIndexForString("1", 1, /*allocStrRep*/ 0, /*inHeap*/ 0, envPtr); objPtr = envPtr->objArrayPtr[objIndex]; Tcl_InvalidateStringRep(objPtr); objPtr->internalRep.longValue = 1; objPtr->typePtr = &tclIntType; TclEmitPush(objIndex, envPtr); jumpDist = (TclCurrCodeOffset() - jumpFixup.codeOffset); if (TclFixupForwardJump(envPtr, &jumpFixup, jumpDist, 127)) { panic("CompileLandExpr: bad jump distance %d\n", jumpDist); } } /* * Duplicate the value on top of the stack to prevent the jump from * consuming it. */ TclEmitOpcode(INST_DUP, envPtr); /* * Emit the "short circuit" jump around the rest of the landExp if * the previous expression was false. We emit a one byte (relative) * jump here, and replace it later with a four byte jump if the jump * target is more than 127 bytes away. */ if (jumpFixupArray.next == jumpFixupArray.end) { TclExpandJumpFixupArray(&jumpFixupArray); } fixupIndex = jumpFixupArray.next; jumpFixupArray.next++; TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &(jumpFixupArray.fixup[fixupIndex])); /* * Compile the subexpression. */ result = CompileBitOrExpr(interp, infoPtr, flags, envPtr); if (result != TCL_OK) { goto done; } maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth); /* * Emit a "logical and" instruction. This does not try to "short- * circuit" the evaluation of both operands of a Tcl "&&" operator, * but instead ensures that we either have a "1" or a "0" result. */ TclEmitOpcode(INST_LAND, envPtr); } /* * Now that we know the target of the forward jumps, update the jumps * with the correct distance. Also, if the distance is too great (> 127 * bytes), replace the jump with a four byte instruction and move the * instructions after the jump down. */ for (j = jumpFixupArray.next; j > 0; j--) { fixupIndex = (j - 1); /* process closest jump first */ currCodeOffset = TclCurrCodeOffset(); jumpDist = (currCodeOffset - jumpFixupArray.fixup[fixupIndex].codeOffset); TclFixupForwardJump(envPtr, &(jumpFixupArray.fixup[fixupIndex]), jumpDist, 127); } /* * We get here only if one or more &&'s appear as top-level operators. */ done: infoPtr->exprIsComparison = 0; TclFreeJumpFixupArray(&jumpFixupArray); envPtr->maxStackDepth = maxDepth; return result;}/* *---------------------------------------------------------------------- * * CompileBitOrExpr -- * * This procedure compiles a Tcl bitwise or expression: * bitOrExpr ::= bitXorExpr {'|' bitXorExpr} * * Results: * The return value is TCL_OK on a successful compilation and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * envPtr->maxStackDepth is updated with the maximum number of stack * elements needed to execute the expression. * * Side effects: * Adds instructions to envPtr to evaluate the expression at runtime. * *---------------------------------------------------------------------- */static intCompileBitOrExpr(interp, infoPtr, flags, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ ExprInfo *infoPtr; /* Describes the compilation state for the * expression being compiled. */ int flags; /* Flags to control compilation (same as * passed to Tcl_Eval). */ CompileEnv *envPtr; /* Holds resulting instructions. */{ int maxDepth = 0; /* Maximum number of stack elements needed * to execute the expression. */ int result; HERE("bitOrExpr", 4);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -