发布于 2026-01-06 3 阅读
0

编译器设计概述

编译器设计概述

引言

你拥有十年使用高级 JavaScript Web 3.0 开发蒸汽朋克软件的经验,你是一位企业家、咨询明星和工程师……但你是否曾想过你的计算机是如何“读取”、“解释”和“执行”你的程序的?本文旨在帮助你轻松理解计算机科学中这一至关重要的部分。

我知道我在这里做了一些简化,也可能做了一些不恰当的比较,但我只是想给自己和其他人提供一个思维模型。现在免责声明完毕,我们可以开始深入探讨了,牵着我的手,让我们一起飞翔吧!

概要

那么,现在来对编译器做一个非常概括的概述:

图片描述

高级语言——它可以是 JavaScript、Python、C++,或者你喜欢的任何语言等等。简而言之,它只是一个字符串。

编译器——基于上一步,您应该已经知道编译器的输入是字符串,输出是汇编语言。因此,我们可以把编译器看作一个简单的函数,它接收一个字符串并生成另一个字符串。



Assembly code string = compiler(high level language string)


Enter fullscreen mode Exit fullscreen mode

最后一个问题是——什么是汇编代码?

汇编语言——就像不同操作系统的使用手册;换句话说,它是一套适用于具有特定架构(例如 x86 架构)的机器的指令集。

这是我们的最后一步:

机器代码——实际上就是 0 和 1。

但你可以提一下,我在最后一个模块中放置了两个部件——装载机/连接器。

仅供参考,我们来简单介绍一下。

链接器是一个程序,它将编译器/汇编器生成的目标文件和其他代码片段组合起来,生成一个带有特定.exe扩展名的可执行文件。在目标文件中,链接器会搜索并添加执行文件所需的所有库。它还会管理每个模块代码的内存空间。

加载是一个特殊的程序,它从链接器接收可执行文件作为输入,将其加载到主内存中,并准备好供计算机执行的代码。加载器会为程序分配内存空间,甚至建立对象之间的符号引用。它负责在操作系统中加载程序和库。嵌入式计算机系统没有加载器。

(我从这个网站复制了这两个定义

深入兔子洞

那么,让我们更进一步,深入研究编译器部分,这对我们来说现在更有趣。

还有一张图片值得欣赏:

图片描述

词法分析——去除空格、无用符号,并返回词法单元流。例如:

输入字符串



SELECT * FROM "docs";


Enter fullscreen mode Exit fullscreen mode

你可以把数据流看作一个迭代器,可以从中提取下一个标记。以下是一些伪代码:



Lexer.next() -> { kind: Keyword, type: "SELECT" }
Lexer.next() -> { kind: Asterisk  }
Lexer.next() -> { kind: Keyword, type: "FROM" }
Lexer.next() -> { kind: Char, value: "\"" }
Lexer.next() -> { kind: String, value: "docs" }
Lexer.next() -> { kind: Char, value: "\"" }


Enter fullscreen mode Exit fullscreen mode

所以它lexer代表了我们语言或字母表中的有效字符。


为了更好地理解,我们先来解析一个简单的字符串:



x = a + b * c;


Enter fullscreen mode Exit fullscreen mode

所以,作为人类,我们可以轻松解析和理解这类语句,但对计算机来说却并非易事。我们已经讨论了解析器的用途,现在让我们来解析上面的语句。我们尝试简化一下:



id = id + id * id


Enter fullscreen mode Exit fullscreen mode

其中 id 是一个标识符,如果我们尝试将其表示为数组,它可能看起来像这样:



[
  { type: 'id', value: x },
  { type: 'symbol', value: '=' },
  { type: 'id', value: 'a' },
  { type: 'symbol', value: '+' }, 
  { type: 'id', value: 'b' },
  { type: 'symbol', value: '*' },
  { type: 'id', value: 'c' },
  { type: 'symbol', value: ';' },
]


Enter fullscreen mode Exit fullscreen mode

解析器——使用上下文无关文法(我们将在下一部分介绍这个定义)来创建解析树。

别紧张,我们会介绍很多复杂的定义和术语,如果你觉得有点迷糊,没关系。接下来的章节会涵盖所有与解析相关的内容。

因此,基于语言语法,解析器会创建解析树,这有助于我们找到语句的正确执行顺序。

让我们来看一个BNF 表示法的语法示例。



S ⭢ id = E
E ⭢ E + T
  |  T
T ⭢ T * F
  | F
F ⭢ id



Enter fullscreen mode Exit fullscreen mode

基于此语法,我们可以构建一个分析树:

图片描述

语义分析器——验证解析树以查找语法错误。

中间码生成器——生成三地址码

例如,它可能看起来像这样:



t1 = b * c;
t2 = a + t1;
x = t2;


Enter fullscreen mode Exit fullscreen mode

代码优化器(CO) ——优化三地址代码。



t1 = b * c;
x = a + t1;


Enter fullscreen mode Exit fullscreen mode

目标代码生成器——生成汇编器可以理解的代码。

一些随机的伪架构:



mul R1, R2
add R0, R2
mov R2, x


Enter fullscreen mode Exit fullscreen mode

其中 a = R0,b = R1,c = R2


欢迎提问、表达意见或疑虑,也欢迎讨论你的观点。分享、订阅,一起编写代码,而不是挑起战争。❤️

如果你发现错误,我很乐意改正或者向你学习——请告诉我。

你可以通过推特私信我或者在领英上联系我。我一直都乐于结识新朋友,拓展人脉,把握新机遇。

文章来源:https://dev.to/frolovdev/high-level-overview-of-compiler-design-2l0o