什么是程序的执行?
程序可以看做一个函数,接受输入和返回输出?
什么是编译器?
将源程序编译成 目标程序。
代表:
- c/c++
- go
- rust
什么是解释器?
代表:
- python
- lua
混合编译器
- 中间代码更容易被翻译成目标程序、优化空间更大
- 中间语言的存在更利于编译器的实现
- 让虚拟机处理复杂的执行环境(跨平台)
代表:
- java
即时编译器(Just-in-time compiler)
- 一种提高效率的方法,中间代码不是直接执行,而是先被编译成机器码执行。
- java
交叉编译
- 在一个平台编译产生多个平台的可执行代码
不同方式优劣势
- 解释执行有性能问题,但也异常灵活,例如支持eval函数,eval 本质上 就是c语言的函数指针,将cs:ip 指向文本,这样就能将一串文本 转换成 代码了。
- 直接交叉编译技术难度是其次,跨平台问题会多;一次编译很多包也有分发问题----产品问题。
- 虚拟化技术提供更好的体验,却没有 提供更好的性能(JIT完美解决这一点)。
编译阶段
词法分析(Parser):
将字符序列转换为单词(Token)序列的过程, 分词断句 + 判断词性的过程。
给定:
var a = 5 * 6.0 + 7;
token | 词性 |
---|---|
var | 关键字 |
a | 变量 |
= | 运算符 |
5 | 整型 |
* | 运算符 |
6.0 | 浮点型 |
+ | 运算符 |
7 | 整形 |
语法分析(LEXical):
学过因为的都知道,单词不是随便都能组合的,按照"主谓宾" i eat a apple 我们可以把一句话,生成一个ast抽象语法树(Abstract Syntax Tree),用来辅助直接计算或者辅助编译器生成字节码的结构。
我们 对 这颗 AST树进行后序(左、右、上) 输出, 5、6.0 、* 、 7 、+ ,到了 这 我们 就可以很方便使用栈的数据结构模拟进行计算了。
语法 分析,可以从前往后 也可以从后往前,一般来说从前往后去解析语法比较方便,解析语法树 我们可以通过 一个表达式,
expr -> number op expr|number
上面的表达式 比较抽象, 举个例子
expr = 1 + 2 + 3 + 5 + 6
expr = 1 + expr1 = ↓
expr = 1 + 2 + expr2 =↓
expr = 1 + 2 + 3 + expr3 = ↓
expr = 1 + 2 + 3 + 5 + expr4
可以看到 expr3 = 5 + expr4 、此时 expr4 = 6 是一个number 那么,递归节结束。
上面,的例子 expr表达式 就是将 一个问题 像套娃、分形图 一样拆解成 一个数 操作符 和 另一个更小规模的expr表达式 ,这就是递归的思维 表达式的最后一层套娃是一个number。
运行时环境
- 有的编译器将代码编译成机器码,按照操作系统约定编译成一个应用,运行称为操作系统的进程.
- 有的编译器将代码编译成中间代码(字节码、三地址代码等),然后在操作系统中启动一个虚拟容器(进程)来执行他们。
- JIT编译器一边执行中间代码,一边编译他们。