乍听之下,不无道理;仔细揣摩,胡说八道

0%

上一篇文章中,jjcc2函数实现了对setq这个语句的编译。这么一来,便可以将加减乘除运算中的嵌套表达式都替换为变量了。比如,将

1
(+ (+ 1 2) 3)

中的嵌套的表达式(+ 1 2)用一个变量G564代替,变成

阅读全文 »

Common Lisp中的setq类似于其它语言中的赋值语句,它可以给一个符号对象设定一个值,类似于将一个值赋值给一个变量一样。简单起见,在jjcc2中,我会将所有的符号都作为全局的一个label来实现。也就是说,如果代码中出现了

1
(setq a 1)

这样的代码,那么在最后生成的代码中,就会相应的在.data段中有一个同名的label,其中存放着数值1。

既然都是全局变量,那么只需要准备一个容器来盛这些变量名即可。现阶段,暂时认为所有的变量都是数值类型即可。简单起见,这个容器直接用Common Lisp内置的HASH-TABLE来表示。

阅读全文 »

progn是什么玩意

progn是Common Lisp里面的一个special operator,见这份文档的说明:http://clhs.lisp.se/Body/s_progn.htm

为嘛要编译这东西

现在已经支持了二元四则运算了,但现在这里有一个大问题,就是这四个运算没办法嵌套着组合使用。比如,遇到下面这样的代码,jjcc2函数就懵逼了

1
(+ 1 (+ 2 3))

那要编译这种代码的话怎么办呢?一个比较直观的做法,是引入临时变量,来保存嵌套在其中的表达式的求值结果,然后再用变量来代替原本嵌套的表达式。修改后的代码可能长这个样子

1
2
(setq a (+ 2 3))
(+ 1 a)

显然,这是有先后的时间依赖关系的两条语句,因此应当使用progn将它们包裹起来,结果如下

1
2
3
(progn
(setq a (+ 2 3))
(+ 1 a))

这样整个表达式的求值结果,或者说它被编译之后的运行结果,应当就是在寄存器EAX中放入整数6了。所以,本篇将来解决对progn的编译问题。

如何编译progn

阅读全文 »

上一篇文章中,初步搭建了一个输入Common Lisp代码,输出汇编代码的编译器的骨架,实现了二元整数的加法运算。在这个基础上,要想实现减法、乘法,以及除法就是手到擒来的事情了。只需依葫芦画瓢,补充更多的分支情况即可。

我自己模仿着x64的调用约定,规定四则运算的结果始终放在EAX这个寄存器中。在稍后给出的代码中,对于减法和除法运算,都是把运算符的左操作数放到EAX寄存器中,再从EAX中减去或者除掉右操作数。

在摸索除法的汇编代码怎么生成时,遇到了个费解的问题,最后才知道,原来需要把EAX寄存器的符号扩展到高位的EDX寄存器中去。对于as这个汇编器来说,需要用到CLTD指令。

最后,jjcc2stringify两个函数被修改为如下的样子

阅读全文 »

最近开始重新用起了Evernote,当然还有Leanote,不过不算是“重新“而已。这两者各有各的优缺点,下面分别列举一下

Evernote的优缺点以及和Leanote的对比

Evernote可以比较灵活地调整文字的字号,如下图所示

image-20190515124117460

阅读全文 »