编译原理2

1 Algorithms for attribute computation

属性 定义 计算方法 Top down Bottom up
Inherited Attributes 依赖关系不是子节点指向父节点,包括父指向子或者兄弟指向兄弟 preorder function Parameter external data structure
Synthesized Attributes 该属性总是由子节点指向父节点。(先计算子节点的属性值,然后赋值给父节点) post order return value value stack

S-attributed grammar:

An attribute grammar in which all the attributes are synthesized

所有属性必须是综合属性

L-attributed Definition

  • 综合属性
  • 继承属性,依赖于父节点或者左边的兄弟节点

S属性一定是L属性的

继承属性转为综合属性:

继承属性一般出现在右子树得到值,然后传递给左子树,接着传递给叶子节点,导致了继承

1: 消除左递归,存在A-> A xxx|B 的,修改为两条:

A->BA’和A’->xxxxA’|e (左边改为右边)

2: 将出现A的式子中A后面的部分替代e。比如有S->A b,此时将A’->xxxxA’|e修改为A’->xxxxA’|b即可,然后将原来的修改为S->A

3: 将多余的非终结符消掉,比如将S->A b修改为S-> BA’

如果没有左递归,则消除右递归,需要修改的地方是:
1: A->xxx A | B 变为 A-> A’B A’-> A’xxx | e

一个右递归的例子:

decl -> type var-list
type -> int|float
var-list -> id,var-list|id

消除右递归:var-list -> v’ id
v’->v’ id, | e
替换e: v’->v’ id, | type
消除var-list: decl -> v’ id
v’->v’ id, | type

2 The symbol table

画Symbol table:

1: 每个节点有三个元素:类型,名称,指向下一个节点的指针

2: 执行到第i句话开始,则从i句话开始往前找,依次按照列表往下画
这是因为symbol table插入是插入到头上的,因此必须从后面开始找

如果遇到块语句(封闭的大括号),则里面声明的变量直接跳过。

3 Data types and type checking

各种等价
Structural equivalence two types are the same if and only if they have the same structure
Name equivalence type and name is same
Declaration equivalence 显示声明了t1=t2

4 Active Record, Stack-based runtime environment

control link:指向调用该函数的函数的AR

Access link: 指向定义该函数的AR,第一个AR没有access link,

函数的定义在函数体之外,比如

program nonlocalRef;
procedure p;
	var n: integer;
	//函数定义,和局部变量一样
	procedure q;
	begin
		(* a reference to n is 
		now non-local and 
		non-global *)
	end; (*q*)
	
	procedure r(n:intege r);
	begin
		q;
	end; (*r*)

//这里是p函数的函数体定义
begin (* p*)
	n :=1;
	r(2);
end; (*p*)

//这里是主函数
begin (*main*)
	p;
end.

fp:指向当前的AR

sp:指向堆栈顶部

在栈中的顺序:参数,之前的fp,返回地址,函数内部局部变量

在这里插入图片描述

5 Parameter passing mechanisms

Pass by Value:

1: 将值拷贝到函数栈中进行计算,
2: 在函数中修改的值不影响外部的值

Pass by Reference:

1: 将值的地址进行传递,因此对变量的变化会反应到函数外部
2: 如果同一个变量传入两次,则对它们的操作是叠加的

Pass by Value-Result:

1: 对变量值的修改不是实时的,而是只在返回之前将对应的变量的值拷贝到参数中去。

int y; 
calling_procedure() 
{
    
    
   y = 10;     
   copy_restore(y); //l-value of y is passed
   printf y; //prints 99 
}
copy_restore(int x) 
{
    
         
   x = 99; // y still has value 10 (unaffected)
   y = 0; // y is now 0 
   //在这里把x的值拷贝到了y的地址中(传进来的是y的地址)
}
void p(int x, int y) {
    
    
	x++; //此时x=2, a[0] = 1
	y++; //此时y=2, a[0] = 1
	//将x拷贝到a[0], a[0] = 2
	//将y拷贝到a[0], a[0] = 2
}

int main() {
    
    
	int a[2] = {
    
    1, 1};
	p(a[0], a[0]);
}

Pass by name:

1: 将函数体拷贝到main中,然后将参数文本替代

void p(int x, int y) {
    
    
	x++; 
	i++;
	y++; 
}

int i  = 0;
int main() {
    
    
	int a[2] = {
    
    1, 1};
	p(a[i], a[i]);
	printf("%d %d", a[0], a[1]);
}

执行过程为:

int i = 0;
int main() {
    
    
	int a[2] = {
    
    1, 1};
	//将p函数体文本拷贝到main中
	a[i]++;
	i++;
	a[i]++;
	printf("%d %d", a[0], a[1]); //结果是2 2
}

猜你喜欢

转载自blog.csdn.net/HGGshiwo/article/details/124903332
今日推荐