7

促进(简化)广泛自动化源代码分析和重新设计(转换)工具的编程语言的共同特征/属性是什么?

我主要考虑编程语言特性,使开发静态分析和重构工具更容易(即比较 Java 与 C++,前者对重构有更好的支持)。

换句话说,一种从一开始就明确设计为支持自动静态分析和重构的编程语言,它最好具有哪些特征?

例如,对于Ada,有ASIS

Ada 语义接口规范 (ASIS) 是一个分层的开放式架构,提供对 Ada 库环境的独立于供应商的访问。它允许对 Ada 程序和库进行静态分析。ASIS,即 Ada 语义接口规范,是一个库,可让应用程序访问 Ada 编译单元的完整句法和语义结构。该库通常由需要对 Ada 程序执行某种静态分析的工具使用。

ASIS 信息: ASIS 为工具提供了一种标准方法来提取数据,这些数据最好由 Ada 编译器或其他源代码分析器收集。使用 ASIS 的工具本身是用 Ada 编写的,可以很容易地在支持 ASIS 的 Ada 编译器之间移植。使用 ASIS,开发人员可以生成具有高度可移植性的强大代码分析工具。它们还可以节省实施从源程序中提取语义信息的算法的可观费用。例如,ASIS 工具已经存在,可以生成源代码指标、检查程序对编码风格或限制的一致性、进行交叉引用以及全局分析程序以进行验证和验证。

另请参阅ASIS 常见问题解答

你能想到其他编程语言提供类似全面和完整的接口来处理源代码,专门用于分析/转换目的吗?

我正在考虑提供低级挂钩的特定实现技术,例如提供一种在运行时检查 AST 或 ASG 的方法的核心库函数。

4

7 回答 7

8

最大的必须是静态类型。这使工具可以更深入地了解代码在做什么。没有它,重构变得困难很多倍。

于 2009-06-10T20:23:04.190 回答
2

确实,特定的编程语言可以使分析更容易。如果您想要易于分析的语言,请选择纯功能语言。

但是没有人在实践中使用纯功能语言进行编程。(Haskell 的人看到这个会跳上跳下,但说真的,Haskell 很少使用)。

使编程语言可分析的是旨在支持分析的基础设施。上面 Ada 的 ASIS 就是一个很好的例子。不要混淆 ASIS 是为 Ada 编写的,或者是用 Ada 编写的;重要的是,有人认真地想要分析 Ada,并投入精力建立 Ada 分析机器。

我相信正确的解决方法是构建通用分析基础架构并将其摊销到多种语言中。当我们这样做的时候,我们也应该建立通用的转换基础设施,因为一旦你有了分析,你就会想用它来实现改变。(医生访问不以诊断结束;他们以治愈结束)。我把我的职业生涯都押在了这上面。

结果是一个我认为非常适合分析、重构、再工程等的引擎:我们的DMS 软件工程工具包。

它具有通用解析、树构建、漂亮打印、树操作、源到源重写、属性语法评估、控制和数据流分析。它为许多广泛使用的 C 和 C++ 方言、Java、C#、COBOL 和 PHP,甚至 Verilog 和 VHDL(还有许多其他语言,但还没有达到那个级别)提供生产质量的前端。

为了让您了解它的实用性,它被用来将 B-2 轰炸机的 JOVIAL 代码转换为 C……而我们从未见过源代码。请参阅http://www.semdesigns.com/Products/Services/NorthropGrummanB2.html

现在,假设一个人有分析基础设施,哪些语言特性有帮助?

静态类型通过限制变量可以采用的可能值集来帮助,但只能通过添加有限的单参数谓词来帮助,例如,“X 是整数”。我认为代码中的断言更有帮助,因为它们捕获 具有多个参数的谓词,这些谓词建立状态变量之间的关系,这通常无法通过检查代码找到(例如,问题或特定领域的信息,例如,“X > Y+3"。)分析基础设施(坦率地说,是阅读代码的程序员)可以理想地利用这些额外的事实来提供更有效的分析。

此类断言通常使用特殊关键字编码,例如“assert”、“pre(condition”和“post(condition”),这些关键字的灵感来自定理证明文献。

但是,即使您的语言中没有断言,它们也很容易编码:只需编写一个包含断言拒绝条件的 if 语句,然后主体执行一些调用表示不可能或违反语言语义的成语的事情(例如,取消引用一个明显的空指针),例如“if (x>0) fail();”

所以真正需要的不是语言中的断言,而是愿意编写它们的程序员。唉,这似乎可悲地缺乏。

于 2009-06-14T04:57:40.457 回答
2

我认为这仍然是一个很大程度上未探索的问题。“工具语言设计”的概念似乎最近才进入主流的边缘,尽管我认为这方面的研究已有二十多年的历史。我同意其他两个答案,即“静态类型”和“自相似性”是一种语言的有用属性,可以使重构支持更容易。

于 2009-06-14T16:42:13.757 回答
1

有一种语言共享“代码即数据”的范式。例如,每一行代码都只是这种语言的数据。这使得重构成为与原始数据操作一样的基本操作。这种语言的名称是 Lisp。;)

严肃地说,“编程语言”和“机器语言”是两个不同的要求。完美的分析语言可能是程序员的噩梦。更重要的是,为某些分析而设计的语言可能根本就不是编程语言。(上周我遇到了用于指针分析的语言,它没有文本表示,只有两个可执行语句)

再说一遍:首先你必须定义任务然后解决它。例如:如果任务是“我想编写安全的程序,例如我想确保我永远不会尝试混合整数和字符操作数”,那么你需要一种具有静态类型的语言。好的,“我需要在运行时知道我可以用外部库做什么”——反射是你的选择。“我需要通用编程语言来进行交换、转换和分析”——这很可能不是你真正想要的。

于 2009-06-14T18:03:28.303 回答
1

反射内置于语言/类型系统中。这使得静态分析和重构变得不那么痛苦。

这就是为什么 Java 和 .NET 工具如此普遍和好用的部分原因。这为工具提供了更好的功能,可以快速可靠地了解源代码的依赖关系,这有助于对源代码进行静态分析。

此外,您还可以分析已编译的代码。

于 2009-06-10T18:50:25.407 回答
0

IMO 最重要的属性是语言是完全指定的和确定性的。例如,在 C 中,语言规范没有定义以下代码的行为:

x++ = x++ + ++x;

如果代码的行为未定义,但它可以编译并执行某些操作,则没有安全的方法可以自动更改(即重构它)以保留某些内容。

下一个重要属性是它不允许访问超出其范围的变量(字段)。指针使得例如在 C 中通过“猜测”地址来访问任何变量的值成为可能。在这样的语言中,在某些情况下,无法判断某个变量的值在代码中的何处被读取和/或更改。同样,没有安全的方法可以自动重构可能执行类似操作的程序。

于 2009-06-15T09:30:28.180 回答
0

对于重构:自相似

能够接受代码移植而无需进行侵入性更改或奇怪的重新解释。例子:

  • 通过使用引用参数给它修改对变量的访问权限,将 C++ 的片段提取到新过程中。
  • Python、Javascript 和 Lua 方法实际上只是具有“self”参数的函数。*
  • 在任何数量的语言中,创建/填充结构的函数都可以(或多或少地)转换为构造函数。

反例...

  • Ruby(模块、类)、方法 lambda 块和原始块:语义上的差异至少可以说是令人困惑。(这是我有资格肯定地说的。)

对于(在我看来)完全不同的自动修改案例,我不太确定,但函数式编程语言提供的无副作用的自由确实如此。(好吧,那我们怎么能用一种语言为我们其他人提供同样的东西呢?)

*Python几乎就是这样。(我忘记了陷阱是什么。如果方法在类中定义或移植到运行时,可能与此有关。)

于 2009-06-14T13:56:49.160 回答