Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit a37423e

Browse files
补充中间代码内容
1 parent 31253c1 commit a37423e

File tree

3 files changed

+132
-28
lines changed

3 files changed

+132
-28
lines changed

‎03_中间代码生成/README.md‎

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
2+
* IR:中间语言。它独立于机器,复杂性介于源码与机器码之间
3+
* ILGen:(Intermediate Code/Language Generator)中间代码生成
4+
* 解释器通常不生成中间码,而是直接计算结果。编译器会生成中间码,例如Java字节码
5+
* 中间代码的设计要求:与机器无关、利于优化、利于目标代码的生成
6+
* 中间码的作用:
7+
<br/>
8+
~&emsp; 易移植:与机器无关,所以它作为中间语言可以为生成多种不同型号的目标机器码服务
9+
<br/>
10+
~&emsp; 机器无关优化:对中间码进行机器无关优化,利于提高代码质量
11+
<br/>
12+
~&emsp; 层次清晰:将AST映射成中间代码表示,再映射成目标代码的工作分层进行,使编译算法更加清晰
13+
* 编译器所使用的IR可以有很多种形式。就其"形状"而言,可以分为:
14+
<br/>
15+
~&emsp;基于图
16+
<br/>
17+
~&emsp;基于线性代码
18+
<br/>
19+
~&emsp;基于图与线性代码混合
20+
* 基于图的IR,常见的情况有:
21+
<br/>
22+
~&emsp;基于树
23+
<br/>
24+
~&emsp;基于DAG(有向无环图)
25+
<br/>
26+
~&emsp;基于一般图
27+
* 基于线性代码的IR,常见的情况有:
28+
<br/>
29+
~&emsp;三地址代码(四元组)
30+
<br/>
31+
~&emsp;二地址代码(三元组)
32+
<br/>
33+
~&emsp;零地址代码
34+
* 基于图与线性代码混合的IR:
35+
<br/>
36+
~&emsp;最常见的情况是控制流图(CFG)用图表示
37+
<br/>
38+
~&emsp;而CFG的每个节点是基本块,每个基本块里的代码是线性代码
39+
* 三地址表达式:表达式中最多只能出现3个地址,因为cpu无法处理4个及其以上地址的操作。可以看成是抽象语法树的一种线性表示,有如下形式:
40+
```
41+
x:=y op z
42+
x:=op y
43+
x:=y
44+
goto L
45+
if x relop y goto L或if a goto L
46+
传参、转子:param x、call p,n
47+
返回语句:return y
48+
索引赋值:x:=y[i]、x[i]:=y
49+
地址和指针赋值:x:=&y、x:=*y、*x:=y
50+
```
51+
* 为什么选择三地址的中间形式:
52+
<br/>
53+
~&emsp;三地址代码是一种线性IR。由于输入源程序及输出目标程序都是线性的,因此,线性IR有着其他形式无法比拟的优势。
54+
<br/>
55+
~&emsp;相对于其他表示形式而言,程序员对于线性表示形式通常会有一种莫名的亲切感,编译器设计者当然也不例外。早期编译器设计者往往都是汇编语言程序设计的高手,可以非常自然、流畅地阅读线性的三地址代码形式。同时,线性表示形式也会降低输入输出的实现难度。
56+
* 中间码生成:按深度优先遍历AST,每个节点生成一个临时变量
57+
* 左值和右值:等号左边和右边的区别。数字1只有右值,变量可以有左值和右值
58+
* BinaryExpr:op左右都有值的称为BinaryExpr
59+
* UaryExpr:op只有右值,没有左值的称为UnaryExpr。例如一个表达式
60+
* 任何一个非叶子节点都能生成一个左值和一个右值,右值是一个表达式例如100+200,左值是一个临时变量例如t1,完整:t1=100+200
61+
* Duck Type:鸭子类型。非鸭子类型语言生成左值时需要判定左值类型是否支持生成左值
62+
* 三地址代码实例1:
63+
源码:
64+
```
65+
var a=1
66+
var b=5
67+
var c=(a+b)*5
68+
```
69+
转换为三地址码如下:
70+
```
71+
declare a
72+
declare b
73+
declare c
74+
a=1
75+
b=5
76+
t1=a+b
77+
t2=t1*5
78+
c=t2
79+
```
80+
转换为OPCode:
81+
```
82+
alloc a
83+
set a #1
84+
alloc b
85+
set b #5
86+
alloc t1
87+
....
88+
```
89+
分析:实例展示了从js源码到三地址码,再到机器码的过程,可以看到三地址码的每行代码永远只存在三个变量。以上只需要按深度优先遍历AST,每个节点生成一个临时变量即可生成。
90+
* 三地址表达式实例2:
91+
源码:
92+
```
93+
function f(n){
94+
if(n==1 || n==2){
95+
return n
96+
}
97+
return f(n-1)+f(n-2)
98+
}
99+
f(5)
100+
```
101+
转换为三地址码如下:
102+
```
103+
declare f
104+
declare n
105+
t1=n==1
106+
t2=n==2
107+
t3=t1 or t2
108+
branch t3==true
109+
goto (return n)行 or (return f(n-1)+f(n-2))行 //return怎么处理??
110+
t4=n-1
111+
t5=f(t4) //如何递归??
112+
t6=n-2
113+
t7=f(t6) //如何递归??
114+
t8=t5+t7
115+
call f //调用函数如何表示??
116+
```
117+
* 文档:
118+
<br/>
119+
&emsp; 中间码简介:https://www.jianshu.com/p/2862623af39e
120+
<br/>
121+
&emsp; 中间码的形式:https://www.hashcoding.net/2015/12/10/%E5%85%AD%E3%80%81%E4%B8%AD%E9%97%B4%E4%BB%A3%E7%A0%81-IR/
122+
<br/>
123+
&emsp; 中间码的设计:https://book.51cto.com/art/201206/340208.htm
124+
<br/>
125+
&emsp; 图解各种三地址码的特点1:https://blog.csdn.net/SHU15121856/article/details/104711426/
126+
<br/>
127+
&emsp; 图解各种三地址码的特点2:https://blog.csdn.net/raojun/article/details/103605349

‎04_运行时刻环境/README.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
## 前言:
2+
从词法分析,到语法分析,到三地址代码生成,这个几个阶段的本质还只是对字符串的转换。而后续的主要内容是对三地址代码进行运行。将介绍计算机能执行怎样的操作,代码是怎样在机器环境中执行的。
3+
4+
## 内容:

‎README.md‎

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -65,39 +65,12 @@
6565
&emsp;&emsp;中间码存在的另外一个价值是提升后端编译的重用,比如我们定义好了一套中间码应该是长什么样子,那么后端机器码生成就是相对固定的。每一种语言只需要完成自己的编译器前端工作即可。这也是大家可以看到现在开发一门新语言速度比较快的原因。编译是绝大部分都可以重复使用的。
6666
<br/>
6767
&emsp;&emsp;而且为了接下来的优化工作,中间代码存在具有非凡的意义。因为有那么多的平台,如果有中间码我们可以把一些共性的优化都放到这里,可使程序的结构在逻辑上更为简单明确,特别是可使目标代码的优化比较容易实现中间代码,即为中间语言程序,中间语言的复杂性介于源程序语言和机器语言之间。
68-
* 编译器所使用的IR可以有很多种形式。就其"形状"而言,可以分为:
69-
<br/>
70-
~&emsp;基于图
71-
<br/>
72-
~&emsp;基于线性代码
73-
<br/>
74-
~&emsp;基于图与线性代码混合
75-
* 基于图的IR,常见的情况有:
76-
<br/>
77-
~&emsp;基于树
78-
<br/>
79-
~&emsp;基于DAG(有向无环图)
80-
<br/>
81-
~&emsp;基于一般图
82-
* 基于线性代码的IR,常见的情况有:
83-
<br/>
84-
~&emsp;三地址代码(四元组)
85-
<br/>
86-
~&emsp;二地址代码(三元组)
87-
<br/>
88-
~&emsp;零地址代码
89-
* 基于图与线性代码混合的IR:
90-
<br/>
91-
~&emsp;最常见的情况是控制流图(CFG)用图表示
92-
<br/>
93-
~&emsp;而CFG的每个节点是基本块,每个基本块里的代码是线性代码
9468
* 编译器后端:即三地址表达式运行时环境(虚拟机)
9569
* 编译器执行流程简述:(Java、Node、C、C++)
9670
<br/>
9771
~&emsp;AST → 中间代码 → 代码生成(二进制或汇编指令)
9872
<br/>
9973
~&emsp;AST → 中间代码 → 字节码
100-
10174
* 代码优化:对三地表达式进行优化,提高用户的执行速度。例如:
10275
```
10376
t1=inttofloat(60)
@@ -264,5 +237,5 @@ src
264237
│ ├─app.json # 全局配置
265238
│ └─app.wxss # 全局样式
266239
├─tokenizer 词法分析
267-
└─project.config.json # 项目配置
240+
└─tsconfig.json # ts项目配置
268241
```

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /