因此,使用新语言编写程序包括:创建语言中概念的实例、为实例的属性赋值、根据语言概念定义的关系将程序中的节点连接在一起;所有这些将会被强大的编辑器支持,你能够为你的语言定义这种编辑器
Editor Language
那么,编写和操作概念模型的界面应该是什么呢?我们的语言需要几种类型的编辑器,但是我们不想要一个通用的编辑器;经验表明通用的编辑器不能像我们希望的那样有用;我们希望快速的编写模型,因此我们需要专为我们的语言概念定做的特殊的编辑器;一定程度上,编辑器是语言的一部分,而我们的目标是容易的创建新语言,那么创建新的编辑器也应该很容易;本质上,我们需要一种创建编辑器的语言,在MPS中,它被称为Editor Language
当人们听我说我们的程序将存储为图形并且我们需要特定的编辑器,我确信很多人认为我将要谈到图形编辑器,事实不是这样子的;尽管程序是图形形式,编辑器却不一定非得将程序描绘成图形;事实上,只有少数情况下图形编辑器才是有用的(也就是说,当它合适的时候,比如对数据库表);相反,我们的Editor Language有更好的灵感来源,讽刺的是,它来自文本编辑器
如果你用文本编辑器浏览一个典型的程序,你可以想象编辑器被分成了矩形单元;一些单元包含必需的标识如关键字、花括号、圆括号等,其它的单元包含用户定义的标识,如类和方法的名称;大的单元由小的单元组成,像方法块包含语句,而语句可能包含自己的嵌套块;事实上,任何主流编程语言中任何良好构造的程序都可以分解为矩形单元的集合;那么,在Editor Language中,你不需要想象这些单元,因为编辑器就是简单的由矩形单元组成的
单元的使用有一些有趣的优点;首先,当直接工作在程序图形而不是程序文本上时,单元可以完美的模仿甚至超过标准的文本编辑器;第二,单元不局限于文本,你可以往单元里塞进颜色选择器、数学符号、图表、矢量图、或任何别的什么;最后,这种单元形式的layout是可选的,程序员可以提供不同的机制,单元形式的 layout只是一种有用的缺省设置
因此,Editor Language帮助你定义语言中每个概念对应的单元的layout;你可以定义哪些部分是不变的,像括号或其它修饰符号,哪些是可变的,需要用户去定义的;Editor Language也帮助你在你自己的编辑器中加入强大的特性,像自动完成、重构、导航、语法加亮、错误加亮、以及任何其它你想到的事情;因此你能够增加现在的编辑器如IntelliJ IDEA等拥有的功能到你自己的语言中;这是可能的,因为程序和语言被构造为图形,而我们有专门的Editor Language帮助我们创造强大的编辑器
Transformation Language
Structure Language和Editor Language已经共同提供了一些功能,你能够用它们和其他人交流思想,比如画UML图,或者编写其它类型的文档;然而,大部分时间我们是想让我们的代码做点什么,因此,我们必须找到一种方法让它能够执行;有两种主要的方式来做这件事情:解释和编译
DSLs支持的解释方式帮助定义计算机应该如何解释程序,DSLs支持的编译方式帮助定义如何为程序产生可执行代码;我将在以后的文章中讨论对解释方式的支持,现在我想说明一下MPS是如何支持编译方式的
编译意味着拿到源代码,并从中产生某种形式的可执行代码;对于结果代码有多种可能的形式;为产生可执行代码,你可以生成本地机器码,也可以生成虚拟机字节码;或者,你可以生成另外一种语言的源代码(比如Java,C++),然后用现有的编译器转换为可执行代码;类似的,你甚至可以产生某种解释型语言的源代码,用现有的解释器解释执行
为了避免处理这么广泛的目标格式,我们的方法是用MPS来做每一件事;首先,你在MPS中使用Structure Language定义一种目标语言,这种目标语言和目标格式之间应该有直接的一对一的映射;例如,如果你的目标格式是机器码,你应该用MPS定义一种对应机器码的目标语言;如果目标格式是Java源代码,你应该定义一种类Java的目标语言;目标语言不必支持目标格式所有的功能特性,只为你需要的语言特性进行简单的一对一的映射即可
那么现在,编译分为两个阶段:一个简单的从目标语言到最终结果的翻译,一个更复杂的从最初的原始语言到中间目标语言的转换;翻译阶段是微不足道的,因此我们把精力集中于更有意思的转换阶段;至少,现在的问题简化为了如何将模型从一种语言转换到另一种语言;但是,有可能源语言与目标语言是完全不同的,导致转换非常复杂,比如映射一个源节点到许多散布在目标模型中的目标节点;我们想让定义转换尽可能的简单容易,因此我们需要一种模型转换DSL来帮助我们;在MPS中,这种 DSL被称为Transformation Language
代码生成有三种主要的方法,我们将结合使用它们来定义模型转换;第一种是遍历方式,你枚举源模型中所有节点,检视每一个,并基于检视到的信息生成目标模型中的一些目标节点;第二种方式是使用模板和宏来定义如何生成目标语言;第三种方式是使用模式匹配来查找在源模型中的哪些节点上应用转换
我们通过定义DSLs把这些方式结合起来以支持任何一种方法;这些DSLs将一起工作来帮助你定义从一种语言到另一种语言的转换;例如,遍历方式激发了 Model Query Language的灵感,它使枚举节点和从概念模型中收集信息变得简单容易;你可以把它想象成某种针对概念模型的SQL;做为一种额外的奖赏,拥有一种强大的查询语言不只是对代码生成有用(例如,能够使编辑器更聪明)
Templates
模板方法工作方式类似Velocity或者XSLT;模板看起来很像目标语言,但是允许你在模板的任何部分中添加宏;宏本质上是当运行转换的时候被执行的代码段;宏允许你检视源模型(使用Model Query Language),并使用得到的信息对模板进行“填空”,得到最终的目标代码
在图5中,你可以看到为概念“Property”生成Java代码的模板的定义,模板为属性添加了field declarations, getters, setters等;这个模板是将代码从Structure Language转换为Java的生成器的一部分
既然模板看起来像目标语言,你可以想象模板是用某种基于目标语言的特殊的语言编写的;这也是它事实上的工作方式;我们实际上使用一个生成器来为你生成模板语言,而不是手工为每一种可能的目标语言创建模板语言;它基本上是复制目标语言,并添加所有模板特定的特性,诸如宏等;甚至模板编辑器也是从目标语言编辑器产生的,因此你同样不需要处理代码
当你使用一种模板语言的时候,你可以认为它是用目标语言编写的,只是某些部分的代码是参数化的,或者是由宏来计算的;这种技术极大的帮助简化了代码生成;模板还可以用在其它任务上,如重构、代码优化、还有更多...
Patterns
模型的模式匹配方法给我们一种作为Model Query Language的代替的查找模型的强大方法;你可以把模式想象成概念模型的正则表达式;与模板方法类似,我们基于源语言产生模式语言;模式语言看起来像源语言,只是添加了一些特性,来帮助你定义处理复杂源模型匹配的灵活的标准;你可以把这种方法想象成一种强大的“查找替换”的技术;再一次,模式语言不只是对代码生成有用,例如,它们在为源语言编辑器编写自动化的代码检查工具方面非常有用
记住Model Query Language, template languages, 和pattern languages都由强大的编辑器支持其自动完成、重构、引用检查、错误勘测、等等;即使复杂的查询、宏、模式,都可以很容易的编写;代码生成从来没有这么强大过
文章来源于领测软件测试网 https://www.ltesting.net/