4

I have been assigned such a problem in my software development course. So, the normal way is to check each procedure one by one and remember each call by each subprogram, however, I am a bit lazy programmer and I have decided to take a shortcut by implementing given pseudocode in an actual programming language.

Problem statement:

    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;

Consider the program above. Given the following calling sequences and assuming that dynamic scoping is used, what variables are visible during the execution of the last subprogram activated? Include with each visible variable the name of the unit where it is declared (e.x. Main.X).

  • Main calls Sub1; Sub1 calls Sub3; Sub3 calls Sub2;

My Attempt:

$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";

I'm stuck at this point and have no idea how to change the code so that it shows me the variables. I see that solution is obvious, but I've coded in C++ and Java so far.

Sakhund
  • 228
  • 1
  • 5
  • 32
  • 2
    You can examine the lexical variables in the caller by using somthing like [PadWalker](https://metacpan.org/pod/PadWalker). Package variables can be inspected using something like [Devel::Symdump](https://metacpan.org/pod/Devel::Symdump) – Håkon Hægland Oct 27 '21 at 19:49
  • @HåkonHægland I don't really know what is Perl package. But I will definitely check PadWalker and Devel::Symdump. Thanks! –  Oct 27 '21 at 19:59
  • Since we don't know which sub is the last one called (since we're too lazy to figure it out), so we need to print the vars in the all subs that don't call other subs. – ikegami Oct 27 '21 at 20:05
  • 2
    Lazy programmer will always find the better ways. But I did figure out the right (hard) way. I was just curious about automatic way. –  Oct 27 '21 at 20:16
  • 1
    You might have a mismatch between what your instructor means by "dynamic scoping" and what in means in Perl. `local` makes a localized change to the value of a value of a global variable. It does not affect the visibility of the variable (which, being global, is visible everywhere). – Michael Carman Nov 19 '21 at 13:25

2 Answers2

4

It would be nice if you've spent the time you used on asking this question on watching tutorials. However, we all have been there at one point, being confused exploring new languages. Try not to ask for the answer to your homework next time.

So, I see you'd like to use Perl, a good choice. I myself have done a similar task recently, here is my approach.

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.

Basically, it is based on the sequence of subprogram calls which are determined only at run time.

The following program shows how the subprogram calls affect variable value:

$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";

Output: Sub2.A, Sub2.B, Sub3.W, Sub3.X, Sub1.Y, Sub2.Z
Note: Sub0 is just Main subprogram scope.

Sakhund
  • 228
  • 1
  • 5
  • 32
2

If you want to check the values of the variables in each subroutine you would dump them out with a module like Data::Dump or Data::Dumper.

sub foo { 
  printf "foo() current values are %s\n\n", 
    Data::Dumper::Dumper($a, $b, $c, $x, $y, $z);
}

If you want to see the call stack of the current subroutine you would use the Carp module.

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



lordadmira
  • 1,807
  • 5
  • 14