用 C# 编写 C# 编译器,先有鸡还是先有蛋?

前段时间翻译了一篇文章 微软是如何重写 C# 编译器并使它开源的,文章讲了微软用 C# 重写 C# 编译器的坎坷路,引发了一些童鞋的思考:用 C# 编写 C# 编译器(Roslyn),那么 C# 编译器本身是由谁来编译的?C# 语言编写了 C# 编译器,而 C# 语言又是由 C# 编译器编译的,这不就是先有鸡还是先有蛋的问题吗?
虽然(博客园)文章下方评论中提出这类问题的人不多(注:除了公众号,我的技术文章一般也会隔天在博客园发布),但我相信有这类疑问的人肯定不少。这个问题提得很好,会产生这个疑问说明你是个善于思考的人,有思辨能力;如果你又恰好看到了我这篇文章,得到了你要的答案,那么这就是我写文章的意义。
看到童鞋们的评论,我并没有立即回复,因为这个问题确实不好回答。但作为 .NET 忠实的布道老者(请允许我装逼一回),我还是觉得有必要给大家解释一下。
首先,编译器 Roslyn 确实是自己编译自己,它的每个版本都是由该版本的上一个版本来编译的。那么 Roslyn 最初的第一个版本是由什么来编译的呢?
这里就要提到了个计算机科学中的一个概念:Bootstrapping Compiler,中文叫自举编译器。它的目的是实现自己编译自己。编译器为了达到自己编译自己的目的,它第一个版本必须由其它编程语言来实现,而它的第一个版本通常是非常简单和基础的版本。
很多编程语言发展成熟后都会用该语言本身来编写自己的编译器,比如 C# 和 Go 语言。
C# 编译器 Roslyn 的第一个版本是由其它语言来编译的。具体是什么语言我不确定,我觉得应该是用 C++ 写的(因为老的 C# 编译器用的是 C++),我还没查到,如果你知道,麻烦留言告诉我。
如果 Roslyn 的第一个版本是由 C++ 来编写的,那么 C++ 编译器的第一个版本又是由什么来编写的呢?如果不是 C 语言那很可能就是直接用机器语言来编写的了,机器语言是操作系统可以直接运行的指令,自然不需要编译器来翻译。
所以,但凡自举编译器是由高级语言来编写的,它的第一个版本一定是由其它语言来编写的,追溯它最初的祖先,一定是用机器语言来编写的。
2018-10-14 续
关于 C# 编译器 Roslyn 的第一个版本是用什么编译的,我在 Medium 留言问了 C# 语言负责人 Mads Torgersen:

他的回答是:

至此,文中的怀疑得到了确认。也就是说 Roslyn 最初的第一版是用老的 C# 编译器编译的(老的编译器是用 C++ 编写的),之后都是用 Roslyn 自己编译的。
用 C# 编写 C# 编译器,先有鸡还是先有蛋?的更多相关文章
- 编写COOL编译器
Coursera上面有Stanford的课程“Compilers”,该课程使用“龙书”作为参考书,并有一个编程项目,完成一个完整的编译器.这个编译器支持的语言称为COOL,是一个面向对象的用于教学的语 ...
- Java中关于先有鸡还是先有蛋的问题----Class&Object
在Java中,我们常常会看到一个类型:Class.并且在类似Person.class,cache.getClass()等代码中见到它的身影. 众所周知,Class是用来描述一个类的类型,而Object ...
- c++类模板之分文件编写问题及解决
我们在实际项目中一般习惯头文件(.h)和源文件(.cpp)分开写,这样做的好处良多,但是如果遇到了类模板,这样可能会有一点儿问题. 我们通过一个例子来看: person.h: #pragma once ...
- [.NET大牛之路 006] 了解 Roslyn 编译器
.NET大牛之路 • 王亮@精致码农 • 2021.07.09 维基百科对编译器的解释是:编译器是一种程序,它将某种编程语言编写的源代码(原始语言)转换成另一种编程语言(目标语言).编译是从源代码(通 ...
- Roslyn 编译器Api妙用:动态生成类并实现接口
在上一篇文章中有讲到使用反射手写IL代码动态生成类并实现接口. 反射的妙用:C#通过反射动态生成类型继承接口并实现 有位网友推荐使用 Roslyn 去脚本化动态生成,今天这篇文章就主要讲怎么使用 Ro ...
- .Net 新一代编译器 Roslyn 会带来怎样的影响?
.Net 新一代编译器 Roslyn 会带来怎样的影响? Roslyn是微软创建的一个.NET编译器平台,该项目于2014年4月3日开源. 最初 C# 语言的编译器是用 C++ 编写的,后来微软推出了 ...
- .Net内存泄露原因及解决办法
.Net内存泄露原因及解决办法 1. 什么是.Net内存泄露 (1).NET 应用程序中的内存 您大概已经知道,.NET 应用程序中要使用多种类型的内存,包括:堆栈.非托管堆和托管堆.这里我们需 ...
- YDKJS:作用域与闭包
作用域与闭包 什么是作用域 编译器 理解作用域 嵌套的作用域 词法作用域 词法分析时 欺骗词法作用域 函数与块作用域 函数中的作用域 隐藏标识符于普通作用域 函数作为作用域 块作为作用域 提升 先有鸡 ...
- 你不知道的JS之作用域和闭包(四)(声明)提升
原文:你不知道的js系列 先有鸡还是先有蛋? 如下代码: a = 2; var a; console.log( a ); 很多开发者可能会认为结果会输出 undefined,因为 var a 在 a ...
随机推荐
- python 操作RabbitMq详解
一.简介: RabbitMq 是实现了高级消息队列协议(AMQP)的开源消息代理中间件.消息队列是一种应用程序对应用程序的通行方式,应用程序通过写消息,将消息传递于队列,由另一应用程序读取 完成通信. ...
- [SRM603] WinterAndSnowmen
Description Sol 设 \(A=\text{XOR}(X)\),\(B=\text{XOR}(Y)\). 因为 \(A<B\),所以写下他们的二进制表示,一定是最高的几位先是相等,紧 ...
- 【.NET Core项目实战-统一认证平台】第十二章 授权篇-深入理解JWT生成及验证流程
[.NET Core项目实战-统一认证平台]开篇及目录索引 上篇文章介绍了基于Ids4密码授权模式,从使用场景.原理分析.自定义帐户体系集成完整的介绍了密码授权模式的内容,并最后给出了三个思考问题,本 ...
- 第61章 IdentityServer Options - Identity Server 4 中文文档(v1.0.0)
IssuerUri 设置将在发现文档和已颁发的JWT令牌中显示的颁发者名称.建议不要设置此属性,该属性从客户端使用的主机名中推断颁发者名称. PublicOrigin 此服务器实例的来源,例如http ...
- Maven(十)通过Maven缺失servlet.api的解决方式看provide(依赖范围)
1. Eclipse解决servlet.api缺失的方法参考此处 2. 通过配置pom.xml里依赖来添加servlet.api 在里面添加如下代码保存后错误立刻消失 <dependencies ...
- Java原型模式
原型模式 原型模式也称克隆模式.原型模式jian ming zhi yi,就是先创造出一个原型,然后通过类似于Java中的clone方法,对对象的拷贝,克隆类似于new,但是不同于new.new创造出 ...
- zabbix server3.4 使用mailx配置邮件报警
软件具体配置如下: 操作系统:Centos7.5 zabbix server版本:zabbix server3.4 zabbix agent版本:zabbix agent3.0 现在开始配置zabbi ...
- windows10 企业版完整激活
windows10 企业版完整激活 cmd管理员运行 1. 以管理员身份执行cmd命令,然后输入以下命令: slmgr.vbs /upk 由于Win10正式版允许在命令提示符界面使用"Ct ...
- getDimension与getDimensionPixelOffset与getDimensionPixelSize的区别
getDimension() 返回float型px值 精确 getDimensionPixelOffset() 返回int型px值 ...
- Android为TV端助力listview 非常重要的几个属性
首先是stackFromBottom属性,这只该属性之后你做好的列表就会显示你列表的最下面,值为true和false Android:stackFromBottom="true" ...