在实现模型驱动开发 中,我们可以解释模型直接运行在领域框架之上,也可以把模型通过代码生成技术转换成代码之后编译运行在框架之上。这两种方式都有利弊,可以搭配使用,在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的一般经过如下步骤:
写语法 写StringTemplate模板(可选) 在AntlrWorks调试语法 从语法生成类 使用生成的类来写应用程序
作者写了一本介绍Antlr的专著 The Definitive Antlr Reference ,我只是几年前大概看过一遍,觉得作者很牛。不过作者又出的另外一本书Language Implementation Patterns ,有人说这本书更好,它将ANTLR内部的设计思想也讲得很清楚了。相比而言,之前那本书只能算是ANTLR的用户手册,而新书算是ANTLR的设计思想。
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示例:
08
do
~From>()~To.State [Watch]
它的语法定义如下:
001
STRING :
"'"
CHAR*
"'"
002
where CHAR
is
any character; a ' character must be doubled
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
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 : (
"%"
<NAMECHAR>+)+;
015
propClauseWithLevel : propClause levelNumber [
";"
];
016
levelNumber : [
";"
]
" "
* [
"-"
] <NUMBER>+;
017
propClause :
":"
(<NAME> |
"()"
);
018
graphEltClause : (objClause | relClause | roleClause | portClause) [
";"
]
019
objClause :
"."
typeChoiceClause
020
relClause :
">"
typeChoiceClause
021
roleClause :
"~"
typeChoiceClause
022
portClause :
"#"
typeChoiceClause
023
typeChoiceClause : NAME
025
|
"( "
WILDNAME {
" | "
WILDNAME}*
")"
026
# General commands (5.3.3)
027
report : oldreport | newreport;
028
oldreport :
"report"
<STRING> clause*
"endreport"
;
029
newreport: [newheadersection] clause*;
030
newheadersection : <NAME> [
"("
[<NAME> (
","
<NAME>)*]
")"
];
047
basicClause : atomicClause | iterableClause;
048
atomicClause : newlineClause | separatorClause | literal | variableRef | simpleClause;
049
newlineClause :
"newline"
[
";"
];
050
separatorClause :
"sep"
[
";"
];
051
literal : <STRING> [translatorNames] [
";"
];
052
variableRef :
"$"
<NAME> [translatorNames] [
";"
];
053
simpleClause : (
"id"
|
"type"
|
"metatype"
|
"oid"
|
"projectid"
|
"objectid"
|
"project"
) [levelNumber] [
";"
] [translatorNames] [
";"
]
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*]
062
condition : (
"not"
condition)
063
| (condition
"and"
condition)
064
| (condition
"or"
condition)
067
expression : comparison | unary;
068
unary : comparableClause;
069
comparison : comparableClause comp comparableClause
071
comparableClause : atomicClause | chainClause;
072
comp :
"<"
|
">"
|
"<="
|
">="
|
"="
|
"<>"
|
"=~"
|
"=/"
;
073
loop : (
"do"
|
"dowhile"
)
074
(chainClause | atomicClause)
075
[whereClause] [filterClause]
080
[whereClause] [filterClause]
081
"{"
clause*
"}"
[
";"
];
082
chainClause : (chainElementClause [levelNumber] [
";"
])+;
083
chainElementClause : graphEltClause | propClause | iterableClause;
084
whereClause :
"where"
condition;
085
filterClause : orderbyClause [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+]
099
modeClause : (
"write"
|
"merge"
|
"append"
) [
";"
];
100
filenameReadClause :
"filename"
[
";"
] clause*
101
[
"encoding"
[
";"
] clause+]
103
filenamePrintClause :
"filename"
[
";"
] clause*
"print"
[
";"
];
104
md5Clause :
"md5id"
[
";"
] clause*
"md5Block"
[
";"
]
107
executeClause : (
"external"
|
"internal"
) [
";"
]
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* [
";"
]
117
variableModeClause : (
"write"
|
"append"
) [
";"
];
118
variableAssign :
"$"
<NAME>
"="
[
";"
] (variableAssign | basicClause | chainOutputClause);
119
translationClause :
"to"
[
";"
] clause*
120
[
"translate"
[
";"
] clause*]
122
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
转载于:https://blog.51cto.com/zhoujg/403113