本科期间发明了个编程语言,和小伙伴一起写了个编译器。
世上现有的编程语言都太破了。我要自己设计个语言,做出编译器。
来证明还可以有更破的。
Shoolang是面向过程的、静态作用域的、强类型的通用编程语言。通俗讲,就是有点像C/C++,但是少了很多的功能,以及多了很少的功能。
Shoo支持多维数组、递归、嵌套函数,可以写出大部分的基础算法。比如冒泡排序,用头等函数(first class functions)自定义比较方式,来把一堆structs排序:
还能拿去砍Leetcode题,比如解数独:
按照用户输入,画个字符画什么的:
我们有17页的语言手册【Shoo语言:从入门到放弃】:
https:// github.com/sam-jay/shoo -lang/blob/master/Language_Reference_Manual.md
作为史上最破,Shoo编译器有以下特性:
Shoo编译器由以下几个模块串在一起——
1)词法分析(scanner.mll)
将读入的ASCII码形式的源代码转化成一个个token,比如关键词、数字、字符串、运算符、括号等等。代码的注释会在这一步被舍弃。
2)语法分析(parser.mly)
把上一步产生的token,根据定义好的Shoo语法,转换成一个抽象语义树(abstract syntax tree,简称AST)。语法糖也在这一步转化。
3)语义分析(sement.ml)
遍历AST树,将其转换为SAST树。这个树的每个节点都是一个包含了多种元数据的对象(object),在后一步骤有用。
理论上不检查源代码是否符合要求也是可以的,我们可以写一个很暴躁的编译器,啥也不检查,二话不说转成二进制码,跑崩了谁写的码谁背锅。为了世界的和平,还是好好地检查错误了。
4)中间代码的转换(lift.ml)
Shoolang支持头等函数(first class functions),所以有对应的模块负责做转换。其它可能的模块有类型推断(type inference),那么再串一个模块做类型的转换。
Shoo编译器用SAST节点的元数据记录语境信息,将所有被嵌套的函数上升到全局范围的同时不改变程序表现。每个语境包含独有的变量,用关联地图(map)存储。
5)代码生成(codegen.ml)
直接对接LLVM模块,把SAST节点转成更低级的语言。这种方法的前提是,Shoo语言的源代码和LLVM代码存在token层级的一一对应关系。举个反例,「or」这个运算符在有的语言中有短路效果,于是我们舍弃了短路这个特性。
然后链接C库(builtins.c),用来辅助完成输入输出的一些功能,还有字符串相关的操作。最后输出二进制码。
关于用OCaml写编译器。OCaml定义上下文无关文法(context free grammar)方便得跟开挂一样,还可以各种调Lex和LLVM模块。
用Ocaml写也有缺点。很难学。超级烦。但是很有用。你会花很多很多的时间,写很少很少的码,来做很多很多事情。
最后,造编译器推荐看龙书(Compilers: Principles, Techniques, and Tools by Alfred V. Aho, Ravi Sethi, Jeffrey D.Ullman)。里面啥都有,除了龙。
==============================================
微博@甜菜欣欣,定期更新写码日常;
公主号「甜菜欣欣」,不定期分享写码留学找工tips~
相关回答: