当前课程知识点:Compilers Techniques > 6 Intermediate Code Generation > 6.2 Declaration Statements > 6.2 Declaration Statements
返回《Compilers Techniques》慕课在线视频课程列表
返回《Compilers Techniques》慕课在线视频列表
各位同学大家好
这节课我们继续来学习
中间代码生成
这节课我们来学习声明语句
我们看到声明语句当中
我们需要为它在符号表当中
建立条目
为它来分配存储单元
然后我们在符号表当中
需要包含这个名字的类型
以及分配给它存储单元的相对地址
需要把这些信息记录下来
我们来看一个例子
假设我们有一个文法
P→D
D→T id ; D1
D→ε
那么我们希望在这个情况下
来计算过程当中
名字的类型和相对地址
我们看到在P→D 这条语句当中
在D之前
我们可以设计一下
相对变量的地址是offset
它的相对地址等于0
在第二条语句当中
D→T id ; D1
在D1之前
我们仍然需要向符号表中写入对应的变量
以及计算它的偏移地址
我们首先看
这里涉及到一个过程enter
这个过程为名字name
来建立它的符号表条目
所以我们在D1之前
需要为id来建立符号表条目
然后我们来计算它的偏移
那么偏移offset
等于原有的偏移offset加上T的宽度
T来决定id的类型
所以T来决定了id的宽度
接下来我们可以通过改写文法
让所有的语义动作
都出现在产生式的末尾
比如说 P→D
在D之前我们发现出现了一个语义动作
offset等于0
我们可以增加一个标记非终结符M
来改写文法
将它写为 P → MD
M → ε
然后在 M→ε 这个语句之后
我们引入offset=0这个语义动作
我们再从另一个例子
学习一下声明语句对应的语义动作
应该如何加入其中
我们先看一下这个文法
P是一个过程
P→D ; S
D是一个声明语句
S是对应的程序语句
D→D ; D
然后D→id : T
也就是D可以产生一个声明id的声明
T可以产生整型、实型、数组类型
或者是指针类型
接下来我们来看一下
它的声明语句
是如何来计算名字的类型和相对地址的
首先针对第一个产生式P→D ; S
我们知道在这种情况下
相对地址应该是0
所以在D之前
我们写入offset=0
针对第三行产生式D→id : T
我们知道,这个时候
出现了一个新的变量id
所以我们使用enter这个函数
将id写入到符号表中
然后我们来计算
当前新的偏移量offset
等于原有的偏移量offset加上T的宽度
T是id的类型
接下来T→integer
那么在这种情况下
我们只需要来计算T的长度和它的类型
所以T的类型T.type
等于integer
也就是整型
T的宽度等于4
下一个产生式是 T可以产生数组类型
在这种情况下
数组元素中
每一个的类型
都和T1的类型是一样的
然后它的宽度等于
T的宽度乘以数组元素的个数
对于最后一个产生式来说
T可以产生指针T1
那么它的类型是指针类型
它的宽度是4
接下来我们通过一个实例
来学习作用域信息的保存
我们先来看一下
我们所讨论语言的文法
P→D ; S
D→D ; D | id : T | proc id ; D ; S
那么我们是以快速排序的算法为例
来学习作用域信息的保存
我们首先来看一下
这是我们构造出来的符号表实例
那么这个符号表是
如何构造出来的呢?
首先我们来学习一下
符号表的特点
每一个过程
都需要有各自的符号表
符号表之间是双向链接的
构造符号表的时候
我们需要符号表的栈
构造符号表的时候
我们也需要用到活动记录的栈
接下来我们来学习一下
语义动作所涉及到的4个函数
首先是mktable这个函数
对于这个函数来说
我们需要去新构造一个符号表
并且返回新符号表的指针
其次是enter这个函数
我们需要在符号表table当中
指向的符号表中
为变量name
来建立一个对应的新条目
接下来是addWidth
那么我们用这个函数来计算
我们需要用到的宽度
也就是在table中
指向的符号表中
所有局部变量条目的累加宽度
记录在这个符号表的首部
最后我们用enterProc这个函数
来在table中指向的符号表中
为一个过程名name建立新的条目
接下来
我们通过快速排序的这段程序
来学习一下
如何构造符号表
首先我们去扫描程序
发现最外围是sort这个函数
而sort向外的指针是空的
那么对于第一个变量a来说
我们将它记录到符号表中
需要用到enter这个函数
当然X也需要用到enter这个函数
写入到对应的符号表中
接下来我们继续来读取快速排序的程序
我们会读取到readarray这个过程
读取到这个过程之后
我们首先会使用mktable
去来构造一个新的表
然后我们会使用enterProc这个函数
将readarray写入到我们的sort符号表中
接下来我们需要继续去读取程序
我们发现接下来
我们读到的是exchange这个过程
那么对于exchange来说
它同样是一个新的过程
我们仍然需要去构造一个新的符号表
然后我们需要将exchange
这个过程写入到
我们对应的符号表中
接下来我们发现
下一个函数是quicksort
那么quicksort也需要新构造一个符号表
然后quicksor和sort之间
是具有双向链接的
继续去读取快速排序程序
我们发现quicksort当中
包含partition这个函数
那么对于partition来说
我们仍然需要构造出它对应的符号表
然后写入到quicksort这个符号表中去
接下来我们来观察一下
对应的语义动作
首先P→M D ; S
那么我们为了将所有的语义动作
都写入到产生式的末尾
我们引入了第一个标记非终结符M
M→ε
那么M→ε 对应的语义动作
是去构造一个新的符号表
t=mktable(nil);
而此时这个符号表是
一个最外围的符号表
所以它的指针为空
然后我们去进行压栈的动作
所以有两个push
一个是将当前的指针压栈
另外一个是将当前的偏移量压栈
接下来我们来看一下第5行产生式
D→id : T
那么对于这个产生式来说
我们需要将id写入符号表中
所以我们调用了enter这个函数
然后我们需要读取栈顶的元素
所以我们用了top(offset)等于top(offset)加上T的宽度
接下来我们来看一下
第4个产生式
D→proc id ; N D1 ; S
我们需要去读取栈顶的元素
然后我们需要去计算
当前的地址偏移
也就是将
之前我们所压栈的数值取出来
来计算它的宽度
接下来我们将当前的这个过程
写入到对应的符号表中去
对于最后一个产生式N→ ε
我们仍然需要去新建一个符号表
并且把它的指针
指向前一个符号表
然后我们去执行压栈的动作
接下来我们来看一下
第一个产生式对应的动作
P→M D ; S
我们在这种情况下
需要去计算它的宽度
以及需要读取栈顶元素
我们观察到在其中
N也作为一个标记非终结符
使得我们将一个语义动作
写入到N→ ε
这个产生式的末尾
这一小节就到这
谢谢大家
-1.1 Overview of Compilers Techniques
--Chapter 1 Overview of Compilers Techniques
--Overview of Compilers Techniques
-2.1 Lexical Tokens, Strings and Language
--2.1 Lexical Tokens, Strings and Language
--2.1 Lexical Tokens, Strings and Language
-2.2 Regular form
--2.2 Regular form
-2.3 Finite automata
--2.3 Finite automata
-2.4 DFA construction, Subset construction, Simpleset DFA
--2.4 DFA construction, Subset construction, Simpleset DFA
-2.5 Lex
--2.5 Lex
-3.1 Context-free Grammars
--3.1.1 The Role of the Parser
--3.1.2 The Formal Definition of a Context-free Grammar
-3.2 Writing a Grammar
--3.2.1 Elimination of Left Recursion
--3.2 Top-Down Parsing
-3.3 Languages and Grammars
--3.3 Language and Grammars
-3.4 Top-Down Parsing
--3.4.3 Recursive Descent Analysis
--3.4.4 Nonrecursive Descent Analysis
-3.5 Bottom-up Parsing
--Bottom-up Parsing
-3.6 LR Parsing
--3.6.6 Characteristics of LR Parsing
--3.6.7 Non Ambiguous and Not LR Context-Free Grammars
-4.1 Syntax-Directed Definitions
--4.1.2 Attribute Dependency Graphs and Ordering the Evaluation of Attributes
--Syntax-Directed Definitions
-4.2 Bottom-Up Calculation of S Attribute
--4.2.1 Bottom-Up Calculation of S-Attributed
-4.3 L-Attributed Definitions
--4.3.1 L-Attributed Definitions
--4.3.3 Design of Predictive Translator
--L-Attributed Definitions
-4.4 Bottom-Up Parsing of L-Attributed Translation
--4.4.1 Bottom-Up Parsing of L-Attributed Translation
--4.4.2 Simulate the Parsing of Inherited Properties
--Bottom-Up Parsing of L-Attributed Translation
-5.1 Overview
--Overview
-5.2 Global Stack Storage
-5.3 Calling Sequences
-5.4 Non Local Names
--5.4 Non Local Names and dynamic scope
--Non Local Name
-6.1 Overview of Intermediate Code Generation
--6.1 Overview of Intermediate Code Generation
-6.2 Declaration Statements
-7.1 Issues in the Design of Code Generator
--7.1 Issues in the Design of Code Generator
-7.2 Target Machine
--Target Machine
-7.3 Basic Blocks and Flow Graphs
--7.3 Basic Blocks and Flow Graphs
-7.4 A Simple Code Generator
-8.1 Demonstration of Compiler Framework based on Python
--8.1 Demonstration of Compiler Framework based on Python
-8.2 Basic
--8.2.4 SA
-8.3 SimpleJava