16

我已经编程多年(主要是 Python),但我不明白当我编译或执行代码时幕后发生了什么。

根据我之前提出的关于操作系统的问题,我正在寻找对编程语言工程的温和介绍。我希望能够定义和理解编译器、解释器、本机代码、托管代码、虚拟机等术语的基础知识。什么是有趣和互动的方式来了解这一点?

4

10 回答 10

13

简而言之要执行的代码

程序(代码)被输入编译器(或解释器)。

字符用于形成标记(+、标识符、数字),它们的值存储在称为符号表的东西中。

这些标记放在一起形成语句:(int a = 6 + b * c;)。主要是语法树的形式:

                     =
                    / \
                   /   \ 
                  a     +
                       / \
                      /   \
                     6     *
                          / \
                         b   c

在解释器中,树被直接执行。

使用编译器,树最终被翻译成中间代码或汇编代码。

您现在拥有一个或多个“目标文件”。这些包含没有精确跳转的汇编代码(因为这些值还不知道,特别是如果目标在其他目标文件中)。目标文件通过链接器链接在一起,链接器为跳转(ans 引用)填充空白。链接器的输出是一个库(也可以链接)或一个可执行文件。

如果您启动可执行文件,程序数据将被复制到内存中,并且还有一些其他链接可以将指针与正确的内存位置匹配。然后将控制权交给第一条指令。

于 2009-10-04T08:55:20.417 回答
4

编译器、解释器和虚拟机只是实现细节的示例。您可能会寻找编程语言理论、生成语法、语言翻译器,并且您可能需要一些计算机体系结构来将理论与实现联系起来。

就个人而言,我是从Sebesta 的书中学到的。它对该主题进行了非常广泛的介绍,而没有涉及到细微的细节。它还有一个关于编程语言历史的好章节(约 20 种语言,每种语言 3 篇论文)。它对语法和语言理论有很好的解释。此外,它很好地介绍了 Scheme、Prolog 和编程范式(逻辑、函数式、命令式^、面向对象)。

^ 它比前两个更关注命令式范式。

于 2009-10-04T08:54:22.160 回答
4

基本上,您编写源文件。这些是花哨的文本文件,由编译器接收,它输出某种形式的可执行代码(执行它的内容取决于您正在谈论的代码类型)。编译器有几个部分:

  • 对处理宏等的文件进行某种形式的预处理(如来自 C 语言)。
  • 解析器,它接收源文件,验证它们是否符合您的语言的句法规则,并将文件转换为更容易被程序的其他部分操作的内存数据结构。这称为抽象语法树或 AST。
  • 某种形式的 AST 分析,它验证您编写的实际代码不违反语言的任何规则(例如,在不支持它的语言中递归),以及许多其他事情。
  • 优化,例如尾调用优化、循环优化和许多其他类型的优化。
  • 代码生成,这是获取最终 AST 和任何其他生成的数据并将其转换为某种可以执行或解释的二进制文件的实际过程。

口译员:

解释器是一个程序,它采用某种形式的二进制数据,该数据表示一个程序,该程序未编译为可直接由目标机器执行的代码,并在其中运行命令。例如 python、java 和 lua。

本机代码:

这是已编译为目标机器可直接执行的本机指令的代码。例如; 如果您在 x86 架构上运行,则 c++ 将编译为处理器可以理解的可执行文件。

虚拟机:

这通常是为模拟处理器的构造和操作而构建的程序。它可能像读取字节码并根据字节码所代表的命令运行本地语言操作的程序一样简单(尽管将其称为虚拟机可能是一种延伸),或者它可能像完全模拟一个人的行为一样复杂处理器和所有相关的外围设备。

这些其他答案有很好的意义,但是这些信息和链接应该可以帮助您入门。有其他问题,尽管问!

(这篇文章大部分是在维基百科的帮助下写的,虽然有些是凭记忆写的)

于 2009-10-04T09:17:52.680 回答
3

该站点有一系列关于计算机程序结构和解释的精彩讲座,这正是您想要学习的类型。随附的教科书也很有用,尽管我没有亲自通读整本书。我认为观看讲座非常好,可以帮助您完成大约 60% 的路程。

于 2009-10-04T08:44:27.847 回答
2

哇,这是一个巨大的问题,有大量关于这方面的书面书籍。我真的怀疑你会在 SO 中得到一个像样的答案。您需要去当地的书店或参加一些计算机科学课程。

给你一个快速的介绍:

  • 编译器:将编写的代码转换为处理器本机可以理解的指令的程序。
  • 解释器:读取书面代码并即时翻译并提供相应处理器原生指令的程序。
  • 托管代码:在虚拟机中运行的代码,例如提供跨平台兼容性 (Java)。
  • 虚拟机:模拟成熟计算机环境的行为或 API 的程序。除其他外,这提供了一些安全优势和跨平台兼容性。
于 2009-10-04T08:49:44.767 回答
2

http://en.wikipedia.org/wiki/Dragon_Book_(computer_science)会解释很多这些概念,你应该读一读,这让我大开眼界。

于 2009-10-04T08:52:24.930 回答
2

如果您想知道如何从源代码转变为在目标机器上实际运行的东西,您应该得到一本著名的红龙书。我用它来构建解析器和词法分析器。虽然它可以追溯到 1986 年,而且我确信在此期间取得了进展,但据我所知,它并没有被超越作为文本。

Addison-Wesley 似乎对其前身《绿龙之书》进行了重印,并且将其作为最近的东西冒充,所以要小心获取真正的文章。

于 2009-10-04T09:54:23.277 回答
1

当我在上个世纪下半叶的某个地方学习编程时,我了解到一切都需要转换为机器码。脚本语言只会根据脚本代码决定调用哪些代码。编译后的代码首先会被编译为 p-code,它代表预编译代码,需要链接到其他预编译代码才能创建完整的应用程序。那时我喜欢 Turbo Pascal,仅仅是因为 Turbo Pascal 直接编译为机器代码,并且它没有使用中间的 p 代码。也就是说,直到 Turbo Pascal 4.0,它创建了 *.tpu 编译单元。大多数其他编译器将编译为 .obj 格式。

当 Java 被创建时,一些相对较新的东西开始流行起来。基本上,Java 编译器只是将代码编译为一些二进制脚本文件。然后可以解释该脚本,尽管该机制很快也发生了变化。

如今,口译员几乎绝迹。大多数脚本语言首先会被编译成机器码,然后机器码会存储在一些缓存中,因此它可以真正快速地执行,而无需系统重新解释任何重复的指令。这适用于文本和二进制脚本。PHP 将是基于文本的脚本的一个示例。Java 和 .NET 是二进制脚本,因为您通常将代码编译成这种二进制脚本格式。(他们会称它不同,但我认为二进制脚本听起来更好。)

一般来说,诀窍是使用任何可能的方式将代码转换为机器代码。有很多方法可以做到这一点,要说清楚有点复杂。

我还记得我可以编写一个 C++ 应用程序,其中 SQL 语句将位于代码本身中。这也很实用,但它需要一个预处理器,它首先从代码中解析 SQL 语句,将其转换为其他 C++ 语句,并用那些更复杂的 C++ 命令替换 SQL 语句。然后整个事情将被编译成p代码。然后你需要将它与其他 SQL 库链接,最后你有一个可执行文件。

于 2009-10-04T09:15:27.943 回答
1

这一系列来自斯坦福的讲座涵盖了几种编程语言的细节,包括 Python(尽管我只看过几个 C 语言)。

于 2009-10-04T09:50:16.370 回答
0

你可以找到很多讲座。例如在 Itunes U

于 2009-10-04T08:46:45.003 回答