文章目录

  • 第三十三章 Caché 命令大全 XECUTE 命令
  • 重点
  • 大纲
    • 参数
  • 描述
  • 参数
    • pc
    • cmdline
    • fparams
    • params
  • 示例
  • 注意
    • `XECUTE` 和 Objects
    • `XECUTE` 和 `FOR`
    • `XECUTE` 和 `DO`
    • `XECUTE` 和 `GOTO`
    • `XECUTE` 和 `QUIT`
    • `XECUTE` 与 `$TEXT`
    • XECUTE的嵌套调用
    • `XECUTE`调用的命令的执行时间
    • 实施通用操作
    • `XECUTE`和`ZINSERT`

 

 
第三十三章 Caché 命令大全 XECUTE 命令

执行指定的命令。

重点
  1. CheckSynTax()命令可以检查x语法格式是否正确
大纲
XECUTE:pc xecutearg,... 
X:pc xecutearg,...

其中,xecutearg可以是以下任一项

"cmdline":pc
("(fparams) cmdline",params):pc

参数

  • pc - 可选-后置条件表达式。
  • cmdline 解析为包含一个或多个有效CachéObjectScript命令的命令行的表达式。请注意,cmdline或(Fparams)cmdline必须指定为带引号的字符串。
  • fparams 可选-形式参数列表,指定为用括号括起来的逗号分隔列表。形参是cmdline使用的变量,其值由传递params提供。请注意,fparams是带引号的代码字符串中的第一项。
  • params 可选-参数列表,指定为逗号分隔的列表。这些是传递给fparams的参数。如果指定了params,则必须指定相等或更大数量的fparams。
描述

XECUTE执行一个或多个CachéObjectScript命令行,每个命令行由一个Xecutearg指定。这些xecutearg按从左到右的顺序执行,每个执行都由可选的后置条件表达式控制。Xecutearg有两种句法形式:

  • 不传递参数。此不使用括号。
  • 使用参数传递。需要用括号括起来。

XECUTE可以包含这两种形式的xecutearg的任意组合。

可以使用%Library.Routine类的CheckSynTax()方法对xecutearg命令行字符串执行语法检查。CheckSynTax()在可执行的ObjectScript代码行之前需要一个或多个空格。CheckSynTax()将没有缩进的行解析为标签,或者将标签后跟可执行代码解析为标签。XECUTE允许但不需要缩进可执行代码;它不允许指定标签名称。XECUTE和CheckSynTax()都不会解析宏预处理器代码。

实际上,每个xecutearg就像一个由do命令调用的单行子例程,并在到达参数末尾或遇到Quit命令时终止。在Caché执行参数之后,它将控制返回到紧接在xecutearg之后的点。

每次调用XECUTE都会在进程的调用堆栈上放置一个新的上下文框架。$STACK特殊变量包含调用堆栈上当前上下文帧的数量。

XECUTE命令执行与$XECUTE函数基本相同的操作,但有以下区别:命令可以使用后置条件,而函数不能。命令可以指定多个xecutearg,函数只能指定一个xecutearg。该命令不需要退出即可完成执行;该函数要求每个执行路径都有一个带参数的退出。

参数

pc

可选的后置条件表达式。如果后置条件表达式附加到COMMAND关键字后,则Caché仅在后置条件表达式为TRUE(计算结果为非零数值)时才执行XECUTE命令。如果后置条件表达式为假(计算结果为零),则Caché不执行XECUTE命令。

如果后置条件表达式附加到xecutearg,则仅当后置条件表达式为真(计算结果为非零数值)时,Caché才会计算参数。如果后置条件表达式为false,则caché跳过该xecutearg并计算下一个xecutearg(如果存在)。

cmdline

每个cmdline的计算结果必须为包含一个或多个CachéObjectScript命令的字符串。请注意,在某些情况下,必须在一个命令和它后面的命令之间插入两个空格。Cmdline字符串的开头不得包含制表符,末尾不得包含<Return>。若要在cmdline字符串中指定引号,请使用双引号。以下示例显示包含两个命令的单个cmdline:

DHC-APP>XECUTE "WRITE ""hello "",!  WRITE ""world"",!"
hello
world

因为cmdline是一个字符串,所以它不能简单地跨多个代码行断开。可以将单个cmdline参数分成使用连接运算符联接的单独字符串:

/// d ##class(PHA.TEST.Command).TestXecute()
ClassMethod TestXecute()
{
	XECUTE "WRITE ""hello "",!"_
	      " WRITE ""world"",!"
}
DHC-APP>d ##class(PHA.TEST.Command).TestXecute()
hello
world
 

可以将单个cmdline参数分为多个单独的逗号分隔的cmdline参数:

/// d ##class(PHA.TEST.Command).TestXecute1()
ClassMethod TestXecute1()
{
	XECUTE "WRITE ""hello "",!",
	      "WRITE ""world"",!"
}

DHC-APP>d ##class(PHA.TEST.Command).TestXecute1()
hello
world
 java

Cmdline的最大长度取决于以下注意事项:Caché将源cmdline字符串及其生成的目标代码存储为单个字符串。生成的字符串不得超过Caché 的最大字符串长度。

可以在cmdline内、连接的cmdline字符串之间或逗号分隔的cmdline参数之间嵌入/*text*/注释:

/// d ##class(PHA.TEST.Command).TestXecute2()
ClassMethod TestXecute2()
{
	XECUTE "SET x=""hello "" /* 1st val */ SET y=""world"" /* 2nd val */ "_
	      " WRITE x,! /* part of 1st cmdline */ ",
	      "WRITE y,! /* 2nd cmdline */ "
}
DHC-APP>d ##class(PHA.TEST.Command).TestXecute2()
hello
world
 

Cmdline可以计算为空字符串(“”)。在这种情况下,Caché不执行任何操作,并继续执行下一个xecutearg(如果存在)。

如果要传递参数,则fparams形参列表必须在cmdline命令之前,两个元素用相同的引号引起来。虽然建议用一个或多个空格将fparams与cmdline隔开,但不需要空格。

/// d ##class(PHA.TEST.Command).TestXecutePara()
ClassMethod TestXecutePara()
{
	SET x=1
	XECUTE ("(in,out) SET out=in+3", x, .y)
	WRITE y,x
	QUIT
}
DHC-APP>d ##class(PHA.TEST.Command).TestXecutePara()
41

默认情况下,cmdline中使用的所有局部变量都是公共变量。通过将命令括起来,可以将命令行中的变量指定为私有变量,将它们设置在大括号中。例如:

/// d ##class(PHA.TEST.Command).TestXecutePara1()
ClassMethod TestXecutePara1()
{
	SET x=1
	XECUTE ("(in,out) { SET out=in+3 }", x, .y)
	WRITE y
	QUIT
}

可以通过指定紧跟在fparams形参列表后面的用方括号括起来的公共变量列表来覆盖特定变量的私有变量指定。下面的示例指定包含变量x的公共变量列表:

/// d ##class(PHA.TEST.Command).TestXecutePara2()
ClassMethod TestXecutePara2()
{
	SET x=1
	XECUTE ("(in,out) [x] { SET out=in+3 }", x, .y)
	WRITE y,x
	QUIT
}

fparams

形式参数列表,用逗号分隔并用括号括起来。形参名称必须是有效的标识符。因为这些形参是在另一个上下文中执行的,所以它们只能在它们的xecutearg中是唯一的;它们对发出XECUTE的程序或另一个xecutearg中同名的局部变量没有影响。不必使用cmdline中的任何或所有fparams。但是,fparams的数量必须等于或超过指定的params数量,否则会生成<PARAMETER>错误。

params

要从调用程序传递到fparams的实际参数,以逗号分隔的列表形式指定。参数必须是调用程序中定义的变量。

可以使用点前缀通过引用传递参数。这对于从cmdline传出值非常有用。下面提供了一个示例。

示例

下面的示例将一个参数传递给设置全局。提供了两个命令行。每个函数的执行取决于它们的后置条件设置。

/// d ##class(PHA.TEST.Command).TestXecutePara3()
ClassMethod TestXecutePara3()
{
	SET bad=0,good=1
	SET val="paid in full"
	XECUTE ("(pay) SET ^acct1=pay",val):bad,("(pay) SET ^acct2=pay",val):good
}
DHC-APP>d ##class(PHA.TEST.Command).TestXecutePara3()
 
DHC-APP>zw ^acct2
^acct2="paid in full"
 
DHC-APP>zw ^acct1

由于后置条件错误的值,这里跳过了第一个xecutearg。执行第二个xecutearg时,val作为参数传入,为命令行中使用的pay形式参数提供一个值。

下面的示例使用按引用传递(.y)将局部变量值从cmdline传递到调用上下文。

/// d ##class(PHA.TEST.Command).CubeIt()
ClassMethod CubeIt()
{
	SET x=5
	XECUTE ("(in,out) SET out=in*in*in",x,.y)
	WRITE !,x," cubed is ",y
}
DHC-APP>d ##class(PHA.TEST.Command).CubeIt()
 
5 cubed is 125

在下面的示例中,XECUTE命令引用本地变量x和y。x和y都包含一个字符串,该字符串由XECUTE调用的三个单独的CachéObjectScript命令组成。

/// d ##class(PHA.TEST.Command).TestXecuteQ()
ClassMethod TestXecuteQ()
{
	SET x="SET id=ans QUIT:ans="""" DO Idcheck"
	SET y="SET acct=num QUIT:acct="""" DO Actcheck"
	XECUTE x,y
}
```java
下面的示例使用具有`$SELECT`结构的`XECUTE`。
```java
/// d ##class(PHA.TEST.Command).TestXecuteQuit()
ClassMethod TestXecuteQuit()
{
	s a = $random(200)
	s b = "大于100"
	s c = "小于100"
	XECUTE ("(A,B,D) SET A=$SELECT(A>100:B,1:D)",.a,b,c)
	w a
}
DHC-APP>d ##class(PHA.TEST.Command).TestXecuteQuit()
小于100
DHC-APP>d ##class(PHA.TEST.Command).TestXecuteQuit()
大于100

下面的示例执行子例程,该子例程是A的值。

/// d ##class(PHA.TEST.Command).TestXecuteFor()
ClassMethod TestXecuteFor()
{
   SET A="WRITE ! FOR I=1:1:5 { WRITE ?I*5,I+1 }"
   XECUTE A
}
DHC-APP>d ##class(PHA.TEST.Command).TestXecuteFor()
 
     2    3    4    5    6
注意

XECUTE 和 Objects

可以使用XECUTE调用对象方法和属性并执行返回值,如以下示例所示:

    XECUTE patient.Name
    XECUTE "WRITE patient.Name"

XECUTE 和 FOR

如果XECUTE参数包含FOR命令,则FOR的作用域是该参数的其余部分。当XECUTE参数中最外层的for终止时,XECUTE参数也将终止。

XECUTE 和 DO

如果XECUTE命令包含DO命令,则Caché执行DO参数中指定的一个或多个例程。当它遇到Quit时,它会将控制返回到紧跟在do参数之后的点。

例如,在以下命令中,Caché执行例程路由并返回到紧跟do参数之后的点,以写入字符串“Done”。

   XECUTE "DO ^ROUT WRITE !,""DONE"""

XECUTE 和 GOTO

如果XECUTE参数包含GOTO命令,则Caché会将控制权转移到GOTO参数中指定的点。当它遇到退出时,它不会立即返回到导致传输的goto参数后面的点。取而代之的是,Caché将控制权返回到紧跟在包含GOTO的XECUTE参数之后的位置。

在下面示例中,Caché将控制转移到例程路由器,并将控制返回到紧跟在XECUTE参数后面的点,以写入字符串“Finish”。它从不写入字符串“Done”。

   XECUTE "GOTO ^ROUT WRITE !,""DONE""" WRITE !,"FINISH"

XECUTE 和 QUIT

在每个XECUTE参数的末尾都有一个隐含的退出。

XECUTE 与 $TEXT

如果在cmdline中包含$TEXT函数,则它指定包含XECUTE的例程中的代码行。例如,在下面的程序中,$TEXT函数检索并执行一行。

/// d ##class(PHA.TEST.Command).TestXecuteA()
ClassMethod TestXecuteA()
{
A
   SET H="WRITE !!,$PIECE($TEXT(HELP+1),"","",3)"
   XECUTE H
   w H
   QUIT
HELP
	
   ;; 从以下位置输入数字1 TO 5
}

运行例程A提取并写入“输入从1到5的数字”。

XECUTE的嵌套调用

CachéObjectScript支持在XECUTE参数中使用XECUTE。但是,应该谨慎使用XECUTE的嵌套调用,因为很难在执行时确定确切的处理流。

XECUTE调用的命令的执行时间

在XECUTE内调用的代码的执行时间可能比在例程主体中遇到的相同代码的执行时间慢。这是因为每次处理XECUTE时,Caché都会编译用XECUTE命令指定的源代码或包含在引用的全局变量中的源代码。

实施通用操作

XECUTE的典型用法是在应用程序内实现泛化操作。例如,假设想要实现一个内联数学计算器,该计算器允许用户对任意两个数字和/或变量执行数学运算。要使计算器在应用程序中的任何位置都可用,可以使用特定的功能键(比如F1)来触发计算器子例程。

实现此类计算器的代码的简化版本可能如下所示。

Start  
	SET ops=$CHAR(27,21)
	READ !,"总金额(或用于计算器的F1): ",amt
	IF $ZB=ops { DO Calc 
	; . . .
	}
Calc  
	READ !,"计算器"
	READ !,"两个数字和/或变量的数学运算."
	READ !,"第一个数字或变量名称: ",inp1
	READ !,"数学运算符(+、-、*、/): ",op
	READ !,"第二个数字或变量名称: ",inp2
	SET doit="SET ans="_inp1_op_inp2
	XECUTE doit
	WRITE !,"答案(ANS)是: ",ans
	READ !,"是否重复?(Y或N) ",inp
	IF (inp="Y")!(inp="y") { GOTO Calc+2 }
	QUIT
DHC-APP>d Start^PHA.TEST.Command
 
总金额(或用于计算器的F1):
计算器
两个数字和/或变量的数学运算.
第一个数字或变量名称: 2
数学运算符(+、-、*、/): +
第二个数字或变量名称: 4
答案(ANS)是: 6
是否重复?(Y或N) N

执行时,Calc例程接受数字和/或变量以及所需操作的用户输入,并将其存储为定义变量doit中适当设置命令的字符串文字。XECUTE命令引用doit并执行它包含的命令字符串。该代码序列可以从应用程序中的任意数量的点调用,用户每次提供不同的输入。XECUTE每次使用提供的输入执行SET命令。

XECUTE和ZINSERT

可以使用XECUTE命令从例程中定义并插入一行可执行代码。可以在程序员提示符下使用ZINSERT命令来定义单行可执行代码并将其按行位置插入到当前例程中。可以在程序员提示符下使用ZREMOVE命令,按行位置从当前例程中删除一行或多行可执行代码。

XECUTE命令不能用于定义新标签。因此,XECUTE在其代码行中的第一个命令之前不需要初始空格。ZINSERT可用于定义新标签。因此,ZINSERT在其命令行中的第一个命令之前需要一个初始空格(或新标签的名称)。