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 00f7670

Browse files
增加中间码和目标代码
1 parent 7d2a43f commit 00f7670

File tree

13 files changed

+1204
-243
lines changed

13 files changed

+1204
-243
lines changed

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

Lines changed: 131 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,149 @@
1+
## 微机原理
2+
### 指令:
3+
* 指令格式:操作码 [操作数] [操作数]
4+
<br/>
5+
~&emsp;操作数:执行对象。第一个操作数 :目标操作数;第二个操作数:源操作数
6+
<br/>
7+
~&emsp;[]表示可以缺省
8+
* 指令格式:
9+
<br/>
10+
~&emsp;零操作数指令:操作码
11+
<br/>
12+
~&emsp;单操作数指令:操作码 [操作数]
13+
<br/>
14+
~&emsp;双操作数指令:操作码 [操作数] [操作数]
15+
* 指令中的操作数
16+
<br/>
17+
~&emsp;立即数:是一个常数
18+
<br/>
19+
~&emsp;寄存器操作数:是一个地址,计算速度最快
20+
<br/>
21+
~&emsp;存储器操作数:是一个地址,计算速度最慢
22+
* 立即数:立即数本身是参加操作的本身,可以是8位或者16位。只能作为源操作数
23+
```
24+
mov AX,1234H
25+
mov BL,22H
26+
```
27+
* 寄存器操作数:参加运算的数存放在指令给出的寄存器中,可以是8位,16位。
28+
```
29+
mov AX,BX
30+
mov DL,CH
31+
```
32+
* 存储器操作数:
33+
<br/>
34+
~&emsp;参与运算的数据存放在存储器的某一个或两个单元中
35+
<br/>
36+
~&emsp;表现形式:【 】:方括号里面是地址(偏移地址)
37+
```
38+
MOV AL,[1200H]
39+
```
40+
41+
### 指令的寻址方式(8种):
42+
* 立即寻址
43+
```
44+
由指令直接给出运算数据。操作数为立即数
45+
MOV AX,1200H
46+
结果:AL=00H,AH=12H
47+
常数1200H存放在代码段
48+
```
49+
* 寄存器寻址
50+
```
51+
参加的操作数在CPU的通用寄存器中
52+
mov AX,BX
53+
```
54+
* 存储器操作数的寻址方式
55+
* 直接寻址
56+
```
57+
方括号里面直接是偏移地址
58+
MOV AX,[1200H]
59+
```
60+
* 寄存器间接寻址
61+
```
62+
偏移地址为通用寄存器中的内容,换句话说:偏移地址放在通用寄存器中
63+
```
64+
* 寄存器相对寻址
65+
```
66+
相对寻址主要用于一维数组的操作
67+
```
68+
* 基址,变址,相对寻址
69+
```
70+
操作数的偏移地址=基址寄存器中的数据+变址寄存器中的数据+偏移地址
71+
主要运用二维数组
72+
```
73+
* 隐含寻址
74+
```
75+
操作数在默认的地址中
76+
MUL BL
77+
指令执行:AL*BL,结果放在AX中
78+
```
79+
80+
81+
## 代码生成器
82+
83+
* 代码生成器:将优化后的三地址码转化为目标码
84+
* 目标码的三种形式:
85+
<br/>
86+
~&emsp;绝对指令代码:能够立即执行的二进制代码,所有地址已经定位
87+
<br/>
88+
~&emsp;可重新定位指令代码:待装配的机器语言模块,执行时由链接器把他们和某些程序连接起来,转换为可执行的二进制机器语言代码
89+
<br/>
90+
~&emsp;汇编指令代码:尚未经过汇编器汇编成二进制的汇编代码
91+
* 代码生成主要考虑的问题:
92+
<br/>
93+
~&emsp;如何使生成目标代码较短
94+
<br/>
95+
~&emsp;如何充分利用寄存器,减少目标代码中访问存储单元次数
96+
<br/>
97+
~&emsp;如何充分利用不同cpu指令系统的特点
198
* 代码生成器的主要任务:
2-
~ 指令选择:代码生成器将中间码转换成目标机器码。一个中间码可以有多种机器码转换,所以代码生成器负责选择指令。
3-
~ 寄存器申请:程序执行过程中可能需要保存一系列值。目标机器架构可能不允许所有的值都保存在CPU内存或寄存器。代码生成器决定寄存器保存哪些值。同样,也决定寄存器保存哪些值。
4-
~ 指令顺序:一个代码生成器决定指令执行的顺序,它创建指令调度来执行它。
99+
<br/>
100+
~&emsp;指令选择:代码生成器将中间码转换成目标机器码。一个中间码可以有多种机器码转换,所以代码生成器负责选择指令。
101+
<br/>
102+
~&emsp;寄存器申请:程序执行过程中可能需要保存一系列值。目标机器架构可能不允许所有的值都保存在CPU内存或寄存器。代码生成器决定寄存器保存哪些值。同样,也决定寄存器保存哪些值。
103+
~&emsp;指令顺序:一个代码生成器决定指令执行的顺序,它创建指令调度来执行它。
5104
* 一个目标原型非常复杂,我们不可能描述出全部细节,所以我们通常会将其简化为一个简单目标机原型。
6105
* 一个简单目标机原型:
106+
<br/>
7107
~ 加载、保存、运算、跳转等操作
108+
<br/>
8109
~ 内存按字节、寄存器、指针指向寻址或其他间接寻址
110+
<br/>
9111
~ n个通用寄存器R0,R1,....,Rn-1
112+
<br/>
10113
~ 所以运算分量都是整数
114+
<br/>
11115
~ 指令之间可能有一个标号
12116
* 目标通常一个机器指令有几十上百个指令,为了简化通常只选取一些典型指令:
117+
<br/>
13118
~ 加载指令:LD r, x
119+
<br/>
14120
~ 保存指令:ST x,r
121+
<br/>
15122
~ 运算指令:OP dst,src1,src2
123+
<br/>
16124
~ 无条件跳转指令:BR L
125+
<br/>
17126
~ 条件跳转指令: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位的位置
127+
<br/>
128+
~ 压栈操作指令:
129+
```
130+
push #1 将数字1压栈
131+
push TOP 将寄存器TOP压栈指令:压栈:
132+
push @sp 将指针sp指向的值压栈
133+
```
134+
<br/>
135+
~ 移动指令:
136+
137+
```
138+
MOVE R0,R1 将寄存器R0的值移入到R1中
139+
MOVE #1 R0 将数字1移入寄存器R0中
140+
MOVE #1 @TOP 将数字1移到寄存器指向的位置
141+
MOVE #1 @(TOP+4) 将数字1移到寄存器指向的位置基础上再加4位的位置
142+
```
143+
<br/>
25144
~ 比较指令:CMP R0,R1 比较两个寄存器中值的大小
26145
* 运算语句的三地址转目标代码:
146+
```
27147
三地址码:
28148
x=y-z
29149
目标代码:
@@ -34,6 +154,7 @@
34154
解析:优秀的代码生成器应该避免使用上面的全部4个指令,如果:
35155
1所需的分量已经在寄存器中了
36156
2运算结果不需要存放内存
157+
```
37158

38159

39160

‎src/SDT/ILGen.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
2+
export class ILGen {
3+
private static labelCounter = 1
4+
private stack: Array<Section> //section存放栈,栈顶为当前作用域
5+
private sections: Array<Section> // section列表
6+
constructor() {
7+
this.stack = []
8+
this.sections = []
9+
}
10+
//为每个作用域单独创建一个section
11+
beginSection(mark): void {
12+
const section = new Section(mark)
13+
this.sections.push(section)
14+
this.stack.push(section)
15+
}
16+
17+
//生成LB标签
18+
genLabel() {
19+
return `LB${ILGen.labelCounter++}`
20+
}
21+
22+
//解析完成时出栈
23+
endSection() {
24+
this.stack.pop()
25+
}
26+
27+
//在当前section中添加中间码数据
28+
add(code) {
29+
return this.current().add(code)
30+
}
31+
32+
//获取当前section
33+
current() {
34+
return this.stack[this.stack.length - 1]
35+
}
36+
37+
//获取当前section中栈顶中间码数据
38+
currentLine() {
39+
const section = this.current()
40+
return section.lines[section.lines.length - 1]
41+
}
42+
43+
//LB与代码行数绑定
44+
bindLabel(index, label) {
45+
const section = this.current()
46+
section.bindLabel(index, label)
47+
}
48+
49+
//将所有中间码结果打印出来,带上行号
50+
print() {
51+
for (let i = this.sections.length - 1; i >= 0; i--) {
52+
const section = this.sections[i]
53+
console.log('section:' + section.mark)
54+
for (let line of section.lines) {
55+
console.log(`${line.lineno}:${line.code}`)
56+
}
57+
}
58+
}
59+
60+
//将数组中的中间码格式化成string,带换行
61+
toText() {
62+
let text = ''
63+
for (let i = this.sections.length - 1; i >= 0; i--) {
64+
const section = this.sections[i]
65+
text += 'section ' + section.mark + '\n'
66+
for (let line of section.lines) {
67+
if (section.labels[line.lineno]) {
68+
text += section.labels[line.lineno] + ":" + line.code + '\n'
69+
} else {
70+
text += line.code + '\n'
71+
}
72+
}
73+
}
74+
return text
75+
}
76+
77+
}
78+
79+
80+
//片段
81+
class Section {
82+
private lineno //记录当前作用域中中间码代码行数
83+
public mark //作用域标识
84+
public lines //当前域的中间码
85+
public labels //LB列表
86+
constructor(mark) {
87+
this.mark = mark
88+
this.lines = []
89+
this.lineno = 0
90+
this.labels = []
91+
}
92+
93+
//LB与代码行数绑定
94+
bindLabel(index, label) {
95+
this.labels[index] = label
96+
}
97+
//将生成的中间码加入lines列表,并返回
98+
add(code) {
99+
const line = {
100+
code,
101+
lineno: this.lineno++
102+
}
103+
this.lines.push(line)
104+
return line
105+
}
106+
}
107+

‎src/SDT/LexicalScope.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
2+
export class LexicalScope {
3+
private static scopeId: number = 1
4+
private globalHash = null //存放标识符的全局hash
5+
public id = null //本作用域id索引
6+
private table = null //存储标识符属性的符号表
7+
private children = null //子作用域列表
8+
private index = null //临时标识符索引
9+
constructor(private parent?, private others?: object) {
10+
//父作用域
11+
this.parent = parent
12+
//其他数据,例如函数的实参
13+
this.others = others
14+
//不存在父作用域时,初始化标识符全局hash
15+
if (!this.parent) {
16+
this.globalHash = {}
17+
} else {
18+
//存在父作用域时,globalHash就是指向父作用域的globalHash地址
19+
this.globalHash = parent.globalHash
20+
//将本作用域加入到父作用域的children中
21+
this.parent.add(this)
22+
}
23+
this.id = LexicalScope.scopeId++
24+
this.table = {}
25+
this.children = []
26+
this.index = 0;
27+
}
28+
//添加子作用域
29+
add(subScope): void {
30+
this.children.push(subScope)
31+
}
32+
//向上寻找id的作用域
33+
public lookup(id): LexicalScope {
34+
if (id.indexOf('$') !== -1) {
35+
return this.globalHash[id]
36+
}
37+
let p:LexicalScope = this
38+
while (p) {
39+
if (p.table[id]) {
40+
return p
41+
}
42+
p = p.parent
43+
}
44+
return null
45+
}
46+
//定义临时标识符名,带上作用域id
47+
bindTempVar(type = 'number'):string {
48+
const varName = `$t` + this.index
49+
this.bind(varName, type)
50+
return varName + '@' + this.id
51+
}
52+
//标识符加入全局hash中,并指向它的作用域
53+
bind(id, type = 'number', others?) {
54+
this.globalHash[id + '@' + this.id] = this
55+
this.table[id] = {
56+
type,
57+
index: this.index++,
58+
...others
59+
}
60+
}
61+
//给词法带上作用域id
62+
getLexemeName(id) {
63+
const scope = this.lookup(id)
64+
if (scope) {
65+
return id + '@' + scope.id
66+
} else {
67+
throw `syntax error: lexeme ${id} not found.`
68+
}
69+
}
70+
//将作用域状态打印出来
71+
print(level = 0) {
72+
const pad = ''.padStart(level * 2)
73+
console.log(`${pad}scope ${this.id}\n${pad}{`)
74+
for (let key in this.table) {
75+
console.log(`${pad} ${key} : ${this.table[key].type}`)
76+
}
77+
this.children.forEach(child => {
78+
child.print(level + 1)
79+
})
80+
console.log(`${pad}}`)
81+
}
82+
//格式化数据为json
83+
toJSON() {
84+
const obj = {
85+
id: this.id,
86+
table: this.table,
87+
children: this.children.map(child => child.toJSON()),
88+
...this.others
89+
}
90+
return obj
91+
}
92+
93+
}
94+

0 commit comments

Comments
(0)

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