西安电子科技大学编译原理04-4
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
13
<1> 值调用 实参的特点: 任何可以作为右值的对象均可作为实参 参数传递和过程内对参数的使用原则: 1. 过程定义时形参被当作局部量看待,并在过程内部为形 参分配存储单元; 2. 调用过程前,首先计算实参并将其值(实参的右值)放 入形参的存储单元; 3. 过程内部对形参单元中的数据直接访问。 调用时: 调用中: 定义时: 返回后: f(a,b)过程内 f(x,y)过程外 f(a,b)过程内 f(x,y)过程外 x 1 a ? x 1 a y 2 b ? y 2 b
6
例 声明的语法制导翻译: <2> 变量声明的语法制导翻译(续3) a : array [10] of int; x : int
D3
D1
a : T2
;
x
D2
: T3
a x
符号表 array(10,integer) integer
0 40
array
[
10 ]
of
T1
int
(1)D→D;D int (2)D→id:T {enter(id.name, T.type, offset); offset:=offset+T.width;} (3)T→int {T.type:=integer; T.width:=4;} (4)T→real {T.type:=real; T.width:=8;} (5)T→array [num] of T1 {T.type:=array(num.val, T1.type); T.width:=num.val*T1.width;} (6)T→^T1 {T.type:=pointer(T1.type); T.width:=4;}
7
D3 D1 a : T2 ; x
<2> 变量声明的语法制导翻译(续4)
D2 : T3 int
array [ 10 ] of T1 int
序号 归约使用的产生式 语义处理结果 (1) T1→int T1.type=integer T1.width=4 (2) T2→array[num]of T1 T2.type=array(10,integer) T2.width=10*4=40 (3) D1→id:T2 enter(a,array(10),0) offset=40 (4) T3→int T3.type=integer T3.width=4 (5) D2→id:T3 enter(x,integer,40) offset=44
5
<2> 变量声明的语法制导翻译(续2) (b) 填写符号表信息的语法制导翻译
1. 全局量offset:记录当前符号存储地址(偏移量,初值设为0) 2. 属性.type和.width:变量的类型和所占据的存储空间大小 3. 过程enter(name, type, offset):为type类型的变量name 建立符号表条目,并为其分配存储空间(位置)offset 4. array(n,type)生成数组类型,pointer(type)生成指针类型 (1)D→D;D (2)D→id:T {enter(id.name, T.type, offset); offset:=offset+T.width;} (3)T→int {T.type:=integer; T.width:=4;} (4)T→real {T.type:=real; T.width:=8;} (5)T→array [num] of T1 {T.type:=array(num.val, T1.type); T.width:=num.val*T1.width;} (6)T→^T1 {T.type:=pointer(T1.type); T.width:=4;}
值调用的特点: 过程内部对参数的修改,不影响作为实参的变量原来的值。
14
值调用举例: program reference ( input, output); var a, b : integer;
<1> 值调用(续1)
procedure swap(x, y : integer); var temp : integer; begin temp:=x; x:=y; y:=temp end; begin a:=1; b:=2; swap(a, b); writeln('a=', a); writeln('b=', b) end. 运行结果: a=1 b=2
12
4.5.3.2 参数传递
1. 形参与实参 • 声明时的参数称为形参(parameter或formal parameter) • 引用时的参数称为实参 (argument或actual parameter) 2. 常见的参数传递形式:(不同的语言提供不同的形式) • 值调用(call by value) • 引用调用(call by reference) • 复写-恢复(copy-in/copy-out) • 换名调用(call by name) 参数传递方法的本质区别: 实参是代表左值、右值、还是实参本身的正文。
4
<2> 变量声明的语法制导翻译(续1) T → array [num] of T (5)
此文法可以声明多维数组,如数组A的声明形式可以是: A : array [d1] of A2 : array [2] of array [d2] of array [3] of int ... array [dn] of int 此多维数组以行为主存储。 因为: 第一维是有d1个元素的一维数组, 每个元素又是一个n-1维的数组; 依此类推。
4.5 声明语句的翻译
• 声明语句的作用是为可执行语句提供信息,以便于 其执行。 • 对声明语句的处理,主要是将所需要的信息正确地 填写进合理组织的符号表中。
1
4.5.1 变量的声明 <1> 变量的类型定义与声明
类型定义:为编译器提供存储空间大小的信息 变量声明:为变量分配存储空间 组合数据的类型定义和变量声明: 定义与声明在一起,定义与声明分离。
3
<2> 变量声明的语法制导翻译 (a) 变量声明的文法: D → D ; D (1) | id : T (2) T → int (3) | real (4) | array [num] of T (5) | ^T (6)
G4.5
产生式(5)是数组类型的声明,其中的数组元素个数由num 表示,如num可以是5或10等,这是一个简化了的表示方法,它 等价于1..5或1..10。 产生式(6)是指针类型的声明,其宽度(大小)是一个常量。 数组元素的类型和指针所指对象的类型可以是任意合法类型。
11
பைடு நூலகம்
4.5.3.1 左值与右值
(1) (2) (3) const two = 2; -- 声明一个值为2的常量two x : integer; -- 声明一个类型为整型数的变量x function max(a, b : integer) return integer; -- 声明一个返回值类型是整型数的函数max (4) x := two; -- 赋值句执行后,x当前值为2 (5) x := two + x; -- 赋值句执行后,x当前值变为4 (6) x := max(two,x)+x; -- 赋值句执行后,x当前值变为8 (7) 4 := x; -- 字面量不能作为左值 (8) two := x; -- 常量不能作为左值 (9) max(two,x) := two; -- 函数返回值不能作为左值 (10) x+two := x+two; -- 表达式的值不能作为左值
9
4.5.3 过程的定义与声明(续) 例:Ada过程 定义: procedure swap(x,y:in out integer) -- 规格说明 is -- 过程体开始 temp : integer; -- 体中的声明 begin temp := x; x := y; y := temp; -- 可执行语句 end swap; -- 过程体结束 声明与调用: procedure swap(x, y: in out integer); -- 过程声明 swap(a, b); -- 过程调用
调用时: f(x,y)过程外 x 1 y 2
调用中: f(a,b)过程内 a &x 3 b &y 5
返回后: f(x,y)过程外 x 3 y 5
引用调用的特点: 过程内部对形参的修改,实质上是对实参的修改。
17
引用调用举例: 值调用举例: program reference ( input, output); var a, b : integer;
16
<2> 引用调用
实参的特点:必须是左值。 参数传递和过程内对参数的使用原则: 1. 定义时形参被当作局部量看待,并在过程内部为形参 分配存储单元; 2. 调用过程前,将作为实参的变量的地址放进形参的存 储单元; 3. 过程内把形参单元中的数据当作地址,间接访问。
定义时: f(a,b)过程内 a b
<2> 引用调用(续1)
procedure swap( var x, y : integer); var temp : integer; begin temp:=x; x:=y; y:=temp end; begin a:=1; b:=2; swap(a,b); writeln('a=', a); writeln(' end.
运行结果: a=2 b=', b) b=1
18
<2> 引用调用(续2)
等价的C++程序 // ---------- 引用调用参数传递的演示程序 #include <iostream> using namespace std; void swap(int & x, int & y) { int temp; temp=x; x=y; y=temp; } void main () { int a = 1, b = 2; cout<<"before: a="<<a<<" b="<<b<<endl; swap(a, b); cout<<"after: a="<<a<<" b="<<b<<endl; } 执行该程序
8
4.5.3 过程的定义与声明
1.过程(procedure): 过程头(做什么) + 过程体(怎么做); 函 数: 有返回值的过程 主程序: 被操作系统调用的过程/函数
2.过程的三种形式:过程定义、过程声明和过程调用。 过程定义:过程头+过程体; 过程声明:过程头;
• • 本节重点讨论过程的规格说明、过程体中的声明的处理 本节将过程定义和过程声明统称为过程声明。
1. 简单数据类型的存储空间是预先确定的,如int可以占4 个字节,double可以占8个字节,char可以占1个字节 等。 2. 组合数据类型变量的存储空间,需要编译器根据程序 员提供的信息计算而定。
2
<1> 变量的类型定义与声明 (续) 例:在Pascal程序中的类型定义与变量声明: 先定义后声明: type player = array[1..2] of integer; matrix = array[1..24] of char; var c, p : player; winner : boolean; display : matrix; movect : integer; 定义与声明同时: var c, p : array[1..2] of integer; display : array[1..24] of char;
15
<1> 值调用(续2)
等价的C++程序 // ---------- 值调用参数传递的演示程序 #include <iostream> using namespace std; void swap(int x, int y) { int temp; temp=x; x=y; y=temp; } void main () { int a = 1, b = 2; cout<<"before: a="<<a<<" b="<<b<<endl; swap(a, b); cout<<"after: a="<<a<<" b="<<b<<endl; } 执行该程序
先声明后引用原则 • 若过程定义出现在对它的引用之后或引用时看不到的地方,则 必须在调用前先声明该过程。 • 若引用前已出现定义,则声明可省略,因为定义已包括了声明。
10
4.5.3.1 左值与右值
直观上,出现在赋值号左边和右边的量分别称为 左值和右值; 如 C 语句: a = b 实质上,左值必须具有存储空间,右值可以仅是 一个值,而没有存储空间。 形象地讲,左值是容器,右值是内容。