Skip to content

Commit 954a7d9

Browse files
committed
添加readme、demo等内容
1 parent 8719c11 commit 954a7d9

File tree

9 files changed

+112
-47
lines changed

9 files changed

+112
-47
lines changed

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

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,8 @@
4545
* 语义:语义跟文法不一样。例如文法E → E + E,表示一个表达式可以推导出另一个表达式加另另一个表达式,如表达式2+3*4可以拆成表达式2加上表达式3*4,虽然表达式都是E表示,但每个E的语义值不同,例如第一个E的语义值为14,第二个E的语义值为2,第三个E的语义值为12。
4646
* 语义分析常常跟中间代码生成一起实现,所以语法分析、语义分析、中间代码生成经常是在语法分析时候一起进行的
4747
* 语义属性:为描述语义动作,为每个文法符号赋予不同的语义属性:值、类型、地址等
48-
* 三地址表达式:表达式中最多只能出现3个地址,因为cpu无法处理4个及其以上地址的操作。可以看成是抽象语法树的一种线性表示,有如下形式:
49-
```
50-
x:=y op z
51-
x:=op y
52-
x:=y
53-
goto L
54-
if x relop y goto L或if a goto L
55-
传参、转子:param x、call p,n
56-
返回语句:return y
57-
索引赋值:x:=y[i]、x[i]:=y
58-
地址和指针赋值:x:=&y、x:=*y、*x:=y
59-
```
48+
* 三地址表达式:表达式中最多只能出现3个地址,因为cpu无法处理4个及其以上地址的操作。可以看成是抽象语法树的一种线性表示。* 三地址代码基于两个基本的概念:地址和指令。简单地说,地址就是运算分量,指令就是运算符,一个地址的表现形式可以是变量名、常量或者编译器生成的临时变量。下面是几种常见的三地址指令形式:
49+
![ir指令行事](./imgs/ir.jpg)
6050
* 为什么选择三地址的中间形式:
6151
<br/>
6252
~&emsp;三地址代码是一种线性IR。由于输入源程序及输出目标程序都是线性的,因此,线性IR有着其他形式无法比拟的优势。
@@ -124,4 +114,5 @@
124114
<br/>
125115
&emsp; 图解各种三地址码的特点1:https://blog.csdn.net/SHU15121856/article/details/104711426/
126116
<br/>
127-
&emsp; 图解各种三地址码的特点2:https://blog.csdn.net/raojun/article/details/103605349
117+
&emsp; 图解各种三地址码的特点2:https://blog.csdn.net/raojun/article/details/103605349
118+
* 要使目标代码正确执行,由上面的三地址码直接转为的目标代码还是不够的,例如在不同作用域中存在同样变量名,我们如何在运行时确定变量的存储单元。所以我们还需要知道程序执行时的上下文环境、变量的作用域等信息才能生成准确的机器码。这些知识我们将在[04_运行时刻环境](../04_运行时刻环境/README.md)中学习到,并生成正确的中间代码

03_中间代码生成/imgs/ir.jpg

76.7 KB
Loading

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
## 前言:
2-
从词法分析,到语法分析,到三地址代码生成,这个几个阶段的本质还只是对字符串的转换。而后续的主要内容是对三地址代码进行运行。将介绍计算机能执行怎样的操作,代码是怎样在机器环境中执行的。
2+
&emsp;&emsp;从词法分析,到语法分析,到三地址代码生成,这个几个阶段的本质还只是对字符串的转换,是静态编译阶段。而运行时指的是程序执行顺序、执行环境、内存动态分配等内容。
3+
</br>
4+
&emsp;&emsp;运行时刻跟编译时刻虽然是两个不同的阶段,但是由于运行时刻用到的指令是由编译器生成的,要使编译器生成正确指令,必需对程序运行时有足够的了解。
35

46
## 内容:
7+

05_目标代码生成/README.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
* 代码生成器的主要任务:
2+
~ 指令选择:代码生成器将中间码转换成目标机器码。一个中间码可以有多种机器码转换,所以代码生成器负责选择指令。
3+
~ 寄存器申请:程序执行过程中可能需要保存一系列值。目标机器架构可能不允许所有的值都保存在CPU内存或寄存器。代码生成器决定寄存器保存哪些值。同样,也决定寄存器保存哪些值。
4+
~ 指令顺序:一个代码生成器决定指令执行的顺序,它创建指令调度来执行它。
5+
* 一个目标原型非常复杂,我们不可能描述出全部细节,所以我们通常会将其简化为一个简单目标机原型。
6+
* 一个简单目标机原型:
7+
~ 加载、保存、运算、跳转等操作
8+
~ 内存按字节、寄存器、指针指向寻址或其他间接寻址
9+
~ n个通用寄存器R0,R1,....,Rn-1
10+
~ 所以运算分量都是整数
11+
~ 指令之间可能有一个标号
12+
* 目标通常一个机器指令有几十上百个指令,为了简化通常只选取一些典型指令:
13+
~ 加载指令:LD r, x
14+
~ 保存指令:ST x,r
15+
~ 运算指令:OP dst,src1,src2
16+
~ 无条件跳转指令:BR L
17+
~ 条件跳转指令:Bcond r,L
18+
~ 压栈操作指令:push #1 将数字1压栈
19+
push TOP 将寄存器TOP压栈指令:压栈:
20+
push @sp 将指针sp指向的值压栈
21+
~ 移动指令:MOVE R0,R1 将寄存器R0的值移入到R1中
22+
MOVE #1 R0 将数字1移入寄存器R0中
23+
MOVE #1 @TOP 将数字1移到寄存器指向的位置
24+
MOVE #1 @(TOP+4) 将数字1移到寄存器指向的位置基础上再加4位的位置
25+
~ 比较指令:CMP R0,R1 比较两个寄存器中值的大小
26+
* 运算语句的三地址转目标代码:
27+
三地址码:
28+
x=y-z
29+
目标代码:
30+
LD R1,y //R1=Y
31+
LD R2,z //R2=Z
32+
SUB R1,R1,R2 //R1=R1-R2
33+
ST x,R1 //X=R1
34+
解析:优秀的代码生成器应该避免使用上面的全部4个指令,如果:
35+
①所需的分量已经在寄存器中了
36+
②运算结果不需要存放内存
37+
38+
39+
40+
41+
42+
43+
44+
45+
46+
47+
48+
49+
50+
51+
52+
53+
54+
55+
56+
57+
58+
59+
60+
61+
62+
63+
64+
65+

README.md

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,28 @@
55
<br/>
66
&emsp;&emsp;理解不到位的地方还望斧正。
77

8+
9+
## 目录
10+
### [01 词法分析](./01_词法分析/README.md)
11+
### [02 语法分析](./02_语法分析/README.md)
12+
### [03 中间代码生成](./03_中间代码生成/README.md)
13+
### [04 运行时刻环境](./04_运行时刻环境/README.md)
14+
### [05 目标代码生成](./05_目标代码生成/README.md)
15+
### 源码目录结构:
16+
```
17+
src
18+
├─common 公共库
19+
├─parse 语法分析
20+
│ ├─expression.ts 表达式
21+
│ ├─exprParser.ts 表达式解析器
22+
│ │─parser.ts 语法解析器
23+
│ ├─statement.ts 陈述语句
24+
│ └─terminal.ts 终结符
25+
├─tokenizer 词法分析
26+
│ └─tokenizer.ts 词法解析器
27+
└─tsconfig.json # ts项目配置
28+
```
29+
830
## 编译器:
931
### 什么是编译器:
1032
&emsp;&emsp;编译器就是将一种编程语言转换为另一种编程语言的程序
@@ -221,25 +243,7 @@ https://www.zhihu.com/question/20004379/answer/20123641
221243
<br/>
222244
~&emsp;因为java需要经过一次JVM转机器码才能运行,所以比c、c++直接编译机器码多一道流程,所以更慢一些
223245

224-
## 目录
225-
### [01 词法分析](./01_词法分析/README.md)
226-
### [02 语法分析](./02_语法分析/README.md)
227-
### [03 中间代码生成](./03_中间代码生成/README.md)
228-
### [04 运行时刻环境](./04_运行时刻环境/README.md)
229-
### [05 目标代码生成](./05_目标代码生成/README.md)
230-
### 源码目录结构:
231-
```
232-
src
233-
├─parse 语法分析
234-
│ ├─parser.ts 语法分析器
235-
│ ├─xxx xxx
236-
│ │─xxx xxx
237-
│ ├─xxx xxx
238-
│ ├─xxx xxx
239-
│ └─xxx xxx
240-
├─tokenizer 词法分析
241-
└─tsconfig.json # ts项目配置
242-
```
246+
243247
## 参考文档:
244248
* 《编译原理》:Alfred V.Aho,机械工业出版社
245249
* 《编译原理》:哈工大·陈鄞,https://www.bilibili.com/video/BV1zW411t7YE

src/demo/parser.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Parser } from '../parser/parser'
2+
3+
const ast = new Parser().parse(`
4+
function febonacci(n) {
5+
if(n == 1 || n == 2) {
6+
return n
7+
}
8+
return febonacci(n-1) + febonacci(n-2)
9+
}
10+
var feb = febonacci(n)
11+
`)
12+
console.log('ast', JSON.stringify(ast.stmts, null, 4))

src/demo/tokenizer.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
import { Tokenizer } from '../tokenizer/tokenizer'
3+
let tokenizer = new Tokenizer('var myName = jacksplwxy + test')
4+
console.log('结果:', JSON.stringify(tokenizer.tokens,null,2))

src/parser/parser.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -213,14 +213,3 @@ export class Parser {
213213
}
214214

215215

216-
//测试
217-
const ast = new Parser().parse(`
218-
function febonacci(n) {
219-
if(n == 1 || n == 2) {
220-
return n
221-
}
222-
return febonacci(n-1) + febonacci(n-2)
223-
}
224-
var feb = febonacci(n)
225-
`)
226-
console.log('ast', JSON.stringify(ast.stmts, null, 4))

src/tokenizer/tokenizer.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,3 @@ export class Tokenizer {
285285
}
286286
}
287287

288-
//代码测试
289-
// let tokenizer = new Tokenizer('var myName = jacksplwxy + test')
290-
// console.log('结果:', tokenizer.tokens)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy