开源EGL语言开发工具EGLDevelopmentTools,第4部分EGL高级话题_第1页
开源EGL语言开发工具EGLDevelopmentTools,第4部分EGL高级话题_第2页
开源EGL语言开发工具EGLDevelopmentTools,第4部分EGL高级话题_第3页
开源EGL语言开发工具EGLDevelopmentTools,第4部分EGL高级话题_第4页
开源EGL语言开发工具EGLDevelopmentTools,第4部分EGL高级话题_第5页
已阅读5页,还剩20页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、开源EGL语言开发工具EGLDevelopmentTools,第4部分EGL高级话题开源EGL语言开发工具EGLDevelopmentTools,第4部分:EGL高级话题1. EDT的可扩展性简介EGL作为一门编程语言,它的编译过程遵循一般语言的编译过程:源程序通过编译器生成中间模型(IRModel,IntermediateRepresentationModel),IR模型通过代码生成器被转换成目标代码。EDT中EGL源文件转换成目标语言的过程如下图所示:图1.EGL编译过程:|rw亡泅+支百营,聃。口匚十+覃"匚。Antirsm口。叫门呻查看大图。这里IR模型之前的工作通常称为前端

2、编译,模型之后的代码生成工作通常称为后端编译。本文将首先介绍通过扩展后端编译来改变EGL语言的行为或者增加新的运行平台和目标语言,然后将介绍如何扩展前端使新的语言概念能够被编译到模型中。所有的扩展都能够以EclipsePlugin的形式方便的增加到EDT中。这一切,使得创造一种新语言变得前所未有的方便。接下来需要做的仅仅是发挥想象力了。2. EGL模型的可扩展性EGL模型在设计之初就考虑了可扩展性。通过扩展EGL模型,可以引入新的元素和概念,使得EGL代码可以表达更多的信息。而这些新的概念和信息,可以被代码生成器识别并利用从而生成全新的功能。下面介绍最常用的几种语言模型的扩展。NativeTy

3、pesNativeType是纯抽象的类型定义,由代码生成器决定怎样把NativeType映射到目标平台。EGL语言中的大多数系统函数都是用NativeType来定义的。比如下面代码中用到的SysLib.writeStdout()方法只是一个抽象函数定义。在Java代码生成器中,它会被生成System.out.println(),而在COBOL代码生成器中,则会生成DISPLAY语句。清单1.EGL抽象函数SysLib.writeStdout()packagesamples.server;programExamplenamestring;functionmain()name="Joe&

4、quot;SysLib.writeStdout(name);endendSysLib的定义,目前,我们使用externaltype<Name>typeNativeType的形式来定义一个NativeType.使用同样的方法,你可以扩展EGL的系统函数库,或者定义自己的函数库。当然,在定义了新的NativeType之后,需要使用上一章中提到的方法扩展代码生成器使得这些新的元素能够被映射成目标平台可执行代码。清单2.定义新的NativeTypeexternalTypeSysLibtypeNativeTypestaticfunctionwriteStdout(textstringin);

5、endAnnotationAnnotation可以用于给已有的语言类型添加额外的注解信息,这些信息能够被代码生成器识别并生相应的目标代码。Annotation用于为任何成员(Member)添加注解,比如变量,方法等。在下面的代码中Id是一个Annotation,它表明cust_no字段是一个用于标识的字段。清单3.Annotation的使用recordMyRecordtypeEntityTableName="Customer"cust_nointId;namestring;end相应的,在代码生成器中,就可以对于有Id标识的字段进行特殊的处理,比如,当我们把MyRecord

6、写入关系数据库的时候,cust_no字段会被当作主键进行处理。下面的代码是对IdAnnotation的定义。我们使用record<Name>typeAnnotation的形式来定义Annotation。targets=FieldMbr表示IdAnnotation可以被用在任何一个FieldMember上。清单4.IdAnnotation的定义packageeglx.persistence;recordIdtypeAnnotationtargets=FieldMbrendIdAnnotation非常简单,没有附带任何额外的信息。下面我们来设计一个略微复杂点的Annotation用于在

7、生成的代码中添加一些注释。如下代码所示,CommentAnnotation同样作用于FieldMember,并且它可以指定一个字符串值text。清单5.可指定字符串text的CommentAnnotation定义recordCommenttypeAnnotationtargets=FieldMbrtextString;end在定义了CommentAnnotation之后,我们就可以在EGL代码中使用它。清单6.使用CommentAnnotationrecordMyRecordtypeEntityTableName="Customer"cust_nointId,Comment

8、text="between10000and19999"namestringComment="hello"end为了让Comment这个新的语言元素能够真正起作用,最后要做的是使用扩展代码生成器。当发现一个CommentAnnotation时,读取text值并在目标代码中生成相应的注释。StereotypeStereotype的概念和Annotation相同,不同的是Stereotype作用于EGL类型,包括DataItem,Record,Program,Library,Service,Interface,Handler,ExternalType。Ster

9、eotype的定义和Annotation基本相同,需要注意的是targets必须是EGL类型,并且需要增加Stereotype注解。下面的代码实例是EGL中对于RUIHandlerstereotype的定义。清单7.RUIHandlerStereotype的定义RecordRUIHandlertypeAnnotationtargets=ElementKind.handlerPart,StereotypedefaultSuperType=View,onConstructionFunctionFunctionMemberRef;includeFileString;cssFileString;tit

10、leString;themeString;endStereotype的使用也和Annotation不用,如下代码所示,在EGL类型之后可以使用type关键字来指定stereotype。清单8.RUIHandlerStereotype的使用handlerHelloWorldtypeRUIhandler抽象IO语句EGL通过抽象的数据操作语句(add,get,replace,delete,open,close)来简化数据读写工作。EDT现有版本已经对关系型数据库SQL实现了这些操作语句。语言的可扩展性决定了这些数据操作语句可以被扩展到任何一个数据存储平台,比如针对文件系统的扩展,针对XML文件的扩

11、展,针对云数据存储的扩展等。下面将以云存储为例简单介绍扩展IO语句的方法。EGL前端编译器通过datasource来决定将抽象IO操作语句编译成哪种特定实现的中间模型(IR)。为了扩展到云存储,首先必须定义一个代表云存储的新datasource。如下代码所示。这里我们又看到了熟悉的NativeType。清单9.云存储CloudDataSource定义externalTypeCloudDataSourceextendsDataSourcetypeNativeTypeend接下来需要定义代表Cloud存储访问的IO语句,这里仅以add作为例子。清单10.云存储CloudDataSourceAdd语

12、句定义externalTypeCloudAddStatementextendsCloudActionStatement,AddStatementtypeMofClassend然后我们需要告诉编译器:当add语句的目标datasource是CloudDataSource时,把该条add语句编译成CloudAddStatement。这条规则需要写成Java代码并包含在Plugin中。最后需要做的是扩展代码生成器,为CloudAddStatement增加新的template以生成相应的目标代码。在完成了所有上述扩展后,用如下EGL代码即可把record添加到云存储中。最终使用者(写这段EGL程序的人

13、),不需要了解存储服务的技术细节也可以方便的使用云存储或者SQL存储,甚至可以将同一个程序在不同存储之间随意的切换。清单11.云存储CloudDataSourceAdd语句使用programPgmdsCloudDataSource?Resource;functionmain()ds=newCloudDataSource();customerCustomer;customer.id="10001"="Joe"addusertods;endend回页首3.EGL代码生成器的可扩展性从图1中可以看出,EGL代码生成器的作用是把EGL模

14、型翻译成目标语言代码,它的输入是EGL模型,输出是目标语言代码。以下是代码生成器中的一些关键概念。Template对象Template对象是EGL代码生成器中的主要部分,EGL模型中的一个元素类型般会对应一个Template类型。一个Template对象的主要功能有两个:1 .把EGL模型中的一个元素转换成目标代码2 .调用EGL模型中一个元素的子元素对应的Template以下图展示了Template的作用:图2.代码生成过程查看大图。一个简单的IR模型,包含一个Program和定义在此Program中的一个Function。从Program中的属性可知,止匕Program的包名是pkgl,程

15、序的名字是HelloWorld;从Function的属性可知,止匕Function的名字是main,没有参数和返回值。当此模型作为输入进入Java代码生成器,ProgramTemplate会对Program进行处理,读取Program对象的属性,生成右边框中红色的代码;然后会调用FunctionTemplate,并把Function对象作为参数,FunctionTemplate读取Function对象的属性,生成右边框中蓝色的代码。对于复杂的IR模型,Template采用以上描述的流程,生成复杂的代码。生成器配置文件IR模型中的对象如何匹配其对应的Template对象呢,在EDT中,是通过一个

16、配置文件实现的。除了Templates配置文件,EDT中还有NativeTypes配置文件和PrimitiveType配置文件。代码生成器的配置文件是Properties文件,由key-value对组成。1.Templates配置文件此文件描述了EGL模型中的一个元素类型和一个Template的对应,在目标代码生成过程中,生成器通过此文件把EGL模型的中的元素类型和Template对象联系起来。例如对于以下例子:清单12.Templates配置示例org.eclipse.edt.mof.egl.Assignment=org.eclipse.edt.demo.csharp.gen.templat

17、es.AssignmentTemplate2.通过以上定义,生成器在生成Assignment对象时,就会调用AssignmentTemplate中的方法。3.NativeTypes配置文件此文件描述了EGL语言中的类型和目标语言中对象类型的对应关系。例如以下例子:清单13.NativeTypes配置示例eglx.ui.widgets.Button=System.Windows.Forms.Button4.以上定义了EGL中的类型eglx.ui.widgets.Button和C#中的类型System.Windows.Forms.Button的对应。5. PrimitiveType配置文件此文件描

18、述了EGL语言中的类型和目标语言中基本数据类型的对应关系。例如以下例子:清单14.PrimitiveType配置示例eglx.lang.EBoolean=boolean6.以上定义了EGL中的类型EBoolean对应于Java中的boolean类型,当生成Java代码时,会使用boolean代替eglx.lang.EBoolean类型。Context对象Context对象是代码生成器中的上下文对象,任何一个Template对象中的可被调用方法都包含Context参数。Context对象主要提供了两种功能:1. 存取生成过程中的信息。在代码生成器运行过程中,会需要保存某些临时信息,以便后面执行的

19、Template使用,这时就需要把这些信息保存到Context中。2. 调用其它Template中的方法。在Context对象中有一个方法为Invoke,此方法的定义为:清单15.invoke方法的定义publicObjectinvoke(StringmethodName,EObjectobject,Object.args)3.参数methodName是要调用的Template中的方法名字;参数object是IR模型中的对象;参数args是调用Template中的methodName所指定的方法时需要传入的参数。下面是一个调用例子:清单16.invoke调用示例ctx.invoke(genAs

20、signment,expr.getType(),ctx,out,expr,arg1,arg2);4.如果expr.getType()的返回类型是DynamicAccess(这是IR模型中的一个类型),则Context.invoke方法会查找类型与DynamicAccess对应的Template,并且查找此Template中名字为genAssignment的方法。如果找到,则调用此方法;如果没有找到,则查找DynamicAccess的父类对应的Template,并在父类对应的Template中查找genAssignment方法;如果没有找到,则继续查找父类,直到找到此方法;如果遍历完所有父类,还

21、是没有找此方法,则抛出异常。对于上面的genAssignment的调用,在DynamicAccess对应的Template类DynamicAccessTemplate中定义了以下方法:清单17.DynamicAccessTemplate类中genAssignment定义eglx.lang.EBoolean=boolean从以上方法定义可以看出,Context.invoke中的参数,除了methodName外,其它的都会作为Template方法中的参数。回页首4.EDTIDE的可扩展性EDTIDE在多个方面提供了可扩展性:工程向导,Record向导,EGL程序部署等。在本篇文章中主要介绍的是任何

22、加入一个新的代码生成器。下图是EDT中代码生成器,用户可以在此处配置代码生成器的属性,例如配置保存目标代码的路径。一个EGL文件可以配置多个代码生成器,所以一个EGL文件可以对应多个目标语百0图3. EDT中的代码生成器查看大图的子类。新添加的代码生成通过此扩展点来为新代码生在EDT中,通过三个扩展点来添加新的代码生成器:1. org.eclipse.edt.ide.core.generators:通过此扩展点来定义新的代码生成器,包含代码生成器的名称,版本,目标语言等信息;另外一个重要信息是新的生成器Class,此Class是org.eclipse.edt.ide.core.Abstract

23、Generator器将显示在图3中的红色方框中。2. org.eclipse.edt.ide.ui.edtGeneratorTabs:成器提供配置页面,用户可3 中的蓝色方框中。3. org.eclipse.edt.ide.core.GenerationContributors:通过此扩展点为代码生成器注册配置文件。过使用以上三个扩展点,可以很容易的添加一个新的代码生成器到EDTIDE中。回页首5.第一个例子:扩展Java代码生成器目前EDT中有Java代码生成器和Javascript代码生成器,这两个代码生成器已经比较完善,普通用户直接使用即可。但需求是千变万化的,如果用户希望生产的代码在某

24、一个地方稍有不同,则可以通过扩展目前已有的代码生成器的功能来实现。在上面已经谈到,目标代码都是通过Template来生成的,而且生成的代码中的每一行都是和IR模型中的一种类型相关。所以可以通过给某一个IR类型定义新的Template来扩展生成的目标代码。下面是一个具体的例子。此例子的需求是输出EGL程序中每一个方法的调用信息,例如对于以下EGL程序:清单18.输出EGL程序调用场景programHelloWorldfunctionmain()test1();endfunctiontest1()endend把以上程序生成Java代码,运行的时候,要求输出以下信息:清单19.输出EGL程序调用信息

25、示例JavaLog:>>>>>EnterFunction:mainJavaLog:>>>>>EnterFunction:test1JavaLog:<<<<<ExitFunction:test1JavaLog:<<<<<ExitFunction:main从以上需求可以看出,这些输出信息是和EGLIR模型中的Function类型相关的,需要扩展Function类型对应的Template。为了实现以上信息的输出,新定义的FunctionTemplate如下:清单20.自定义Func

26、tionTemplate代码publicclassFunctionTemplateextendsorg.eclipse.edt.gen.java.templates.FunctionTemplateOverridepublicvoidgenFunctionBody(Functionfunction,Contextctx,TabbedWriterout)ctx.invoke(Constants.genFunctionEntry,function,ctx,out);super.genFunctionBody(function,ctx,out);ctx.invoke(Constants.genFun

27、ctionExit,function,ctx,out);publicvoidgenFunctionEntry(Functionfunction,Contextctx,TabbedWriterout)out.print("System.out.println("JavaLog:>>>>>EnterFunction:");ctx.invoke(genName,function,ctx,out);out.println("");");publicvoidgenFunctionExit(Functionfunct

28、ion,Contextctx,TabbedWriterout)out.print("System.out.println("JavaLog:<<<<<ExitFunction:");ctx.invoke(genName,function,ctx,out);out.println("");");新的FunctionTemplate继承于Java代码生成器中的FunctionTemplate,并且重写了genFunctionBody方法。genFunctionBody方法提供了生成此Function中所有目标

29、代码的功能。在genFunctionBody中,通过genFunctionEntry和genFunctionExit的调用,把要生成的输出信息代码加入到了方法主体代码的前面和后面,从而实现调用信息的输出。获得源程序和安装:1. 下载此例子的源代码包2. 把源代码包中的工程导入到EDT中3. 在此EDT中启动一个新的EclipseApplication4. 创建一个EGL项目,设置此EGL项目使用JavaLogGenerator5. 创建一个EGLProgram,把上面的EGL代码拷贝到此程序6. 保存此程序,则此程序对应的Java文件就会生成7. 运行生成的Java,会看到输出信息回页首6.第

30、二个例子:C#代码生成器此例子主要展示了EGL代码生成器和EDTIDE的可扩展性。EDT目前支持的目标语言有Java和JavaScript。在本例中,通过添加新的EGL代码生成器,把EGL代码转换成C#目标代码;通过扩展EDTIDE,把本例中的C#代码生成器加入到IDE中。任何一个代码生成器都是一个复杂的工程,需要涉及到EGL语言模型的各个方面,而且实用的代码生成器生成的目标代码都是基于一个目标代码Runtime,例如Java代码生成器对应的JavaRuntime,此Runtime封装可重用代码,来尽量减少代码生成器需要生成的目标代码。本例子主要展示如何扩展代码生成器,所以省略了Runtime

31、部分。下面是一个简单的EGL程序:清单21.调用场景示例packagecsharp;programHelloWorldfunctionmain()sysLib.writeStdout("HelloWorld!");endend此EGL程序经过EGL编译器编译之后生成IR模型,而IR模型是C#代码生成器的输入,输出是C#代码。IR模型是EDT中关键的部分,理解IR模型的结构有助于编写优秀的代码生成器。对于以上EGL例子,其IR模型的结构如下图所示,其中省略了一些不必要的属性信息。图4.IR结构图查看大图。1111 u n ± -对于上图中的每一个对象,在代码生成器中

32、都会有一个Template和其对应例如对于上图的Function对象,其对应的FunctionTemplate有如下实现:清单22.FunctionTemplate实现publicclassFunctionTemplateextendsCSharpTemplatepublicvoidgenDeclaration(Functionfunction,Contextctx,TabbedWriterout)ctx.invoke(genFunctionHeader,function,ctx,out);out.println("");ctx.invoke(genFunctionBody

33、,function,ctx,out);out.println("");publicvoidgenFunctionHeader(Functionfunction,Contextctx,TabbedWriterout)/processthefunctionout.print("publicvoideze_");ctx.invoke(genName,function,ctx,out);out.print("()");publicvoidgenFunctionBody(Functionfunction,Contextctx,TabbedWri

34、terout)ctx.invoke(genStatementBody,function.getStatementBlock(),ctx,out);在第3节中介绍过,每一个Template都肩负两项任务:一是处理其对应模型对象,生成模型对象对应的目标代码;二是调用此模型对象的子对象的Template对象。上面的FunctionTemplate中的genDeclaration和genFunctionHeader方法用来处理第一项任务;genFunctionBody用来处理第二项任务。通过ctx.invoke(genStatementBody,function.getStatementBlock()

35、,ctx,out)的调用,把控制权交给了StatementBlock对应的Template。模型类型和Template的对应,需要在配置文件中描述,在本例子中,是通过perties描述。以下是perties中的部分内容:清单23.perties定义org.eclipse.edt.mof.egl.Program=org.eclipse.edt.demo.csharp.gen.templates.ProgramTemplateorg.eclipse.edt.mof.egl.Part=org.eclipse.edt.dem

36、o.csharp.gen.templates.PartTemplateorg.eclipse.edt.mof.egl.EGLClass=org.eclipse.edt.demo.csharp.gen.templates.EGLClassTemplateorg.eclipse.edt.mof.egl.FunctionInvocationorg.eclipse.edt.demo.csharp.gen.templates.FunctionInvocationTemplateorg.eclipse.edt.mof.egl.Function=org.eclipse.edt.demo.csharp.gen

37、.templates.FunctionTemplateorg.eclipse.edt.mof.egl.NamedElement=.这样C#代码生成器在被调用时,将会加载perties其中的Template来生成目标代码。以下是对于上面的简单例子所生成的C#代码:清单24.生成的C#代码usingSystem;namespacecsharpclassHelloWorldpublicstaticvoidMain()newHelloWorld();publicHelloWorld()eze_initialize();eze_main();publicvoideze_init

38、ialize()publicvoideze_main()Console.Write("HelloWorld!");获得源程序和安装:1. 下载此例子的源代码包2. 把源代码包中的工程导入到EDT中3. 在此EDT中启动一个新的EclipseApplication4. 创建一个EGL项目,设置此EGL项目使用C#代码生成器5. 创建一个EGLProgram,把上面的EGL代码拷贝到此程序6. 保存此程序,则此程序对应的C#文件就会生成回页首7. 第三个例子:扩展EGL模型EGL目前可以用来开发Java批处理程序和Web2.0应用,可是应用程序的类型是千变万化的,例如用户要开发

39、一个GUI应用,目前的EGL并不提供这样的功能。但是EGL模型是可以扩展的,通过扩展EGL模型,可以支持新的应用程序类型。本例是基于第一个例子,通过加入新的模型,为EGL提供了开发GUI应用程序的能力。:WindowHandler和Button清单25.WindowHandler定义packageeglx.ui.stereotypes;recordWindowHandlertypeAnnotationtargets=ElementKind.HandlerPart,StereotypecontentViewFieldRef;endcontentView是WindowHandler的一个属性,指向

40、此WindowHandler中的主控件。清单26.Button定义packageeglx.ui.widgets;externalTypeButtonextendsViewtypeAbstractTypeTextString;endText属性定义了此Button上显示的内容。定义完以上模型,就可以在EGL语言中使用它们,以下是一个例子:清单27.Button使用示例importeglx.ui.stereotypes.WindowHandler;importeglx.ui.widgets.Button;handlerHelloWindowtypeWindowHandlercontentView=buttonbuttonButtonText="C

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论