编程语言的本质:语言只是一串字符,我们认为它是什么,它就可以是什么
编译原理在编程世界中无处不在,是我们向高级或底层开发路上不得不要逾越的一道坎。编译原理比较复杂,我们不求写出一个完整的编译器,但掌握基本原理还是很有必要的。
核心内容:自动机、上下文无关文法、自顶向下语法分析、中序转换为后序算法解决语法优先级问题、中间代码生成、运行时内存分配分析、opcode生成、计算机原理等。
理解不到位的地方还望斧正。
src
├─common 公共库
├─demo
│ │─tokenizer.ts 词法解析器demo
│ │─parser.ts 语法解析器demo
│ ├─ILGen.ts 中间码生成demo
│ └─opcodeCompiler.ts 机器码生成demo
├─parse 语法分析
│ ├─expression.ts 表达式
│ ├─exprParser.ts 表达式解析器
│ │─parser.ts 语法解析器
│ ├─statement.ts 陈述语句
│ └─terminal.ts 终结符
├─tokenizer 词法分析
│ └─tokenizer.ts 词法解析器
├─opcodeCompiler 机器码生成
│ └─opcodeCompiler.ts opcode翻译
├─SDT 语法制导翻译
│ ├─ILGen.ts 中间码生成
│ └─LexicalScope.ts 词法作用域
└─tsconfig.json ts项目配置
编译器就是将一种编程语言转换为另一种编程语言的程序
t1=inttofloat(60)
t2=id3*t1
t3=id2+t2
id1=t3
可以优化为:
t1=id3*60.0
di1=id2+t1
t1=id3*60.0
di1=id2+t1
生成汇编指令为:
LD R2, id3
MUL R2, R2, #60.0
LD R1, id2
ADD R1, R1, R2
ST id1, R1
源码: 中间码: 汇编码:
var x=1 0:x=1 0:set sp #1
function(foo(y)){ foo 1:r=nil 1:inc sp #4
return x+y 2:r=x+y 2:set sp #nil
} 3:return 3:inc sp #4
foo(100) 4:pass 100 4:add x y R
5:call foo 1 5:load R (sp-4)
6:goto (sp-8)
7:set sp #100
8:inc sp #4
9:set sp #11 (sp+4)
10:goto #1
编译器前端主要用于通过词法语法规则对语言的定义的翻译,是跟机器无关的。例如JS的语法规则在ecma-262中有详细的定义,我们便可以利用相关规则和算法进行转换。
而中间代码和机器码的生成通常是跟机器相关的,为此,掌握基本的计算机原理知识是十分必要的。本节对计算机基本知识进行了简介,并在计算机的工作原理一文中进行原理的系统介绍,它向我们展示了从人脑计算到冯诺依曼机、从晶体管到逻辑门、从物理内存到虚拟内存、从二进制到汇编码,人们是如何一步一步将人脑计算抽象到汇编码。
而我们的编译器的作用就是将代码文本一步一步编译为汇编码。
通过汇编码这个节点,便可以知道程序员编写的代码是如何被计算机理解并执行的。如此,我们的计算机知识孤岛将能够被真正连接起来。