第十章 Caché 函数大全 $COMPILE 函数

第十章 Caché 函数大全 $COMPILE 函数

编译源代码,生成可执行的目标代码。

大纲

$COMPILE(source,language,errors,object)

$COMPILE(source,language,errors,object,,,rname)

参数

  • source 指定包含要编译的源代码的下标数组的局部或全局变量。
  • language 指定源代码编程语言的整数标志。0=ObjectScript。
  • errors 接收编译期间发生的任何错误的无下标局部变量。此变量是一个列表结构,每个报告的错误对应一个元素。每个错误本身都是一个列表结构,指定错误位置和类型(见下文)。
  • object 第一个语法-一个无下标的局部或全局变量,用于生成用于保存编译后的目标代码的数组。第二个语法-此参数是可选的。如果指定,对象将清除其先前值,但不会设置。通常,第二种语法省略宾语并指定占位符逗号。
  • rname 第二个语法-指定用于在^rOBJ全局变量数据库中存储编译的目标代码的例程名称的字符串。

描述

$COMPILE编译源代码并生成OBJ(对象)代码(例程的可执行形式)。$COMPILE报告编译错误,可用于检查源代码是否存在编译错误,而无需实际生成目标代码。$COMPILE接受INT代码,而不是MAC代码作为输入。因此,在编译之前,源代码中的任何宏都必须由预处理器(如ObjectScript宏预处理器)解析。

注意:Caché提供了几个强大的源代码编译工具,Studio就是其中之一。通常,源代码编译是使用这些工具执行的,而不是这个$COMPILE函数。

$COMPILE有两种语法形式:

  • 第一个$COMPILE语法形式返回对象数组中的对象代码。它首先终止对象变量。编译之后,对象数组被设置为编译后的目标代码的大小。

对象数组包含的目标代码格式与^rOBJ全局变量格式相同。可以使用命令MERGE ^rOBJ(rname)=object(1)^rOBJ中的目标代码替换为新的目标代码。但是,设置多个节点时,MERGE命令不是原子的,因此,如果另一个进程同时加载同一例程,则此操作可能会导致不可预测的结果。

如果省略object参数,则将编译源代码并检查是否有错误,但不会创建任何目标代码。

  • 第二种$COMPILE语法形式将目标代码直接返回到名为rname的例程中。可以通过返回^rOBJ(rname)来查看此OBJ代码。$COMPILE操作在内部锁定^rOBJ(rname),从而防止任何其他进程在完全存储新的目标代码之前加载例程目标代码。

如果省略rname参数,则将编译源代码并检查是否有错误,但不会创建目标代码。

通常,以这种语法形式省略对象参数(第4个参数)。如果指定对象参数,则将杀死对象变量,但未设置。其他省略的参数(以占位符逗号表示)仅供内部使用,不应指定。

$COMPILE返回如下的整数代码:0 =未检测到错误,并且创建了目标代码。1 =检测到错误并创建了目标代码。-1 =检测到错误,并且没有创建目标代码。当省略保存目标代码的参数(第一语法:object;第二语法rname)时,将返回相同的返回代码。

当ObjectScript编译器检测到错误时,它将在该点创建目标代码,该目标代码在执行该行时将引发错误。当Basic编译器检测到错误时,它们不会产生任何目标代码。

编译类方法

Caché提供了用于编译一个或多个类的类方法。这些方法提供了许多限定符和标志,以更精确地指定编译选项:

  • $SYSTEM.OBJ.Compile()编译指定的类和该类中的所有例程。
DHC-APP>d $SYSTEM.OBJ.Compile("PHA.TEST.Function")
 
编译于07/31/2020 14:42:01开始,包含限定符''
编译类 PHA.TEST.Function
正在编译例程 PHA.TEST.Function.1
0.011s中已成功完成编译.
  • $SYSTEM.OBJ.CompileList()编译指定类和这些类中所有例程的列表。
  • $SYSTEM.OBJ.CompilePackage()编译指定包(模式)中的所有类/例程。
DHC-APP>w $SYSTEM.OBJ.CompilePackage("PHA.TEST")
 
编译于07/31/2020 14:41:25开始,包含限定符''
,正在编辑5类,正在使用5工作者作业
编译类 PHA.TEST.Arithmetic
编译类 PHA.TEST.Function
编译类 PHA.TEST.Command
编译类 PHA.TEST.ObjectScript
编译类 PHA.TEST.ObjectScriptTwo
正在编译例程 PHA.TEST.ObjectScriptTwo.1
正在编译例程 PHA.TEST.Command.1
正在编译例程 PHA.TEST.ObjectScript.1
正在编译例程 PHA.TEST.Arithmetic.1
正在编译例程 PHA.TEST.Function.1
0.296s中已成功完成编译.
1
  • $SYSTEM.OBJ.CompileAll()编译当前名称空间中的所有类/例程。
  • $SYSTEM.OBJ.CompileAllNamespaces()编译所有名称空间中的所有类/例程。

参数

source

包含要编译的源代码的数组。源的格式可以是ObjectScript的int例程、CachéBasic的BAS例程或CachéMVBasic的MVI例程。数组元素source(0)必须包含源代码的行数,每个source(N)包含源代码的第n行。源行必须从1到n连续编号,不能遗漏行。可执行的ObjectScript代码必须缩进。例如:

/// d ##class(PHA.TEST.Function).compiles()
ClassMethod compiles()
{
    SET mysrc(0)=6
    SET mysrc(1)="  SET x=1"
    SET mysrc(2)="Main"  // a label
    SET mysrc(3)="  WRITE ""x is:"",x,!"
    SET mysrc(4)="  SET x=x+1"
    SET mysrc(5)="  IF x=4 {WRITE ""x is:"",x,"" all done""   QUIT}"
    SET mysrc(6)="  GOTO Main"
    SET rtn=$COMPILE(mysrc,0,errs,,,,"myobj")
    IF rtn=0 {
        WRITE "成功生成OBJ代码",!
    } ELSE {
        WRITE "未生成OBJ代码返回代码: ",rtn,!  QUIT
    }
    WRITE "运行代码",!!
    DO ^myobj
}
DHC-APP>d ##class(PHA.TEST.Function).compiles()
成功生成OBJ代码
运行代码
 
x is:1
x is:2
x is:3
x is:4 all done

Source参数可以是无下标的局部变量名,也可以是可能有下标的全局变量名称。

如果未定义source(0),则无论%SYSTEM.Process.Unfined()方法设置如何,系统都会生成<UNDEFINED>错误。

如果source(0)值大于源代码行数,或者缺少连续的源代码行,则系统会生成<UNDEFINED>错误,后跟缺少的源代码行的名称。可以通过设置%SYSTEM.Process.Unfined()方法来更改此行为。以下示例中显示了这些类型的错误:

/// d ##class(PHA.TEST.Function).compiles1()
ClassMethod compiles1()
{
    SET src(0)=4,src(1)="TestA ",src(2)=" WRITE 123",src(3)=" WRITE 456,!"
    SET stat=$COMPILE(src,0,errs,TestA)    /* generates <UNDEFINED> *src(4) */
}

DHC-APP>d ##class(PHA.TEST.Function).compiles1()
 
 SET stat=$COMPILE(src,0,errs,TestA)    /* generates <UNDEFINED> *src(4) */ }
 ^
<UNDEFINED>zcompiles1+2^PHA.TEST.Function.1 *src(4)
DHC-APP 2d1>
/// d ##class(PHA.TEST.Function).compiles2()
ClassMethod compiles2()
{
    SET src(0)=4,src(1)="TestA ",src(3)=" WRITE 123",src(4)=" WRITE 456,!"
    SET stat=$COMPILE(src,0,errs,TestA)    /* generates <UNDEFINED> *src(2) */
}
DHC-APP>d ##class(PHA.TEST.Function).compiles2()
 
 SET stat=$COMPILE(src,0,errs,TestA)    /* generates <UNDEFINED> *src(2) */ }
 ^
<UNDEFINED>zcompiles2+2^PHA.TEST.Function.1 *src(2)
/// d ##class(PHA.TEST.Function).compiles3()
ClassMethod compiles3()
{
    SET src(0)=3,src(1)="TestA ",src(3)=" WRITE 123",src(4)=" WRITE 456,!"
    SET stat=$COMPILE(src,0,errs,TestA)    /* generates <UNDEFINED> *src(2) */
}
DHC-APP>d ##class(PHA.TEST.Function).compiles3()
 
 SET stat=$COMPILE(src,0,errs,TestA)    /* generates <UNDEFINED> *src(2) */ }
 ^
<UNDEFINED>zcompiles3+2^PHA.TEST.Function.1 *src(2)

language

指定要编译的源的类型的语言模式。常见值包括:

  • 0 = ObjectScript
  • 9 = Caché Basic
  • 11 = Caché MVBasic

其他值指定旧版ObjectScript模式,应仅在咨询系统间支持人员后才能使用。

errors

设置为编译器检测到的任何错误的无下标局部变量。任何现有值都将被取消。如果未检测到错误,则将变量设置为空字符串(“”)。如果检测到错误,则将ERROR变量设置为$LIST结构,每个错误对应一个元素。每个错误本身都是$LISTBUILD(line,offset,errnum,text) 格式 $LIST 结构,其中:

  • line =检测到错误的行号
  • offset =错误源行中的偏移量
  • errnum =错误类型的错误号
  • text =描述错误的文字

Basic编译器将另外两个元素添加到列表中,文字描述错误的位置以及源代码行本身。

object

接收编译器目标代码输出的数组。对象参数可以是未下标的局部变量名称,也可以是可能下标的全局名称。上面描述了对象数组的内容。

rname

例程名称,用于指定目标代码在^rOBJ 下的全局变量中应保存的位置。 $COMPILE在保存新的目标代码之前会杀 ^rOBJ(rname)的所有现有内容。在以下示例中, rname=”myobj”

要查看OBJ代码:

DHC-APP>WRITE ^rOBJ("myobj")
 
=!�m??#_
        J?? �???? ?????? H?? ?? �A?�???? ??�??????�??p   all done�x is:�Mainxó??�???@@@@@@@@@@@@@@@@@@@@@@@@@@@@HHHHf??ù??
DHC-APP> ZWRITE ^rOBJ("myobj")
^rOBJ("myobj")=$c(12)_"=!"_$c(22)_"m??#_"_$c(1,0,10,8,0)_" J"_$c(0,149)_" "_$c(17)_"??"_$c(138)_" ????"_$c(137)_" H"_$c(152)_" "_$c(129)_" "_$c(4)_"A??"_$c(8,17)_"??"_$c(138)_" ??"_$c(18)_"??????"_$c(18,0)_"??"_$c(0,0,0)_"p"_$c(9)_" all done"_$c(5)_"x is:"_$c(4)_"Main"_$c(1)_"x"_$c(2,0)_"ó??é??"_$c(0,0,23,0,6,0,2,0,2,0,8,0,13,0,27,0,30,0,1,0)_"????"_$c(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"@"_$c(0)_"H"_$c(0)_"H"_$c(0)_"H"_$c(0)_"H"_$c(0)_"f??ù??"_$c(2,0,0,0)

要执行OBJ代码:

DHC-APP>DO ^myobj
x is:1
x is:2
x is:3
x is:4 all done

列出创建时间戳记和OBJ代码的长度:

DHC-APP>ZWRITE ^rINDEX("myobj")
^rINDEX("myobj","OBJ")=$lb("2020-07-31 14:47:09",196)

请注意,^rINDEX() 仅列出OBJ代码行,因为$COMPILE创建的代码没有相应的存储的MAC或INT代码版本。

中断编译

可以发出Ctrl-C或调用^RESJOB实用程序来中断正在进行的编译。所有语言模式均支持这些编译中断。

示例

下面的示例使用第一种$COMPILE格式编译四行ObjectScript程序:

/// d ##class(PHA.TEST.Function).compiles4()
ClassMethod compiles4()
{
SourceCode
    SET src(0)=4
    SET src(1)="TestA "
    SET src(2)=" WRITE ""Hello "" "
    SET src(3)=" WRITE ""World"",!"
    SET src(4)=" QUIT"
CompileSource
    SET stat=$COMPILE(src,0,errs,TestA)
    IF stat=0 {
        WRITE "编译成功" 
    } ELSE {
        WRITE "状态",stat,!
        WRITE "编译错误长度=",$LISTLENGTH(errs) 
    }
}

DHC-APP>d ##class(PHA.TEST.Function).compiles4()
编译成功

下面的示例使用第二种$COMPILE格式编译相同的四行ObjectScript程序:

/// d ##class(PHA.TEST.Function).compiles5()
ClassMethod compiles5()
{
SourceCode
      SET src(0)=4
      SET src(1)="TestB "
      SET src(2)=" WRITE ""Hello "" "
      SET src(3)=" WRITE ""World"",!"
      SET src(4)=" QUIT"
CompileSource
    SET stat=$COMPILE(src,0,errs,,,,"TestB")
    IF stat=0 {
        WRITE "编译成功",!
        DO ^TestB 
    } ELSE {
        WRITE "状态=",stat,!
        WRITE "编译错误长度==",$LISTLENGTH(errs) 
    }
}
DHC-APP>d ##class(PHA.TEST.Function).compiles5()
编译成功
Hello World

下面的示例对七行ObjectScript程序执行编译错误检查。请注意,此$COMPILE仅测试错误。它没有提供变量来从成功的编译中接收目标代码。在这个例子中,每一行源代码都包含一个错误; $COMPILE仅返回第1、3、5、6和7行中的编译时错误,而不返回诸如零除错误(第2行)或未定义的变量错误(第4行)之类的运行时错误:

/// d ##class(PHA.TEST.Function).compiles6()
ClassMethod compiles6()
{
SourceCode
    SET src(0)=7
    SET src(1)="?TestC "
    SET src(2)=" SET a=2/0"
    SET src(3)=" SET b=3+#2"
    SET src(4)=" SET c=xxx"
    SET src(5)=" SET? d=5"
    SET src(6)=" SET 123=""abc"""
    SET src(7)=" SETT f=7"
CompileSource
    SET stat=$COMPILE(src,0,errs)
    zw errs
    IF stat {
        WRITE $LISTLENGTH(errs)," 编译错误 ",!
        FOR i=1:1:$LISTLENGTH(errs) {
            WRITE !,i,": " 
            SET errn=$LIST(errs,i)
            FOR j=1:1:$LISTLENGTH(errn) {
                WRITE $LIST(errn,j)," "
            }
        }
    } ELSE {
        WRITE "编译成功",!
        WRITE "但没有生成目标代码" 
    }
}
DHC-APP>d ##class(PHA.TEST.Function).compiles6()
errs=$lb($lb(1,1,1002,"Invalid character in tag"),$lb(3,10,1054,"Invalid expression"),$lb(5,5,1003,"Expected space"),$lb(6,6,1027,"Error in SET command"),$lb(7,5,1026,"Invalid command"))
5 编译错误
 
1: 1 1 1002 Invalid character in tag
2: 3 10 1054 Invalid expression
3: 5 5 1003 Expected space
4: 6 6 1027 Error in SET command
5: 7 5 1026 Invalid command
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343