关键思想是程序转换。Ondrej 对 DMS 有正确的想法,但我是 DMS 的作者,所以我可能有偏见。
用于完成转换的DMS语言称为“(DMS)规则规范语言”,或RSL,用于指定(程序转换)规则。这样的规则有:
- 一个名字(我们往往有很多,这是一种方便的方式来引用它们)
- 参数(定义模式变量),根据感兴趣的目标语言语法键入,
- 左手“匹配这个”模式
- 右手“用这个替换”模式
模式通常用目标语言的表面语法编写,即被转换的语言的本机语法,带有模式变量的扩展。为了区分 RSL 语言语法和目标语言,模式写在(元)引号“...”内。模式中的 \ 字符是(元)转义回 RSL。模式变量写成“\x”。(meta)function foobar 写成 \foobar( ... ),注意 (meta)functions 参数上的 (meta)escape。在引号之外,需要元转义,并且这些结构不带 \,例如 foobar(...)。
DMS 规则可能比这复杂得多,但这些是基础。表面句法模式不代表文本;相反,它们实际上代表了模式中代码的等效 AST。DMS 规则用于匹配和更改 AST。程序转换系统当然必须有解析器来生成 AST,以及反解析器(“prettyprinters”)来将 AST 转换回文本。(DMS 拥有一个庞大的语言前端库,涵盖了地球上所有广泛使用的语言和许多不常见的语言;我们刚刚添加了 MUMPS)。
对于您的具体示例,以下规则可以解决问题:
“...删除给定的功能”:
rule remove_function(f:IDENTIFIER,p:parameters,b:body): declarations -> declarations
" \f \p \b " -> " ; " -- replace function delcaration by empty declation
if f==target_function_name();
...在代码块周围添加一个 if 条件:
rule wrap_in_if(s:statement): statement -> statement
" \s " -> " \if ( \generated_condition\(\) ) \s ";
...添加一个什么都不做的新函数声明:
rule insert_noop_function(d:declarations): delcarations -> declarations
" \d " -> " \target_function\name\(\) ( ) { } ";
正如您所观察到的,您必须将它们指向某个地方;这是一个“元程序”的工作,它定位你希望在 AST 中应用规则的位置,然后应用它们。对于您的规则,您需要(使用 DMS)和明确的程序方法来找到正确的位置。对于某些 DMS 规则,您可以简单地应用然后“无处不在”;DMS 基本上会遍历指定的 AST 并为您应用规则。
几条规则永远不会令人印象深刻,就像几行代码并不令人印象深刻一样。几百或几千条规则就可以完成非常壮观的事情(例如完整的语言翻译),就像几百或几千行代码可以产生非常有趣的结果一样。不同之处在于,传统代码使用数字、字符串和结构,而程序转换工具通过程序结构 (AST) 进行计算。
有一个完整的工作示例展示了如何为 DMS 定义语言和规则,以及如何应用这些规则来实现“程序修改”(该示例实际上修改了“代数表达式”,但想法完全相同)。
DMS 是毫不掩饰的商业化,它不是一个 dimestore 工具,所以它可能不是你的论文所需要的。
如果不是 DMS,您可以获得具有相同想法的免费工具。考虑 TXL (www.txl.ca) 或 StrategoXt (www.strategoxt.org)。DMS、TXL、Stratego 都使用表面语法模式进行程序转换,但 TXL 和 Stratego 无法像 DMS 恕我直言一样处理代码的大量更改。(出于某些原因,请阅读 DMS 网站上的流量分析)。不过,TXL 和 Stratego 非常适合学习基础知识和构建强大的演示。