预处理器和编译器之间的界限到底在哪里?

8
根据多种来源(例如SE广播中的Kevlin Henney剧集,如果我没记错的话),"C with classes"是使用预处理器技术实现的(然后输出被馈送到C编译器),而C ++始终是使用编译器实现的(在早期只发出C)。这似乎会引起一些混淆,所以我想知道:
预处理器和编译器之间的确切界限在哪里?何时称呼实现语言的软件为“预处理器”,何时称其为“编译器”?
顺便问一下,“编译语言”是一个已经确定的术语吗?如果是,它究竟意味着什么?

关于“编译语言”:它被使用,但很少附带定义,并且经常被那些不知道存在非AOT编译和编译到除机器码以外的目标,或者对编译有过于严格的定义而排除上述情况的人使用 - 我不会认真看待使用该术语而没有定义它的文本 ;) - user395760
6个回答

8

这是一个有趣的问题。我不知道一个确定的答案,但如果必须回答的话,我会说:

预处理器不解析代码,而是扫描嵌入式模式并扩展它们

编译器实际上通过构建抽象语法树(AST)来解析代码,然后将其转换为另一种语言。


4

预处理器输出的语言是输入语言的子集。

编译器输出的语言(通常)与输入语言非常不同(机器码)。


@Fred和Janusz:因此,“通常情况下” - Tomas

2

从一个简化、个人的角度来看:

我认为预处理器是任何形式的文本操作,它没有底层语言的概念(即:语义或构造),因此只依赖于自己的一套规则来执行其职责。

当规则和条例应用于被处理的内容时,编译器开始工作(是的,这使得“我的”预处理器成为了编译器,但为什么不呢:P),这包括语义和词法检查以及从x(文本)到y(二进制/中间形式)的转换。正如我的一位教授所说:“它是一个具有输入、处理和输出的系统。”


2

C/C++编译器关注类型正确性,而预处理器只是扩展符号。


动态语言编译器怎么样? - user395760
@delnan: 你是说脚本解释器吗?它们不是编译器,对吧? - Janusz Lenar
没有编译器。编译器只是一个将一种编程语言翻译成另一种编程语言的程序(或者,如果你想特别严格,是一种低级语言)。没有人会提到类型检查等等 - 这是一些语言需要的检查,但它并不决定一个程序是否是编译器。大多数广泛使用的动态类型语言都是编译的(到字节码,但再次强调,确切的输出格式并不重要)。甚至有数十个编译器(主要用于Lisp方言),可以编译成机器代码(而Lisp也是动态类型的)。 - user395760

0

编译器由多个进程(组件)组成。预处理器只是其中之一,相对来说是最简单的。

根据维基百科文章编译器进程划分

除了最小的编译器外,大多数编译器都有两个以上的阶段。然而,这些阶段通常被视为前端或后端的一部分。这两个端点的交汇点是有争议的。

前端通常被认为是语法和语义处理的地方,以及将代码翻译成比源代码更低级别的表示。

中间层通常设计为在源代码或机器代码之外的形式上执行优化。这种源代码/机器代码的独立性旨在使通用优化能够在支持不同语言和目标处理器的编译器版本之间共享。

后端获取中间层的输出。它可能会执行更多的分析、转换和针对特定计算机的优化。然后,它会为特定的处理器和操作系统生成代码。

预处理只是前端工作的一小部分。

第一个C++编译器是通过在现有的C编译器工具集前面附加额外的进程来制作的,这不是因为它是好的设计,而是因为时间和资源有限。

如今,在商业领域中,我认为这样的非本地C++编译器无法生存。

我敢说cfront对于C++11是不可能制作的。


0
答案非常简单。 预处理器以文本作为输入并生成文本作为输出。例如,旧的Unix命令m4、cpp(C预处理器)以及像roff和nroff和troff这样的Unix程序,它们被用于格式化man页面(Unix命令“man”)或格式化文本以进行打印或排版。 预处理器非常简单,它们不知道它们处理的文本的“语言”。换句话说,它们通常处理自然语言。除了其名称外,C预处理器只识别#define、#include、#ifdef、#ifndef、#else等。如果您使用#define MACRO,它会尝试在找到宏的任何地方“展开”该宏。但这不需要是C或C++程序文本,它也可以是用意大利语或希腊语编写的小说。 将编译成不同语言的编译器通常称为翻译器。因此,发出C代码的旧cfront“编译器”就是一个C++翻译器。 历史上使用预处理器和后来的翻译器是因为旧机器简单地缺乏内存,无法通过一个程序完成所有操作,而是通过专门的程序从磁盘到磁盘完成操作。 典型的C程序将从各种来源编译。构建过程将使用make进行管理。在我们的日子里,C预处理器通常直接构建到C/C++编译器中。典型的make运行将在*.c文件上调用CPP,并将输出写入不同的目录,从那里,C编译器CC要么将其直接编译为机器代码,要么更常见地将输出汇编代码作为文本。注意:c编译器仅检查语法,它并不真正关心类型安全等。然后,汇编程序将获取该汇编代码,并输出一个*.o文件,稍后可以将其与其他*.o文件和*.lib文件链接成可执行程序。另一方面,您可能有一个make规则,该规则不会调用C编译器,而是lint命令,即C语言分析器,该分析器正在寻找典型的错误和错误(这些错误被c编译器忽略)。 在维基百科(或使用man)上查找lint、nroff、troff、m4等非常有趣;D


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接