Nov 17

 

编译原理:
 
        lexical analyze -> syntax analyze  -> build Abstruct Syntax Tree -> convert 
AST to  Concreat Syntax Tree -> Generating  "register reallocate" intermediate  
language -> Generating NATIVE assembly -> native machine code -> executable 
object .
 
为了学习编译原理, 找了个简单的语言编写编译器. 我选择了 QBASIC 这个人人都会的语言.
 
QBASIC 曾经有编译器, 在 16位时代的时候. 到了 32位时代, BASIC 语言就进入脚本行列, 解释执行
了. 到64位时代嘛 .. ... 恩恩, 没有编译器了. 解释器还算是有开源的几个.
 
QBASIC 语言漂亮,优雅别致. 简单易学. 大家不用它的原因无外忽无法和C 和谐共存. 而无法和C和谐
的原因很简单: 不是编译为本机代码.
 
所以, 我决定开始写一个QBASIC编译器, 能利用现代硬件, 利用上现代意义的优化能力的编译技术来
为 QBASIC 加速!
 
QBASIC 比 Go 语言简单多了, 如果能用编译解决效率问题, 自然打败Go不在话下.
 
幸运的是我们有 LLVM . 我只需要写个前端就可以了. 生成平台汇编的事情全权交给 llvm 打理了.
So, 这就是我的想法, 经过5 天紧张的开发, 已经实现基本功能了.
 
有人说我又写一个编译器, 是个国际笑话, so , 主题就如此了.
 
 
在这里宣布这样的事情是因为觉得可能找到共同兴趣的人能一起研究开发编译器.
 
我设定了3个目标:
 
        1 实现完整的 QBASIC 语言. 至少是除了不建议使用的功能, 其他都要实现.
 
        2 实现和C的无缝集成. 我将 BASIC 的函数调用约定设定为和C语言一致来解决这个问题. 因为是本
机码, 所以使用外部库的任务和C语言一样,交给链接器完成. 使用动态链接库不需要语言和运行时本
身的任何支持. 
 
        3 进行未来方向的语言扩展.
 
 
最后, 最重要的, show me the code 
请移步访问 https://github.com/microcai/llvm-qbasic
 
 
实现方面的细节考虑:
1)      QBASIC 支持数组, 数组的下标可以在定义的时候设定起始点. 第二, 数组自动扩展
        实现办法: [1] 数组实现为一个 STL 容器. 对下标的访问由编译器自动转化为对 operator [] 的调用.
operator 函数由编译器自动生成. [2] 内置类型的operator则由运行时实现. 以便进行快速实现更好
的算法 [2] 变量离开作用域后要自动调用构析函数释放资源. 这样数组才不会导致内存泄漏.
 
2) 字符串. QBASIC 的字符串是内置类型. 字符串可以进行很多操作. 内存自动管理. 字符串可以做 + 
法和比较运算.
        实现办法: 字符串实际上为一个结构体, 由运行时库实现. 编译器自动插入对运行时的调用来完成
字符串操作. 字符串离开作用域要自动调用释放函数释放内存
 
3) PRINT/INPUT 语句. 和C不一样, BASIC 把 IO 操作内置为语言的一部分.
        到目前为止我的编译器已经实现了部分的 PRINT 指令. 对打印到屏幕的PRINT语句直接转化为对
printf的操作. 这样一个不使用字符串,不输出到文件的QBASIC程序, 编译后将只依赖 C 运行时.
        PRINT 有个可选的参数 #(数字) , 表示打印到数字指示的文件中. 这个必须由运行时来完成了.
 
 
4) 所有的运行时我都放到了  libbrt -   the qBasic RunTime library  -里了. 目前为止没有任何实现. 运
行时默认将采取静态链接的方式. 对于生成脱离运行时的程序非常有用.