NRE(3tcl)
π NRE β Non-Recursive (stackless) evaluation, the whole serve π
okay bestie, sit down, hydrate, because today we are learning about NRE, aka the Tcl Library Procedures section of the manual (that's the 3tcl part, iykyk). This is the non-recursive, stackless evaluation lore and it is so much better than it sounds, I promise. π«Ά
β¨ NAME β¨
Not one, not two, but a whole friend group of functions, all here for the same reason:
Tcl_NRCreateCommandTcl_NRCreateCommand2Tcl_NRCallObjProcTcl_NRCallObjProc2Tcl_NREvalObjTcl_NREvalObjvTcl_NRCmdSwapTcl_NRExprObjTcl_NRAddCallback
and what are they all doing? Non-Recursive (stackless) evaluation of Tcl scripts. periodt. π
π SYNOPSIS π
here's the whole lineup, no cuts, no edits, exactly as written:
#include <tcl.h>
Tcl_Command
Tcl_NRCreateCommand(interp, cmdName, proc, nreProc, clientData, deleteProc)
Tcl_Command
Tcl_NRCreateCommand2(interp, cmdName, proc2, nreProc2, clientData, deleteProc)
int
Tcl_NRCallObjProc(interp, nreProc, clientData, objc, objv)
int
Tcl_NRCallObjProc2(interp, nreProc2, clientData, objc, objv)
int
Tcl_NREvalObj(interp, objPtr, flags)
int
Tcl_NREvalObjv(interp, objc, objv, flags)
int
Tcl_NRCmdSwap(interp, cmd, objc, objv, flags)
int
Tcl_NRExprObj(interp, objPtr, resultPtr)
Tcl_NRAddCallback(interp, postProcPtr, data0, data1, data2, data3)
chef's kiss. immaculate. moving on. π
π§ ARGUMENTS π§
every single one, bestie, nobody gets left on read:
Tcl_Interp *interp(in) β The relevant Interpreter. the main character, honestly.const char *cmdName(in) β Name of the command to create.Tcl_ObjCmdProc *proc(in) β Called in order to evaluate a command. Is often just a small wrapper that usesTcl_NRCallObjProcto callnreProcusing a new trampoline. Behaves in the same way as the proc argument toTcl_CreateObjCommand(3tcl)(q.v.).Tcl_ObjCmdProc2 *proc2(in) β Called in order to evaluate a command. Is often just a small wrapper that usesTcl_NRCallObjProc2to callnreProc2using a new trampoline. Behaves in the same way as the proc2 argument toTcl_CreateObjCommand2(3tcl)(q.v.).Tcl_ObjCmdProc *nreProc(in) β Called instead ofprocwhen a trampoline is already in use.Tcl_ObjCmdProc2 *nreProc2(in) β Called instead ofproc2when a trampoline is already in use.void *clientData(in) β Arbitrary one-word value passed toproc,nreProc,deleteProcandobjProc.Tcl_CmdDeleteProc *deleteProc(in/out) β Called beforecmdNameis deleted from the interpreter, allowing for command-specific cleanup. May beNULL.Tcl_Size objc(in) β Number of items inobjv.Tcl_Obj **objv(in) β Words in the command.Tcl_Obj *objPtr(in) β A script or expression to evaluate.int flags(in) β As described forTcl_EvalObjv.Tcl_Command cmd(in) β Token to use instead of one derived from the first word ofobjvin order to evaluate a command.Tcl_Obj *resultPtr(out) β Pointer to an unsharedTcl_Objwhere the result of the evaluation is stored if the return code isTCL_OK.Tcl_NRPostProc *postProcPtr(in) β A function to push.void *data0(in)void *data1(in)void *data2(in)void *data3(in) βdata0throughdata3are four one-word values that will be passed to the function designated bypostProcPtrwhen it is invoked.
π DESCRIPTION π
okay so here's the vibe. These functions provide an interface to the function stack that an interpreter iterates through to evaluate commands. The routine behind a command is implemented by an initial function and any additional functions that the routine pushes onto the stack as it progresses. The interpreter itself pushes functions onto the stack to react to the end of a routine and to exercise other forms of control such as switching between in-progress stacks and the evaluation of other scripts at additional levels without adding frames to the C stack. To execute a routine, the initial function for the routine is called and then a small bit of code called a trampoline iteratively takes functions off the stack and calls them, using the value of the last call as the value of the routine. πͺ
like⦠the trampoline is the whole moment. it's giving no C stack frames were harmed in the making of this evaluation.
Tcl_NRCallObjProccallsnreProcusing a new trampoline.Tcl_NRCreateCommand, an alternative toTcl_CreateObjCommand, resolvescmdName, which may contain namespace qualifiers, relative to the current namespace, creates a command by that name, and returns a token for the command which may be used in subsequent calls toTcl_GetCommandName. Except for a few cases noted below any existing command by the same name is first deleted. Ifinterpis in the process of being deletedTcl_NRCreateCommanddoes not create any command, does not delete any command, and returnsNULL.Tcl_NRCreateCommand2, is an alternative toTcl_NRCreateCommandin the same way asTcl_CreateObjCommand2.Tcl_NREvalObjpushes a function that is likeTcl_EvalObjExbut consumes no space on the C stack.Tcl_NREvalObjvpushes a function that is likeTcl_EvalObjvbut consumes no space on the C stack.Tcl_NRCmdSwapis likeTcl_NREvalObjv, but usescmd, a token previously returned byTcl_CreateObjCommandorTcl_GetCommandFromObj, instead of resolving the first word ofobjv.Tcl_NRExprObjpushes a function that evaluatesobjPtras an expression in the same manner asTcl_ExprObjbut without consuming space on the C stack.
All of the functions return TCL_OK if the evaluation of the script, command, or expression has been scheduled successfully. Otherwise (for example if the command name cannot be resolved), they return TCL_ERROR and store a message as the interpreter's result. π
Tcl_NRAddCallback pushes postProcPtr. The signature for Tcl_NRPostProc is:
typedef int
Tcl_NRPostProc(
void * data[],
Tcl_Interp *interp,
int result);
data is a pointer to an array containing data0 through data3. result is the value returned by the previous function implementing part the routine.
πΈ EXAMPLE πΈ
okay this is the glow-up arc, watch closely. The following command uses Tcl_EvalObjEx, which consumes space on the C stack, to evaluate a script:
int
TheCmdOldObjProc(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
int result;
Tcl_Obj *objPtr;
... preparation ...
result = Tcl_EvalObjEx(interp, objPtr, 0);
... postprocessing ...
return result;
}
Tcl_CreateObjCommand(interp, "theCommand",
TheCmdOldObjProc, clientData, TheCmdDeleteProc);
To avoid consuming space on the C stack, TheCmdOldObjProc is renamed to TheCmdNRObjProc and the postprocessing step is split into a separate function, TheCmdPostProc, which is pushed onto the function stack. Tcl_EvalObjEx is replaced with Tcl_NREvalObj, which uses a trampoline instead of consuming space on the C stack. A new version of TheCmdOldObjProc is just a a wrapper that uses Tcl_NRCallObjProc to call TheCmdNRObjProc:
int
TheCmdOldObjProc(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
return Tcl_NRCallObjProc(interp, TheCmdNRObjProc,
clientData, objc, objv);
}
int
TheCmdNRObjProc
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *objPtr;
... preparation ...
Tcl_NRAddCallback(interp, TheCmdPostProc,
data0, data1, data2, data3);
/* data0 .. data3 are up to four one-word items to
* pass to the postprocessing procedure */
return Tcl_NREvalObj(interp, objPtr, 0);
}
int
TheCmdNRPostProc(
void *data[],
Tcl_Interp *interp,
int result)
{
/* data[0] .. data[3] are the four words of data
* passed to Tcl_NRAddCallback */
... postprocessing ...
return result;
}
Any function comprising a routine can push other functions, making it possible implement looping and sequencing constructs using the function stack. π (yes that sentence says "making it possible implement" β we are quoting the source, not fixing its grammar, okay? respect the original.)
π REFERENCE COUNT MANAGEMENT π
this is the part where you pay attention, bestie, because refcounts do not play. π¨
The first objc values in the objv array passed to the functions Tcl_NRCallObjProc, Tcl_NREvalObjv, and Tcl_NRCmdSwap should have a reference count of at least 1; they may have additional references taken during the execution.
The objPtr argument to Tcl_NREvalObj and Tcl_NRExprObj should have a reference count of at least 1, and may have additional references taken to it during execution.
The resultObj argument to Tcl_NRExprObj should be an unshared object.
Use Tcl_NRAddCallback to schedule any required final decrementing of the reference counts of arguments to any of the other functions on this page, as with any other post-processing step in the non-recursive execution engine.
and then the section just stops. the last line of it is literally the word:Theπ that's it. that's the whole thing. the source page ends the paragraph right there, mid-thought, no period even. I am not adding words to it, because not me making up technical claims that aren't in the original. we honor theThe.
π₯ SEE ALSO π₯
go read your sisters, they're all iconic:
Tcl_CreateCommand(3tcl), Tcl_CreateObjCommand(3tcl), Tcl_EvalObjEx(3tcl), Tcl_GetCommandFromObj(3tcl), Tcl_ExprObj(3tcl)
β KEYWORDS β
drop these in your search bar and slay:
stackless, nonrecursive, execute, command, global, value, result, script
π COPYRIGHT π
Copyright Β© 2008 Kevin B. Kenny. Copyright Β© 2018 Nathan Coulter.
and that's the whole page, bestie!! πβ¨ this was the NRE(3tcl) manual page from the Tcl Library Procedures, and the footer said we're rocking Tcl 8.6 π β so go forth, use that trampoline, take zero space on the C stack, and remember: TCL_OK when it works, TCL_ERROR + a message in the interp result when it doesn't. π¦ no cap. bye bestie!! πππ§
π¦ where this page comes from
- ubuntu stonking: tcl9.0-doc 9.0.4+dfsg-1
- Copyright (c) 2008 Kevin B. Kenny
- Copyright (c) 2018 Nathan Coulter
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms