GitHub 上这份计算机自学指南火了~


 

点击上方“码农突围”,马上关注

这里是码农充电第一站,回复“666”,获取一份专属大礼包

真爱,请设置“星标”或点个“在看

0436300337fa4fe9863f085303136d3c.png

最近在逛GitHub的时候,发现了一个宝藏开源仓库「TeachYourselfCS-CN」,内容涉及计算机科学专业的自学指南,目前收获了10k+的Star。

这份指南最早是由 Bradfield 计算机科学学院的两名教员 Ozan Onay 和 Myles Byrne 编写的,内容主要源自他们对数千名自学成才的工程师和培训班学生教授计算机科学基础的经验。

此前,一名毕业自上海交通大学,现为微软实习生的开发者 Keith Null 将其翻译成了中文,并将其中文版本正式开源到了 GitHub 上,开源地址为:https://github.com/izackwu/TeachYourselfCS-CN/blob/master/TeachYourselfCS-CN.md

现把这个自学指南分享给大家看下,下面是正文。

---

如果你是一个自学成才的工程师,或者从编程培训班毕业,那么你很有必要学习计算机科学。幸运的是,不必为此花上数年光阴和不菲费用去攻读一个学位:仅仅依靠自己,你就可以获得世界一流水平的教育💸。

互联网上,到处都有许多的学习资源,然而精华与糟粕并存。你所需要的,不是一个诸如 “200 + 免费在线课程” 的清单,而是以下问题的答案:

  • 你应当学习哪些科目,为什么?

  • 对于这些科目,最好的书籍或者视频课程是什么?

在这份指引中,我们尝试对这些问题做出确定的回答。

简而言之

大致按照列出的顺序,借助我们所建议的教材或者视频课程(但是最好二者兼用),学习如下的九门科目。目标是先花 100 到 200 个小时学习完每一个科目,然后在你职业生涯中,不时温习其中的精髓🚀。

科目

为何要学?

最佳书籍

最佳视频





编程

不要做一个 “永远没彻底搞懂” 诸如递归等概念的程序员。

《计算机程序的构造和解释》

Brian Harvey’s Berkeley CS 61A

计算机架构

如果你对于计算机如何工作没有具体的概念,那么你所做出的所有高级抽象都是空中楼阁。

《深入理解计算机系统》

Berkeley CS 61C

算法与数据结构

如果你不懂得如何使用栈、队列、树、图等常见数据结构,遇到有难度的问题时,你将束手无策。

《算法设计手册》

Steven Skiena’s lectures

数学知识

计算机科学基本上是应用数学的一个 “跑偏的” 分支,因此学习数学将会给你带来竞争优势。

《计算机科学中的数学》

Tom Leighton’s MIT 6.042J

操作系统

你所写的代码,基本上都由操作系统来运行,因此你应当了解其运作的原理。

《操作系统导论》

Berkeley CS 162

计算机网络

互联网已然势不可挡:理解工作原理才能解锁全部潜力。

《计算机网络:自顶向下方法》

Stanford CS 144

数据库

对于多数重要程序,数据是其核心,然而很少人理解数据库系统的工作原理。

《Readings in Database Systems》 (暂无中译本)

Joe Hellerstein’s Berkeley CS 186

编程语言与编译器

若你懂得编程语言和编译器如何工作,你就能写出更好的代码,更轻松地学习新的编程语言。

《Crafting Interpreters》

Alex Aiken’s course on Lagunita

分布式系统

如今,多数 系统都是分布式的。

《数据密集型应用系统设计》

MIT 6.824

还是太多?

如果花几年时间自学 9 门科目让人望而却步,我们建议你只专注于两本书:《深入理解计算机系统》《数据密集型应用系统设计》。根据我们的经验,投入到这两本书的时间可以获得极高的回报率,特别适合从事网络应用开发的自学工程师。这两本书也可以作为上面表格中其他科目的纲领。

为什么要学习计算机科学?

软件工程师分为两种:一种充分理解了计算机科学,从而有能力应对充满挑战的创造性工作;另一种仅仅凭着对一些高级工具的熟悉而勉强应付。

这两种人都自称软件工程师,都能在职业生涯早期挣到差不多的工资。然而,随着时间流逝,第一种工程师不断成长,所做的事情将会越来越有意义且更为高薪,不论是有价值的商业工作、突破性的开源项目、技术上的领导力或者高质量的个人贡献。

全球短信系统每日收发约 200 亿条信息,而仅仅靠 57 名工程师,现在的 WhatsApp 每日收发 420 亿条。

— Benedict Evans (@BenedictEvans) 2016 年 2 月 2 日

第一种工程师总是寻求深入学习计算机科学的方法,或是通过传统的方法学习,或是在职业生涯中永无止息地学习;第二种工程师 通常浮于表面,只学习某些特定的工具和技术,而不研究其底层的基本原理,仅仅在技术潮流的风向改变时学习新的技能。

如今,涌入计算机行业的人数激增,然而计算机专业的毕业生数量基本上未曾改变。第二种工程师的供过于求正在开始减少他们的工作机会,使他们无法涉足行业内更加有意义的工作。对你而言,不论正在努力成为第一种工程师,还是只想让自己的职业生涯更加安全,学习计算机科学是唯一可靠的途径。

23333 然而他们... pic.twitter.com/XVNYlXAHar

— Jenna Bilotta (@jenna) 2017 年 3 月 4 日

分科目指引

编程

大多数计算机专业本科教学以程序设计 “导论” 作为开始。这类课程的最佳版本不仅能满足初学者的需要,还适用于那些在初学编程阶段遗漏了某些有益的概念和程序设计模式的人。

对于这部分内容,我们的标准推荐是这部经典著作:《计算机程序的构造和解释》。在网络上,这本书既可供免费阅读(英文版),也作为 MIT 的免费视频课程。不过尽管这些视频课程很不错,我们对于视频课程的推荐实际上是 Brian Harvey 开设的 SICP 课程(即 Berkeley 的 61A 课程)。比起 MIT 的课程,它更加完善,更适用于初学者。

我们建议至少学完 SICP 的前三章,并完成配套的习题。如果需要额外的练习,可以去解决一些小的程序设计问题,比如 exercism。

中文翻译新增:

  • 关于 SICP 国内视频观看地址

    • MIT 的免费视频课程(中英字幕)

    • Brian Harvey 开设的 SICP 课程(英文字幕)

  • Scheme 学习的相关资源参见:https://github.com/DeathKing/Learning-SICP

  • 更详细的补充说明:#3

自从 2016 年首次发布这份指南以来,最常被问到的一个问题是,我们是否推荐由 John DeNero 讲授的更新的 CS 61A 课程,以及配套的书籍 《Composing Programs》,这本书 “继承自 SICP” 但使用 Python 讲解。我们认为 DeNero 的课程也很不错,有的学生可能更喜欢,但我们还是建议把 SICP, Scheme 和 Brian Harvey 的视频课程作为首选。

为什么这么说呢?因为 SICP 是独一无二的,它可以 —— 至少很有可能 —— 改变你对计算机和编程的基本认识。不是每个人都有这样的体验。有的人讨厌这本书,有的人看了前几页就放弃了。但潜在的回报让它值得一读。

如果你觉得 SICP 过于难,试试 《Composing Programs》。如果还是不合适,那我们推荐 《程序设计方法》(中文版,英文版) ;如果你觉得 SICP 过于简单,那我们推荐 《Concepts, Techniques, and Models of Computer Programming》 。如果读这些书让你觉得没有收获,也行你应该先学习其他科目,一两年后再重新审视编程的理念。

新版原文删除了对 《Concepts, Techniques, and Models of Computer Programming》 一书的推荐,但这本书对各种编程模型有深入的见解,值得一读。所以译文中依然保留。 — 译者注

最后,有一点要说明的是:本指南不适用于完全不懂编程的新手。我们假定你是一个没有计算机专业背景的程序员,希望填补一些知识空白。事实上,我们把 “编程” 章节包括进来只是提醒你还有更多知识需要学习。对于那些从来没有学过编程,但又想学的人来说,这份指南更合适。

31eff8278f62ae78a4337922cd476100.png

计算机架构

计算机架构 —— 有时候又被称为 “计算机系统” 或者 “计算机组成”—— 是了解软件底层的的重要视角。根据我们的经验,这是自学的软件工程师最容易忽视的领域。

我们最喜欢的入门书是 《深入理解计算机系统》。典型的计算机体系结构导论课程会涵盖本书的 1 - 6 章。

我们喜爱《深入理解计算机系统》,因为它的实用性,并且站在程序员的视角。虽然计算机体系结构的内容比本书所涉及的内容多得多,但对于那些想了解计算机系统以求编写更快、更高效、更可靠的软件的人来说,这本书是很好的起点。

对于那些既想了解这个主题又想兼顾硬件和软件的知识的人来说,我们推荐 《计算机系统要素》,又名 “从与非门到俄罗斯方块”(“Nand2Tetris”),这本书规模宏大,让读者对计算机内的所有部分如何协同工作有完全的认识。这本书的每一章节对应如何构建计算机整体系统中的一小部分,从用 HDL(硬件描述语言)写基本的逻辑门电路出发,途经 CPU 和汇编,最终抵达诸如俄罗斯方块这般规模的应用程序。

我们推荐把此书的前六章读完,并完成对应的项目练习。这么做,你将更加深入地理解,计算机架构和运行其上的软件之间的关系。

这本书的前半部分(包括所有对应的项目)均可从 Nand2Tetris 的网站上免费获得。同时,在 Coursera 上,这是一门视频课程。

为了追求简洁和紧凑,这本书牺牲了内容上的深度。尤其值得注意的是,流水线和存储层次结构是现代计算机架构中极其重要的两个概念,然而这本书对此几乎毫无涉及。

当你掌握了 Nand2Tetris 的内容后,我们推荐要么回到《深入理解计算机系统》,或者考虑 Patterson 和 Hennessy 二人所著的 《计算机组成与设计》,一本优秀的经典著作。这本书中的不同章节重要程度不一,因此我们建议根据 Berkeley 的 CS61C 课程 “计算机架构中的伟大思想” 来着重阅读一些章节。这门课的笔记和实验在网络上可以免费获得,并且在互联网档案中有这门课程的过往资料。

ac549af1bf19ff5bc31da24bbc249946.png

硬件是平台。

— Mike Acton, Engine Director at Insomniac Games (观看他在 CppCon 上的演说)

算法与数据结构

正如几十年来的共识,我们认为,计算机科学教育所赋予人们的最大能量在于对常见算法和数据结构的熟悉。此外,这也可以训练一个人对于各种问题的解决能力,有助于其他领域的学习。

关于算法与数据结构,有成百上千的书可供使用,但是我们的最爱是 Steven Skiena 编写的 《算法设计手册》。显而易见,他对此充满热爱,迫不及待地想要帮助其他人理解。在我们看来,这本书给人一种焕然一新的体验,完全不同于那些更加经常被推荐的书(比如 Cormen,Leiserson,Rivest 和 Stein,或者 Sedgewick 的书,后两者充斥着过多的证明,不适合以 解决问题 为导向的学习)。

如果你更喜欢视频课程,Skiena 慷慨地提供了他的课程。此外,Tim Roughgarden 的课程也很不错, 在 Stanford 的 MOOC 平台 Lagunita,或者 Coursera 上均可获得。Skiena 和 Roughgarden 的这两门课程没有优劣之分,选择何者取决于个人品味。

至于练习,我们推荐学生在 Leetcode 上解决问题。Leetcode 上的问题往往有趣且带有良好的解法和讨论。此外,在竞争日益激烈的软件行业,这些问题可以帮助你评估自己应对技术面试中常见问题的能力。我们建议解决大约 100 道随机挑选的 Leetcode 问题,作为学习的一部分。

最后,我们强烈推荐 《怎样解题》。这本书极为优秀且独特,指导人们解决广义上的问题,因而一如其适用于数学,它适用于计算机科学。

9f0999d7ba3387f8b587bcc86db95f34.png

我可以广泛推荐的方法只有一个:写之前先思考。

— Richard Hamming

数学知识

从某个角度说,计算机科学是应用数学的一个 “发育过度” 的分支。尽管许多软件工程师试图 —— 并且在不同程度上成功做到 —— 忽视这一点,我们鼓励你用学习来拥抱数学。如若成功,比起那些没有掌握数学的人,你将获得巨大的竞争优势。

对于计算机科学,数学中最相关的领域是 “离散数学”,其中的 “离散” 与 “连续” 相对立,大致上指的是应用数学中那些有趣的主题,而不是微积分之类的。由于定义比较含糊,试图掌握离散数学的全部内容是没有意义的。较为现实的学习目标是,了解逻辑、排列组合、概率论、集合论、图论以及密码学相关的一些数论知识。考虑到线性代数在计算机图形学和机器学习中的重要性,该领域同样值得学习。

学习离散数学,我们建议从 László Lovász 的课程笔记开始。Lovász 教授成功地让这些内容浅显易懂且符合直觉,因此,比起正式的教材,这更适合初学者。

对于更加高阶的学习,我们推荐 《计算机科学中的数学》,MIT 同名课程的课程笔记,篇幅与书籍相当(事实上,现已出版)。这门课程的视频同样可免费获得,是我们所推荐的学习视频。

对于线性代数,我们建议从 Essence of linear algebra 系列视频开始,然后再去学习 Gilbert Strang 的《线性代数导论》和视频课程。

48df5a7082104e49d076f46008197134.png

如果人们不相信数学是简单的,那么只能是因为他们没有意识到生活有多么复杂。

— John von Neumann

操作系统

《操作系统概念》 (“恐龙书”)和 《现代操作系统》 是操作系统领域的经典书籍。二者都因为写作风格和对学生不友好而招致了一些批评。

《操作系统导论》(Operating Systems: Three Easy Pieces) 是一个不错的替代品,并且可在网上免费获得(英文版)。我们格外喜欢这本书的结构,并且认为这本书的习题很值得一做。

在读完《操作系统导论》后,我们鼓励你探索特定操作系统的设计。可以借助 “{OS name} Internals” 风格的书籍,比如 Lion's commentary on Unix, The Design and Implementation of the FreeBSD Operating System,以及 Mac OS X Internals。对于 Linux ,我们推荐 Robert Love 的 《Linux 内核设计与实现》

为了巩固对操作系统的理解,阅读小型系统内核的代码并且为其增加特性是一个很不错的方法。比如,xv6,由 MIT 的一门课程所维护的从 Unix V6 到 ANSI C 和 x86 的移植,就是一个很棒的选择。《操作系统导论》有一个附录,记载了一些可能的 xv6 实验项目,其中充满了关于潜在项目的很棒想法。

196d79af9923ae30103dc4a5ebbf9ad4.png

计算机网络

鉴于有那么多关于网络服务端和客户端的软件工程,计算机网络是计算机科学中价值最为 “立竿见影” 的领域之一。我们的学生,系统性地学习了计算机网络,最终能够理解那些曾困扰他们多年的术语、概念和协议。

在这一主题上,我们最爱的书籍是 《计算机网络:自顶向下方法》。书中的小项目和习题相当值得练习,尤其是其中的 “Wireshark labs”(这部分在网上可以获得)。

如果更喜欢视频课程,我们推荐 Stanford 的 Introduction to Computer Networking,可在他们的 MOOC 平台 Lagunita 上免费观看。

对于计算机网络的学习,做项目比完成小的习题更有益。一些可能的项目有:HTTP 服务器,基于 UDP 的聊天 APP,迷你 TCP 栈,代理,负载均衡器,或者分布式哈希表。

8981cac92115a5c63e18d39c83b9ec97.png

你无法盯着水晶球预见未来,未来的互联网何去何从取决于社会。

— Bob Kahn

数据库

比起其他主题,自学数据库系统需要更多的付出。这是一个相对年轻的研究领域,并且出于很强的商业动机,研究者把想法藏在紧闭的门后。此外,许多原本有潜力写出优秀教材的作者反而选择了加入或创立公司。

鉴于如上情况,我们鼓励自学者大体上抛弃教材,而是从 2015 年春季学期的 CS 186 课程(Joe Hellerstein 在 Berkeley 的数据库课程)开始,然后前往阅读论文。

对于初学者,有一篇格外值得提及的论文:“Architecture of a Database System”。这篇论文提供了独特的对关系型数据库管理系统(RDBMS)如何工作的高层次观点,是后续学习的实用梗概。

《Readings in Database Systems》,或者以数据库 “红书” 更为人知,是由 Peter Bailis,Joe Hellerstein 和 Michael Stonebraker 编纂的论文合集。对于那些想要在 CS 186 课程的水平更进一步的学习者,“红书” 应当是下一步。

如果你坚持一定要一本导论教材,那我们推荐 Ramakrishnan 和 Gehrke 所著的 《数据库管理系统:原理与设计》。如需更深一步,Jim Gray 的经典著作 《Transaction Processing: Concepts and Techniques》 值得一读,不过我们不建议把这本书当作首要资源。

如果没有编写足够数量的代码,很难巩固数据库理论。CS 186 课程的学生给 Spark 添加特性,倒是不错的项目,不过我们仅仅建议从零实现一个简单的关系型数据库管理系统。自然,它将不会有太多的特性,但是即便只实现典型的关系型数据库管理系统每个方面最基础的功能,也是相当有启发的。

最后,数据模型往往是数据库中一个被忽视的、教学不充分的方面。关于这个主题,我们推荐的书籍是 Data and Reality: A Timeless Perspective on Perceiving and Managing Information in Our Imprecise World

6a3d51bee4bdee10f57e907e3bf95e3f.png

编程语言与编译器

多数程序员学习编程语言的知识,而多数计算机科学家学习编程语言 相关 的知识。这使得计算机科学家比起程序员拥有显著的优势,即便在编程领域!因为他们的知识可以推而广之:相较只学习过特定编程语言的人,他们可以更深入更快速地理解新的编程语言。

我们推荐的入门书是 Bob Nystrom 所著的优秀的 Crafting Interpreters,可在网上免费获取。这本书条理清晰,富有趣味性,非常适合那些想要更好地理解语言和语言工具的人。我们建议你花时间读完整本书,并尝试任何一个感兴趣的 “挑战”。

另一本更为传统的推荐书籍是 《编译原理》,通常称为 “龙书”。不幸的是,这本书不是为自学者而设计的,而是供教师从中挑选一些主题用于 1-2 学期的教学。

如果你选择使用龙书进行自学,你需要从中甄选主题,而且最好是在导师的帮助下。我们建议依据某个视频课程来设定学习的结构,然后按需从龙书中获取深入的内容。我们推荐的在线课程是 Alex Aiken 在 MOOC 平台 edX 所开设的。

282aa0d012bc74085810d87b23e0a342.png

不要做一个只写样板代码的程序员。相反,给用户和其他程序员创造工具。从纺织工业和钢铁工业中学习历史教训:你想制造机器和工具,还是操作这些机器?

— Ras Bodik 在他的编译器课程伊始

分布式系统

随着计算机在数量上的增加,计算机同样开始 分散。尽管商业公司过去愿意购买越来越大的大型机,现在的典型情况是,甚至很小的应用程序都同时在多台机器上运行。思考这样做的利弊权衡,即是分布式系统的研究所在,也是越来越重要的一项技能。

我们推荐的自学参考书是 Martin Kleppmann 的 《数据密集型应用系统设计》。与传统的教科书相比,它是一本为实践者设计的具有很高的可读性的书,并且保持了深度和严谨性。

对于那些偏爱传统教材,或者希望可以从网上免费获取的人,我们推荐的教材是 Maarten van Steen 和 Andrew Tanenbaum 所著的 《分布式系统原理与范型》(中文第二版,英文第三版)

对于喜欢视频课程的人,MIT 的 6.824 是一门很好的在线视频课程,由 Robert Morris 教授的研究生课程,在这里可以看到课程安排。

不管选择怎样的教材或者其他辅助资料,学习分布式系统必然要求阅读论文。这里有一个不错的论文清单,而且我们强烈建议你出席你当地的 Papers We Love(仅限美国)。

7b3f1f5d12a5c34ad41fa4bb9ab999da.png

常见问题解答

这份指引的目标受众是?

我们面向自学的软件工程师、培训班学生、“早熟的” 高中生或者想要通过自学补充正式教育的大学生。关于何时开启这段自学旅程,完全取决于个人,不过多数人在有一定的职业经历后深入学习计算机科学理论会获益匪浅。比如,我们注意到,如果学生在工作中曾经使用过数据库,他们会 喜爱 学习数据库系统课程;如果学生从事过一两个 Web 项目,他们会 喜爱 学习计算机网络。

人工智能 / 计算机图形学 / XX 主题怎么样?

我们试图把计算机科学主题清单限制到那些我们认为 每一个软件工程师 都应该了解的内容,不限于专业或行业。拥有了这些基础,你将能更加轻松地挑选教材或论文,然而无需指引地学习核心概念。在这里,我们给出一些其他常见主题的自学起点:

  • 人工智能:通过观看视频并完成 Pacman 项目来学习 Berkeley 的 AI 课程。至于教材,使用 Russell 和 Norvig 编写的 《人工智能:一种现代方法》

  • 机器学习:学习吴恩达在 Coursera 上的课程。耐心学习,先确保理解了基础概念再奔向类如深度学习的诱人新主题。

  • 计算机图形学:学习 Berkeley CS 184 课程的材料,使用《计算机图形学:原理及实践》作为教材。

一定要严格遵守推荐的学习次序吗?

事实上,所有主题之间都有一定程度的重叠,彼此循环引用。以离散数学和算法的关系为例:先学习数学可以帮助你更深入地分析和理解算法,然而先学习算法可以为学习离散数学提供更大的动力和应用背景。理想情况下,你将在你的职业生涯多次重温二者。

因此,我们所推荐的次序主要是为了帮助你 起步…… 如果你出于某种强烈的原因而倾向以不同的顺序学习,那也没有关系,勇敢开始吧!不过在我们看来,最重要的 “先决条件” 是:先学计算机架构再学操作系统或数据库,先学计算机网络和操作系统再学分布式系统。

和 Open Source Society、freeCodeCamp curricula 等比起来,这份指引?

OSS 指引涵盖太多主题,在许多主题中推荐劣质资源,没有就特定课程哪些方面有价值提供原因或指引。我们努力对这份指引中的课程加以限制,仅仅包括那些你作为软件工程师 确实需要了解的,不论你的专业方向,并且对每门课程为何必要做出了解释以帮助你理解。

FreeCodeCamp 主要关注编程,而不是计算机科学。至于你为什么要学习计算机科学,参见上文。如果你是个新手,我们建议先学 freeCodeCamp 的课程,一两年后再回归本指南。

XX 编程语言怎么样?

学习一门特定的编程语言和学习计算机科学的一个领域完全不在一个维度 —— 相比之下,学习语言 容易 且 缺乏价值。如果你已经了解了一些语言,我们强烈建议遵照我们的指引,然后在学习的空当中习得语言,或者暂且不管以后再说。如果你已经把编程学得不错了(比如学完了 《计算机程序的构造和解释》),尤其是如果你学习过编译器,那么面对一门新的语言,你只需要花一个周末稍多的时间即可基本掌握,之后你可以在工作中学习相关的类库 / 工具 / 生态。

XX 流行技术怎么样?

没有任何一种技术的重要程度可以达到学习其使用足以成为计算机科学教学的核心部分。不过,你对学习那门技术充满热情,这很不错。诀窍是先从特定的技术回退到基本的领域或概念,判断这门流行技术在技术的宏观大局中位于何处,然后才深入学习这门技术。

为什么你们还在推荐 SICP?

先尝试读一下,有些人觉得 SICP 让人神魂颠倒,这在其他书很少见。如果你不喜欢,你可以尝试其他的东西,也许以后再回到 SICP。

为什么你们还在推荐龙书?

龙书依旧是内容最为完整的编译器单本书籍。由于过分强调一些如今不够时新的主题的细节,比如解析,这本书招致了恶评。然而事实上,这本书从未打算供人一页一页的学习,而仅仅是为了给教师准备一门课程提供足够的材料。类似地,自学者可以从书中量身按需挑选主题,或者最好依照公开课授课教师在课程大纲中的建议。

如何便宜获取教材?

我们所建议的许多教材在网上都可以免费获得,这多亏了作者们的慷慨。对于那些不免费的书籍,我们建议购买旧版本的二手书籍。广而言之,如果一本教材有多个版本,旧版本大概率是完全足够使用的。即便新版本的价格是旧版本的 10 倍,新版本也绝不可能比旧版本好 10 倍!

这份指引是谁写的?

这份指引由 Bradfield School of Computer Science(旧金山)的两位教员:Ozan Onay 和 Myles Byrne 编写,并由 Oz 于 2020 年更新。这份指引基于对数千名自学成才的工程师和培训班学生教授计算机科学基础的经验。

这份指引是谁翻译的?

这份指引的中文翻译是社区共同贡献的成果,欢迎任何反馈和改进!

GitHub 地址:

https://github.com/keithnull/TeachYourselfCS-CN/blob/master/TeachYourselfCS-CN.md

-End-
最近有一些小伙伴,让我帮忙找一些 面试题 资料,于是我翻遍了收藏的 5T 资料后,汇总整理出来,可以说是程序员面试必备!所有资料都整理到网盘了,欢迎下载!

点击👆卡片,关注后回复【面试题】即可获取

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
``Crafting a Compiler'' by Charles N. Fisher & Richard J. LeBlanc, Jr. 1988. Benjamin/Cummings Publishing Company. Menlo Park, CA. Brief Contents xvi 1 Introduction 1 2 A Simple Compiler 31 3 Scanning—Theory and Practice 57 4 Grammars and Parsing 113 5 Top-Down Parsing 143 6 Bottom-Up Parsing 179 7 Syntax-Directed Translation 235 8 Symbol Tables and Declaration Processing 279 9 Semantic Analysis 343 10 Intermediate Representations 391 11 Code Generation for a Virtual Machine 417 12 Runtime Support 445 13 Target Code Generation 489 14 Program Optimization 547 Contents xvii 1 Introduction 1 1.1 History of Compilation 2 1.2 What Compilers Do 4 1.2.1 Machine Code Generated by Compilers 4 1.2.2 Target Code Formats 7 1.3 Interpreters 9 1.4 Syntax and Semantics 10 1.4.1 Static Semantics 11 1.4.2 Runtime Semantics 12 1.5 Organization of a Compiler 14 1.5.1 The Scanner 16 1.5.2 The Parser 16 1.5.3 The Type Checker (Semantic Analysis) 17 1.5.4 Translator (Program Synthesis) 17 1.5.5 Symbol Tables 18 1.5.6 The Optimizer 18 1.5.7 The Code Generator 19 1.5.8 Compiler Writing Tools 19 1.6 Programming Language and Compiler Design 20 1.7 Computer Architecture and Compiler Design 21 1.8 Compiler Design Considerations 22 1.8.1 Debugging (Development) Compilers 22 1.8.2 Optimizing Compilers 23 1.8.3 Retargetable Compilers 23 1.9 Integrated Development Environments 24 1.10 Exercises 26 2 A Simple Compiler 31 2.1 An Informal Definition of the ac Language 32 2.2 Formal Definition of ac 33 2.2.1 Syntax Specification 33 2.2.2 Token Specification 36 2.3 Phases of a Simple Compiler 37 2.4 Scanning 38 2.5 Parsing 39 2.5.1 Predicting a Parsing Procedure 41 2.5.2 Implementing the Production 43 2.6 Abstract Syntax Trees 45 2.7 Semantic Analysis 46 2.7.1 Symbol Tables 47 2.7.2 Type Checking 48 2.8 Code Generation 51 2.9 Exercises 54 3 Scanning—Theory and Practice 57 3.1 Overview of a Scanner 58 3.2 Regular Expressions 60 3.3 Examples 62 3.4 Finite Automata and Scanners 64 3.4.1 Deterministic Finite Automata 65 3.5 The Lex Scanner Generator 69 3.5.1 Defining Tokens in Lex 70 3.5.2 The Character Class 71 3.5.3 Using Regular Expressions to Define Tokens 73 3.5.4 Character Processing Using Lex 76 3.6 Other Scanner Generators 77 3.7 Practical Considerations of Building Scanners 79 3.7.1 Processing Identifiers and Literals 79 3.7.2 Using Compiler Directives and Listing Source Lines 83 3.7.3 Terminating the Scanner 85 3.7.4 Multicharacter Lookahead 86 3.7.5 Performance Considerations 87 3.7.6 Lexical Error Recovery 89 3.8 Regular Expressions and Finite Automata 92 3.8.1 Transforming a Regular Expression into an NFA 93 3.8.2 Creating the DFA 94 3.8.3 Optimizing Finite Automata 97 3.8.4 Translating Finite Automata into Regular Expressions 100 3.9 Summary 103 3.10 Exercises 106 4 Grammars and Parsing 113 4.1 Context-Free Grammars 114 4.1.1 Leftmost Derivations 116 4.1.2 Rightmost Derivations 116 4.1.3 Parse Trees 117 4.1.4 Other Types of Grammars 118 4.2 Properties of CFGs 120 4.2.1 Reduced Grammars 120 4.2.2 Ambiguity 121 4.2.3 Faulty Language Definition 122 4.3 Transforming Extended Grammars 122 4.4 Parsers and Recognizers 123 4.5 Grammar Analysis Algorithms 127 4.5.1 Grammar Representation 127 4.5.2 Deriving the Empty String 128 4.5.3 First Sets 130 4.5.4 Follow Sets 134 4.6 Exercises 138 5 Top-Down Parsing 143 5.1 Overview 144 5.2 LL(k) Grammars 145 5.3 Recursive-Descent LL(1) Parsers 149 5.4 Table-Driven LL(1) Parsers 150 5.5 Obtaining LL(1) Grammars 154 5.5.1 Common Prefixes 156 5.5.2 Left Recursion 157 5.6 A Non-LL(1) Language 159 5.7 Properties of LL(1) Parsers 161 5.8 Parse Table Representation 163 5.8.1 Compaction 164 5.8.2 Compression 165 5.9 Syntactic Error Recovery and Repair 168 5.9.1 Error Recovery 169 5.9.2 Error Repair 169 5.9.3 Error Detection in LL(1) Parsers 171 5.9.4 Error Recovery in LL(1) Parsers 171 5.10 Exercises 173 6 Bottom-Up Parsing 179 6.1 Overview 180 6.2 Shift-Reduce Parsers 181 6.2.1 LR Parsers and Rightmost Derivations 182 6.2.2 LR Parsing as Knitting 182 6.2.3 LR Parsing Engine 184 6.2.4 The LR Parse Table 185 6.2.5 LR(k) Parsing 187 6.3 LR(0) Table Construction 191 6.4 Conflict Diagnosis 197 6.4.1 Ambiguous Grammars 199 6.4.2 Grammars that are not LR(k) 202 6.5 Conflict Resolution and Table Construction 204 6.5.1 SLR(k) Table Construction 204 6.5.2 LALR(k) Table Construction 209 6.5.3 LALR Propagation Graph 211 6.5.4 LR(k) Table Construction 219 6.6 Exercises 224 7 Syntax-Directed Translation 235 7.1 Overview 235 7.1.1 Semantic Actions and Values 236 7.1.2 Synthesized and Inherited Attributes 237 7.2 Bottom-Up Syntax-Directed Translation 239 7.2.1 Example 239 7.2.2 Rule Cloning 243 7.2.3 Forcing Semantic Actions 244 7.2.4 Aggressive Grammar Restructuring 246 7.3 Top-Down Syntax-Directed Translation 247 7.4 Abstract Syntax Trees 250 7.4.1 Concrete and Abstract Trees 250 7.4.2 An Efficient AST Data Structure 251 7.4.3 Infrastructure for Creating ASTs 252 7.5 AST Design and Construction 254 7.5.1 Design 256 7.5.2 Construction 258 7.6 AST Structures for Left and Right Values 261 7.7 Design Patterns for ASTs 264 7.7.1 Node Class Hierarchy 264 7.7.2 Visitor Pattern 265 7.7.3 Reflective Visitor Pattern 268 7.8 Exercises 272 8 Symbol Tables and Declaration Processing 279 8.1 Constructing a Symbol Table 280 8.1.1 Static Scoping 282 8.1.2 A Symbol Table Interface 282 8.2 Block-Structured Languages and Scopes 284 8.2.1 Handling Scopes 284 8.2.2 One Symbol Table or Many? 285 8.3 Basic Implementation Techniques 286 8.3.1 Entering and Finding Names 286 8.3.2 The Name Space 289 8.3.3 An Efficient Symbol Table Implementation 290 8.4 Advanced Features 293 8.4.1 Records and Typenames 294 8.4.2 Overloading and Type Hierarchies 294 8.4.3 Implicit Declarations 296 8.4.4 Export and Import Directives 296 8.4.5 Altered Search Rules 297 8.5 Declaration Processing Fundamentals 298 8.5.1 Attributes in the Symbol Table 298 8.5.2 Type Descriptor Structures 299 8.5.3 Type Checking Using an Abstract Syntax Tree 300 8.6 Variable and Type Declarations 303 8.6.1 Simple Variable Declarations 303 8.6.2 Handling Type Names 304 8.6.3 Type Declarations 305 8.6.4 Variable Declarations Revisited 308 8.6.5 Static Array Types 311 8.6.6 Struct and Record Types 312 8.6.7 Enumeration Types 313 8.7 Class and Method Declarations 316 8.7.1 Processing Class Declarations 317 8.7.2 Processing Method Declarations 321 8.8 An Introduction to Type Checking 323 8.8.1 Simple Identifiers and Literals 327 8.8.2 Assignment Statements 328 8.8.3 Checking Expressions 328 8.8.4 Checking Complex Names 329 8.9 Summary 334 8.10 Exercises 336 9 Semantic Analysis 343 9.1 Semantic Analysis for Control Structures 343 9.1.1 Reachability and Termination Analysis 345 9.1.2 If Statements 348 9.1.3 While, Do, and Repeat Loops 350 9.1.4 For Loops 353 9.1.5 Break, Continue, Return, and Goto Statements 356 9.1.6 Switch and Case Statements 364 9.1.7 Exception Handling 369 9.2 Semantic Analysis of Calls 376 9.3 Summary 384 9.4 Exercises 385 10 Intermediate Representations 391 10.1 Overview 392 10.1.1 Examples 393 10.1.2 The Middle-End 395 10.2 Java Virtual Machine 397 10.2.1 Introduction and Design Principles 398 10.2.2 Contents of a Class File 399 10.2.3 JVM Instructions 401 10.3 Static Single Assignment Form 410 10.3.1 Renaming and φ-functions 411 10.4 Exercises 414 11 Code Generation for a Virtual Machine 417 11.1 Visitors for Code Generation 418 11.2 Class and Method Declarations 420 11.2.1 Class Declarations 422 11.2.2 Method Declarations 424 11.3 The MethodBodyVisitor 425 11.3.1 Constants 425 11.3.2 References to Local Storage 426 11.3.3 Static References 427 11.3.4 Expressions 427 11.3.5 Assignment 429 11.3.6 Method Calls 430 11.3.7 Field References 432 11.3.8 Array References 433 11.3.9 Conditional Execution 435 11.3.10 Loops 436 11.4 The LHSVisitor 437 11.4.1 Local References 437 11.4.2 Static References 438 11.4.3 Field References 439 11.4.4 Array References 439 11.5 Exercises 441 12 Runtime Support 445 12.1 Static Allocation 446 12.2 Stack Allocation 447 12.2.1 Field Access in Classes and Structs 449 12.2.2 Accessing Frames at Runtime 450 12.2.3 Handling Classes and Objects 451 12.2.4 Handling Multiple Scopes 453 12.2.5 Block-Level Allocation 455 12.2.6 More About Frames 457 12.3 Arrays 460 12.3.1 Static One-Dimensional Arrays 460 12.3.2 Multidimensional Arrays 465 12.4 Heap Management 468 12.4.1 Allocation Mechanisms 468 12.4.2 Deallocation Mechanisms 471 12.4.3 Automatic Garbage Collection 472 12.5 Region-Based Memory Management 479 12.6 Exercises 482 13 Target Code Generation 489 13.1 Translating Bytecodes 490 13.1.1 Allocating memory addresses 493 13.1.2 Allocating Arrays and Objects 493 13.1.3 Method Calls 496 13.1.4 Example of Bytecode Translation 498 13.2 Translating Expression Trees 501 13.3 Register Allocation 505 13.3.1 On-the-Fly Register Allocation 506 13.3.2 Register Allocation Using Graph Coloring 508 13.3.3 Priority-Based Register Allocation 516 13.3.4 Interprocedural Register Allocation 517 13.4 Code Scheduling 519 13.4.1 Improving Code Scheduling 523 13.4.2 Global and Dynamic Code Scheduling 524 13.5 Automatic Instruction Selection 526 13.5.1 Instruction Selection Using BURS 529 13.5.2 Instruction Selection Using Twig 531 13.5.3 Other Approaches 532 13.6 Peephole Optimization 532 13.6.1 Levels of Peephole Optimization 533 13.6.2 Automatic Generation of Peephole Optimizers 536 13.7 Exercises 538 14 Program Optimization 547 14.1 Overview 548 14.1.1 Why Optimize? 549 14.2 Control Flow Analysis 555 14.2.1 Control Flow Graphs 556 14.2.2 Program and Control Flow Structure 559 14.2.3 Direct Procedure Call Graphs 560 14.2.4 Depth-First Spanning Tree 560 14.2.5 Dominance 565 14.2.6 Simple Dominance Algorithm 567 14.2.7 Fast Dominance Algorithm 571 14.2.8 Dominance Frontiers 581 14.2.9 Intervals 585 14.3 Introduction to Data Flow Analysis 598 14.3.1 Available Expressions 598 14.3.2 Live Variables 601 14.4 Data Flow Frameworks 604 14.4.1 Data Flow Evaluation Graph 604 14.4.2 Meet Lattice 606 14.4.3 Transfer Functions 608 14.5 Evaluation 611 14.5.1 Iteration 611 14.5.2 Initialization 615 14.5.3 Termination and Rapid Frameworks 616 14.5.4 Distributive Frameworks 620 14.6 Constant Propagation 623 14.7 SSA Form 627 14.7.1 Placing φ-Functions 629 14.7.2 Renaming 631 14.8 Exercises 636 Bibliography 651 Abbreviations 661 Pseudocode Guide 663 Index 667
©️2022 CSDN 皮肤主题:技术黑板 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值