xtext_使用Xtext为Eclipse和IntelliJ开发DSL

xtext

在这篇文章中,我们将看到如何开发一种简单的语言。 我们的目标是:

  • 语言的解析器
  • IntelliJ的编辑器 。 编辑器应具有语法突出显示,验证和自动完成功能

我们还将免费提供Eclipse和Web编辑器的编辑器 ,但请包含您的兴奋之处,本文中不再赘述。

去年,我专注于学习新知识(主要是Web和ops知识),但我仍然最喜欢的一件事就是开发DSL(领域特定语言)。 我使用的第一个相关技术是Xtext :Xtext是一种出色的工具,可让您定义语言的语法并生成该语言的出色编辑器。 到目前为止,仅针对Eclipse平台进行了开发:这意味着可以使用Eclipse开发新语言,然后可以在Eclipse中安装生成的编辑器。

最近,我使用的Eclipse少了很多,所以直到现在,我对Xtext的兴趣逐渐消失,直到最后,新版本的Xtext(仍处于beta版)瞄准了IntelliJ。 因此,当我们使用Eclipse开发语言时,我们将生成插件以在IntelliJ中使用我们的语言。

我们将要看到的技术可以用于开发任何种类的语言,但是我们将把它们应用于特定的情况:AST转换。 这篇文章是为Xtext新手准备的,我现在不做任何详细介绍,我只是分享对IntelliJ目标的第一印象。 考虑到该功能目前是测试版,因此我们可以预期会有一些粗糙的边缘。

我们正在尝试解决的问题:调整ANTLR解析器以获取出色的AST

我喜欢玩解析器,而ANTLR是出色的解析器生成器。 对于像Java这样的功能强大的语言,有很多漂亮的语法。 现在,问题是Java之类的语言的语法非常复杂,并且生成的解析器会生成不易于使用的AST。 主要问题是由于如何处理优先级规则。 考虑一下Terence Parr和Sam Harwell编写的Java 8语法 。 让我们看看如何定义一些表达式:

conditionalExpression:   conditionalOrExpression|   conditionalOrExpression '?' expression ':' conditionalExpression;conditionalOrExpression:   conditionalAndExpression|   conditionalOrExpression '||' conditionalAndExpression;conditionalAndExpression:   inclusiveOrExpression|   conditionalAndExpression '&&' inclusiveOrExpression;inclusiveOrExpression:   exclusiveOrExpression|   inclusiveOrExpression '|' exclusiveOrExpression;exclusiveOrExpression:   andExpression|   exclusiveOrExpression '^' andExpression;andExpression:   equalityExpression|   andExpression '&' equalityExpression;equalityExpression:   relationalExpression|   equalityExpression '==' relationalExpression|   equalityExpression '!=' relationalExpression;relationalExpression:   shiftExpression|   relationalExpression '<' shiftExpression|   relationalExpression '>' shiftExpression|   relationalExpression '<=' shiftExpression|   relationalExpression '>=' shiftExpression|   relationalExpression 'instanceof' referenceType;shiftExpression:   additiveExpression|   shiftExpression '<' '<' additiveExpression|   shiftExpression '>' '>' additiveExpression|   shiftExpression '>' '>' '>' additiveExpression;additiveExpression:   multiplicativeExpression|   additiveExpression '+' multiplicativeExpression|   additiveExpression '-' multiplicativeExpression;multiplicativeExpression:   unaryExpression|   multiplicativeExpression '*' unaryExpression|   multiplicativeExpression '/' unaryExpression|   multiplicativeExpression '%' unaryExpression;unaryExpression:   preIncrementExpression|   preDecrementExpression|   '+' unaryExpression|   '-' unaryExpression|   unaryExpressionNotPlusMinus;

这只是用于定义表达式的大部分代码的一部分。 现在考虑您有一个简单的preIncrementExpression (类似: ++ a )。 在AST中,我们将拥有类型为preIncrementExpression的节点,该节点将包含在unaryExpression中。

一元表达式将包含在一个乘法 表达式中,表达式将包含在一个additiveExpression中 ,依此类推。 该组织对于处理不同类型的运算之间的运算符优先级很有必要,因此将1 + 2 * 3解析为1和 2 * 3的总和,而不是1 + 23的乘法。 问题是,从逻辑的角度来看,乘法和加法是同一级别的表达式:拥有Matryoshka AST节点没有意义。 考虑以下代码:

class A { int a = 1 + 2 * 3; }

虽然我们想要这样的东西:

[CompilationUnitContext][TypeDeclarationContext][ClassDeclarationContext][NormalClassDeclarationContext]classA[ClassBodyContext]{[ClassBodyDeclarationContext][ClassMemberDeclarationContext][FieldDeclarationContext][UnannTypeContext][UnannPrimitiveTypeContext][NumericTypeContext][IntegralTypeContext]int[VariableDeclaratorListContext][VariableDeclaratorContext][VariableDeclaratorIdContext]a=[VariableInitializerContext][ExpressionContext][AssignmentExpressionContext][ConditionalExpressionContext][ConditionalOrExpressionContext][ConditionalAndExpressionContext][InclusiveOrExpressionContext][ExclusiveOrExpressionContext][AndExpressionContext][EqualityExpressionContext][RelationalExpressionContext][ShiftExpressionContext][AdditiveExpressionContext][AdditiveExpressionContext][MultiplicativeExpressionContext][UnaryExpressionContext][UnaryExpressionNotPlusMinusContext][PostfixExpressionContext][PrimaryContext][PrimaryNoNewArray_lfno_primaryContext][LiteralContext]1+[MultiplicativeExpressionContext][MultiplicativeExpressionContext][UnaryExpressionContext][UnaryExpressionNotPlusMinusContext][PostfixExpressionContext][PrimaryContext][PrimaryNoNewArray_lfno_primaryContext][LiteralContext]2*[UnaryExpressionContext][UnaryExpressionNotPlusMinusContext][PostfixExpressionContext][PrimaryContext][PrimaryNoNewArray_lfno_primaryContext][LiteralContext]3;}<EOF>

虽然我们想要这样的东西:

[CompilationUnit][FieldDeclaration][PrimitiveTypeRef][Sum][Multiplication][IntegerLiteral][IntegerLiteral][IntegerLiteral]

理想情况下,我们希望指定产生Matryoshka风格的AST的语法,但在对代码进行分析时使用更平坦的AST,因此我们将根据Antlr和“逻辑” AST产生的AST构建适配器。 我们打算如何做? 我们将首先开发一种定义节点形状的语言,以使它们出现在逻辑AST中,并且还将定义如何将Antlr节点( Matryoshka风格的节点)映射到这些逻辑节点中。 这只是我们要解决的问题:Xtext可用于开发任何一种语言,只是作为解析器狂人,我喜欢使用DSL解决与解析器相关的问题。 这是很元的

入门:安装Eclipse Luna DSL并创建项目

我们将下载一个包含Xtext 2.9 Beta的 Eclipse版本。 在全新的Eclipse中,您可以创建一种新型的项目: Xtext Projects

屏幕截图-自2015-06-01-094403-1024x584

我们只需要定义项目的名称,然后选择与我们的新语言相关联的扩展名即可

屏幕截图-自-2015-06-01-0945141

然后,我们选择我们感兴趣的平台(是的,还有Web平台……我们将在将来进行研究)

屏幕截图-自-2015-06-01-094727

创建的项目包含一个示例语法。 我们可以按原样使用它,我们只需要生成几个运行MWE2文件的文件即可。

MWE

运行此命令后,我们可以仅在IntelliJ或Eclipse中使用我们的新插件。 但是,我们将改为首先更改语法,以在光荣的DSL中转换给定的示例。

我们的DSL示例

我们的语言在IntelliJ IDEA中看起来像这样(很酷,是吗?)。

屏幕截图-自-2015-06-02-194214

当然这只是一个开始,但是我们开始为Java解析器定义一些基本节点类型:

  • 表示可能的修饰语的枚举(警告:这不是完整列表)
  • CompilationUnit,其中包含可选的PackageDeclaration和可能的许多TypeDeclaration
  • TypeDeclaration是一个抽象节点,有三种扩展它的具体类型: EnumDeclaration,ClassDeclarationInterfaceDeclaration (我们缺少注释声明)

我们将需要添加数十个表达式和语句,但是您应该对我们尝试构建的语言有所了解。 还要注意,我们已经引用了Antlr语法(在第一行中),但尚未指定定义的节点类型如何映射到Antlr节点类型。 现在的问题是:我们如何构建它?

定义语法

我们可以使用简单的EBNF表示法(带有一些扩展名)来定义语言的语法。 在您的项目中查找带有xtext扩展名的文件, 并按如下所示进行更改:

grammar me.tomassetti.AstTransformationsDsl with org.eclipse.xtext.common.Terminalsgenerate astTransformationsDsl "http://www.tomassetti.me/AstTransformationsDsl"Model:antlr=AntlrGrammarRef   declarations+=Declaration*;AntlrGrammarRef:'adapt' grammarFile=STRING;Declaration: NodeType | NamedEnumDeclaration;NamedEnumDeclaration: 'enum' name=ID '{' values+=EnumNodeTypeFieldValue+ '}';
UnnamedEnumDeclaration: 'enum' '{' values+=EnumNodeTypeFieldValue+ '}';NodeType:'abstract'? 'type' name=ID ('extends' superType=[NodeType])? ('from' antlrNode=ID)? '{' fields+=NodeTypeField*'}';    NodeTypeField:name=ID (many='*='|optional='?='|single='=') value=NodeTypeFieldValue;  NodeTypeFieldValue:UnnamedEnumDeclaration | RelationNodeTypeField | AttributeNodeTypeField;EnumNodeTypeFieldValue: name=ID;RelationNodeTypeField: type=[NodeType];AttributeNodeTypeField:{AttributeNodeTypeField}('string'|'int'|'boolean');

我们定义的第一个规则对应于AST的根(在本例中为Model )。 我们的模型始于对Antlr文件的引用和声明列表 想法是指定我们的“逻辑”节点类型的声明以及应如何将“ antlr”节点类型映射到它们。 因此,我们将定义转换,该转换将引用在AntlrGrammarRef规则中指定的antlr语法中定义的元素的引用。

我们可以定义EnumNodeType。 NodeType有一个名称,可以是抽象的,并且可以扩展另一个NodeType。 请注意, 超类型是对NodeType的引用。 这意味着生成的编辑器将自动能够为我们提供自动完成功能(列出文件中定义的所有NodeType )并进行验证,从而验证我们是否引用了现有的NodeType

在我们的NodeTypes中,我们可以定义任意多个字段( NodeTypeField )。 每个字段均以名称开头,后跟一个运算符:

  • * =表示我们可以在此字段中使用0..n值
  • ?=表示该字段是可选的(0..1)值
  • =表示始终存在一个值

NodeTypeField还具有一个值类型,该值类型可以是内联定义的枚举( UnnamedEnumDeclaration ),关系(表示此节点包含其他节点)或属性(表示此节点具有一些基本属性,如字符串或布尔值)。

很简单,是吗?

因此,我们基本上重新运行了MWE2文件,我们准备好了。

查看实际使用的插件

要查看我们在IntelliJ IDEA中安装的插件,我们只需要从包含想法插件的目录(在我们的示例中为me.tomassetti.asttransf.idea )运行gradle runIdea 。 请注意,您需要使用gradle的最新版本,并且需要定义JAVA_HOME 。 此命令将下载IntelliJ IDEA,安装我们开发的插件并启动它。 在打开的IDE中,您可以创建一个新项目并定义一个新文件。 只需使用我们在创建项目时指定的扩展名(本例中为.anttr  IDEA应该使用我们新定义的编辑器。

目前验证工作正常,但编辑器的React似乎很慢。 自动完成功能反而对我不利。 考虑到这只是一个beta,因此我希望这些问题在Xtext 2.9发布之前会消失。

下一步

我们才刚刚起步,但是令人惊奇的是,如何在几分钟内就可以使用其IDEA编辑器创建DSL。

我计划朝几个不同的方向工作:

  • 我们需要了解如何打包和分发插件:我们可以使用gradle runIdea尝试它,但我们只想生成一个二进制文件供人们安装,而无需处理编辑器的源代码
  • 使用来自Maven的任意依赖项:这将变得相当复杂,因为Maven和Eclipse插件(OSGi捆绑包)以自己的方式定义了它们的依赖关系,因此通常必须将jar打包成捆绑包才能在Eclipse插件中使用。 但是,还有其他选择,例如Tycho和p2-maven-plugin 。 剧透 :我不希望这太快又容易……
  • 我们还不能引用Antlr语法中定义的元素。 现在,这意味着我们应该能够解析Antlr语法并以编程方式创建EMF模型,以便我们可以在DSL中引用它。 它需要了解EMF(并且需要一些时间……)。 我将在将来使用它,这可能需要使用loooong教程。

结论

虽然我不再喜欢Eclipse(现在我已经习惯了IDEA,但对我来说似乎好得多了:更快,更轻便),但是Eclipse Modeling Framework一直是一个非常有趣的软件,并且能够与IDEA一起使用非常棒。

一段时间以来,我没有使用EMF和Xtext,不得不说我看到了一些改进。 我感到Eclipse并不是非常命令行友好的,并且通常很难将其与CI系统集成。 我看到正在努力解决这些问题(请参阅Tycho或使用我们开发的编辑器来启动IDEA的gradle作业),这对我来说似乎非常积极。

我的理念是混合技术,以务实的方式结合不同世界的最佳方面,因此,我希望找到时间玩这些东西。

翻译自: https://www.javacodegeeks.com/2015/08/develop-dsls-for-eclipse-and-intellij-using-xtext.html

xtext

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337138.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

sed 插入多行_Linux三剑客之sed

sed命令用法小记版本&#xff1a;CentOS7▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼好久没更新文章了&#xff0c;项目的事情太多&#xff0c;总得给自己的懒惰找个借口&#xff0c;哈哈~话不多说进入正题创建测试数据[aliscaspark02 a]$ cat data#test the sedThis is the header l…

分享一些超级炫酷的C语言小技巧

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删C语言常常让人觉得它所能表达的东西非常有限。它不具有类似第一级函数和模式匹配这样的高级功能。但是C非常简单&#xff0c;并且仍然有一些非常…

C++编程新手容易犯的 10 种编程错误

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删公司每年都会有一定的人员流动&#xff0c;相应地也会招一些应届生补充进来&#xff0c;指导应届生已经成为老员工的必修课了。平日里会我们会经…

Linux上C语言程序编译过程详解

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删本文将介绍如何将高层的C/C语言编写的程序转换成为处理器能够执行的二进制代码的过程&#xff0c;包括四个步骤&#xff1a;预处理&#xff08;P…

C语言,动图展示十大经典排序算法

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删以前也零零碎碎发过一些排序算法&#xff0c;但排版都不太好&#xff0c;又重新整理一次&#xff0c;排序算法是数据结构的重要部分&#xff0c;…

java ee各类组件_在Java EE组件中使用骆驼路线

java ee各类组件从现在开始我一直在与Camel合作&#xff0c;我真的很喜欢它的简单性。 在Java EE之上使用它一直是一个挑战&#xff0c;我最近发表了一篇关于如何做到这一点的演讲&#xff0c;而在Java EE中引导Camel的不同方法实际上建议使用WildFly-Camel Subsystem 。 在正在…

5gnr帧结构特点有哪些_真空离子束刻蚀设备的结构特点有哪些

离子束刻蚀设备有立式、卧式两种结构。通常情况下&#xff0c;该设备以卧式的结构居多&#xff0c;因为采用卧式结构的话&#xff0c;离子源发出的离子束为水平喷射方向&#xff0c;大部分的刻蚀溅射物将落在真空室的底部&#xff0c;可在一定程度上将溅射材料的重新沉积减少。…

老了就不能编程?大龄程序员在线“辟谣”:15 年后,我变得更好了

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删几年前&#xff0c;Quora 上的一个提问在程序员圈内掀起热议&#xff1a;“随着年龄的增长&#xff0c;人们会对编程失去兴趣吗&#xff1f;预计…

wildfly管理控制台_WildFly管理控制台已更新–请求反馈

wildfly管理控制台红帽JBoss企业应用程序平台&#xff08;EAP&#xff09;和WildFly具有共生关系 。 简而言之&#xff0c;红帽JBoss企业应用程序平台&#xff08;JBoss EAP&#xff09;保留了WildFly社区项目&#xff08;以前称为JBoss Application Server&#xff09;的所有创…

性能测试中脚本怎么写_脚本在流程中的性能影响

性能测试中脚本怎么写我们经常看到人们出于各种目的而使用脚本&#xff08;例如&#xff0c;在服务任务&#xff0c;执行侦听器等中&#xff09;。 使用脚本和Java逻辑通常很有意义&#xff1a; 它不需要打包到jar中并放在classpath上 它使流程定义更易于理解&#xff1a;无需…

超炫酷的C语言技巧

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删C语言常常让人觉得它所能表达的东西非常有限。它不具有类似第一级函数和模式匹配这样的高级功能。但是C非常简单&#xff0c;并且仍然有一些非常…

java8默认垃圾收集器_Java 8中最快的垃圾收集器是什么?

java8默认垃圾收集器OpenJDK 8具有几种垃圾收集器算法&#xff0c;例如Parallel GC &#xff0c; CMS和G1 。 哪一个最快&#xff1f; 如果默认GC从Java 8中的并行GC更改为Java 9中的G1&#xff08;当前建议&#xff09;&#xff0c;将会发生什么&#xff1f; 让我们对其进行基…

u盘启动 联想一体机_联想Y430pAT-ISE(H)U盘安装Win7系统教程

最近听到有人在问联想Y430pAT-ISE(H)笔记本安装WIN 7系统的方法&#xff0c;联想Y430pAT-ISE(H)笔记本从发行到现在也快5年了&#xff0c;不过有人在问该电脑安装系统就说明有人还在使用&#xff0c;关于联想Y430pAT-ISE(H)安装Win 7系统的方法有很多&#xff0c;不过大多过时了…

收藏|C语言常用的一些转换工具函数!

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删1、字符串转十六进制代码实现&#xff1a;void StrToHex(char *pbDest, char *pbSrc, int nLen) {char h1,h2;char s1,s2;int i;for (i0; i<n…

apache camel_学习Apache Camel –实时索引推文

apache camel在大多数软件开发项目中&#xff0c;有一点需要使应用程序开始与其他应用程序或第三方组件通信。 无论是发送电子邮件通知&#xff0c;调用外部api&#xff0c;写入文件还是将数据从一个地方迁移到另一个地方&#xff0c;您都可以推出自己的解决方案或利用现有框架…

让你不再害怕指针——C指针详解(经典,非常详细)

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删前言:复杂类型说明要了解指针,多多少少会出现一些比较复杂的类型,所以我先介绍一下如何完全理解一个复杂类型,要理解复杂类型其实很简单,一个类型…

C语言实现可写入文件的账号密码登录系统

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删账号登录系统在很多系统设计时都时必不可少的&#xff0c;今天这个登录系统功能较全&#xff0c;可以注册&#xff0c;登录&#xff0c;找回密码…

一文搞懂 | Linux 内核的 4 大 IO 调度算法

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删Linux 内核包含4个IO调度器&#xff1a;Noop IO schedulerAnticipatory IO schedulerDeadline IO scheduler CFQ IO scheduler。anticipatory, 预…

众神进入瓦尔哈拉_一时冲动:“通往瓦尔哈拉之路的冒险”

众神进入瓦尔哈拉通过所有有关Java 9和Project Jigsaw的讨论&#xff0c;我们不应忽视Java的另一重大变化。 希望在第10版或第11版中&#xff0c; Valhalla项目能够实现并介绍价值类型和专业化。 那么&#xff0c;这是什么一回事&#xff0c;项目进展如何&#xff0c;面临什么…

当电子工程师十余年,感慨万千!

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删当电子工程师也一些年头了&#xff0c;不算有出息&#xff0c;环顾四周&#xff0c;也没有看见几个有出息的。回顾工程师生涯&#xff0c;感慨万…