MDSF:代码生成(Code Generation)介绍

  在实现模型驱动开发中,我们可以解释模型直接运行在领域框架之上,也可以把模型通过代码生成技术转换成代码之后编译运行在框架之上。这两种方式都有利弊,可以搭配使用,在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):

它的一个Report示例:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Report 'Test'
foreach .State [Watch]
'State : '
   :State name;
   newline
   'Connects to: '
   newline
   do ~From>()~To.State [Watch]
   '   '
      :State name;
      newline
   }
   newline
}
endreport

 

它的语法定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
STRING  : "'" CHAR* "'"
where CHAR is any character; a ' character must be doubled
NUMBER  : ("0".."9")+
NAMECHAR    : "a".."z" | "0".."9" | " " | {_+-[]?} | INTLNAMECHAR | ESCAPECHAR
INTLNAMECHAR    : {äëïöü} | {áéíóú} | {àèìòù} | {âêîôû} | {ñãœçÿ} | {߀} | {¿¡«»}
ESCAPECHAR  : "\" ECHAR
where ECHAR is anything that is not a letter number or underscore
NAME    : NAMECHAR+
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
WILDNAME    : ["^"] (NAMECHAR | "*" | "#")+
If WILDNAME contains a space, the whole name should have a ";" after it.
#   Design element access and output commands (5.3.2)
chainOutputClause   : (propClauseWithLevel | propClause | (graphEltClause+ propClause)) [";"] [translatorNames] [";"];
translatorNames : ("%" <NAMECHAR>+)+;
propClauseWithLevel : propClause levelNumber [";"];
levelNumber : [";"] " "* ["-"] <NUMBER>+;
propClause  : ":" (<NAME> | "()");
graphEltClause  : (objClause | relClause | roleClause | portClause) [";"]
objClause   : "." typeChoiceClause
relClause   : ">" typeChoiceClause
roleClause  : "~" typeChoiceClause
portClause  : "#" typeChoiceClause
typeChoiceClause    : NAME
    | "()"
    | "( " WILDNAME {" | " WILDNAME}* ")"
#   General commands (5.3.3)
report  : oldreport | newreport;
oldreport   : "report" <STRING> clause* "endreport";
newreport:  [newheadersection] clause*;
newheadersection    : <NAME> ["(" [<NAME> ("," <NAME>)*] ")" ];
clause  : (comment
| basicClause
| ifClause
| loop
| subreportClause
| fileClause
| md5Clause
| executeClause
| promptAskClause
| variableAssign
| variableClause
| translationClause
| mathClause
| chainOutputClause
;
comment : <comment>;
basicClause : atomicClause | iterableClause;
atomicClause    : newlineClause | separatorClause | literal | variableRef | simpleClause;
newlineClause   : "newline" [";"];
separatorClause : "sep" [";"];
literal : <STRING> [translatorNames] [";"];
variableRef     : "$" <NAME> [translatorNames] [";"];
simpleClause    : ("id" | "type" | "metatype" | "oid" | "projectid" | "objectid" | "project") [levelNumber] [";"] [translatorNames] [";"]
|
("x" | "y" | "left" | "right" | "top" | "bottom" | "centerX" | "centerY" | "width" | "height" | "area") [levelNumber] [";"] [translatorNames] [";"];
iterableClause  : ("decompositions" | "explosions" | "containers" | "contents" | "stack" | "graphs") [";"];
#   Control and navigation commands (5.3.4)
ifClause    : "if" [condition]
"then" [";"] (clause* | ";")
["else" [";"] clause*]
"endif" [";"];
condition   : ("not" condition)
| (condition "and" condition)
| (condition "or" condition)
| ("(" condition ")")
| expression;
expression  : comparison | unary;
unary   : comparableClause;
comparison  : comparableClause comp comparableClause
["num"];
comparableClause    : atomicClause | chainClause;
comp    : "<" | ">" | "<=" | ">=" | "=" | "<>" | "=~" | "=/";
loop    : ("do" | "dowhile")
(chainClause | atomicClause)
[whereClause] [filterClause]
"{" clause* "}" [";"]
|
"foreach"
graphEltClause [";"]
[whereClause] [filterClause]
"{" clause* "}" [";"];
chainClause : (chainElementClause [levelNumber] [";"])+;
chainElementClause  : graphEltClause | propClause | iterableClause;
whereClause : "where" condition;
filterClause    : orderbyClause [uniqueClause]
| uniqueClause;
orderbyClause   : "orderby" orderCriterion ("," orderCriterion)*;
uniqueClause    : "unique" [clause+ ("," clause+)*];
orderCriterion  : clause+ ["num"] ["asc" | "desc"];
subreportClause : ("subreport" | "subgenerator") [";"] clause* "run" [";"];
#   External I/O commands (5.3.5)
fileClause  : outputFileClause | filenameReadClause | filenamePrintClause;
outputFileClause    : "filename" [";"] clause*
["encoding" [";"] clause+]
["md5start" [";"] clause+]
["md5stop" [";"] clause+]
modeClause clause*
"close" [";"];
modeClause  : ("write" | "merge" | "append") [";"];
filenameReadClause  : "filename" [";"] clause*
["encoding" [";"] clause+]
"read" [";"];
filenamePrintClause : "filename" [";"] clause* "print" [";"];
md5Clause   : "md5id" [";"] clause* "md5Block" [";"]
clause*
"md5sum" [";"];
executeClause   : ("external" | "internal") [";"]
clause*
("execute" | "executeBlocking") [";"];
promptAskClause : "prompt" [";"] clause* "ask" [";"];
#   String and number commands (5.3.6)
variableClause  : variableReadClause | variableWriteClause;
variableReadClause  : "variable" [";"] clause+ "read" [";"];
variableWriteClause : "variable" [";"] clause+
variableModeClause clause* [";"]
"close" [";"];
variableModeClause  : ("write" | "append") [";"];
variableAssign  : "$" <NAME> "=" [";"] (variableAssign | basicClause | chainOutputClause);
translationClause   : "to" [";"] clause*
["translate" [";"] clause*]
"endto" [";"];
mathClause  : "math" [";"] clause* "evaluate" [";"];

书籍

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/ ]

posted on   周 金根  阅读(7865)  评论(7编辑  收藏  举报

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
历史上的今天:
2009-09-27 软件产品线工程方法 - 四个主要方法原则

导航

点击右上角即可分享
微信分享提示