当前位置: 华文星空 > 知识

你写过什么有趣的程序?

2016-10-08知识

本科期间发明了个编程语言,和小伙伴一起写了个编译器。

世上现有的编程语言都太破了。
我要自己设计个语言,做出编译器。
来证明还可以有更破的。

Shoolang是面向过程的、静态作用域的、强类型的通用编程语言。通俗讲,就是有点像C/C++,但是少了很多的功能,以及多了很少的功能。

Shoo支持多维数组、递归、嵌套函数,可以写出大部分的基础算法。比如冒泡排序,用头等函数(first class functions)自定义比较方式,来把一堆structs排序:

Shoolang冒泡排序展示

还能拿去砍Leetcode题,比如解数独:

Leetcode #37 Sudoku Solver

按照用户输入,画个字符画什么的:

Shoolang生成字符画

我们有17页的语言手册【Shoo语言:从入门到放弃】:

Shoolang语言手册截图

https:// github.com/sam-jay/shoo -lang/blob/master/Language_Reference_Manual.md

作为史上最破,Shoo编译器有以下特性:

  • 垃圾回收全靠重启。遇到问题,重启试试。
  • 不支持互相递归,所以写不了Lisp解释器。
  • 不能链多个文件,所有源码要写在一个文件里。
  • 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~

    相关回答: