📄 tclproc.c
字号:
varPtr->value.objPtr = objPtr; varPtr->flags &= ~VAR_UNDEFINED; Tcl_IncrRefCount(objPtr); /* since the local variable now has * another reference to object. */ } else { Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "no value given for parameter \"", localPtr->name, "\" to \"", Tcl_GetStringFromObj(objv[0], (int *) NULL), "\"", (char *) NULL); result = TCL_ERROR; goto procDone; } varPtr++; localPtr = localPtr->nextPtr; } if (argCt > 0) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "called \"", Tcl_GetStringFromObj(objv[0], (int *) NULL), "\" with too many arguments", (char *) NULL); result = TCL_ERROR; goto procDone; } /* * Invoke the commands in the procedure's body. */ if (tclTraceExec >= 1) { fprintf(stdout, "Calling proc "); for (i = 0; i < objc; i++) { bytes = Tcl_GetStringFromObj(objv[i], &length); TclPrintSource(stdout, bytes, TclMin(length, 15)); fprintf(stdout, " "); } fprintf(stdout, "\n"); fflush(stdout); } iPtr->returnCode = TCL_OK; procPtr->refCount++; result = Tcl_EvalObj(interp, procPtr->bodyPtr); procPtr->refCount--; if (procPtr->refCount <= 0) { TclProcCleanupProc(procPtr); } if (result != TCL_OK) { if (result == TCL_RETURN) { result = TclUpdateReturnInfo(iPtr); } else if (result == TCL_ERROR) { char msg[100]; sprintf(msg, "\n (procedure \"%.50s\" line %d)", procName, iPtr->errorLine); Tcl_AddObjErrorInfo(interp, msg, -1); } else if (result == TCL_BREAK) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "invoked \"break\" outside of a loop", -1); result = TCL_ERROR; } else if (result == TCL_CONTINUE) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "invoked \"continue\" outside of a loop", -1); result = TCL_ERROR; } } procDone: /* * Pop and free the call frame for this procedure invocation. */ Tcl_PopCallFrame(interp); /* * Free the compiledLocals array if malloc'ed storage was used. */ if (compiledLocals != localStorage) { ckfree((char *) compiledLocals); } return result;#undef NUM_LOCALS}/* *---------------------------------------------------------------------- * * TclProcCompileProc -- * * Called just before a procedure is executed to compile the * body to byte codes. If the type of the body is not * "byte code" or if the compile conditions have changed * (namespace context, epoch counters, etc.) then the body * is recompiled. Otherwise, this procedure does nothing. * * Results: * None. * * Side effects: * May change the internal representation of the body object * to compiled code. * *---------------------------------------------------------------------- */ intTclProcCompileProc(interp, procPtr, bodyPtr, nsPtr, description, procName) Tcl_Interp *interp; /* Interpreter containing procedure. */ Proc *procPtr; /* Data associated with procedure. */ Tcl_Obj *bodyPtr; /* Body of proc. (Usually procPtr->bodyPtr, * but could be any code fragment compiled * in the context of this procedure.) */ Namespace *nsPtr; /* Namespace containing procedure. */ CONST char *description; /* string describing this body of code. */ CONST char *procName; /* Name of this procedure. */{ Interp *iPtr = (Interp*)interp; int result; Tcl_CallFrame frame; Proc *saveProcPtr; ByteCode *codePtr = (ByteCode *) bodyPtr->internalRep.otherValuePtr; /* * If necessary, compile the procedure's body. The compiler will * allocate frame slots for the procedure's non-argument local * variables. If the ByteCode already exists, make sure it hasn't been * invalidated by someone redefining a core command (this might make the * compiled code wrong). Also, if the code was compiled in/for a * different interpreter, we recompile it. Note that compiling the body * might increase procPtr->numCompiledLocals if new local variables are * found while compiling. * * Precompiled procedure bodies, however, are immutable and therefore * they are not recompiled, even if things have changed. */ if (bodyPtr->typePtr == &tclByteCodeType) { if ((codePtr->iPtr != iPtr) || (codePtr->compileEpoch != iPtr->compileEpoch) || (codePtr->nsPtr != nsPtr)) { if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) { if (codePtr->iPtr != iPtr) { Tcl_AppendResult(interp, "a precompiled script jumped interps", NULL); return TCL_ERROR; } codePtr->compileEpoch = iPtr->compileEpoch; codePtr->nsPtr = nsPtr; } else { tclByteCodeType.freeIntRepProc(bodyPtr); bodyPtr->typePtr = (Tcl_ObjType *) NULL; } } } if (bodyPtr->typePtr != &tclByteCodeType) { char buf[100]; int numChars; char *ellipsis; if (tclTraceCompile >= 1) { /* * Display a line summarizing the top level command we * are about to compile. */ numChars = strlen(procName); ellipsis = ""; if (numChars > 50) { numChars = 50; ellipsis = "..."; } fprintf(stdout, "Compiling %s \"%.*s%s\"\n", description, numChars, procName, ellipsis); } /* * Plug the current procPtr into the interpreter and coerce * the code body to byte codes. The interpreter needs to * know which proc it's compiling so that it can access its * list of compiled locals. * * TRICKY NOTE: Be careful to push a call frame with the * proper namespace context, so that the byte codes are * compiled in the appropriate class context. */ saveProcPtr = iPtr->compiledProcPtr; iPtr->compiledProcPtr = procPtr; result = Tcl_PushCallFrame(interp, &frame, (Tcl_Namespace*)nsPtr, /* isProcCallFrame */ 0); if (result == TCL_OK) { result = tclByteCodeType.setFromAnyProc(interp, bodyPtr); Tcl_PopCallFrame(interp); } iPtr->compiledProcPtr = saveProcPtr; if (result != TCL_OK) { if (result == TCL_ERROR) { numChars = strlen(procName); ellipsis = ""; if (numChars > 50) { numChars = 50; ellipsis = "..."; } sprintf(buf, "\n (compiling %s \"%.*s%s\", line %d)", description, numChars, procName, ellipsis, interp->errorLine); Tcl_AddObjErrorInfo(interp, buf, -1); } return result; } } else if (codePtr->nsEpoch != nsPtr->resolverEpoch) { register CompiledLocal *localPtr; /* * The resolver epoch has changed, but we only need to invalidate * the resolver cache. */ for (localPtr = procPtr->firstLocalPtr; localPtr != NULL; localPtr = localPtr->nextPtr) { localPtr->flags &= ~(VAR_RESOLVED); if (localPtr->resolveInfo) { if (localPtr->resolveInfo->deleteProc) { localPtr->resolveInfo->deleteProc(localPtr->resolveInfo); } else { ckfree((char*)localPtr->resolveInfo); } localPtr->resolveInfo = NULL; } } } return TCL_OK;} /* *---------------------------------------------------------------------- * * TclProcDeleteProc -- * * This procedure is invoked just before a command procedure is * removed from an interpreter. Its job is to release all the * resources allocated to the procedure. * * Results: * None. * * Side effects: * Memory gets freed, unless the procedure is actively being * executed. In this case the cleanup is delayed until the * last call to the current procedure completes. * *---------------------------------------------------------------------- */voidTclProcDeleteProc(clientData) ClientData clientData; /* Procedure to be deleted. */{ Proc *procPtr = (Proc *) clientData; procPtr->refCount--; if (procPtr->refCount <= 0) { TclProcCleanupProc(procPtr); }}/* *---------------------------------------------------------------------- * * TclProcCleanupProc -- * * This procedure does all the real work of freeing up a Proc * structure. It's called only when the structure's reference * count becomes zero. * * Results: * None. * * Side effects: * Memory gets freed. * *---------------------------------------------------------------------- */voidTclProcCleanupProc(procPtr) register Proc *procPtr; /* Procedure to be deleted. */{ register CompiledLocal *localPtr; Tcl_Obj *bodyPtr = procPtr->bodyPtr; Tcl_Obj *defPtr; Tcl_ResolvedVarInfo *resVarInfo; if (bodyPtr != NULL) { Tcl_DecrRefCount(bodyPtr); } for (localPtr = procPtr->firstLocalPtr; localPtr != NULL; ) { CompiledLocal *nextPtr = localPtr->nextPtr; resVarInfo = localPtr->resolveInfo; if (resVarInfo) { if (resVarInfo->deleteProc) { (*resVarInfo->deleteProc)(resVarInfo); } else { ckfree((char *) resVarInfo); } } if (localPtr->defValuePtr != NULL) { defPtr = localPtr->defValuePtr; Tcl_DecrRefCount(defPtr); } ckfree((char *) localPtr); localPtr = nextPtr; } ckfree((char *) procPtr);}/* *---------------------------------------------------------------------- * * TclUpdateReturnInfo -- * * This procedure is called when procedures return, and at other * points where the TCL_RETURN code is used. It examines fields * such as iPtr->returnCode and iPtr->errorCode and modifies * the real return status accordingly. * * Results: * The return value is the true completion code to use for * the procedure, instead of TCL_RETURN. * * Side effects: * The errorInfo and errorCode variables may get modified. * *---------------------------------------------------------------------- */intTclUpdateReturnInfo(iPtr) Interp *iPtr; /* Interpreter for which TCL_RETURN * exception is being processed. */{ int code; code = iPtr->returnCode; iPtr->returnCode = TCL_OK; if (code == TCL_ERROR) { Tcl_SetVar2((Tcl_Interp *) iPtr, "errorCode", (char *) NULL, (iPtr->errorCode != NULL) ? iPtr->errorCode : "NONE", TCL_GLOBAL_ONLY); iPtr->flags |= ERROR_CODE_SET; if (iPtr->errorInfo != NULL) { Tcl_SetVar2((Tcl_Interp *) iPtr, "errorInfo", (char *) NULL, iPtr->errorInfo, TCL_GLOBAL_ONLY); iPtr->flags |= ERR_IN_PROGRESS; } } return code;}/* *---------------------------------------------------------------------- * * TclGetInterpProc -- * * Returns a pointer to the TclProcInterpProc procedure; this is different * from the value obtained from the TclProcInterpProc reference on systems * like Windows where import and export versions of a procedure exported * by a DLL exist. * * Results: * Returns the internal address of the TclProcInterpProc procedure. * * Side effects: * None. * *---------------------------------------------------------------------- */TclCmdProcTypeTclGetInterpProc(){ return TclProcInterpProc;}/* *---------------------------------------------------------------------- * * TclGetObjInterpProc -- * * Returns a pointer to the TclObjInterpProc procedure; this is different * from the value obtained from the TclObjInterpProc reference on systems * like Windows where import and export versions of a procedure exported * by a DLL exist. * * Results: * Returns the internal address of the TclProcInterpProc procedure. * * Side effects: * None. * *---------------------------------------------------------------------- */TclObjCmdProcTypeTclGetObjInterpProc(){ return TclObjInterpProc;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -