第三章 Caché 变量大全 $ESTACK 变量
包含从用户定义的点保存在调用堆栈上的上下文帧的数量。
大纲
$ESTACK
$ES
描述
$ESTACK包含从用户定义的点为JOB保存在调用堆栈上的上下文帧的数量。可以通过使用new命令创建$ESTACK的新副本来指定这一点。
$ESTACK特殊变量类似于$STACK特殊变量。两者都包含当前保存在JOB或程序的调用堆栈中的上下文框架的数量。更改上下文时,Caché会递增并恢复两者。主要区别在于,可以随时使用NEW命令将$ESTACK计数重置为零。无法重置$STACK计数。
上下文框架和调用堆栈
启动Caché映像时,在将任何上下文保存到调用堆栈之前,$ESTACK和$STACK的值均为零。每次例程使用DO调用另一个例程时,系统都会将当前正在执行的例程的上下文保存在调用堆栈中,递增$ESTACK和$STACK,并在新创建的上下文中开始执行被调用例程。被调用的例程可以依次调用另一个例程,依此类推。每次调用另一个例程时,Caché都会递增$ESTACK和$STACK并将更多保存的上下文放在调用堆栈中。
发出DO命令,EXECUTE命令或对用户定义函数的调用会建立新的执行上下文。不会发出GOTO命令。
当DO命令,XECUTE命令或用户定义的函数引用创建新上下文时,Caché将增加$STACK和$ESTACK的值。当QUIT命令导致上下文退出时,Caché从调用堆栈中恢复以前的上下文,并减小$STACK和$ESTACK的值。
不能使用SET命令修改$ESTACK和$STACK特殊变量。尝试这样做会导致<SYNTAX>错误。
创建$ESTACK
可以使用NEW命令在任何上下文中创建$ESTACK的新副本。 Caché采取以下行动:
- 保存
$ESTACK的旧副本。 - 创建新的
$ESTACK副本,其值为零(0)。
这样,可以将特定上下文建立为$ESTACK级别0上下文。当使用DO,XECUTE或用户定义的函数创建新的上下文时,Caché会将此$ESTACK值递增。但是,当退出创建新$ESTACK的上下文时($ESTACK处于级别0),Caché会还原$ESTACK的先前副本的值。
示例
以下示例显示了$ESTACK上的NEW命令的作用。在此的示例MainRoutine显示$STACK和$ESTACK的初始值(它们是相同的值)。然后,它调用Sub1。该调用将增加$STACK和$ESTACK。 NEW命令创建一个值为0的$ESTACK。Sub1调用Sub2,递增$STACK和$ESTACK。返回MainRoutine将恢复$STACK和$ESTACK的初始值:
/// d ##class(PHA.TEST.SpecialVariables).ESTACK()
ClassMethod ESTACK()
{
Main
WRITE !,"Initial: $STACK=",$STACK," $ESTACK=",$ESTACK
DO Sub1
WRITE !,"Return: $STACK=",$STACK," $ESTACK=",$ESTACK
QUIT
Sub1
WRITE !,"Sub1Call: $STACK=",$STACK," $ESTACK=",$ESTACK
NEW $ESTACK
WRITE !,"Sub1NEW: $STACK=",$STACK," $ESTACK=",$ESTACK
DO Sub2
QUIT
Sub2
WRITE !,"Sub2Call: $STACK=",$STACK," $ESTACK=",$ESTACK
QUIT
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ESTACK()
Initial: $STACK=1 $ESTACK=1
Sub1Call: $STACK=2 $ESTACK=2
Sub1NEW: $STACK=2 $ESTACK=0
Sub2Call: $STACK=3 $ESTACK=1
Return: $STACK=1 $ESTACK=1
下面的示例演示了如何通过发出DO和XECUTE命令在创建新上下文时增加$ESTACK的值,并在退出这些上下文时减小其值。它还显示GOTO命令不会创建新上下文或增加$ESTACK:
/// d ##class(PHA.TEST.SpecialVariables).ESTACK1()
ClassMethod ESTACK1()
{
Main
NEW $ESTACK
WRITE !,"Initial Main: $ESTACK=",$ESTACK // 0
DO Sub1
WRITE !,"Return Main: $ESTACK=",$ESTACK // 0
QUIT
Sub1
WRITE !,"Sub1 via DO: $ESTACK=",$ESTACK // 1
XECUTE "WRITE !,""Sub1 XECUTE: $ESTACK="",$ESTACK" // 2
WRITE !,"Sub1 post-XECUTE: $ESTACK=",$ESTACK // 1
GOTO Sub2
Sub1Return
WRITE !,"Sub1 after GOTO: $ESTACK=",$ESTACK // 1
QUIT
Sub2
WRITE !,"Sub2 via GOTO: $ESTACK=",$ESTACK // 1
GOTO Sub1Return
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ESTACK1()
Initial Main: $ESTACK=0
Sub1 via DO: $ESTACK=1
Sub1 XECUTE: $ESTACK=2
Sub1 post-XECUTE: $ESTACK=1
Sub2 via GOTO: $ESTACK=1
Sub1 after GOTO: $ESTACK=1
Return Main: $ESTACK=0
注意
终端提示的上下文级别
从程序调用的例程与在终端提示下使用DO命令调用的例程在不同的上下文级别开始。在终端提示下输入DO命令时,系统会为该例程创建一个新的上下文。
调用的例程可以通过建立$ESTACK Level 0上下文进行补偿,然后对所有上下文级引用使用$ESTACK。
请考虑以下例程:
/// d ##class(PHA.TEST.SpecialVariables).ESTACK2()
ClassMethod ESTACK2()
{
START
; 建立$ESTACK 0级上下文
NEW $ESTACK
; 显示$STACK上下文级别
WRITE !,"$STACK level in routine START is ",$STACK
; 显示$ESTACK上下文级别并退出
WRITE !,"$ESTACK level in routine START is ",$ESTACK
QUIT
}
从程序运行Start时,会看到以下显示:
$STACK level in routine START is 0
$ESTACK level in routine START is 0
当在终端提示符下发出do^start命令来运行START时,会看到以下显示:
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ESTACK2()
$STACK level in routine START is 1
$ESTACK level in routine START is 0
$ESTACK和错误处理
当错误处理程序必须将调用堆栈展开到特定上下文级别时,$ESTACK在错误处理期间特别有用。