自定义表达式内函数

翻译自原文档:https://osdn.net/projects/emuera/wiki/UserMeth

表达式内函数,即除了内置函数之外,还可以在表达式中调用@~~中定义的函数。

关于表达式内函数的更多信息,请参见表达式内函数

格式

被调用的函数必须有#FUNCTION#FUNCTIONS标志,并且必须以RETURNF结束。

#FUNCTION表示该函数返回一个数字。

#FUNCTION(S):返回一个字符串。

一个带有#FUNCTION(S)的函数不能用通常的RETURN来终止。 相反,它们是以RETURNF终止的。

RETURNF可以是一个公式或一个字符串表达式。 它必须符合#FUNCTION(S)中给出的类型。

如果省略RETURNF参数,或者在没有RETURNF的情况下到达函数的终点,则返回0""

X = GET_CFLAG(TARGET, Y)
STR = %GET_NAME(TARGET)%

@GET_CFLAG(ARG:0, ARG:1)
#FUNCTION
  SIF ARG:0 <= 0 || ARG:0 >= CHARANUM
    RETURNF 0
  RETURNF CFLAG:(ARG:0):(ARG:1)

@GET_NAME(ARG:0)
#FUNCTIONS
  SIF ARG:0 <= 0 || ARG:0 >= CHARANUM
    RETURNF ""
  RETURNF NAME:(ARG:0)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

函数定义的参数用()括起来,但这不是定义的必要语法。

如果你想在表达式中调用一个函数,你需要使用带()的语法。

你也可以用逗号把函数名和参数分开,就像你对普通函数那样。

下面两行的意思是一样的:

@GET_CFLAG(ARG:0, ARG:1)
@GET_CFLAG, ARG, ARG:1
1
2

也可以为参数设置初始值。

关于初始值的语法的更多信息,请参阅在你自己的函数中指定参数

限制条件

不能从CALL中调用

带有FUNCTION(S)标志的函数不能以通常的方式调用,例如CALL

它只能在一个表达式中被调用。

;错误
CALL GET_CFLAG, X, Y

@GET_CFLAG(ARG:0, ARG:1)
#FUNCTION
  SIF ARG:0 <= 0 || ARG:0 >= CHARANUM
    RETURNF 0
  RETURNF CFLAG:(ARG:0):(ARG:1)
1
2
3
4
5
6
7
8

#FUNCTION(S)可以从CALLFCALLFORMF中调用,它们是调用FUNCTION(S)的专用指令。

有些指令是不可用的

在带有FUNCTION(S)标志的函数中,不允许有输入的命令,如WAIT,和带有函数调用的命令,如CALL

如果使用它们,就会发生错误。

不能使用CALL指令,但可以在表达式中调用带有FUNCTION(S)标志的函数。

也可以用CALLFCALLFORMF指令调用#FUNCTION(S)

不支持函数重载

不可能用不同数量或类型的参数调用一个以上的#FUNCTION(S)函数。

只能定义一个同名的函数,如果定义了多个同名的函数,只有第一个函数是有效的。

覆盖内置函数

如果你定义了一个与内置函数同名的函数,你将无法调用该内置函数。

例如,如果你定义了@ABS,你将无法调用原来的ABS

如果一个内置函数被覆盖,Emuera 将在启动时显示一个警告。

如果一个内置函数被覆盖,它可能无法按预期工作,所以可以通过配置来禁止函数的覆盖。

对于故意覆盖的情况(不推荐),也有一个配置选项,如果一个函数被覆盖,则不发出警告。

注意事项

带有FUNCTION(S)标志的函数不应该改变除局部变量以外的任何变量。

改变非局部变量的函数(有副作用的函数)可能会由于短路评估或表达式评估的顺序而改变其行为,如下所述。

对这些函数的意外调用,例如从调试命令或从调试变量观察窗口,也可能导致非预期的行为。

短路逻辑导致调用省略

即使表达式中存在一个函数,也可能由于短路逻辑而无法调用。

例如,下面的脚本在IF语句中调用GET_ASSI_CFLAG,并改变GET_ASSI_CFLAG中的ASSI

IF X || GET_ASSI_CFLAG(0)
  Y = CFLAG:ASSI:2
ENDIF

@GET_ASSI_CFLAG(ARG:0)
#FUNCTION
  SIF ASSI < 0
    ASSI = 0
  RETURNF CFLAG:ASSI:(ARG:0)
1
2
3
4
5
6
7
8
9

乍一看,执行Y = CFLAG:ASSI:2时,似乎不可能出现ASSI < 0

然而,如果X非零,GET_ASSI_CFLAG由于短路评估而不被执行,当试图评估CFLAG:ASSI:2ASSI < 0时可能发生错误。

其结果取决于方程的评估顺序

变量和函数在表达式中被评估的顺序是未定义的。

有副作用的函数可能取决于表达式中的函数被调用的顺序。

请不要写这样的代码。

对于同一版本的 Emuera,调用顺序将是相同的,但在未来可能会发生变化。

在下面的脚本中,TARGETADDCHARA_CFLAG中被改变:

X = CFLAG:TARGET:10 + ADDCHARA_CFLAG(0)

@ADDCHARA_CFLAG(ARG)
#FUNCTION
  ADDCHARA ARG
  TARGET = CHARANUM -1
  RETURNF CFLAG:TARGET:2
1
2
3
4
5
6
7

根据CFLAG:TARGET:10是在ADDCHARA_CFLAG之前还是之后被评估,CFLAG:TARGET:10所指向的变量将会改变。

因此,这个脚本取决于评价的顺序。

你不应该在带有FUNCTION(S)标志的函数中赋值给ADDCHARATARGET

可由调试函数调用

FUNCTION(S)标记的函数不仅可以被*.ERB文件中的脚本动态调用,还可以被调试命令和调试变量观察窗口调用。

特别是,变量watch将试图频繁地更新其值,并在每次更新时调用该函数。

有副作用的功能可能会因为这种调用而发生故障。

Last Updated: 2021/9/30 上午5:06:17
Contributors: Miswanting