MSH语言实现的功能

我继续有关MSH编程语言的系列文章。上一篇文章中,我已经描述了这种语言的规范。但是该规范并未揭示语言的所有功能。我想通过这篇文章消除这种差距。当然,我没有设法描述所有内容,但是基本上我描述了主要功能。我们将把其余的推迟到更好的时候。

当语言的形象刚刚成形时,似乎一切都是合乎逻辑且一致的。但是在实现语言的入口处,必须通过选择一种或另一种策略来解决问题。现在,语言解释器已经准备就绪,您可以看到它如何解决一个或另一个实现问题。

MSH编程语言概念


目录


介绍2
程序的组织。 2
运行时。 2
数据管理。 3
数据本地化。 3
速记语法。 5个
常数。 5
一些团队的功能。 5
CONSTANT命令。 5
XECUTE命令。 6
命令COPY和MOVE。 6
资源同步。 7
SET命令的缩写形式。 8个
团队。 8
IF命令。 8
CASE命令。 9
WHILE命令。 10个
块循环迭代器。 10
NEXT队。 11
BACK命令。 12
查询团队。 12
非块命令数据树遍历命令。 12
NEXT1队。 12
命令BACK1。十三
查询团队1。13
程序执行管理。13
传递参数。14
事件处理。15
EVENTTRAP命令。15
队伍EVENTDELETE。16
EVENTCALL团队。16
EVENTWAIT团队。16个
向量。16
64位向量。16
32位向量。17
16位向量。17
8位向量。17
操作。17个
对象。18
对象的继承。19
交换文件。20
结论。二十

介绍


MSH语言建立在MUMPS语言的概念之上。 MUMPS是上个世纪开发的鲜为人知的语言。但是它仍然用于信息应用程序中。有关该语言的信息可在Internet上找到。有此语言的有效实现,并且有一群程序员支持它。 MUMPS正在美国和俄罗斯开发。另外,据我所知,它在拉丁美洲,德国,澳大利亚和中国使用。一般来说,这种生活语言的概念。与MUMPS会面时,其古老的性质令人震惊。此开发旨在消除其缺点,同时保留其优势,简单性,一致性和数据组织性。
程序的组织。

翻译单元是MSH语言模块。该模块从标识语言版本的标准8字节开始。该行的开头可能是一个标签或空格。标签以“:”结尾,并且与其余命令之间用任意数量的空格隔开。行由命令组成。团队结束的标志是符号“;”。该命令与参数用空格分隔。字符的大小写无关紧要。该命令可以用任何寄存器的字符编写。此外,许多团队都有缩写形式。命令可能具有执行条件。如果有一个,则符号“?”跟随命令而没有空格以及执行此命令的条件。如果执行命令的条件不等于0,则执行命令。在条件内部,不允许使用空格,否则它们将作为命令和参数之间的分隔符进行处理。

例如:

SET?[5]> 5 Val [1] = 25; //
设置正确吗?[2]> 5 Val [1] = 25; //语法错误
SET?([1,2]> 5)Val [1] = 25; //正确地,内部()空格是允许的,

参数之间用符号“,”分隔。在参数内部,空格不是特殊字符,可以包含在任何位置。通常,命令可以具有任意数量的参数。模块中的标签位于模块内部,并且在模块中必须唯一(CASE命令中的标签除外)该命令内部本地化CASE命令的标签应仅在此命令内部唯一,并且可以在此命令外部和嵌套CASE命令中重复使用

运行


在运行时,该应用程序具有一个或多个任务。所有任务并行执行。在每个任务中,程序都按顺序执行。在每个时间点,任务中仅执行一个程序代码。该任务以最后运行的程序的结尾结束。主要任务由语言运行时启动。剩余的作业由Job命令生成

数据管理


对于那些熟悉MUMPS语言的人来说,MSH中的数据组织非常清楚。 MSH中没有数据描述。没有数据声明。数据可以存储为树,然后通过可选的名称和索引执行对树节点的访问。索引括在方括号[]中。名字在他们前面。

例如:

SET Pr [4,5,“ rt”] =是[“ ty ^ 578”]; PrIs
在这里名称。4,5,“ rt”“ ty ^ 578”是节点索引。

该树可以具有任意数量的级别,因此,索引具有以逗号分隔的相应字段数。索引字段可以具有基本类型的任意值。 MSH中的基本类型是数字和字符串。仅将进行记录的节点直接存储在树中。名称,索引字段和索引本身可以是表达式。计算后,该名称只能是一个标识符。

同样,数据可以存储为连续数组,然后对数组元素的访问包括一个可选的符号名称“ $”和一个索引。索引是整数。最小的数组索引是1。名称和索引可以是表达式。计算后,名称只能是标识符,而索引只能是整数。数组可以按任何顺序填充,但是如果您写mc $ 1000,然后将创建一个包含1000个元素mc数组未定义的元素将不包含值,但它们将存在。数组中元素的数量可以通过引用该数组的零元素来找到。 例如:mc $ 0 可以通过向该元素写入新的数组长度来更改数组大小。但是在一般情况下,这是没有必要的,因为数组会自动扩展。 树节点和数组元素包含基本类型的数据。这些是字符串或数字。不关心程序员数据的存储方式。数据类型的存储及其操作是MSH语言实现的职责。






数据本地化


MSH数据分为全局和本地。它们的名称类型不同。全局数据存储在长期内存中,并且不依赖于应用程序的生存期。创建它们后,它们可以由应用程序更改,并且将一直存在,直到应用程序使用KILL命令销毁它们为止。所有全局数据名称中均带有前缀“ ^”。

通过各种任务可以同时访问全局数据。因此,在访问全局变量时,必须进行同步。这种同步总是自动的。全局描述符中始终有一个同步原语,它控制对全局的访问。此外,在读取全局变量时,通过读取阻止,而在写入全局变量时,则通过写入阻止。不需要其他全局同步。对全局数组的访问也将同步。

例如:

^ gl [87,9] -访问全局树节点。

^ glar $ 45-访问全局数组的元素。

本地数据仅在应用程序运行时存在。下一次启动的应用程序无法访问上一次启动的本地数据。

本地数据的范围取决于其类型。有三种类型的数据本地化。

1.本地程序数据。它们位于程序内部,并且从程序启动到完成一直存在。如果程序调用该子例程,则将创建新的子例程数据,并且该子例程内部的本地程序数据不可见。当您返回程序时,本地程序数据将再次变为可用。本地程序数据没有名称。

例如:

[7,9] -访问位于程序内部的树的节点。

$ 5-访问位于程序内部的数组元素。

有一个例外。传递给A $程序的参数数组也位于程序内部。

2.本地应用程序数据。它们在应用程序的所有任务中可见。您可以通过任何任务与他们联系。它们从通过任何任务在应用程序中创建的那一刻起存在,直到应用程序完成或被KILL团队销毁为止。此类数据的名称以“ 为前缀。这些变量可同时在不同任务中使用,因此它们与全局变量一样同步。

例如:

%dapp [87.9] -访问位于应用程序内部的树的节点。

%dapp $ 45-访问位于应用程序内部的数组元素。

3.本地作业数据。它们位于任务内部,并且从它们在任何任务程序中创建之日起一直存在,直到任务由KILL团队完成或销毁为止此类数据必须具有名称,并且不包含前缀“ ^ ”和“ ”。程序参数数组A $一个例外,它位于程序内部,

例如:

djob [87,9] -访问位于任务内部的树的节点。
djob $ 45-访问位于作业内部的数组元素。
访问变量只能具有此处列出的类型。

速记语法


该术语与MUMPS语言中的相似术语无关。 MSH中的缩写语法用于指代整个树或整个数组。它仅在单独的团队中使用,并且始终在允许的地方进行协商。对整棵树的吸引力包括名称和必需的方括号。没有为本地程序树指定名称。
例如:
us [] -访问整个us树。
[] -访问本地程序树。

对整个数组的访问由名称和必需的字符“ $ ”组成。没有为程序的本地数组提供名称。

例如:
us $ -访问整个us数组。
$ -访问本地程序数组。

常数


基本数据类型可以是数字或字符串。在存在小数点的情况下,数字形式可以是整数或实数。数字的底数是10。它们可以是正数或负数。
例如:
25,-4、789.56,-9.3

字符串常量是任何字符序列。如果常量仅由字母和数字组成,则不能将其用引号引起来,因为它不能与变量混淆。如果常量包含其他字符,则必须将其用单引号或双引号引起来。
例如:
“ rt @ tty#123”
'14“ 5 * 7” 89 \?'
125Dsv

一些团队的特点


恒大团队


您可以使用CONSTANT命令为常量命名。这些是广播时间名称。广播将其替换为它们的值。在运行时,这些名称不再存在。因此,您不能CONSTANT命令中将表达式分配给名称。该值必须正好是一个常数。必须选择常量的名称,以使其与不带引号的程序中指定的常量的值不一致。

例如:
常数ioInOut =“ /ini/par.ini>,maxIs=25;
ioInOut和maxIs常量被分配了值。此外,在程序中,可以使用这些名称代替这些值。不断的
团队它有2种形式。在这种情况下,等式的右边不存在。这个团队的含义是不同的。名称是包含常量的模块的名称。该模块的常量将导出到当前模块。模块导入常量不包含有关导入的任何其他描述。导入模块只能包含常量和程序。
例如:
CONSTANT sysCnsNet,usrCnsByx;
sysCnsNetusrCnsByx是包含常量的模块名称。
两种形式都可以作为单个CONSTANT命令的参数出现

XECUTE团队


XECUTE 命令是一个比较特殊的团队,但是它以MUMPS语言提供。在其他编程语言中,她只在JavaScript中遇到了我。那里被称为评估。执行该命令时,将计算该命令的自变量表达式,然后将该表达式转换为字符串,解释为MSH命令并执行。

例如:
XECUTE“ SET $ 1 = 89;”;
结果,变量$ 1将接收值89
这是一个原始示例,以这种形式使用此命令几乎没有任何意义。XECUTE命令的参数是表达式,使您可以在程序运行时生成各种MSH命令。
在命令所在的程序的上下文中执行该命令。她可以使用所有程序资源,包括本地程序数据。

COPY和MOVE命令


COPY命令是类似于MERGE流行性腮腺炎命令这些命令将源节点以及所有后代复制到接收者节点。这些命令的参数由两个字段组成,用符号“ =分隔此标记的右侧是源节点,左侧是接收方。允许使用缩写链接作为节点,在这种情况下,将使用整个树。这些命令不仅复制后代,还复制节点本身。COPY命令进行数据合并。源数据被复制到接收器而不进行清洗。来源没有改变。MOVE团队执行实际的移动数据。以前,清理接收器,然后复制源节点的所有后代,并删除源节点及其所有后代。

例如:
//将节点us [5,6]复制到节点[1]
COPY [1] = us [5,6];
//将整个us树移动到节点[8]
MOVE [8] = us [];
这些命令也可以用于复制阵列。在这种情况下,只有缩短的链接可以用作源和接收器。
程序参数将复制到arg数组。
COPY arg $ = A $;
您可以使用MOVE命令移动。
移动a1 $ = b1 $;
您可以复制和移动任何阵列。

资源同步


执行多个任务时,有必要访问共享资源。同步由锁定命令执行。同步命令本身不会阻塞任何内容,这是一组协议,可以区分对共享资源的访问。如果未在作业之间共享锁定命令,则不会发生访问同步。同步建立在锁名上。这些名称在应用程序中本地化,并且在所有任务中都相同。在锁中,接受许多读者且一次只允许一个作家的概念。因此,存在读锁定和写锁定。洛克

团队阻止读取名称。她的论点中列出的姓名将被阅读阻止。任意数量的任务都可以阻止相同的名称,但是尝试阻止任何这些名称的任务将等待所有这些名称被解锁。捕获写名称后,在写锁定释放名称之前,无法执行任何读锁定命令。如果无法锁定,该命令将等待释放名称。

例如:
LockR name1,name2,name3;
这些名称将被读取阻止。另一项任务也可以锁定这些名称,而不等待它们被解锁。LockW

命令按记录阻止名称。她的论点中列出的姓名将被记录阻止。如果参数中列出的名称已被任何lock命令阻止,则此命令将等待释放这些名称。
例如:
LockW name1,name2,name3;
这些名称将被记录锁定。LockUn
命令解锁该名称。如果通过多次读取阻止了该名称,则需要解锁相同的次数。
例如:
LockUn name1,name2,name3;
标准功能具有超时的这些命令的类似物。

SET命令的缩写


SET 命令具有缩写形式。在这种情况下,等式的左侧不存在;其作用由表达式中提到的最后一个变量发挥。
例如:
SET $ 1 = 2,$ 1 + 3;
变量$ 1将等于5
如果表达式中有多个变量,则结果将分配给最后一个变量。

例如:
SET $ 1 = 1,$ 2 = 2,$ 3 = 3,$ 1 + $ 2 + $ 3; $ 3
变量将变为1 + 2 + 3 = 6。尽管这种形式更适合仅在非常简单的情况下使用,类似于第一个示例。提供第二个示例只是为了说明这种形式的SET命令的功能

块队


块命令形成命令块,并同时用作该块的标题。即使块中只有一个命令,每个块命令也必须具有自己的END命令

中频团队


如果执行该命令的条件为真,则IF 命令形成一个块。该命令没有参数。该块可能包含ELSE命令ELSE命令没有参数。在IF块之外,这些命令没有意义,因此无法应用。如果满足IF命令的条件时,如果IF块中ELSE命令,则仅执行IF命令后面的命令,直到下一个ELSE命令为止ELSE团队可能包含一个执行条件,则在这种情况下为真时,仅执行位于该命令之后的命令,直到下一个ELSE命令或END命令为止一个IF只能包含一个ELSE命令,没有执行条件,并且它必须是ELSE命令中的最后一个

例如:
IF?[6] <0;
SET y [1] = 1;
否[6] <5;
SET y [1] = 2;
否[6] <10;
SET y [1] = 3;
其他 SET y [1] = 4;
结束
可能不存在执行该命令的条件,因此在任何情况下都将执行此块。尽管很难想象为什么这可能有用。

案例团队


该命令的语义与其他MSH团队的语义有所不同。在其中执行命令的条件并非如此。在执行CASE命令的条件下,表达式应计算将控制权转移到的标签。该命令没有参数。

该命令中的每个标签形成一个从该标签到下一个标签的块。当控制权转移到标签时,仅执行命令直到下一个标签,然后退出当前的CASE。该命令更接近Pascal表示法,而不是C切换命令。如果作为计算标签名称的结果,发现当前CASE块中不存在名称,则将执行CASE命令之后,第一个标签之前的命令

CASE?L_ $ J; //评估标签
SET x [1] = 1; //如果未找到标签,则执行该块的命令
SET a [2] = x [1] +1;
L1:SET x [1] = 2;//标签命令块L1
SET a [2] = x [1] +2;
L2:SET x [1] = 3;//标签命令块L2
SET a [2] = x [1] +3;
结束
该命令中的标签隐式形成一个内部命令块。在执行了此类命令块之后,控制权将转移到CASE命令块之外

WHILE命令


WHILE 命令用于组织循环。该命令的执行条件设置了继续循环的条件。只要执行命令的条件不为0,就将执行由该命令形成的块。该块以END命令结尾这样的块END命令具有功能。它可能具有块终止条件。如果条件不为0,则该块将完成。而且,这些条件可能同时出现在WHILE命令END命令中
例如:
WHILE?X [7]> 0; //继续循环的条件
SET y [2] = x [7] +2;
BREAK?是[2] <0;
SET x [7] = x [7] +1;
END?X [7]> 20; //结束循环的条件
在块内部,可以通过BREAK命令中断循环。

块循环迭代器


块循环迭代器针对访问树节点进行了优化。他们使用内部链接来优化对旁路节点的访问。这对块迭代器的使用施加了限制。在块内部,您无法更改树的结构。您不能写这棵树。在块循环迭代器命令中,带有2个参数。
第一个参数是必需的,指向其后代将被绕过的节点的链接。参考索引。可以使用缩短的链接。第二个参数是到将存储后代索引的节点的链接。此参数是可选的。在块内部,第二个参数不应更改。如果$ 2[3],不允许使用$$ 2[[3]]之类的表达式在迭代器块内进行更改。这些变量的更改将不被考虑。可以通过%queryKey系统变量以及%queryData属性的节点数据来访问后代索引如果一定不能从头开始绕过后代,则需要第二个参数,并且必须在其中放置节点索引,此后才开始绕过后代。如果有第二个参数,但是您需要从头开始,那么在循环之前,您需要使用KILL命令删除此变量
命令可能具有块执行条件。进入该块后,仅检查一次此条件。

您不仅可以遍历树的节点,还可以遍历数组。在这种情况下,数组字段的序列号进入第二个参数。只有缩短的链接可以用作第一个参数。

下一队


NEXT 命令遍历树节点的直接后代。后代在从最小索引到最大索引的向前方向上付出代价。
例如:
NEXT us [4,5]; //未指定2个参数,
//从系统变量%queryKey
SET中获取索引$ 1 =%queryKey,$ 2 =%queryData;
END?$ 1> 1000; //结束循环
条件节点索引立即放入数据
KILL $ 1;中。
NEXT我们[4,5],$ 1;
SET $ 2 =%queryData;
结束

缩写链接用作参考节点。在这种情况下,树的第一级被绕过。
杀$ 1;
NEXT us [],$ 1;
SET $ 2 =%queryData;
结束
检索索引3。
SET $ 1 = 3;
NEXT我们[4,5],$ 1;
SET $ 2 =%queryData;
结束
当遍历数组时,所有字段都是按顺序排列的,即使未定义数据的字段也是如此。
例如:
KILL $ 1;
NEXT我们$,$ 1;
SET $ 2 =%queryData;
结束
在块内部,可以通过BREAK命令中断循环

BACK队


BACK 命令NEXT命令的区别仅在于从最后一个顶点到第一个顶点的遍历方向。
例如:
KILL $ 1;
返回我们[4,5],$ 1;
SET $ 2 =%queryData;
结束

查询团队


QUERY 命令在向前方向上从左到右以及从上到下遍历节点的所有后代到整个深度。第二个参数包含整个可选索引。如果该索引具有多个字段,则该列表将放置在第二个参数中。

否则,此命令类似于NEXT命令QUERY

命令仅在从左到右的向前方向上遍历数组

例如:
KILL $ 1;
查询我们[4,5],$ 1;
SET $ 2 =%queryData;
结束
但是此命令仅绕过重要的顶点。

非块命令数据树遍历命令


在这些命令中,两个命令参数都是必需的。第二个参数存储索引,之后下一条命令将找到下一个顶点。在这些命令中,不会保存内部链接,因此对调整绕过的树没有任何限制。由于相同的原因,到达峰的时间可能会更长。也可以使用这些命令绕过阵列。

命令NEXT1

命令NEXT1提供参考节点下同一级别的下一个节点。
节点数据在%queryData系统变量中可用
例如:
SET $ 1 = 2;
NEXT1我们[1,4],$ 1;
//将给出位于节点us [1,4,2]之后的第3级的节点

BACK1团队


BACK1 命令在参考节点下方的同一级别上提供先前的顶点。
否则,它类似于NEXT1命令

QUERY1小组


QUERY1 命令给出了树枝的下一个顶点,同时从上到下以及从左到右遍历整个节点。第二个参数包含整个可选索引。如果该索引具有多个字段,则该列表将放置在第二个参数中。

否则,它类似于NEXT1命令

计划管理


模块标签可以是程序,函数的调用点,新任务的调用点,对象属性,对象方法和标签,这取决于对该标签的访问。
此外,可以在模块的不同部分以不同方式访问标签。
例如:
LB:设置Val [25] = 7 + A $ 1;返回值[25];
做LB(78); //访问程序。返回值将被忽略。
设置Val [7] = 8 * LB(6); //将返回值用作函数调用。
工作LB(17,“ yt”); //调用新作业
Set Val [9] = Mod.LB(3); //访问类方法Mod-在此上下文中,模块的名称被视为对象的类的名称。
设置Val [15] = Obj [1,2,A] .LB; //访问对象Obj [1,2,A]的LB属性,
去LB; //转到LB标签
在上面的示例中,除了4和5,该调用在当前模块内部执行。程序和功能的调用可以在任何可用模块上进行。顺便说一句,这也适用于围棋团队。
例如,在Mod模块中,有一个标签Lb。然后,它的吸引力将如下所示:
做Mod.Lb(78);
设置Val [7] = 8 * Mod.Lb(6);
设置Val [9] = Mod.Lb(3);
JOB Mod.Lb(78);
去Mod.Lb;

通常,标签用作程序或功能。如果模块用作对象类,则标签是此对象的属性或方法。对象及其方法的属性是访问程序和函数的另一种形式,因此,有关程序和函数的所有说明均适用于属性和方法。仅在继承方面访问对象时,没有任何细微差别。此问题将在下面更详细地描述。

在一般情况下,模块的名称和对其的调用中的标签的名称均为表达式,可以在调用时进行计算。
例如:
设置$ 1 =“ Md”,$ 2 =“ Lb”;
做$ 1. $ 2;

程序以Return命令终止可以使用End命令来完成一个模块

传递参数


在MSH中,仅按值传递参数。通常,原则上不存在关于C ++语言的引用和指针,以及在此使用它们所带来的巨大问题。程序总是在A $数组中接受任意数量的参数。它们的编号可以通过引用数组A $ 0的0元素来找到。程序员负责这些参数的含义。

例如:
我们有一个Lb程序。可以解决:
DO Lb(1,2,7);
DO Lb(25.7);
DO Lb();
作业磅(8);
SET [7.8] = Lb(187,“公主”);

程序中未传递的参数未定义。
通过值传递参数不会干扰将变量名称传递到程序中并在其中使用它们。
例如:
设置我们[5] = 48;
做Lb(“我们”);
...
返回
Lb:设置面值[8,1,9] = A $ 1 [5];
// $ 1-传递的第一个参数包含
变量名称//:us
// [5] -访问树的顶部
//因此,节点值us [5] = 48
Return;
结果,变量的名称可以被任意操纵。
使用GO命令转到标签时,参数数组不会更改。MSH具有GO命令格式,可以传输新参数。在这种情况下,当前参数数组将替换为GO命令调用中指定的新参数数组
例如:
GO Lb(1,2,7);

事件处理


事件处理是一种强大的编程机制,通常不包含在高级语言中。但是它在库和操作系统中的存在说明了它的重要性。视觉组件库基于此机制构建。语言中事件处理的存在扩展了语言的功能。打开新的事件驱动的编程样式。顺便说一句,像Assembler这样受人尊敬的编程语言具有这样的功能。因此,此机制已被添加到MSH语言中。

这种机制的基础是事件。它位于应用程序内部。因此,这些名称在整个应用程序中必须是唯一的。如果事件名称与CONSTANT命令中声明的名称匹配,那么事件名称将被声明的常量的值替换。小心。在命名事件时,建议遵循某种命名策略。例如,分配以evu开头的事件名称。考虑到UTF8编码,名称的长度不应超过18个字节。此限制仅与当前的语言实现有关。

在一个任务中创建的事件是可见的,可以在任何任务中进行处理。事件处理程序可以是任意数量,并且可以执行不同的任务。
事件发生后,将检查是否有该事件的处理程序;如果没有处理程序,则将事件删除。如果有处理程序,则它们将按顺序执行。事件可以是系统用户。系统事件由系统生成。EVENTTRAP命令生成一个自定义事件该事件将参数传递给处理程序,就像调用程序时一样。处理后,不会删除事件处理程序。要删除事件,请使用EVENTDELETE命令可以通过EVENTCALLEVENTWAIT命令处理事件

EVENTTRAP团队


该命令创建一个自定义事件。命令格式类似于程序调用,仅使用事件名称代替程序名称。事件名称在应用程序中是本地的,因此它们在所有任务中都是可见的。

小组将创建一个具有指定名称的事件。将向事件处理程序传递命令参数中列出的参数。

例如:
EVENTTRAP?X [1]> 8 evuBoxData(我们[7],$ 4),evuKorXY(我们[X],我们[Y],sh);生成
2个事件evuBoxDataevuKorXY作为变量us [7],$ 4,us [X],us [Y]和字符串常量sh
如果当前没有此事件的处理程序,则不会生成该事件。

活动团队


该命令将删除程序参数中列出的事件处理程序。
例如:
EVENTDELETE?X [1]> 7 evuKorXY,evuBoxData;
活动将按照小组中的顺序删除。

赛事团队


该命令分配一个事件处理程序。处理程序是程序。该程序将从正在运行的任务中异步调用,并将参数传递给它。执行处理程序后,控制权将返回到中断站点的主任务。

例如:
EVENTCALL evuBoxData = Mod1.intEvuBoxData,evuKorXY = Mod2.intevuKorXY;

EVENTWAIT团队


团队正在等待事件发生。该命令将阻止当前任务,直到发生其参数中列出的事件为止。它的参数中列出的所有事件都应发生,以继续执行当前线程。当前的程序参数将替换为事件创建命令中传输的参数。
例如:
EVENTWAIT evuBoxData,evuKorXY;
这些命令使您可以组织程序的异步执行。

向量


向量与当前的实现紧密相关。它们存储有符号和无符号整数。这些向量的维数取决于向量分量的位深度,并且它是固定的。

64位向量


这样的向量的维数是2。组件可以是64位整数或无符号整数。这样的数字存储在任何变量中。
对向量的标志性整数分量的吸引力。
设置我们[5]。%V64(0)= ss $ 1.%v64(1);
%v64-访问向量的整数符号部分。
对向量的无符号整数分量的吸引力。
设置我们[5]。%vu64(0)= ss $ 1.%vu64(1);
%vu64-访问向量的整个无符号部分。

32位向量


这样的向量的维数是5。这些分量可以是32位整数或无符号整数。这样的数字存储在任何变量中。
对向量的标志性整数分量的吸引力。
设置我们[5]。%V32(0)= ss $ 1.%v32(4);
%v32-访问向量的整数符号部分。
对向量的无符号整数分量的吸引力。
设置我们[5]。%vu32(0)= ss $ 1.%vu32(4);
%vu32-访问向量的整个无符号部分。

16位向量


这样的向量的维数是11。这些分量可以是整数或无符号的16位数字。这样的数字存储在任何变量中。
对向量的标志性整数分量的吸引力。
设置我们[5]。%V16(0)= ss $ 1.%v16(10);
%v16-访问向量的整数符号部分。
对向量的无符号整数分量的吸引力。
设置我们[5]。%Vu16(0)= SS $ 1.%vu16(4);
%vu16-访问向量的无符号整数部分。

8位向量


这样的向量的维数是22。这些分量可以是整数或无符号的8位数字。这样的数字存储在任何变量中。
对向量的标志性整数分量的吸引力。
设为[5]。%V8(0)= ss $ 1.%v8(21);
%v8-访问向量的整数符号部分。
对向量的无符号整数分量的吸引力。
设置我们[5]。%vu8(0)= ss $ 1.%vu8(21);
%vu8-访问向量的整个无符号部分。

运作方式


MSH中的操作扮演着特殊的角色。是他们控制数据类型的转换。根据操作的不同,操作数将转换为所需的数据类型。数据结果的类型唯一地对应于操作的类型。字符串和数字运算不重叠,就像C语言中的+运算一样。 MSH中的操作类型不取决于操作数的类型,所有情况都完全相反。 MSH中没有操作优先级;这是MUMPS的历史遗产。

例如:
SET $ 1 = 2 + 3 * 4;
$ 1将为20,而不是14。
为了使结果为14,将使用括号。
SET $ 1 = 2 +(3 * 4);
作为连接字符串的操作,使用符号“ _ ”。
缺乏操作优先权的情况很少见,但很方便。当操作多于累加时,提到优先级的自然性就​​变得非常令人怀疑。一旦了解到没有优先级,就无需费劲地回忆一下它们的优先级,并且无需考虑文档中的内容。通常,这是一个习惯问题。

对象


现代编程语言中对象的存在是一种很好的形式。在一般情况下,对象由两部分组成。部分说明性描述和部分实现。在MUMPS系统中,变量不具有类型声明的声明部分。类基本上是用户数据类型。为了不违反MUMPS的原理,MSH缺少类描述的声明部分。事实证明,您可以完美地做到这一点。该类只剩下一部分实现。该类的实现可以由标准模块完美地表示。仅对于该类,必须引入与对象属性描述相关的其他约定。对象只能在树中。将对象放置在数组中将失败,因为没有地方可以存储对象的属性。尽管如果对象没有属性,则可以尝试。虽然是什么样的对象。
要描述一个公共属性,您需要一个返回该属性值的函数。它必须具有属性名称,并且在模块中具有类名称。写入属性的程序。该程序的属性名称以“。”为前缀。和财产清除计划。该程序的属性名称以“ ..”为前缀。

模块中的功能名称可以对应于要读取的公共属性。在这种情况下,此类函数的返回值将作为公共属性的值传递给调用程序。

该类的构造函数是%objNew数据方法。如果在创建对象时需要确定任何属性或获取资源,则可以使用任何类模块程序(类方法)。但是建议坚持使用任何命名类构造函数的策略。例如,构造函数的名称必须与类的名称匹配。

通过系统属性this可以访问该类的受保护属性

析构函数是使用KILLD命令删除对象。如果您需要释放任何资源或执行其他操作,则可以通过此类的任何程序(类方法)来完成此操作。与构造函数的情况一样,建议在命名析构函数时遵循某种命名策略。

例如:
//类人
//属性年龄
//读取公共属性年龄
年龄:RETURN [%this,Age];
//公共财产
Age.Age的记录:SET [%this,Age] = A $ 1;
返回
结束

程序对对象及其公共属性的吸引力如下所示。
//创建对象Person
设置我们[1,2]。%objNew = Person;
//将值50写入Age属性
SET us [1,2] .Age = 50;
//读取Age
SET属性u $ 1 = us [1,2] .Age + 5;
//删除属性Age
KILL us [1,2] .Age;

对象继承


MSH类支持多重继承。PARENT命令设置该类的所有祖先。此外,命令参数中此类祖先名称的顺序决定了继承的优先级。提及该类的时间越晚,其优先级就越低。

例如:
PARENT USER,BOX;
该类继承自USERBOX的祖先USER祖先优先级更高。优先级是什么。访问对象时,将在类本身中搜索类的公共属性或方法,如果在该类中找不到它们,则将在优先级最高的祖先中搜索它们,然后在该类的祖先中搜索它们,依此类推。

文件共享

在MSH中,文件共享是在最原始的级别进行组织的。 MSH中的文件起辅助作用。交换仅使用文本文件进行组织。文件结构是由指定的分隔符分隔的文本字段。定界符在%dlmIO系统变量中。默认情况下,该变量为“ ”。它可用于阅读和写作。写入文件时,变量将转换为字符串类型,并通过定界符写入文件。从文件读取时,变量通过分隔符进行选择,并被归一化。如果该字段是数字的记录,则将数字放置在变量中。通过数组B $与文件交换。写入时,数组为B $通过定界符写入文件。从文件读取时,这些字段将被选择到B $ array中

文件交换命令将文件路径作为参数。
例如:
B $数组将数据写入文件。通过写入打开文件。文件中的数据将被替换。
写“ txt / tt1.txt”;
数据读入B $数组该阵列已预先清除。
阅读“ txt / tt1.txt”;
txt / tt1.txt-文件的路径。

结论


本文档不能替代MSH语言描述,而只是对其进行补充。这里没有考虑MSH语言的所有功能,只有我想引起您注意的那些功能。

作者:Sharymov Mikhail Alekseevich。电子邮件:misha_shar53@mail.ru

使用此材料时,需要链接到来源和作者。

All Articles