静态(词法)范围与dynamic范围(伪码)
Program A() { x, y, z: integer; procedure B() { y: integer; y=0; x=z+1; z=y+2; } procedure C() { z: integer; procedure D() { x: integer; x = z + 1; y = x + 1; call B(); } z = 5; call D(); } x = 10; y = 11; z = 12; call C(); print x, y, z; }
根据我的理解,使用静态范围运行时此程序的结果是:x = 13,y = 7和z = 2。
但是,使用dynamic范围运行时,结果为:x = 10,y = 7和z = 12。
这些结果是我们的教授给我们的。 然而,我不明白他是如何达到这些结果的。 有人可能通过伪代码来解释它们在两种不同types的示波器中的值吗?
使用静态(词法)作用域 ,程序源代码的结构决定了你所指的variables。 通过dynamic范围确定 ,程序堆栈的运行时状态决定了您所指的是哪个variables。 这可能是一个非常陌生的概念,因为现在基本上每一种广泛使用的编程语言(除了emacs lisp也许除外)都使用词法作用域,这对于人类和分析工具来说都是非常容易理解的。
考虑这个更简单的示例程序(用你的伪代码语法编写):
program a() { x: integer; // "x1" in discussions below x = 1; procedure b() { x = 2; // <-- which "x" do we write to? } procedure c() { x: integer; // "x2" in discussions below b(); } c(); print x; }
程序和编译器把这两个variables都称为x
,但是我已经把它们标记为x1
和x2
来简化下面的讨论。
通过词汇范围确定,我们在编译时根据程序源代码的静态,词汇结构来确定我们所指的x
。 定义 b
时x
的最内层定义是x1
,所以写的问题parsing为x1
,这就是x = 2
写的地方,所以我们在运行这个程序时打印2
。
通过dynamic作用域,我们有一堆在运行时跟踪的variables定义 – 所以我们写的x
取决于在作用域内究竟是什么,并且已经在运行时dynamic定义。 开始运行时a
将x => x1
推入堆栈,调用c
将x => x2
推入堆栈,然后当我们到达b
,堆栈的顶部是x => x2
,所以我们写入x2
。 这使得x1
不受影响,所以我们在程序结束时打印1
。
此外,请考虑这个略有不同的计划:
program a() { x: integer; // "x1" in discussions below x = 1; procedure b() { x = 2; // <-- which "x" do we write to? } procedure c() { x: integer; // "x2" in discussions below b(); } c(); b(); }
注b
被称为两次 – 第一次通过c
,第二次直接。 通过词汇范围界定,上面的解释不会改变,我们两次写入x1
。 但是,dynamic范围的确定取决于x
在运行时如何绑定。 我们第一次调用b
,就像上面解释的那样写入了x2
,但是第二次,我们写入了x1
,因为这就是栈顶的东西! (当c
返回时, x => x2
被popup。)
所以,这里是你的教授的代码,用哪个确切的variables用哪个写词法范围来注释。 程序结束时打印的结尾标有*
:
program A() { x, y, z: integer; // x1, y1, z1 procedure B() { y: integer; // y2 y=0; // y2 = 0 x=z+1; // x1 = z1 + 1 = 12 + 1 = 13* z=y+2; // z1 = y2 + 2 = 0 + 2 = 2* } procedure C() { z: integer; // z2 procedure D() { x: integer; // x2 x = z + 1; // x2 = z2 + 1 = 5 + 1 = 6 y = x + 1; // y1 = x2 + 1 = 6 + 1 = 7* call B(); } z = 5; // z2 = 5 call D(); } x = 10; // x1 = 10 y = 11; // y1 = 11 z = 12; // z1 = 12 call C(); print x, y, z; // x1, y1, z1 }
这里是dynamic的范围界定。 注意唯一的变化是在B
和*
标签的位置:
program A() { x, y, z: integer; // x1, y1, z1 procedure B() { y: integer; // y2 y=0; // y2 = 0 x=z+1; // x2 = z2 + 1 = 5 + 1 = 6 z=y+2; // z2 = y2 + 2 = 0 + 2 = 2 } procedure C() { z: integer; // z2 procedure D() { x: integer; // x2 x = z + 1; // x2 = z2 + 1 = 5 + 1 = 6 y = x + 1; // y1 = x2 + 1 = 6 + 1 = 7* call B(); } z = 5; // z2 = 5 call D(); } x = 10; // x1 = 10* y = 11; // y1 = 11 z = 12; // z1 = 12* call C(); print x, y, z; }
静态作用域和dynamic作用域是在用任何语言编写的程序中查找具有特定唯一名称的特定variables的不同方法。
它特别有助于解释器或编译器决定在哪里以及如何findvariables。
考虑下面的代码,
f2(){ f1(){ } f3(){ f1() } }
静态的:
这基本上是文本的,首先定义的variables是否在本地函数中被检查(让它命名为f1()),如果不在本地函数f1()中,那么variables将在函数f2 (通过这个我的意思是f1()),…这继续…直到findvariables。
dynamic:
这不同于静态的,从某种意义上讲,因为它是更多的运行时或者dynamic的,第一个variables被定义或者不会在本地函数中被检查,如果不在本地函数f1()中,则variables将在函数f3 )调用这个函数( 这是我的意思是f1()再次),…这继续…直到findvariables。