Programming Language Pragmatics 部分习题解答 三、四、六

第三章介于词法和语法分析之间,讲的是作用域、闭包等的概念,算是PL的部分。这本书有一半的篇幅是在讲programming language的feature,然后又从编译的角度说明如何实现。
第四章讲了语义分析,语法树的标注,IR之前的部分
第五章讲的是目标机器的特点,翻译成的汇编语言的结构,为后端的学习做准备,相当于简单的体系结构内容,就跳过了

第六章讲的是控制流,所谓控制流就是语句执行的顺序逻辑,包括:顺序、选择、迭代、过程抽象、递归、并发、非确定性。这章给出了很多有意思的例子:比如各种记法(前缀、中缀、后缀),引用透明/副作用,左值/右值,值模型/引用模型,短路求值,选择条件的查找方式(哈希,折半,顺序),迭代器,逻辑控制的检查(前、中间、后),尾递归,应用序求值/正则序求值/惰性求值,模式匹配,非确定性,卫式命令。这一章包括后面的几章都是PL的部分。

第三章

复习

  • 1.What is binding time?
    约束时间是指做出实现的决定的时间,可能有集中不同的时间
    Language design time
    Language implementation time
    Program writing time
    Compile time
    Link time
    Load time
    Run time

  • 2.Explain the distinction between decisions that are bound statically and those
    that are bound dynamically.
    静态绑定就是编译器绑定,动态绑定是指运行期绑定

  • 3.What is the advantage of binding things as early as possible? What is the
    advantage of delaying bindings?
    早绑定增加了效率,晚绑定增加了灵活性

  • 4.Explain the distinction between the lifetime of a name-to-object binding and its visibility.
    生存期和可见性的区别
    生存期指的是对象从创建到销毁的阶段,可见性可能和生存期一致,但是可见的约束可能在对象销毁之后仍然存在,也就是"dangling reference"

  • 5.What determines whether an object is allocated statically, on the stack, or in the heap?
    老生常谈的问题了,冯诺依曼机器上的语言的共性就是static,stack和heap
    给出书上的标准回答:
    static:objects are given an absolute address that is retained throughout the
    program’s execution.
    stack:objects are allocated and deallocated in last-in, first-out order, usually in conjunction with subroutine calls and returns.
    heap: objects may be allocated and deallocated at arbitrary times. They require
    a more general (and expensive) storage management algorithm

  • 6.List the objects and information commonly found in a stack frame.
    栈帧上常见的对象和信息 :局部变量,寄存器,返回地址,函数参数

  • 7.What is a frame pointer? What is it used for?
    编译器在调用序列或者prologue(代码开始执行时)中预定一个特殊的寄存器,帧指针总是指向当前子例程帧内的已知位置。

  • 8.What is a calling sequence?
    我觉得这个地方作者应该想说的是“调用例程(routine)”,解释也的确是调用例程的意思,不过序列(sequence)也无所谓——
    the code executed by the caller immediately before and after the call—
    and of the prologue (code executed at the beginning) and epilogue (code executed
    at the end) of the subroutine itself.

  • 9.What are internal and external fragmentation?
    堆的内碎片和外碎片,详情请参加你的操作系统的内存管理章节。

  • 10.What is garbage collection?
    垃圾收集

  • 11.What is a dangling reference?
    A dangling reference is a reference to an object that no longer exists. Dangling reference arise during object destruction, when an object that has an incoming reference is deleted or deallocated, without modifying the value of the pointer, so that the pointer still points to the memory location of the deallocated memory.

第四章

复习

  • 1.是什么决定了一条语言规则是语法规则还是静态语义规则?
    语法规则关注程序的形式,语义分析关注意义

  • 2.为什么某些特定程序错误不能在编译时检查而只能在运行时检查?
    输入值的部分只能在运行时才能够检查

  • 3.什么是属性文法
    属性文法使用基于属性的记法在语法表达式中将表达式和数学的概念联系起来

  • 4.什么是断言?
    一种语义动态检查手段

  • 5.综合属性和继承属性的不同在哪里?
    综合属性:每个符号最多只有一个属性
    继承属性:根据符号右边的部分计算得到的属性

  • 7 信息从一个属性传到另一个属性的模式称为属性流

  • 8 语义分析、代码生成和语法分析交错进行的编译器称为一遍编译器

  • 9 S-属性 所有属性都是综合属性 所有属性能在下级节点中推导出来
    L-属性 AST中某个节点的属性是由其上级节点、兄弟节点和它自身来决定的

  • 10 动作例程就是在特定点执行的语义函数

  • 4.11 一遍编译器能够在完成语法的同时完成产生式的属性求值,不必构造完整的分析树
    交错进行则更加容易并且能够处理LR分析器的算法

  • 4.12 综合属性
    产生式的右部都可以在属性栈顶部的项中找到,可以通过弹出右部记录并通过$ 替 代 替代 完成

  • 4.13 使用语义挂钩

  • 4.14 上下文无关文法的产生式右部,由左角和迹组成,左角是LR文法中移入的部分,迹是可以规约的部分。LL文法中左角总是空的

  • 4.15 语义挂钩只能用在编译器确定在某个特定的产生式里的位置

  • 4.18 上下文无关文法的是要定义一个单词串组成的语言,树文法则是要定义树本身

第六章

复习

  • 1 请列举七类主要的控制流机制
    七个主要类别:顺序执行、选择执行、迭代、过程抽象、递归、并发、非确定性
  • 2 运算符和其它种类的函数有什么不同?
    运算符指的是采用特殊的简单语法形式的内部函数,运算对象指的是预算符的参数。有的语言把运算符定义为普通函数的语法糖。
  • 3什么是剑桥波兰记法?
    剑桥波兰记法:对函数采用前缀记法,函数名放在括号内
  • 4 为什么Postscript和Forth没有结合性和优先级的问题?
    后缀记法隐式说明了优先级
  • 5 什么是引用透明
    对引用透明 表达式求值只依赖于求值所在的引用环境,不依赖于发生的时间
  • 6 值模型和引用模型的区别?
    值模型和引用模型
    值模型是保存值的容器的名字,引用模型是对于值的命名引用
  • 7左值和右值的区别?
    左值:赋值语句左部的指称位置的表达式
    右值:表示一个值的表达式
  • 8 为什么对于引用模型的语言可变和不可变的值很重要?
    不能将可变的值用于不变值的上下文
  • 9 程序语言设计的正交性?
    用尽可能少的特性得到尽可能多的结果,这些组合都有意义
  • 10 什么叫面向表达式的语言?
    任何表达式都可以当作语句,任何语句可以出现在表达式里
  • 11 为什么对于变量赋初值是有用的?
    减少开销,减少错误
  • 12 什么是聚集值?
    用户定义的复合类型的编译时常量值
  • 13什么是定义性赋值
    在所有可能的控制路径上,都必须为这个表达式中的每一个变量赋过值
  • 14 为什么在运行中捕捉所有的未初始化变量的情况代价很高昂?
    解释性的语言每次变量的访问都需要很大的代价,但是对于编译型的语言,这种标记将会是很大的开销。
  • 15 采用赋值运算符有什么优点?
    赋值运算符直接更新变量更加清晰,保证地址的运算只做一次
  • 16 为什么不明确说明运算符或者函数参数的求值顺序?
    这个题很有意思,运算符或者函数的求值顺序不指定是为了方便编译器优化,java明确要求从左向右求值
  • 17 短路求值
    跳过不必要的条件计算
  • 18 goto的三种使用情况:从循环中退出,从子程序中返回,错误和其它异常情况
  • 6.19 因为lisp的函数没有副作用,所以顺序复合没有意义
  • 6.20 每次调用返回值相同
  • 6.21 随机数函数需要有副作用
  • 6.22 case语句可以提供跳转表的效率提高
  • 6.23 顺序搜索,折半搜索和散列表
  • 6.24 循环中修改了i的值
    goto的跳入跳出
    上界的比较出现在下界之前
  • 4.25 浮点数无法精确表示语义,并且给编译器条件判断带来了困难
  • 6.26 用于在其它任何定义良好的集合的元素上迭代
    Icon中用成功和失败取代布尔的判断
    对于生成器来说,失败意味着取得下一个值继续比较
    成功意味着块得到执行
  • 6.27 modula的中间检测循环写成C是
- for(;;){
	dosomething();
	if(condition) break;
	dosomething();
	if(condition) break;
}

如果控制流是这样的,那么采用中间循环就会更好

  • 6.28 尾递归在递归调用后不进行其它计算,这样就能使编译器无需分配栈空间
  • 6.29 在调用前求值称为应用序求值,在实际需要值的时候求值称为正则序求值
  • 6.31 惰性求值和正则序求值的关键不同在于正则序求值有副作用。前者的典型实现是Scheme的delay函数,后者的典型实现是C的宏。
    一个delay也成为一个允诺,维护允诺过期的机制称为记忆器。
  • 6.32 在并发程序中,非确定性影响着程序的正确性。
  • 6.33 非确定性语境并不经常出现,建议使用非确定性结构也基于美学考虑和形式化语义证明方面,在并发程序中非确定性语义影响程序正确性。SR提供了卫来解决非确定性问题。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值