08 | 作用域和生存期:实现块作用域和函数
该思维导图由 AI 生成,仅供参考
作用域(Scope)
- 深入了解
- 翻译
- 解释
- 总结
本文深入探讨了作用域和生存期在编程语言中的重要性,通过比较分析C、Java和JavaScript中作用域的处理机制,展示了不同语言的语义差异。文章通过具体的代码示例展示了变量的作用域大小、声明后开始的特点,以及在函数和块中声明同名变量时的覆盖情况。此外,还介绍了块作用域的概念,以及不同语言对块作用域的处理方式。文章还涉及了作用域和生存期对应到了运行时的内存管理的基本机制,包括栈和堆来做内存管理。在实现作用域和栈的部分,文章提到了设计了一个数据结构来区分不同变量的作用域,并展示了作用域的树状结构。最后,文章提到了实现块作用域的功能,让if语句和for循环语句使用块作用域和本地变量。通过本文的阅读,读者可以深入了解作用域和生存期在编程语言中的重要性,以及相关的实现机制,对于理解编程语言的内存管理和作用域规则有很大帮助。
《编译原理之美》,新⼈⾸单¥59
全部留言(26)
- 最新
- 精选
- 许童童变量的使用范围由作用域决定,作用域由词法规则决定,词法分析生成作用域链,之后查找变量就沿着这条作用域链查找,与函数调用栈就没有关系了。一般函数的生存期就是出栈后就结束了,如果是引用对象会在本次GC中回收,如果产生了闭包,那就要等到引用闭包的变量销毁,生存期才结束。
作者回复: 很准确,很清晰!
2019-08-3027 - 幻境之桥我在上图中展现了这种情况,在调用 fun 函数的时候,栈里一共有三个栈桢:全局栈桢、main() 函数栈桢和 fun() 函数栈桢,其中 main() 函数栈桢的 parentFrame 和 fun() 函数栈桢的 parentFrame 都是全局栈桢。 老师这里没有明白为什么 fun()函数栈桢的 parentFrame 是全局栈桢而不是 main()的函数栈桢 这个 parentFrame 怎么定义呢?
作者回复: 因为fun函数和main函数都是在全局作用域中定义的。fun中如果有一个变量,不是在本地声明的,那到哪里去找呢?要到全局作用域中去找,而不是到main函数中找。 我在课程里没有介绍一个概念:词法作用域(Lexical Scope),等以后找机会加上。 词法作用域又叫做静态作用域,也就是说,程序里用到的变量,在编译时,就知道是哪个变量定义。因为完全是根据声明时的位置关系来做变量引用解析的。
2020-04-01516 - Johnson现在课程的做法相当于AST之后直接解析执行了,所有的逻辑都堆在AST和紧接着的语义分析,没有把AST转化成IR,然后在这个IR上做各种事情,最后再到interpreter执行。是因为前期为了简单起见,所以先这么直观的来么?
作者回复: 因为目前是在讲前端,所以就先不引入IR。 同时也是在告诉同学们,哪怕我们只拿到了AST,也已经能做很多事情了。 IR在后端部分会讲。我会给出一个自己设计的IR的例子,用IR重新实现部分功能。然后再去采用LLVM的IR。
2019-08-3011 - 吃瓜群众路人丙也就是说,栈里的上一级栈桢,不一定是 Scope 的父节点。 老师能举个反例吗
作者回复: 递归函数的调用。 int a; int foo(){ a = a+1; if (a<10){ return foo(); } else{ return a; } } 在递归调用的时候,你在函数里仍然可以访问全局变量。这个全局变量不在上一级的函数栈桢里。而是在最底下那个全局变量的栈桢。
2019-09-228 - mcuking其实 js 的 es6 版本已经支持块级作用域,可以用 let const 声明
作者回复: 是的,我注意到了。 严格的表述这样写可能比较好:如果只是像java和c那样声明变量,就没有块作用域:-)
2019-09-0727 - Geek_f9ea2dfunctionDeclaration : typeTypeOrVoid? IDENTIFIER formalParameters ('[' ']')* (THROWS qualifiedNameList)? functionBody 中的('[' ']')* 这个没明白什么意思,函数的声明,我觉得这样就够了:typeTypeOrVoid? IDENTIFIER formalParameters
作者回复: 这是直接照搬的Java的语法。这是对数组的支持。目前playscript并没有支持数组,但语法也就先这么放着了。
2019-09-1123 - ZYS宫老师,可否兼顾一下用c++的学员,介绍一下cpp版本playscript如何在visual studio2010或更高的版本运行?
作者回复: 讲后端部分的时候,主要是用cpp版本实现的。那部分的指导资料我整理一下,写一个README.md,尽快更新到Github和码云上。 先简单说一下: 1.如果仅仅用cpp版本的Antlr,这个比较简单,你做练习的时候可以试用一下。 2.把Antlr和LLVM一起用的时候,要配置的东西更多一些,好在有cmake。
2019-08-313 - Aaaaaaaaaaayou老师,playscript-java/src/main/play/DefaultFunctionType.java 中 public static boolean isType(FunctionType type1, FunctionType type2) 函数中 List<Type> paramTypes2 = type1.getParamTypes(); 是不是写错了? type1 应该改为 type2
作者回复: 是的。谢谢你细心的阅读代码。 我已经在github里更新了,并且在commit comment中专门感谢了你:)
2020-02-052 - 北冥Master牛逼,越来越深入了,看的有点吃力了
作者回复: 后几讲涉及的都是语义功能,并涉及了一部分运行期技术(给后端技术部分提前做铺垫)。 语义上的差别是每种语言真正的差别,但底层有一些共通的机制。搞搞明白对我们学各种语言都有好处。
2019-08-302 - 草戊//全局变量 int i = 0; { //这里引用的是全局变量 i = 2; println(i); //输出:2 //允许在块里新创建一个同名的变量 int i = 3; println(i); //输出:3 } 您好,上面例子中 【i = 2;】这句话在块中使用全局变量,但是实际上此块中也定义了i变量,只不过位置比较靠后,这种情况,本文中的作用域有办法解决吗?如果优先在本块中查找,那么会不会找到自己块中的i,而不是全局的i呢?
作者回复: 实际上,在每一行代码,可以见到的“可用表达式”的集合都是不一样的。也就是说,在每一行,你可以反问的变量都是不同的。 比如,在int i = 3之后,你访问的i,和在它前面访问的i,是不一样的。 也就是说,块作用域,并不是在整个块里可见,而是在这个块里变量声明之后才可见。 在28讲,数据流分析中,专门有活跃性分析的一个算法,会教会你确定在每个位置的可用变量。
2019-12-221