第三章 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上下文。当使用DOXECUTE或用户定义的函数创建新的上下文时,Caché会将此$ESTACK值递增。但是,当退出创建新$ESTACK的上下文时($ESTACK处于级别0),Caché会还原$ESTACK的先前副本的值。

示例

以下示例显示了$ESTACK上的NEW命令的作用。在此的示例MainRoutine显示$STACK$ESTACK的初始值(它们是相同的值)。然后,它调用Sub1。该调用将增加$STACK$ESTACKNEW命令创建一个值为0的$ESTACKSub1调用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

下面的示例演示了如何通过发出DOXECUTE命令在创建新上下文时增加$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在错误处理期间特别有用。