xtext语法示例

770 阅读2分钟

定义出的语法如下:

datatype String

entity Blog{
    title: String
    many posts: Post
}

entity HasAuthor{
    author: String
}

entity Post extends HasAuthor{
    title: String
    content: String
    many commnets: Comment
}

entity Comment extends HasAuthor{
    content: String
}

1、语法中第一个规则通常作为入口或者开始的规则

Domainmodel:
    elements += Type*
;

Domainmodel包含任意数量(*)的Type,且该Type会被加到(+=)一个名为elements的特性中去。

2、Type的规则表明Type是规则DataType或者(|)规则Entity。

Type:
    DataType | Entity
;

3、规则DataType以关键字“datatype”开始,后面跟着一个标示符,该标示符被解析为规则ID,其中规则ID的定义在语法超集org.eclipse.xtext.common.Terminals中,规则ID是一个单词,即标示符。

DataType:
    'datatype' name = ID
;

4、规则Entity也是以一个关键字开头,后面跟着一个名称(name)。

Entity:
    'entity' name = ID ('extends' superType = [Entity])? '{'
        features += Features*
    '}'
;

后面是一个带有括号和可选项(?)的extends从句。因为名为superType的特性采用交叉引用(注意其中的中括弧),不对中括弧中的规则Entity进行解析,而仅仅对标示符进行解析(ID)。在链接过程中才会对Entity进行解析。最后,大括弧中可以由任意数量的Features。

5、Feature规则的定义如下:

Feature:
    (many ?= 'many')? name = ID ':' type = [Type]
;

关键字many是用来对域建模DSL中对一个多值特性进行建模,赋值操作(?=)表明特性many的类型为boolean。

改进后语法定义

//datatypes.dmodel

datatype String
//commons.dmodel

package my.company.common{
    entity HasAuthor{
        author: String
    }
}
//blogs.dmodel

package my.company.blog{
    import my.company.common.*
    
    entity Blog{
        title: String
        many posts: Post
    }
    
    entity Post extends my.company.commom HasAuthor{
        title: String
        content: String
        many comments: Comment
    }
    
    entity Comment extend HasAuthor{
        content: String
    }
}

语法改进

1、由于Domainmodel不但包含类型而且包含包,因此,需要对入口进行修改。此外,需要定义通用的超类型Packages和Types:AbstractElement

Domainmodel:
    (elements += AbstractElement)*
;
AbstractElement:
    PackagesDeclaration | Type
;

2、PackageDeclaration包含一系列的Imports和AbstractElements,因为Imports可以作为root-Domainmodel,所以讲Import加入到AbstractElement中

PackageDeclaration:
    'package' name = QualifiedName '{'
        (elements += AbstractElement)*
    '}'
;

AbstractElement:
    PackageDeclaration | Type | Import
;

QualifiedName:
    ID ('.' ID)*

QualifiedName有一点特殊,其不包含任何赋值。因此仅作为数据类型规则,返回一个字符串。因此Package的特性name是String类型

3、使用xtext,可以很方便的定义imports。如果在解析规则中使用ImportedNameSpace,基础结构将会视其为import,甚至支持通配符。

Import:
    'import' importNamespace  = QualifiedNameWithWildcard
;

QualifiedNameWithWildcard:
    QualifiedName '.*'?
;

同QualifiedName类似,QualifiedNameWithWildcard返回一个字符串。

4、最后一步是允许用完整的命名来交叉引用,否则,只有import之后,才能进行引用。

Entity:
    'entity' name = ID ('extends' superType = [Entity | QualifiedName])?
    '{'
        (features += Feature)*
    '}'
;

Feature:
    (many ?= 'many')? name = ID ':' type = [Type | QualifiedName]
;