静态(词法)范围与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 ,但是我已经把它们标记为x1x2来简化下面的讨论。

通过词汇范围确定,我们在编译时根据程序源代码的静态,词汇结构来确定我们所指的x定义 bx的最内层定义是x1 ,所以写的问题parsing为x1 ,这就是x = 2写的地方,所以我们在运行这个程序时打印2

通过dynamic作用域,我们有一堆在运行时跟踪的variables定义 – 所以我们写的x取决于在作用域内究竟是什么,并且已经在运行时dynamic定义。 开始运行时ax => x1推入堆栈,调用cx => 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。