📄 tclexecute.c
字号:
Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "invalid command name \"", cmdName, "\"", (char *) NULL); TRACE(("%s %u => unknown proc not found: ", opName[opCode], objc)); result = TCL_ERROR; goto checkForCatch; } cmdPtr = (Command *) cmd;#ifdef TCL_COMPILE_DEBUG isUnknownCmd = 1;#endif /*TCL_COMPILE_DEBUG*/ stackTop++; /* need room for new inserted objv[0] */ for (i = objc; i >= 0; i--) { objv[i+1] = objv[i]; } objc++; objv[0] = Tcl_NewStringObj("unknown", -1); Tcl_IncrRefCount(objv[0]); } /* * Call any trace procedures. */ if (iPtr->tracePtr != NULL) { Trace *tracePtr, *nextTracePtr; for (tracePtr = iPtr->tracePtr; tracePtr != NULL; tracePtr = nextTracePtr) { nextTracePtr = tracePtr->nextPtr; if (iPtr->numLevels <= tracePtr->level) { int numChars; char *cmd = GetSrcInfoForPc(pc, codePtr, &numChars); if (cmd != NULL) { DECACHE_STACK_INFO(); CallTraceProcedure(interp, tracePtr, cmdPtr, cmd, numChars, objc, objv); CACHE_STACK_INFO(); } } } } /* * Finally, invoke the command's Tcl_ObjCmdProc. First reset * the interpreter's string and object results to their * default empty values since they could have gotten changed * by earlier invocations. */ Tcl_ResetResult(interp); if (tclTraceExec >= 2) { char buffer[50]; sprintf(buffer, "%d: (%u) invoking ", iPtr->numLevels, (unsigned int)(pc - codePtr->codeStart)); Tcl_DStringAppend(&command, buffer, -1); #ifdef TCL_COMPILE_DEBUG if (traceInstructions) { /* tclTraceExec == 3 */ strncpy(cmdNameBuf, cmdName, 20); TRACE(("%s %u => call ", opName[opCode], (isUnknownCmd? objc-1 : objc))); } else { fprintf(stdout, "%s", buffer); }#else /* TCL_COMPILE_DEBUG */ fprintf(stdout, "%s", buffer);#endif /*TCL_COMPILE_DEBUG*/ for (i = 0; i < objc; i++) { bytes = TclGetStringFromObj(objv[i], &length); TclPrintSource(stdout, bytes, TclMin(length, 15)); fprintf(stdout, " "); sprintf(buffer, "\"%.*s\" ", TclMin(length, 15), bytes); Tcl_DStringAppend(&command, buffer, -1); } fprintf(stdout, "\n"); fflush(stdout); Tcl_DStringFree(&command); } iPtr->cmdCount++; DECACHE_STACK_INFO(); result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, objc, objv); if (Tcl_AsyncReady()) { result = Tcl_AsyncInvoke(interp, result); } CACHE_STACK_INFO(); /* * If the interpreter has a non-empty string result, the * result object is either empty or stale because some * procedure set interp->result directly. If so, move the * string result to the result object, then reset the * string result. */ if (*(iPtr->result) != 0) { (void) Tcl_GetObjResult(interp); } /* * Pop the objc top stack elements and decrement their ref * counts. */ i = (stackTop - (objc-1)); while (i <= stackTop) { valuePtr = stackPtr[i].o; TclDecrRefCount(valuePtr); i++; } stackTop -= objc; /* * Process the result of the Tcl_ObjCmdProc call. */ switch (result) { case TCL_OK: /* * Push the call's object result and continue execution * with the next instruction. */ PUSH_OBJECT(Tcl_GetObjResult(interp)); TRACE_WITH_OBJ(("%s %u => ...after \"%.20s\", result=", opName[opCode], objc, cmdNameBuf), Tcl_GetObjResult(interp)); ADJUST_PC(pcAdjustment); case TCL_BREAK: case TCL_CONTINUE: /* * The invoked command requested a break or continue. * Find the closest enclosing loop or catch exception * range, if any. If a loop is found, terminate its * execution or skip to its next iteration. If the * closest is a catch exception range, jump to its * catchOffset. If no enclosing range is found, stop * execution and return the TCL_BREAK or TCL_CONTINUE. */ rangePtr = TclGetExceptionRangeForPc(pc, /*catchOnly*/ 0, codePtr); if (rangePtr == NULL) { TRACE(("%s %u => ... after \"%.20s\", no encl. loop or catch, returning %s\n", opName[opCode], objc, cmdNameBuf, StringForResultCode(result))); goto abnormalReturn; /* no catch exists to check */ } switch (rangePtr->type) { case LOOP_EXCEPTION_RANGE: if (result == TCL_BREAK) { newPcOffset = rangePtr->breakOffset; } else if (rangePtr->continueOffset == -1) { TRACE(("%s %u => ... after \"%.20s\", %s, loop w/o continue, checking for catch\n", opName[opCode], objc, cmdNameBuf, StringForResultCode(result))); goto checkForCatch; } else { newPcOffset = rangePtr->continueOffset; } TRACE(("%s %u => ... after \"%.20s\", %s, range at %d, new pc %d\n", opName[opCode], objc, cmdNameBuf, StringForResultCode(result), rangePtr->codeOffset, newPcOffset)); break; case CATCH_EXCEPTION_RANGE: TRACE(("%s %u => ... after \"%.20s\", %s...\n", opName[opCode], objc, cmdNameBuf, StringForResultCode(result))); goto processCatch; /* it will use rangePtr */ default: panic("TclExecuteByteCode: unrecognized ExceptionRange type %d\n", rangePtr->type); } result = TCL_OK; pc = (codePtr->codeStart + newPcOffset); continue; /* restart outer instruction loop at pc */ case TCL_ERROR: /* * The invoked command returned an error. Look for an * enclosing catch exception range, if any. */ TRACE_WITH_OBJ(("%s %u => ... after \"%.20s\", TCL_ERROR ", opName[opCode], objc, cmdNameBuf), Tcl_GetObjResult(interp)); goto checkForCatch; case TCL_RETURN: /* * The invoked command requested that the current * procedure stop execution and return. First check * for an enclosing catch exception range, if any. */ TRACE(("%s %u => ... after \"%.20s\", TCL_RETURN\n", opName[opCode], objc, cmdNameBuf)); goto checkForCatch; default: TRACE_WITH_OBJ(("%s %u => ... after \"%.20s\", OTHER RETURN CODE %d ", opName[opCode], objc, cmdNameBuf, result), Tcl_GetObjResult(interp)); goto checkForCatch; } /* end of switch on result from invoke instruction */ } case INST_EVAL_STK: objPtr = POP_OBJECT(); DECACHE_STACK_INFO(); result = Tcl_EvalObj(interp, objPtr); CACHE_STACK_INFO(); if (result == TCL_OK) { /* * Normal return; push the eval's object result. */ PUSH_OBJECT(Tcl_GetObjResult(interp)); TRACE_WITH_OBJ(("evalStk \"%.30s\" => ", O2S(objPtr)), Tcl_GetObjResult(interp)); TclDecrRefCount(objPtr); ADJUST_PC(1); } else if ((result == TCL_BREAK) || (result == TCL_CONTINUE)) { /* * Find the closest enclosing loop or catch exception range, * if any. If a loop is found, terminate its execution or * skip to its next iteration. If the closest is a catch * exception range, jump to its catchOffset. If no enclosing * range is found, stop execution and return that same * TCL_BREAK or TCL_CONTINUE. */ int newPcOffset = 0; /* Pc offset computed during break, * continue, error processing. Init. * to avoid compiler warning. */ rangePtr = TclGetExceptionRangeForPc(pc, /*catchOnly*/ 0, codePtr); if (rangePtr == NULL) { TRACE(("evalStk \"%.30s\" => no encl. loop or catch, returning %s\n", O2S(objPtr), StringForResultCode(result))); Tcl_DecrRefCount(objPtr); goto abnormalReturn; /* no catch exists to check */ } switch (rangePtr->type) { case LOOP_EXCEPTION_RANGE: if (result == TCL_BREAK) { newPcOffset = rangePtr->breakOffset; } else if (rangePtr->continueOffset == -1) { TRACE(("evalStk \"%.30s\" => %s, loop w/o continue, checking for catch\n", O2S(objPtr), StringForResultCode(result))); Tcl_DecrRefCount(objPtr); goto checkForCatch; } else { newPcOffset = rangePtr->continueOffset; } result = TCL_OK; TRACE_WITH_OBJ(("evalStk \"%.30s\" => %s, range at %d, new pc %d ", O2S(objPtr), StringForResultCode(result), rangePtr->codeOffset, newPcOffset), valuePtr); break; case CATCH_EXCEPTION_RANGE: TRACE_WITH_OBJ(("evalStk \"%.30s\" => %s ", O2S(objPtr), StringForResultCode(result)), valuePtr); Tcl_DecrRefCount(objPtr); goto processCatch; /* it will use rangePtr */ default: panic("TclExecuteByteCode: unrecognized ExceptionRange type %d\n", rangePtr->type); } Tcl_DecrRefCount(objPtr); pc = (codePtr->codeStart + newPcOffset); continue; /* restart outer instruction loop at pc */ } else { /* eval returned TCL_ERROR, TCL_RETURN, unknown code */ TRACE_WITH_OBJ(("evalStk \"%.30s\" => ERROR: ", O2S(objPtr)), Tcl_GetObjResult(interp)); Tcl_DecrRefCount(objPtr); goto checkForCatch; } case INST_EXPR_STK: objPtr = POP_OBJECT(); Tcl_ResetResult(interp); DECACHE_STACK_INFO(); result = Tcl_ExprObj(interp, objPtr, &valuePtr); CACHE_STACK_INFO(); if (result != TCL_OK) { TRACE_WITH_OBJ(("exprStk \"%.30s\" => ERROR: ", O2S(objPtr)), Tcl_GetObjResult(interp)); Tcl_DecrRefCount(objPtr); goto checkForCatch; } stackPtr[++stackTop].o = valuePtr; /* already has right refct */ TRACE_WITH_OBJ(("exprStk \"%.30s\" => ", O2S(objPtr)), valuePtr); TclDecrRefCount(objPtr); ADJUST_PC(1); case INST_LOAD_SCALAR4: opnd = TclGetInt4AtPtr(pc+1); pcAdjustment = 5; goto doLoadScalar; case INST_LOAD_SCALAR1: opnd = TclGetUInt1AtPtr(pc+1); pcAdjustment = 2; doLoadScalar: DECACHE_STACK_INFO(); valuePtr = TclGetIndexedScalar(interp, opnd, /*leaveErrorMsg*/ 1); CACHE_STACK_INFO(); if (valuePtr == NULL) { TRACE_WITH_OBJ(("%s %u => ERROR: ", opName[opCode], opnd), Tcl_GetObjResult(interp)); result = TCL_ERROR; goto checkForCatch; } PUSH_OBJECT(valuePtr); TRACE_WITH_OBJ(("%s %u => ", opName[opCode], opnd), valuePtr); ADJUST_PC(pcAdjustment); case INST_LOAD_SCALAR_STK: namePtr = POP_OBJECT(); DECACHE_STACK_INFO(); valuePtr = Tcl_ObjGetVar2(interp, namePtr, (Tcl_Obj *) NULL, TCL_LEAVE_ERR_MSG); CACHE_STACK_INFO(); if (valuePtr == NULL) { TRACE_WITH_OBJ(("loadScalarStk \"%.30s\" => ERROR: ", O2S(namePtr)), Tcl_GetObjResult(interp)); Tcl_DecrRefCount(namePtr); result = TCL_ERROR; goto checkForCatch; } PUSH_OBJECT(valuePtr); TRACE_WITH_OBJ(("loadScalarStk \"%.30s\" => ", O2S(namePtr)), valuePtr); TclDecrRefCount(namePtr); ADJUST_PC(1); case INST_LOAD_ARRAY4: opnd = TclGetUInt4AtPtr(pc+1); pcAdjustment = 5; goto doLoadArray; case INST_LOAD_ARRAY1: opnd = TclGetUInt1AtPtr(pc+1); pcAdjustment = 2; doLoadArray: { Tcl_Obj *elemPtr = POP_OBJECT(); DECACHE_STACK_INFO(); valuePtr = TclGetElementOfIndexedArray(interp, opnd, elemPtr, /*leaveErrorMsg*/ 1); CACHE_STACK_INFO(); if (valuePtr == NULL) { TRACE_WITH_OBJ(("%s %u \"%.30s\" => ERROR: ", opName[opCode], opnd, O2S(elemPtr)), Tcl_GetObjResult(interp)); Tcl_DecrRefCount(elemPtr); result = TCL_ERROR; goto checkForCatch; } PUSH_OBJECT(valuePtr); TRACE_WITH_OBJ(("%s %u \"%.30s\" => ", opName[opCode], opnd, O2S(elemPtr)), valuePtr); TclDecrRefCount(elemPtr); } ADJUST_PC(pcAdjustment); case INST_LOAD_ARRAY_STK: { Tcl_Obj *elemPtr = POP_OBJECT(); namePtr = POP_OBJECT(); DECACHE_STACK_INFO(); valuePtr = Tcl_ObjGetVar2(interp, namePtr, elemPtr, TCL_LEAVE_ERR_MSG); CACHE_STACK_INFO(); if (valuePtr == NULL) { TRACE_WITH_OBJ(("loadArrayStk \"%.30s(%.30s)\" => ERROR: ", O2S(namePtr), O2S(elemPtr)), Tcl_GetObjResult(interp)); Tcl_DecrRefCount(namePtr); Tcl_DecrRefCount(elemPtr); result = TCL_ERROR; goto checkForCatch; } PUSH_OBJECT(valuePtr); TRACE_WITH_OBJ(("loadArrayStk \"%.30s(%.30s)\" => ", O2S(namePtr), O2S(elemPtr)), valuePtr); TclDecrRefCount(namePtr); TclDecrRefCount(elemPtr); } ADJUST_PC(1); case INST_LOAD_STK: namePtr = POP_OBJECT(); DECACHE_STACK_INFO(); valuePtr = Tcl_ObjGetVar2(interp, namePtr, NULL, TCL_PARSE_PART1|TCL_LEAVE_ERR_MSG); CACHE_STACK_INFO(); if (valuePtr == NULL) { TRACE_WITH_OBJ(("loadStk \"%.30s\" => ERROR: ", O2S(namePtr)), Tcl_GetObjResult(interp)); Tcl_DecrRefCount(namePtr); result = TCL_ERROR; goto checkForCatch; } PUSH_OBJECT(valuePtr); TRACE_WITH_OBJ(("loadStk \"%.30s\" => ", O2S(namePtr)), valuePtr); TclDecrRefCount(namePtr); ADJUST_PC(1); case INST_STORE_SCALAR4: opnd = TclGetUInt4AtPtr(pc+1); pcAdjustment = 5; goto doStoreScalar; case INST_STORE_SCALAR1: opnd = TclGetUInt1AtPtr(pc+1); pcAdjustment = 2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -