编程语言问题,过程语言,动态范围

Programming Languages problem, Procedural Language, Dynamic Scope

我在软件开发课程中遇到过这样的问题。所以,通常的方法是一个一个地检查每个过程并记住每个子程序的每次调用,但是,我是一个有点懒惰的程序员,我决定走捷径,用实际的编程语言实现给定的伪代码。

问题陈述:

    procedure Main is
        X, Y, Z : Integer;
        procedure Sub1 is
            A, Y, Z : Integer;
        begin
        ...
        end;

        procedure Sub2 is
            A, B, Z : Integer;
        begin
        ...
            procedure Sub4 is
                A, B, W : Integer;
            begin
            ...
            end;
        end;

        procedure Sub3 is
            A, X, W : Integer;
        begin
        ...
        end;
    begin
    ...
    end;

考虑上面的程序。给定以下调用序列并假设 使用了动态作用域,在最后一个子程序的执行过程中哪些变量是可见的 活性?在每个可见变量中包含声明它的单元的名称 (e.x.Main.X).

我的尝试:

$x = 10;
$y = 20;
$z = 30;
sub Sub2 
{ 
   return $x; 
}
sub Sub1
{ 
   local $x = 9; 
   local $y = 19; 
   local $z = 29; 
   return Sub2(); 
}
print Sub1()."\n";

我被困在这一点上,不知道如何更改代码以便它向我显示变量。我看到解决方案很明显,但到目前为止我已经用 C++ 和 Java 编写了代码。

如果你把问这个问题的时间花在看教程上就好了。然而,我们都曾经有过这样的经历,对探索新语言感到困惑。下次尽量不要问你作业的答案。

那么,我看出你想使用 Perl,这是一个不错的选择。我自己最近也做过类似的任务,这里是我的做法。

As R. Sebesta (2019) writes in the book named "Concepts of Programming Languages" (12 ed.), the best examples of dynamic scoping are Perl and Common Lisp.

基本上是根据运行次才确定的子程序调用顺序

下面的程序展示了子程序调用是如何影响变量值的:

$x = 0;
$y = 0;
$z = 0;
sub sub1
{
    local $a = 1;
    local $y = 1;
    local $z = 1;
    return sub3();
}

sub sub2
{
    local $a = 2;
    local $b = 2;
    local $z = 2;
    sub sub4
    {
        local $a = 4;
        local $b = 4;
        local $w = 4;
    }
    return "Sub".$a.".A, "."Sub".$b.".B, "."Sub".$w.".W, "."Sub".$x.".X,
"."Sub".$y.".Y, "."Sub".$z.".Z";
    
}

sub sub3
{
    local $a = 3;
    local $x = 3;
    local $w = 3;
    return sub2();
}
print sub1()."\n";

输出: Sub2.A, Sub2.B, Sub3.W, Sub3.X, Sub1.Y, Sub2.Z
注意Sub0只是主子程序范围。

如果你想检查每个子例程中变量的值,你可以使用 Data::DumpData::Dumper.

之类的模块将它们转储出来
sub foo { 
  printf "foo() current values are %s\n\n", 
    Data::Dumper::Dumper($a, $b, $c, $x, $y, $z);
}

如果您想查看当前子例程的调用堆栈,您可以使用 Carp 模块。

use Carp;
sub foo { Carp::cluck("foo() here"); }
sub bar { foo() }

&bar;

# Output
foo() here at (eval 284) line 1.
        W::foo() called at (eval 284) line 1
        W::bar() called at (eval 285) line 1
        eval 'package W; bar' called at script.pl line 116
        console::_console called at script.pl line 473