9.1 具体语法的结构
OCL的具体语法以一种完全属性文法的形式描述。属性文法中的每个产生式可以有附加到自身的合成属性。产生式规则左手边元素的合成属性值总是从该产生式右手边的元素属性衍生而来。每个产生式还可以附加有继承的属性。产生式右手边元素的继承属性的值总是由该产生式左手边元素的属性衍生而来。
在该规定了具体语法的属性文法中,每条产生式规则用EBNF表示,并且用合成和继承的属性,以及消除歧义的规则做注解。有一些特殊的注解,如下。
合成的属性
每条产生式都有一个合成属性称作ast(抽象语法树的简称),它持有该条规则所返回的OCL抽象语法的实例。对于每条规则,ast的类型都是不同的,但它总是一个抽象语法的元素。在标题“抽象语法映射”下每个类型连同它的产生式规则都做了声明。ast属性构成了从具体语法到抽象语法的形式映射。
使用一个属性文法的动机是构造的简易性和这种映射的清晰性。注意,EBNF形式的产生式规则中的每个名字的后缀都有一个“CS”来清晰地区分具体语法元素及其对应的抽象语法。
继承的属性
每条产生式规则都有一个继承的属性称作env(环境的简称),它持有一组来自表达式的变量名称。所有的名称都是模型中元素的引用。事实上,对于由产生式规则所指示的表达式或表达式部分,env是一个命名空间环境。如图9.1所示,env属性的类型是Environment。这个类型上定义了许多操作。它们的定义以及更详细的Environment类型说明可以在子章节 9.4 中看到。我们使用OCL表达式来给出ast和env的内部行为。
图9.1 The Environment type
注意env属性的内容完全由OCL表达式的上下文来决定。当一个OCL表达式用作类X的一个不变式时,它的环境将会与它作为类Y的一个操作的后置条件表达式中的不同。在第12章(UML模型中的Ocl表达式的使用)详细定义了OCL表达式的上下文。
多产生式规则
对于一些元素,会涉及有多个产生式规则选项,此时,每条产生式规则的EBNF格式都以一个方括号中的大写字母做前缀。相同的前缀用于相应的ast和env属性的决定规则。
产生式名称的多次出现
在一些产生式中,相同的元素名会使用多次。为了区分这些名字的不同的出现,在其后面加一个方括号的数字后缀,如下示例所示。
CollectionRangeCS::= OclExpressionCS[1] '..' OclExpression[2]
消除歧义的规则
一些产生式规则在语法是是有二义性的。对此我们定义了一些消除歧义的规则。使用这些规则,每条产生式以及由此而来的完整文法都变得毫无歧义。例如,在解析a.b()时,至少会有三种解析方案:
- a是一个变量表达式 (一个let或一个迭代器变量的引用)
- a是一个AttributeCallExp (self是隐式的)
- a是一个NavigationCallExp(self是隐式的)
要使用哪条文法产生式规则的决定在考虑表达式环境的事实作出。这些消除歧义的规则基于环境来描述这些选择并无歧义地对a.b()进行解析。在这个案例中规则(以普通话描述)会是:
- 如果在当前的范围内a是一个定义的变量,那么a是一个变量表达式。
- 如果不是,检查self和范围内的所有迭代器变量。在最内层范围内要么:
- 有一个名称为a的属性,则产生一个AttributeCallExp,或者
- 有一个名称为a的另一端的关联端,则产生一个NavigationCallExp
- 如果都没有,该表达式是无效的/不正确的,无法被解析。
消除歧义的规则可能要基于OCL表达式所附加到的MUL模型(例如,判断一个属性是否存在)。因此,当OCL表达式被解析时,该UML模型必须是可用的,否则,它不能被校验为一个正确的表达式。文法以尽量符合消除歧义的方式被结构化组织。消除歧义的规则以OCL的方式表达,使用来自UML的一些元类和额外操作。