博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
·使用Xtext/Xtend 实现域专用语言DSL(1)
阅读量:593 次
发布时间:2019-03-12

本文共 3371 字,大约阅读时间需要 11 分钟。

 本博文通过一个简单的例子介绍如何使用Xtext 编写一个简单DSL 的语法。

建立一个DSL语言

假设我们要建立一个DSL 语言来描述一个会议的信息:最终的描述文本是这样的:

datatype Stringdatatype Boolentity Session {title: StringisTutorial : Bool}entity Conference {name : Stringattendees : Person*speakers : Speaker*}entity Person {name : String}entity Speaker extends Person {sessions : Session*}

下面我们来看看如何使用Xtext来设计这个DSL的语法

语法的开头两行

第一行是语法的描述

grammar org.eclipse.xtext.example.Domainmodelwith org.eclipse.xtext.common.Terminals

其中: 

org.eclipse.xtext.example.Domainmodel 是语法的名称、

 org.eclipse.xtext.common.Terminals 是语法的状态。表示该语法重用和覆盖了特定的语法。org.eclipse.xtext.common.Terminals是Xtext 的库语法。它预定义了大多数公用Terminal 规则,比如ID,STRGING 和INT 等等。

下一个语句

generate domainmodel "http://www.eclipse.org/xtext/example/Domainmodel"

指定从该语法导出的EMF Ecore 包。(Ecore package) 

常用的符号

(no operator) exactly one
? zero or one
* zero or more
+ one or more

 

 

 

 

 

 

例如:

DomainModel :Entity*;

一个Xtext 语法不仅描述语法规则,而且描述AST(_Abstract Syntax Tree  抽象语法树)的结构。通常,每个语法建立树上的一个对象。元素的类型可以在名称的后面使用returns 关键字。

DomainModel returns DomainModel: ...

 也可以写成:

DomainModel : ...

为了连接多个不同的对象在一起,可以写成:

DomainModel :(elements+=Entity)*;

 

赋值符号

feature=... 相当于 setFeature(...)
list+=... 相当于 getList().add(...)
condition?=... 相当于 setCondition(true)

 

 

 

 

例如:规则Entity 可以定义多个Feature

Entity :'entity' name=ID '{'(features+=Feature)*'}';

下面再增加Extends 的语法描述:

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

 

       比较特别的是右边的('extends' superType=[Entity])? 短句。这是一个交叉引用在别的地方说明的Entity。所以在这里并不是指向某个语法规则,而是指向一个EClass(你认为是一个实例就好了)。

数据类型的定义

在我们的例子中,不仅定义了Entity ,而且定义了两种数据类型

DomainModel :(elements+=Type)*;Type:DataType | Entity;DataType:'datatype' name=ID;

下一步我们继续要定义Feature 的语法。

Feature:name=ID ':' type=TypeRef;

定义TypeRef 

TypeRef :referenced=[Type] (multi?='*')?;

 terminal 规则

从计算机编译技术中我们知道,编译分成词法分析和语法分析两部分,词法分析主要是提取每一个单词,在编译技术中叫做tockens 。在Xtext 中,词法分析的规则称为Terminal rule。例如

terminal ID:    '^'?('a'..'z'|'A'..'Z'|'_')('a'..'z'|'A'..'Z'|'_'|'0'..'9')*; terminal INT returns ecore::EInt:    ('0'..'9')+;

完整的语法

于是,我们完成了完整的语法描述:

grammar org.eclipse.xtext.example.Domainmodelwith org.eclipse.xtext.common.Terminalsgenerate domainmodel "http://www.eclipse.org/xtext/example/Domainmodel"DomainModel :(elements+=Type)*;Type:DataType | Entity;DataType:'datatype' name=ID;Entity:'entity' name=ID ('extends' superType=[Entity])? '{'(features+=Feature)*'}';Feature:name=ID ':' type=TypeRef;TypeRef:referenced=[Type] (multi?='*')?;

另一个例子:

 语言格式

var int avar int bvar int ccalc int x = acalc int y = a + ccalc int z = a * a + b

Xtext 描述的语法

grammar expr.ExprDemo with org.eclipse.xtext.common.Terminalsgenerate exprDemo "http://www.ExprDemo.expr"import "http://www.eclipse.org/emf/2002/Ecore" as ecoreModel:  elements+=Element*;Element:  VarDecl | Formula;VarDecl returns Symbol:  {VarDecl} "var" type=Type name=ID ";";Type:  IntType | BoolType | FloatType;IntType:  {IntType} "int";BoolType:  {BoolType} "bool";FloatType:  {FloatType} "float";Formula:  "calc" type=Type name=ID "=" expr=Expr ";";Expr:  Addition;Addition returns Expression:  Multiplication ({Plus.left=current}"+" right=Multiplication)*;Multiplication returns Expression:  Atomic ( {Multi.left=current} "*" right=Atomic)*;Atomic returns Expression:  {SymbolRef} symbol=[Symbol|QID] |  {NumberLiteral} value=NUMBER;terminal NUMBER returns ecore::EBigDecimal:  ('0'..'9')* ('.' ('0'..'9')+)?;QID:   ID ("." ID)*;

小结

语言的形式化描述是比较令人晦涩的。好像也没有详细描述Xtext 规则的文章。只能从实例中慢慢摸索。

转载地址:http://cazxz.baihongyu.com/

你可能感兴趣的文章