不知道你有没有想过,某种编程语言的第一个编译器是怎么来的呢?这不就是“鸡生蛋,蛋生鸡”的问题吗?
先说最后的结论:任何一种语言的第一个编译器肯定是使用其他语言写出来的。
以我们嵌入式开发中经常使用的C语言为例,我们来介绍一下第一个C语言编译器的来源。
还是让我们回顾一下C语言历史:1970年Tomphson和Ritchie在BCPL(一种解释型语言)的基础上开发了B语言,1973年又在B语言的基础上成功开发出了现在的C语言。在C语言被用作系统编程语言之前,Tomphson也用过B语言编写操作系统。
可见,在C语言实现以前,B语言已经可以投入实用了,因此第一个C语言编译器的原型完全可能是用B语言或混合B语言与PDP汇编语言编写的。
但是,B语言的效率比较低,如果全部用汇编语言来编写,不仅开发周期长、维护难度大,更可怕的是失去了高级程序设计语言必需的移植性。
所以,早期的C语言编译器就采取了一个取巧的办法:
auto enum restrict unsigned
break extern return void
case float short volatile
char for signed while
const goto sizeof _Bool
continue if static _Complex
default inline struct _Imaginary
do int switch double long typedef
else register union
auto,restrict,extern,volatile,const,sizeof,static,inline,register,typedef
,这样就形成了C的子集,C3语言,C3语言的关键字如下://共27个enum unsigned break return
void case float short char
for signed while goto _Bool
continue if _Complex default
struct _Imaginary do int switch
double long else union
unsigned,float,short,char(charisint),signed,_Bool,_Complex,_Imaginary,long
,这样就形成了我们的C2语言,C2语言关键字如下://共18个enum break return void
case for while goto continue
if default struct do int
switch double else union继续思考,即使是只有18个关键字的C2语言,依然有很多,高级的地方,比如基于基本数据类型的复合数据结构。另外,我们的关键字表中是没有写运算符的,在C语言中的复合赋值运算符->运算符等的++,--等过于灵活的表达方式此时也可以完全删除掉,因此可以去掉的关键字有:enum,struct,union,这样我们可以得到C1语言的关键字:break return void case for while
goto continue if default do int
switch double else
//共15个接近完美了,不过最后一步手笔自然要大一点。这个时候数组和指针也要去掉了,另外C1语言其实仍然有很大的冗杂度,比如控制循环和分支的都有多种表述方法,其实都可简化成一种。具体来说,循环语句有while循环,do...while循环和for循环,只需要保留while循环就够了;分支语句又有if...{},if...{}...else,if...{}...elseif...,switch,这四种形式,它们都可以通过两个以上的if...{}来实现,因此只需要保留if,...{}就够了。可是再一想,所谓的分支和循环不过是条件跳转语句罢了,函数调用语句也不过是一个压栈和跳转语句罢了,因此只需要goto(未限制的goto)。
break voidgoto int double

赵工
13488683602
zhaojh@kw.beijing.gov.cn
欢迎各公众号,媒体转载,申请加白名单秒通过
投稿/推广/合作/入群/赞助/转发 请加微信13488683602