在实现模型驱动开发中,我们可以解释模型直接运行在领域框架之上,也可以把模型通过代码生成技术转换成代码之后编译运行在框架之上。这两种方式都有利弊,可以搭配使用,在OpenExpessApp中将采用这两种方法,类库通过代码生成,UI等元模型通过框架解释执行。由于代码生成是MDD中很重要的一项技术,所以本篇我将介绍一下代码生成相关的知识。

模型驱动中的代码生成

在EMF中,Metamodel为EMF元模型,Model为EMF模型;在MS DSL Tools中,MetaModel为DSL元模型,模板为T4模板

代码生成技术

  • Antlr3
    Antlr是一个非常著名的开源语言生成工具,官方网站是这么介绍的:
    ANTLR, ANother Tool for Language Recognition, is a languagetool that provides a framework for constructing recognizers,interpreters, compilers, and translators from grammatical descriptionscontaining actions in a variety of targetlanguages. ANTLR provides excellent support for treeconstruction, tree walking, translation, error recovery, and errorreporting. There are currently about 5,000 ANTLR sourcedownloads a month.

  研究过一阵子Antlr,用它来写过一个.Net下的表达式引擎,参考使用Antlr实现表达式引擎

  使用Antlr的一般经过如下步骤:

  1. 写语法
  2. 写StringTemplate模板(可选)
  3. 在AntlrWorks调试语法
  4. 从语法生成类
  5. 使用生成的类来写应用程序

  作者写了一本介绍Antlr的专著 The Definitive Antlr Reference,我只是几年前大概看过一遍,觉得作者很牛。不过作者又出的另外一本书Language Implementation Patterns,有人说这本书更好,它将ANTLR内部的设计思想也讲得很清楚了。相比而言,之前那本书只能算是ANTLR的用户手册,而新书算是ANTLR的设计思想。

       

  • Irony - .NET Language Implementation Kit
    Irony是在Codeplex网站上的一个开源语言实现工具,官方介绍如下:
     
     Irony is a development kit for implementing languages on .NET platform. It uses the flexibility and power of c# language and .NET Framework 3.5 to implement a completely new and streamlined technology of compiler construction. Unlike most existing yacc/lex-style solutions Irony does not employ any scanner or parser code generation from grammar specifications written in a specialized meta-language. In Irony the target language grammar is coded directly in c# using operator overloading to express grammar constructs. Irony's scanner and parser modules use the grammar encoded as c# class to control the parsing process. See the expression grammar sample for an example of grammar definition in c# class, and using it in a working parser.

......

代码生成定义语言

  在特定领域建模 DSM(Domain Specific)介绍中介绍了DSM的不同工具的比较,其中代码生成定义语言也可以从表中看到,下面将会介绍一下DSL tools的T4和MetaEdit+的MERL(MetaEdit+ Reporting Language):

  • MetaEdit+的MERL语言
    MetaEdit+提供代码生成编辑器,还支持生成的调试。OpenExpressApp采用类似MetaEdit+的元元模型来编写语言,所以将来的代码生成可能也会主要参考它来做。具体可参考安装程序目录中的User's Guides MetaEdit+ Workbench 代码生成章节内容


它的一个Report示例:

 

view source print ?
01 Report 'Test'
02 foreach .State [Watch]
03 'State : '
04    :State name;
05    newline
06    'Connects to: '
07    newline
08    do ~From>()~To.State [Watch]
09    '   '
10       :State name;
11       newline
12    }
13    newline
14 }
15 endreport

 

它的语法定义如下:

view source print ?
001 STRING  : "'" CHAR* "'"
002 where CHAR is any character; a ' character must be doubled
003 NUMBER  : ("0".."9")+
004 NAMECHAR    : "a".."z" | "0".."9" | " " | {_+-[]?} | INTLNAMECHAR | ESCAPECHAR
005 INTLNAMECHAR    : {äëïöü} | {áéíóú} | {àèìòù} | {âêîôû} | {ñãœçÿ} | {߀} | {¿¡«»}
006 ESCAPECHAR  : "\" ECHAR
007 where ECHAR is anything that is not a letter number or underscore
008 NAME    : NAMECHAR+
009 If NAME contains a space, the whole name should have a ";" after it, or one of ".>~#" forming the start of the next element in a chainClause
010 WILDNAME    : ["^"] (NAMECHAR | "*" | "#")+
011 If WILDNAME contains a space, the whole name should have a ";" after it.
012 #   Design element access and output commands (5.3.2)
013 chainOutputClause   : (propClauseWithLevel | propClause | (graphEltClause+ propClause)) [";"] [translatorNames] [";"];
014 translatorNames : ("%" +)+;
015 propClauseWithLevel : propClause levelNumber [";"];
016 levelNumber : [";"] " "* ["-"] +;
017 propClause  : ":" ( | "()");
018 graphEltClause  : (objClause | relClause | roleClause | portClause) [";"]
019 objClause   : "." typeChoiceClause
020 relClause   : ">" typeChoiceClause
021 roleClause  : "~" typeChoiceClause
022 portClause  : "#" typeChoiceClause
023 typeChoiceClause    : NAME
024     | "()"
025     | "( " WILDNAME {" | " WILDNAME}* ")"
026 #   General commands (5.3.3)
027 report  : oldreport | newreport;
028 oldreport   : "report" clause* "endreport";
029 newreport:  [newheadersection] clause*;
030 newheadersection    : ["(" [ ("," )*] ")" ];
031 clause  : (comment
032 | basicClause
033 | ifClause
034 | loop
035 | subreportClause
036 | fileClause
037 | md5Clause
038 | executeClause
039 | promptAskClause
040 | variableAssign
041 | variableClause
042 | translationClause
043 | mathClause
044 | chainOutputClause
045 ;
046 comment : ;
047 basicClause : atomicClause | iterableClause;
048 atomicClause    : newlineClause | separatorClause | literal | variableRef | simpleClause;
049 newlineClause   : "newline" [";"];
050 separatorClause : "sep" [";"];
051 literal : [translatorNames] [";"];
052 variableRef     : "$" [translatorNames] [";"];
053 simpleClause    : ("id" | "type" | "metatype" | "oid" | "projectid" | "objectid" | "project") [levelNumber] [";"] [translatorNames] [";"]
054 |
055 ("x" | "y" | "left" | "right" | "top" | "bottom" | "centerX" | "centerY" | "width" | "height" | "area") [levelNumber] [";"] [translatorNames] [";"];
056 iterableClause  : ("decompositions" | "explosions" | "containers" | "contents" | "stack" | "graphs") [";"];
057 #   Control and navigation commands (5.3.4)
058 ifClause    : "if" [condition]
059 "then" [";"] (clause* | ";")
060 ["else" [";"] clause*]
061 "endif" [";"];
062 condition   : ("not" condition)
063 | (condition "and" condition)
064 | (condition "or" condition)
065 | ("(" condition ")")
066 | expression;
067 expression  : comparison | unary;
068 unary   : comparableClause;
069 comparison  : comparableClause comp comparableClause
070 ["num"];
071 comparableClause    : atomicClause | chainClause;
072 comp    : "<" | ">" | "<=" | ">=" | "=" | "<>" | "=~" | "=/";
073 loop    : ("do" | "dowhile")
074 (chainClause | atomicClause)
075 [whereClause] [filterClause]
076 "{" clause* "}" [";"]
077 |
078 "foreach"
079 graphEltClause [";"]
080 [whereClause] [filterClause]
081 "{" clause* "}" [";"];
082 chainClause : (chainElementClause [levelNumber] [";"])+;
083 chainElementClause  : graphEltClause | propClause | iterableClause;
084 whereClause : "where" condition;
085 filterClause    : orderbyClause [uniqueClause]
086 | uniqueClause;
087 orderbyClause   : "orderby" orderCriterion ("," orderCriterion)*;
088 uniqueClause    : "unique" [clause+ ("," clause+)*];
089 orderCriterion  : clause+ ["num"] ["asc" | "desc"];
090 subreportClause : ("subreport" | "subgenerator") [";"] clause* "run" [";"];
091 #   External I/O commands (5.3.5)
092 fileClause  : outputFileClause | filenameReadClause | filenamePrintClause;
093 outputFileClause    : "filename" [";"] clause*
094 ["encoding" [";"] clause+]
095 ["md5start" [";"] clause+]
096 ["md5stop" [";"] clause+]
097 modeClause clause*
098 "close" [";"];
099 modeClause  : ("write" | "merge" | "append") [";"];
100 filenameReadClause  : "filename" [";"] clause*
101 ["encoding" [";"] clause+]
102 "read" [";"];
103 filenamePrintClause : "filename" [";"] clause* "print" [";"];
104 md5Clause   : "md5id" [";"] clause* "md5Block" [";"]
105 clause*
106 "md5sum" [";"];
107 executeClause   : ("external" | "internal") [";"]
108 clause*
109 ("execute" | "executeBlocking") [";"];
110 promptAskClause : "prompt" [";"] clause* "ask" [";"];
111 #   String and number commands (5.3.6)
112 variableClause  : variableReadClause | variableWriteClause;
113 variableReadClause  : "variable" [";"] clause+ "read" [";"];
114 variableWriteClause : "variable" [";"] clause+
115 variableModeClause clause* [";"]
116 "close" [";"];
117 variableModeClause  : ("write" | "append") [";"];
118 variableAssign  : "$" "=" [";"] (variableAssign | basicClause | chainOutputClause);
119 translationClause   : "to" [";"] clause*
120 ["translate" [";"] clause*]
121 "endto" [";"];
122 mathClause  : "math" [";"] clause* "evaluate" [";"];
  • 微软的T4

    T4: Text Template Transformation Toolkit

书籍

What's Inside:

  • Code generation basics
  • CG techniques and best practices
  • Patterns of CG design
  • How to deploy generators
  • Many example generators

Includes generators for:

  • Database access
  • RPC
  • Unit tests
  • Documentation
  • Business logic
  • Data translation

 

       

LOP中的代码生成 

  LOP中的代码生成有三种主要的方法,我们将结合使用它们来定义模型转换;第一种是遍历方式,你枚举源模型中所有节点,检视每一个,并基于检视到的信息生成目标模型中的一些目标节点;第二种方式是使用模板和宏来定义如何生成目标语言;第三种方式是使用模式匹配来查找在源模型中的哪些节点上应用转换。

 

Code Generation by Model Transformation - A Case Study in Transformation Modularity

 

 

推荐:你可能需要的在线电子书

 

欢迎转载,转载请注明:转载自周金根 [ http://zhoujg.cnblogs.com/ ]