编译原理与技术 运行环境 2018/11/24 《编译原理与技术》-运行环境.

Slides:



Advertisements
Similar presentations
第七章 运行时刻环境 赵建华 南京大学计算机系.
Advertisements

6.3 非局部名字的访问 本节介绍 无过程嵌套的静态作用域(C语言) 有过程嵌套的静态作用域(Pascal语言) 动态作用域(Lisp语言)
第8章 函数 信息管理系.
孟宁 电话: 主页:
计算机体系结构 应用程序 软件 操作系统 编译器 固件 指令集 输入输出 CPU 硬件 内存 (I/O) 集成电路 元件,逻辑门.
Oracle数据库 Oracle 子程序.
新世代計算機概論 第14章 程式語言.
本章内容: 中断的概念 MCS-51单片机中断系统 外部事件中断及应用
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
第9章 运行时的存储组织 重点:符号表的内容、组织,过程调用实现, 难点:参数传递,过程说明语句代码结构,
Using C++ The Weird Way Something about c++11 & OOP tricks
EBNF与操作语义 请用扩展的 BNF 描述 javascript语言里语句的结构;并用操作语义的方法描述对应的语义规则
Introduction to the C Programming Language
4.3函数 4.3.1函数的概念及定义 1、函数的概念: 可以被其它程序调用具有 特定功能的一段相对独立的 程序(模块),称函数。
第一章 C语言概述.
第八章 函数 §8.1 概述 一个较大程序一般分为若干个程序模块,每一个模块实现一个特定的功能。所有的高级语言中都有子程序的概念,在C中子程序就是函数。 一个C程序可由一个主函数和若干个函数构成,由主函数调用其它函数,其它函数也可以相互调用.
授课老师:龚涛 信息科学与技术学院 2017年3月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
陳維魁 博士 儒林圖書公司 第七章 參數的傳遞 陳維魁 博士 儒林圖書公司.
C语言程序设计基础 刘新国.
编译原理与技术 第6章 运行时存储空间的组织和管理 6学时.
第六章 运行时存储空间的组织和管理 术语 本章内容 讨论一个活动记录中的数据布局 程序执行过程中,所有活动记录的组织方式 过程的活动
第7章 函 数 本章要点: C语言程序结构和特点 函数的定义 函数的返回值与函数的类型 函数的调用及参数的传递关系 函数的嵌套与递归
管理信息结构SMI.
走进编程 程序的顺序结构(二).
辅导课程六.
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
Chap 5 函数 5.1 计算圆柱体积 5.2 使用函数编写程序 5.3 变量与函数.
Online job scheduling in Distributed Machine Learning Clusters
本节内容 模拟线程切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
逆向工程-汇编语言
动态规划(Dynamic Programming)
3 变量访问环境 临时变量区 变量访问环境 机器状态 返回值 Size InitOff 过程层数 top 堆区空间 栈区空间 静态区空间
第七章 函数 西安工程大学.
第八章 运行时存储空间的组织与管理 目标程序运行时的存储结构 过程活动记录和运行时栈 变量访问环境 是CPU能直接寻址的存储空间.
《编译原理与技术》 期末复习 计算机科学与技术学院 郑启龙 李 诚 25/12/2018.
第七章 操作符重载 胡昊 南京大学计算机系软件所.
第8章 函 数 一、函数与调用约定 二、函数的总体概念.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C语言程序设计 主讲教师:陆幼利.
EBNF与操作语义 请用扩展的 BNF 描述 javascript语言里语句的结构;并用操作语义的方法描述对应的语义规则
$9 泛型基础.
第 3 章、組合語言 作者:陳鍾誠 旗標出版社.
运行时刻环境 (Runtime Environment)
第7章 函 数 7.1 函数的定义与调用 7.2 函数的嵌套调用与递归调用 7.3 数组作为函数参数 7.4 内部变量与外部变量
微机原理与接口技术 微机原理与接口技术 朱华贵 2015年11月13日.
目录 7.1 用户自定义函数的种类 7.2 函数的定义 7.3 被调函数的声明 7.4 函数的调用 7.5 函数的嵌套调用
開放電腦計劃 報告人:陳鍾誠 2011 年 8 月 20 日 台灣開源人年會 COSCUP 2011 – 中研院
成绩是怎么算出来的? 16级第一学期半期考试成绩 班级 姓名 语文 数学 英语 政治 历史 地理 物理 化学 生物 总分 1 张三1 115
第4章 Excel电子表格制作软件 4.4 函数(一).
第九章 运行时存储空间组织 网上教学系统: : 编译原理
第九节 赋值运算符和赋值表达式.
College of Computer Science & Technology
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
第二章 高级函数特性.
第四章 函数 丘志杰 电子科技大学 计算机学院 软件学院.
第7章 模板 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
本节内容 C语言的汇编表示 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第二节 函数的极限 一、函数极限的定义 二、函数极限的性质 三、小结 思考题.
本节内容 通用寄存器 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
基于列存储的RDF数据管理 朱敏
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
本节内容 导出表 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
大数据搜索挖掘实验室 第五章 子程序设计 张华平 副教授 博士 Website: 大数据搜索挖掘实验室
陳維魁 博士 儒林圖書公司 第六章 領域與範圍 陳維魁 博士 儒林圖書公司.
编译原理实践 6.程序设计语言PL/0.
计算机编程 信息管理与工程学院 2014年9月.
Presentation transcript:

编译原理与技术 运行环境 2018/11/24 《编译原理与技术》-运行环境

运行环境 存储组织与分配 参数传递 程序单元、运行时内存划分与活动记录 静态/动态存储分配 动态栈式的过程调用/返回 非局部名字的访问 参数传递的方式及其实现 2018/11/24 《编译原理与技术》-运行环境

存储组织与分配 程序单元 -FORTRAN的子例程(subroutine) -PASCAL的过程/函数(procedure/function) -C的函数 程序单元的激活(调用)与终止(返回) 程序单元的执行需要: 代码段+活动记录(程序单元运行所需的额外信息,如参数,局部数据,返回地址等) 2018/11/24 《编译原理与技术》-运行环境

运行时内存划分 代码段 静态数据区 栈(stack) 堆(heap) 大小可以静态确定 全局/局部静态变量 活动记录栈 动态分配的数据 2018/11/24 《编译原理与技术》-运行环境

活动记录 活动记录-AR (Activation Record) 是一连续存储区域,用于管理与存放和程序单元执行相关的重要信息。 - 临时区域。用以保存临时计算结果 - 局部数据区。源程序中程序单元声明的局部变量对应在此区域。 - 机器状态保存区。存有机器的寄存器,程序指令计数器 ip(返回地址)等。 2018/11/24 《编译原理与技术》-运行环境

活动记录 AR中的内容 - 访问链(静态链)。当前程序单元可以访问的(静态程序中)外围程序单元的活动记录链。 - 控制链(动态链)。程序单元的活动记录按它们的生成(或调用)次序串成链。 - 实在参数 - 返回值 2018/11/24 《编译原理与技术》-运行环境

活动记录的内容 返回值(return value) 实在参数(actual parameter) 控制链(control link) 可选的访问链(optional access/static link) 机器状态(saved machine status) 局部数据(local data) 临时区(temporaries) 2018/11/24 《编译原理与技术》-运行环境

活动记录内容的存取 AR的基地址bp 返回值 实在参数 控制链 (old bp) 可选的访问链 机器状态 局部数据 临时区 2018/11/24 《编译原理与技术》-运行环境

活动记录内容的存取 bp 返回值 实在参数 控制链(old bp) 可选的访问链 机器状态 局部数据 临时区 地址: bp+d1 偏移 d1 2018/11/24 《编译原理与技术》-运行环境

静态存储分配 - 全局变量的存储绑定、AR均在编译时确定 且在整个程序执行中保持。 - 不支持: 1)动态数据结构 2)过程递归调用 - 实现静态分配的语言: (早期)FORTRAN 2018/11/24 《编译原理与技术》-运行环境

e.g.1 FORTRAN静态存储分配 CALL sub SUBROUTINE sub CALL sub DATA I/10 END WRITE(*.*) I I = 100 END 第一次调用sub,输出10 第二次调用sub,输出100 第一次调用前 机器状态 I ( 10 ) 第一次调用后 机器状态 I ( 100 ) 第二次调用后 机器状态 I ( 100 ) 2018/11/24 《编译原理与技术》-运行环境

动态存储分配 栈式分配 - AR在过程被调用(激活)时才在栈(stack)上分配;而在被调用过程(返回)终止时从栈上撤销。 - 过程中(非静态)局部变量的存储绑定在过程执行时有效;过程终止时失效。 - 支持过程递归调用。每次递归调用时,局部变量绑定到不同的存储。 2018/11/24 《编译原理与技术》-运行环境

动态存储分配 栈式分配下的AR内容布局 bp 栈顶sp 返回值 实在参数 可选的访问链 返回地址 调用者 bp 可选机器状态 局部数据 临时区 参数/返回值区域放在AR高端-靠近调用者过程的活动记录,既便于双方存取,又适应参数可变情况 高地址 长度固定的区域放在AR中间 bp 低地址 长度可变的区域放在AR低端 栈顶sp 2018/11/24 《编译原理与技术》-运行环境

- 过程调用:分配被调过程的AR并填入相关信息,然后程序控制转移到被调过程入口; -过程A 调用 过程B 的过程调用序列: 栈式分配下的过程调用与返回 - 过程调用:分配被调过程的AR并填入相关信息,然后程序控制转移到被调过程入口; -过程A 调用 过程B 的过程调用序列: A的“调用”准备操作:1)~ 3) 1)A 计算实在参数并放入(对应栈操作-push) B的活动记录中;(亦可考虑返回值存放空间) 2)A将可选的访问链放入(push)B的活动记录; 3)A将返回地址放入B的活动记录并跳转到过程B 的代码入口,开始B的执行;(一般通过A中的 代码指令-“call B” 来完成这一步) 4) 2018/11/24 《编译原理与技术》-运行环境

4)在B自己的AR中保存A的活动记录的基址(即当前bp,对应操作 push bp)并且将这个位置作为B自己AR的基址(对应操作) 栈式分配下的过程调用与返回 -过程A 调用 过程B 的过程调用序列: B的入口代码:4)~ 6) 4)在B自己的AR中保存A的活动记录的基址(即当前bp,对应操作 push bp)并且将这个位置作为B自己AR的基址(对应操作) mov sp,bp 即 bpsp) 5)保存可选的机器状态(寄存器) 6)为局部数据分配空间,(对应操作) sub local_size,sp,即sp sp – local_size 7)“开始”B的执行。(至此,B的AR建好) 2018/11/24 《编译原理与技术》-运行环境

- 过程返回:回收分配的被调过程的AR,并将程序控制转移回调用过程继续执行; -过程A 调用 过程B 的过程返回序列: 栈式分配下的过程调用与返回 - 过程返回:回收分配的被调过程的AR,并将程序控制转移回调用过程继续执行; -过程A 调用 过程B 的过程返回序列: B的出口代码:1)~ 2) 1)B回收局部数据空间;恢复原先保存的机器状态2)B恢复A的AR基址;取出返回地址将程序控制交回到A。对应操作: mov bp,sp spbp pop bp //恢复调用者A的bp ret // B执行结束并返回 注:X86-Linux中的leave 和ret组合亦能达到目的。 至此,B的AR中除了参数/返回值区域,其余区域全部回收(撤销)了。 2018/11/24 《编译原理与技术》-运行环境

4)A调整栈顶sp(主要根据参数个数以及可能有的访问链和可能有的返回值)。对应操作: 栈式分配下的过程调用与返回 -过程A 调用 过程B 的过程返回序列: A的“调用”善后代码:3)~ 4) 3)A取回返回值以及引用型参数(有的话) 4)A调整栈顶sp(主要根据参数个数以及可能有的访问链和可能有的返回值)。对应操作: add para_size, sp 即spsp + para_size 至此,B的AR区域全部回收(撤销)了。 2018/11/24 《编译原理与技术》-运行环境

e.g.2 栈式存储分配 有C程序如下: void g() { int a ; a = 10 ; } void h() { int a ; a = 100; g(); } main() { int a = 1000; h(); } 2018/11/24 《编译原理与技术》-运行环境

e.g.2 栈式存储分配 过程g被调用时,活动记录栈的(大致)内容 返回地址 main程序的AR old bp a : 1000 返回地址 函数h的AR old bp a : 100 返回地址 bp 函数g的AR old bp a : 10 sp 2018/11/24 《编译原理与技术》-运行环境

e.g.3 有参函数的活动记录 .file "ar.c" .text void func( int a , int b ) .globl func .type func,@function func: pushl %ebp movl %esp, %ebp subl $8, %esp movl 8(%ebp), %eax movl %eax, -4(%ebp) movl 12(%ebp), %eax movl %eax, -8(%ebp) leave ret 参数 b 参数 a 返回地址 老bp 局部变量c 局部变量d bp+12 void func( int a , int b ) { int c , d; c = a; d = b; } bp+8 bp bp-4 bp-8 2018/11/24 《编译原理与技术》-运行环境

e.g.4. scanf的可变参数 有如下C程序: main() { int i ; float f; int j ; scanf(“%d%f”, &i, &f); //第一次调用时3个参数 scanf(“%d”, &j ); //第二次调用时 2个参数 return 0; } 2018/11/24 《编译原理与技术》-运行环境

e.g.4. scanf的可变参数 由于C语言采用逆序传递参数,格式串参数将被放在AR中的“固定”位置,即bp+8。而由此参数即可确定待输入值的参数(变量)的个数。从而适应参数个数变化的情况。 &f &i &j 格式串1指针 bp+8 格式串2指针 返回地址 返回地址 老bp 老bp bp … … … … scanf的第一次调用时AR scanf的第二次调用时AR 2018/11/24 《编译原理与技术》-运行环境

e.g.5 悬空引用 有C程序如下: main() int * dangle() { { { { int * p = dangle(); int i; … return &i; } } 2018/11/24 《编译原理与技术》-运行环境

非局部变量访问 静态作用域规则 vs. 动态作用域规则 “最接近嵌套” vs. 现行单元活动(调用次序) 分程序 - 含有声明和语句;如C的{…} - 分程序具有以下特征: -- 可以嵌套; -- 没有参数; -- 控制流沿静态文本进入、流出 -- 采用“最接近嵌套”的规则 2018/11/24 《编译原理与技术》-运行环境

非局部变量访问 e.g.6 分程序 main() { int a = 0 ; int b =0; //local VAR of main { int b = 1 ; // block 1 { int a = 2 ; printf(“%d %d\n”,a,b);//block 2 } { int b = 3 ; printf(“%d %d\n”,a,b);//block 3 } printf(“%d %d\n”,a,b); } 2018/11/24 《编译原理与技术》-运行环境

分程序的实现 1)按无参过程方式来实现 -控制流进入分程序时,在栈上分配局部变量空间 ,退出时撤销上述空间。e.g.6中各变量存储如下: a0 = 0 a0 = 0 a0 = 0 a0 = 0 a0 = 0 b0 = 0 b0 = 0 b0 = 0 b0 = 0 b0 = 0 b1 = 1 b1 = 1 b1 = 1 b1 = 1 a1 = 2 b2 = 3 a)进入block 1, 未进入block 2 b)进入block 2, 未进入block 3 c)退出block 2, 进入block 3 d)退出block 3, 进入block 1 e)退出block 1, 进入main 2018/11/24 《编译原理与技术》-运行环境

分程序的实现 2)按过程为单位统一分配 -将分程序中的局部变量独立地看成过程的局部变量。e.g.6中各变量存储如下: (两种方案) a0 = 0 a0 = 0 b0 = 0 b0 = 0 b1 = 1 b1 = 1 a1 = 2 a1 = 2, b2 = 3 b2 = 3 a)a1和b2将先后被分配在同一空间,因为它们的生存期(作用域)不重叠、不嵌套。 b)a1和b2将被分配在不同的空间。 2018/11/24 《编译原理与技术》-运行环境

过程嵌套定义语言中非局部名字访问 e.g.7 嵌套的过程定义 主程序 : 0 A:1 i: 2 B:2 C B A 主程序 j: 3 C:3 program dynamic_static_link; procedure A ; var i : integer ; procedure B ; var j : integer; procedure C ; begin B; end; j := i; C ; B ; A ; end. 主程序 : 0 嵌套深度:1 A:1 嵌套深度:2 i: 2 C B:2 B A 嵌套深度:3 主程序 j: 3 C:3 嵌套深度:4 e.g.7 嵌套的过程定义 2018/11/24 《编译原理与技术》-运行环境

过程嵌套定义语言中非局部名字访问 设嵌套深度的初值为0。在“读过”函数名字后,即进入新的嵌套层次,嵌套深度加1。也即,函数体(从参数算起)区域的嵌套深度与函数名字的嵌套深度之差为1。 定义点嵌套深度N-def: 任何名字(包括普通变量名和函数名)的定义点嵌套深度是包围该名字定义的最内层函数体(body)的嵌套深度。 一个名字有且仅有一个定义点嵌套深度。 2018/11/24 《编译原理与技术》-运行环境

过程嵌套定义语言中非局部名字访问 引用点嵌套深度N-ref: 任何名字(包括普通变量名和函数名)的一个引用点嵌套深度是引用该名字的语句所在的最内层函数体(body)的嵌套深度。 一个名字可以有多个不同引用点嵌套深度。(名字可能出现在不同函数体的多条语句里嘛。^_^) 函数的参数与其局部声明变量均定义在同一函数体内,它们的定义点嵌套深度相同哦! 2018/11/24 《编译原理与技术》-运行环境

使用静态访问链来存取非局部名字 名字 类别 定义点 嵌套深度Def 引用点 嵌套深度Ref 层次差diff = Ref - Def dynamic_static_link 函数 A 1 i 变量 2 3 B 2/4 0/2 j C 2018/11/24 《编译原理与技术》-运行环境

使用静态访问链来存取非局部名字 一个函数的活动记录中的静态链,指向包围该函数定义的最内层函数所对应的一个活动记录,此最内层函数也即是“父”函数。 在函数体C中被引用的名字a的定义点嵌套深度为defa ,而该名字在该函数体中的引用点嵌套深度为refa。由于“定义在先,引用在后”,故而, refa≥ defa 2018/11/24 《编译原理与技术》-运行环境

使用静态访问链来存取非局部名字 设层差diff = refa – defa,那么,通过追踪函数C的活动记录的静态链diff次,即到达定义了名字a的某个(父或祖先)函数P对应的活动记录。 base = bp; while(diff--) base = base[offset_StaticLink] 当层差diff==0,名字a的定义点和引用点位于同一个函数体内,即函数C和P是同一个函数,也即当前函数就是父函数!此时,无需追踪静态链! 2018/11/24 《编译原理与技术》-运行环境

使用静态访问链来存取非局部名字 当层差diff==0,无需追踪静态链! 1)如名字a是普通变量,则可以通过当前活动记录(对应函数C)基址bp+offset_a来访问。 2)如名字a是函数名,显然,a是定义在函数C中(子)函数。引用a属于父函数调用子函数。则函数a的静态链就是当前活动记录(对应函数C)基址bp。(建立函数a静态链,push bp) 2018/11/24 《编译原理与技术》-运行环境

使用静态访问链来存取非局部名字 当层差diff==1,名字a是一个函数。 1)调用函数C(caller)与被调函数a(callee)是兄弟函数,拥有相同的父函数。则仅需追踪C的静态链1次,即可获得父函数P活动记录基址,也即是函数a的静态链。 2)调用函数C与被调函数a是同一个函数,也即函数C是递归函数。 2018/11/24 《编译原理与技术》-运行环境

使用静态访问链来存取非局部名字 当层差diff >1,名字a是一个函数。则被调函数a(callee)是调用函数C(caller)的父/祖先函数(或父/祖先函数的兄弟函数)。 2018/11/24 《编译原理与技术》-运行环境

静态链的追踪操作 当层差diff ≥1,静态链追踪操作的语义如下 base = bp; while(diff--) base = base[offset_StaticLink] 代码序列可以是: 1)(bp + offset_StaticLink)  Reg //追踪1次 2)(Reg + offset_StaticLink) Reg //追踪2次 … … // 追踪diff次 对于变量读写: (Reg+Var_offset) 对函数调用,建立静态链:push Reg 2018/11/24 《编译原理与技术》-运行环境

e.g.7 嵌套的过程定义 过程的调用次序 主程序 A  B  C  B1 … 过程B第一次被过程C调用时,C需追踪2次访问链才能为找到过程B1的父过程A的AR。 具体如下: 2018/11/24 《编译原理与技术》-运行环境

e.g.7 嵌套的过程定义 … 主程序AR 控制链:bp(系统) 运行时栈:主程序 2018/11/24 《编译原理与技术》-运行环境

e.g.7 嵌套的过程定义 … 主程序AR 控制链:bp(系统) 访问链:bp(main) 访问链的地址表示: bp + 8 在此活动记录中的偏移为8 返回地址1 过程A的AR 控制链:bp(main) 局部名字:i 运行时栈:主程序 A 主程序负责建立A(活动记录中)的访问链。此时该链指向主程序运行时的活动记录(why?)。此访问链的位置(或偏移)是多少? 2018/11/24 《编译原理与技术》-运行环境

e.g.7 嵌套的过程定义 运行时栈:主程序 A  B B中语句j := i如何执行的? 主程序AR j := i执行如下: … 主程序AR j := i执行如下: 取过程A的活动记录地址: (bp + 8) -> R 取A中局部变量i的值: (R – 4 ) -> R 将该值赋给B的局部变量j: R -> (bp – 4) 控制链:bp(系统) 访问链:bp(main) 返回地址1 过程A的AR 控制链:bp(main) 局部名字:i 访问链:bp(A) 返回地址2 过程B的AR 控制链:bp(A) 局部名字:j0 运行时栈:主程序 A  B B中语句j := i如何执行的? 2018/11/24 《编译原理与技术》-运行环境

运行时栈:主程序 A  B  C 主程序AR 过程A的AR 过程B的AR 过程C的AR … 控制链:bp(系统) 访问链:bp(main) 返回地址1 过程A的AR 控制链:bp(main) 局部名字:i 访问链:bp(A) 返回地址2 过程B的AR 控制链:bp(A) 局部名字:j0 访问链:bp(B) 过程C的AR 返回地址3 控制链:bp(B) 运行时栈:主程序 A  B  C 2018/11/24 《编译原理与技术》-运行环境

运行时栈: 主程序 A  B  C  B1 过程C为过程B1 建立访问链: 1: (bp+8)R 2:(R+8)R … 主程序AR 控制链:bp(系统) 访问链:bp(main) 返回地址1 过程A的AR 控制链:bp(main) 局部名字:i 2 访问链:bp(A) 运行时栈: 主程序 A  B  C  B1 返回地址2 过程B的AR 控制链:bp(A) 过程C为过程B1 建立访问链: 1: (bp+8)R 2:(R+8)R 3: push R 局部名字:j0 1 访问链:bp(B) 过程C的AR 返回地址3 控制链:bp(B) 访问链:bp(A) 返回地址4 过程B的AR 控制链:bp(C) 局部名字:j1

参数传递 实参与形参 - 存储单元(左值) - 存储内容(右值) 根据所传递的实参的“内容”,参数传递可分为: - 传值调用:传递实参的右值到形参单元; - 引用调用:传递实参的左值到形参单元; - 值-结果调用:传递实参的右值;在控制返回时将右值写回到实参相应左值单元(如果有的话); - 换名调用:传递实参的“正文”。 2018/11/24 《编译原理与技术》-运行环境

e.g.8 参数传递 procedure swap( a , b ) a, b : int; temp : int; begin temp := a ; a := b; b := temp; end. 讨论下面程序在不同参数传递方式下输出: 1) x := 10 ; y := 20; swap( x,y ); print ( x, y ); 2) i := 10; a[ i ] := 20; swap( i, a[ i ] ); print( i, a[ i ] ); 2018/11/24 《编译原理与技术》-运行环境

e.g.8 参数传递 讨论下面程序在不同参数传递方式下输出: 1) x := 10 ; y := 20; swap( x,y ); print ( x, y ); 5000: x 10 4000: y 20 2004: a 2000: b 1990: temp 实参x,y和过程swap中形参a,b,和局部数据temp的存储分布示意 2018/11/24 《编译原理与技术》-运行环境

e.g.8 参数传递-传值调用 过程调用-swap(x,y) 传参-形、实结合 5000: x 10 4000: y 20 2004: a 2000: b 20 1990: temp 2018/11/24 《编译原理与技术》-运行环境

e.g.8 参数传递-传值调用 过程调用-swap(x,y) 过程执行 temp := a 5000: x 10 4000: y 20 2000: b 20 1990: temp 10 2018/11/24 《编译原理与技术》-运行环境

e.g.8 参数传递-传值调用 过程调用-swap(x,y) 过程执行 a := b 5000: x 10 4000: y 20 1990: temp 10 2018/11/24 《编译原理与技术》-运行环境

e.g.8 参数传递-传值调用 过程调用-swap(x,y) 过程执行 b := temp 5000: x 10 4000: y 20 2018/11/24 《编译原理与技术》-运行环境

e.g.8 参数传递-传值调用 过程swap(x,y)执行后 print( x, y ) 10, 20 5000: x 10 4000: y 2004: 20 2000: 10 1990: 10 2018/11/24 《编译原理与技术》-运行环境

e.g.8 参数传递-引用调用 过程调用-swap(x,y) 传参-形、实结合 5000: x 10 4000: y 20 2004: a 2000: b 4000 1990: temp 2018/11/24 《编译原理与技术》-运行环境

e.g.8 参数传递-引用调用 过程调用-swap(x,y) 过程执行 temp := a 5000: x 10 4000: y 20 2000: b 4000 1990: temp 10 2018/11/24 《编译原理与技术》-运行环境

e.g.8 参数传递-引用调用 过程调用-swap(x,y) 过程执行 a := b 5000: x 10 4000: y 20 1990: temp 10 2018/11/24 《编译原理与技术》-运行环境

e.g.8 参数传递-引用调用 过程调用-swap(x,y) 过程执行 a := b 5000: x 20 4000: y 20 1990: temp 10 2018/11/24 《编译原理与技术》-运行环境

e.g.8 参数传递-引用调用 过程调用-swap(x,y) 过程执行 b := temp 5000: x 20 4000: y 10 2018/11/24 《编译原理与技术》-运行环境

e.g.8 参数传递-引用调用 过程swap(x,y)执行后 print( x, y ) 20, 10 5000: x 20 4000: y 2004: 2000: 1990: 2018/11/24 《编译原理与技术》-运行环境

e.g.9 参数传递 以下C程序的输出是什么? void func(char *s){s = (char*)malloc(10);} int main() { char *p = NULL; func(p); if(!p)printf("error\n");else printf("ok\n"); return 0; } 2018/11/24 《编译原理与技术》-运行环境

e.g.10.1 参数传递 swap void swap1(int p,int q) { int temp; temp = p; p = q; q = temp; } pushl %ebp movl %esp, %ebp subl $4, %esp movl 8(%ebp), %eax movl %eax, -4(%ebp) movl 12(%ebp), %eax movl %eax, 8(%ebp) movl -4(%ebp), %eax movl %eax, 12(%ebp) leave ret 2018/11/24 《编译原理与技术》-运行环境

e.g.10.2 参数传递 swap void swap2(int *p,int *q) { int temp; temp = *p; *p = *q; *q = temp; } pushl %ebp movl %esp, ebp subl $4, %esp movl 8(%ebp), %eax movl (%eax), %eax movl %eax, -4(%ebp) movl 8(%ebp), %edx movl 12(%ebp), %eax movl (%eax), %eax movl %eax, (%edx) movl 12(%ebp), %edx movl -4(%ebp), %eax movl %eax, (%edx) leave ret 2018/11/24 《编译原理与技术》-运行环境

e.g.10.3 参数传递 swap void swap3(int *p, int *q) { int *temp ; temp = p ; p = q ; q = temp; } pushl %ebp movl %esp, ebp subl $4, %esp movl 8(%ebp), %eax movl %eax, -4(%ebp) movl 12(%ebp), %eax movl %eax, 8(%ebp) movl -4(%ebp), %eax movl %eax, 12(%ebp) leave ret 2018/11/24 《编译原理与技术》-运行环境

e.g.10.4 参数传递 swap void swap4(int &p, int &q) { int temp; temp = p; p = q; q = temp; } pushl %ebp movl %esp,%ebp subl $4, %esp movl 8(%ebp), %eax movl (%eax), %eax movl %eax, -4(%ebp) movl 8(%ebp), %edx movl 12(%ebp), %eax movl (%eax), %eax movl %eax, (%edx) movl 12(%ebp), %edx movl -4(%ebp), %eax movl %eax, (%edx) leave ret 2018/11/24 《编译原理与技术》-运行环境