 Welcome to part two of the lecture on runtime environments. So, we saw the need for runtime support and the parameter passing methods in the last part. Today, we will continue with the rest of the topics on storage location etcetera. So, programming languages the implementation usually distinguishes between code and data and even in the language specification you know we have code which uses the variables whereas, the data which declares the variables these are all different. And when we compile the program the code that is produced is actually just machine instructions and in 99.9 percent of the cases it does not have any embedded data in it. So, it is a good idea to keep both the data and the code separate even when the program executes on a machine. The reasons for this are many actually for example, the code area does not grow or shrink in size as the execution proceeds whereas, the data area can grow or shrink in size. But when can the code area change well if you consider java which has dynamic loading of classes and of course, it also has another facility to produce classes during runtime using reflection and then creating objects of that particular class. So, these features of java actually increase the code size because once you produce a class or load a class which did not exist before the methods of that class will also be loaded and that means, more code is added to the existing program. Memory area of course, can be allocated to codes statically and the reason is in general if we do not use java or any other language similar to that the code size does not change and we can say now the code will be placed in a particular area and it will never be shifted out of that area. And we will not consider java in this lecture, we will consider java and update oriental languages sometime later. Of course, as I already mentioned the data area of a program may grow or shrink in size during execution and that is precisely what we are going to discuss in the rest of this lecture. We have two types of storage allocation, one is the static allocation, the other is the dynamic allocation. So, what exactly is static allocation? The compiler says here is the data and now it makes the decision regarding storage allocation of for this particular data by looking at the program text, it has no other consideration. I will give you an example of this in a few minutes and what about dynamic allocation? In this case the storage allocation decisions are made only when the program is running, in the static case the compiler itself makes the decision and nothing is left to the runtime system. And there are two types two possible allocations, one is the stack allocation other is the heap allocation. So, names local to a function or procedure are allocated space on a stack that would be a stack allocation whereas, in the case of heap allocation usually this is not used for the names, but this is used for dynamic data structures such as symbol tables etcetera. And this is used for data that may leave sometimes even after a procedure call returns of course, it can be used within a procedure also, but the data structure being separate from the stack allocation given to variables etcetera. The data structure can leave even after the procedure which created the data structure actually terminates. For example, in the symbol table structure that is used by compilers many stages or phases of the compiler modify or use the symbol table and it is created at different places in the compiler, but it leaves as a global data structure. So, heap allocation requires a memory manager and garbage collection is also required whether it is explicit or automatic that is up to the language and the runtime system. So, we will study this little later. So, let us come back to static data storage allocation, here is a memory map of the of a particular program. There are main program variables then procedure p 1 and its you know its variables procedure p 2 its variables procedure p 4 its variables and so on and so forth. As I said the code is separate. So, these are just the data areas and all this is in the main memory. So, what is being shown here is that the addresses from this point to this point are occupied by the main program variables from here to here it is occupied by variables of p 1 from here to here it is occupied by the variables of p 2 and from here to here by the variables of p 4. So, these addresses are fixed they are not going to change at any time. The compiler allocates the space for all the variables both local and global of all the procedures at compile time itself. The characteristics of this are there is no stack or heap allocation. So, there is no overhead in accessing the variables there is no need to create what is known as an activation record as we will see later. So, the overheads are very less the languages which have such static data allocation are 4 trans 4 which and 4 trans 7 to 7 which are very old programming languages. Then the advantage is because the addresses are all known at compile time accessing the variables is very fast and disadvantage of this scheme is you cannot implement recursion using static allocation. I will I will I will simply tell you why see suppose procedure p 1 calls itself. Now, the data area of p 1 is fixed the same area will be used by the second instance of p 1 which is being recursively called. The original instance of p 1 and the second instance are both alive at the same time, but the data area being single the second instance of procedure p 1 will overwrite all the data which was probably created by the first instance. So, this implies that we really cannot use recursion profitably like for example, in the case of factorial the values of the factorial for smaller numbers will all be over written by the higher numbers. So, this is the this is the problem that we have here. So, rather any other Fibonacci or any other number you know when you write a recursive program as the recursion goes deeper and deeper the old data would be destroyed and the new data will be written over that and thereby no useful work gets done. So, what exactly is dynamic data storage allocation? The compiler allocates space only for the global variables at compile time it does not allocate any space for the variables of procedures at compile time they will all be allocated only at run time. So, the implication of this is that there is either a stack or heap necessary to create the space for all these variables and the languages which use such data storage allocation or C C plus plus java 4 drawn 8 or 9 etcetera. The access to variables is a bit slow compared to the static allocation simply because the addresses are now access through a stack or heap pointer and of course, the biggest advantage is that recursion can be implemented in this case. So, this is how the schema would be in the case of dynamic storage allocation here is the main program which calls the function R R calls Q and then Q calls R again. The what is shown here are the what are known as activation records which are nothing but the data areas for the various activations of the functions or procedures. So, the variables of main are all stored here variables of R are all stored here similarly, for Q and this is the second instance of the function or procedure R and you can observe that the variable space for this second instance and the first instance are different thereby useful work can be done by both the instances. So, the currently active procedure is at the top of the stack here. So, if there is a so to begin with we have allocation only for the global variables and main when calls R the data space for R is created and then when it calls Q the space for Q gets created and then there is a recursive call to R another space for R gets created and so on and so forth. And as the procedures terminate so, when R terminates the space for R will be released and the picture would be you know base will be here and next will be here. Similarly, when Q returns the space of space required by Q used by Q will be returned and similarly, the space of R as well and finally, when the main program terminates all the space will be released by the run time system. So, I kept mentioning the activation record more than once basically an activation record has space for all the variables temporary is you know the machine status, the function result and the return address apart from what is known as static and dynamic links. So, let me explain some of these now and we will postpone a few others later to other to a later point in time. Another important thing is the position of the fields which are shown here are only notional it is not necessary that the same layout is used by all compilers. For example, you know saved machine status and you know the could possibly be at the beginning return address could also be at the end the function result possibly could be somewhere here. So, it is possible to change the location of these fields without affecting either the efficiency or speed of the program itself. So, we know very well what exactly the return address is it is required by the program to return to the caller. We will postpone the discussion of static and dynamic link which is used to access global variables from a from the current procedure. The function result so, we already saw in the case of intermediate code generation that the address of the function result the variable which is going to contain the function result you know the address of that variable will be passed as a parameter implicit parameter and that is what is put here. So, the address of this variable actually belongs to the caller address space. These are the actual parameters then there is a lot of space for local variables and temporaries used by the function and finally, of course, saved machine status and space for local arrays. The question that arises is why is the space for local arrays at the end instead of being somewhere here. Suppose there are local variables which are arrays why was the space not allocated among these variables and why is it being pushed to the end. Well the same is true for parameters as well if there are array parameters why are they not being allocated here and why are they being allocated here. The answer is the local the local variables or parameters which are non arrays will all require known amounts of space. Therefore, the offsets for the various variables and parameters can be computed very quickly and very easily by the compiler whereas, the size of the arrays can possibly vary you know if it is a parameter and the size of the array is not being supplied. Then it is best left to the end of the activation record because we will know the space for this array only after we enter the procedure you know the caller calls the procedure only then the size of that array will be known otherwise when we compile the procedure this size of the array will not be known. So, and of course, making it more uniform among these is the other reason, but technically speaking including the unless the size of the arrays is unknown at compile time including it within the space for local variables or parameters does not make any difference as far as the compiler is concerned. So, there is you know a little more on the variable storage offset computation we saw how this could be done during the you know the other lectures. For example, the compiler should to compute the offsets at which the variables and constants will be stored in the activation record. So, I showed you this picture. So, here are the local variables and if there are several variables here we should know at which position these variables will be placed on the stack. So, with the with respect to the beginning of the activation record which is known as which is denoted as a 0 the offsets of all the variables and temporaries will be computed. So, the variables are usually stored in the activation record in the declaration order. So, this is something I already mentioned and they can be computed during semantic analysis of the declarations. I want to show you a little more than what we did in the semantic analysis stage for the variable storage allocation or rather offset computation. Here is a program procedure called int example. So, it returns int as its result it has two parameters then it has three way you know variables a b c each of size 10. So, 10, 10 and 10. So, now for this particular beginning it is very easy to compute the offset because a begins at 0. Obviously, b will have an offset of 10 and c will have an offset of 20. Let us assume that in the c style there are blocks in between not procedures just you know the blocks compound blocks. So, the block b 2 will have three variables d e and f these are possibly arrays. So, they have sizes 100, 180 and 40 respectively and now the last variable was given offset of 20 here its size was 10. So, it is only correct that the offset of the variable d here is 30 then 130 you know 30 plus 100 and then 130 plus 180 would be 310. So, this is the offset information as far as b 2 is concerned b 2 ends here and another block b 3 begins at this point. So, the variables of this block and this block have nothing to do with each other. In fact, I cannot access the variables of the block b 2 from within the block b 3. Therefore, there is nothing wrong in reusing the space that was given to the variables of b 2 for the variables of b 3. So, that is what we are trying to do. So, now how do we do that the offsets began here at 30. So, we will also begin the overlapping block offset at 30 here the sizes are 20, 20 and 10 for the variables of b 3. So, the offsets are appropriately computed as 30, 50 and 70 within b 3 there are two more overlapping blocks b 4 and b 5 which again share the same storage area. So, for b 4 the offsets begin at 80 because this is 70 and plus 10 would give you 80 and the other two are 150 and 300 because 80 plus 70 and 150 plus 150. This b 5 also begins its offsets at the same value 80 and then of course, 80 plus 20 is 100, 100 plus 50 is 150. The storage is overlapped for these two blocks and of course, the storage is overlapped for this block and this block these two inclusive of within b 3. So, what is the maximum storage that is required for the entire function and its variables. So, this is very easy to compute the storage required would be the storage required for b 1 then the maximum of the storage required by this and this. So, b 2 and followed by you know the b 3 within b 3 we have b 4 and b 5. So, again we have a max of b 4 and b 5. So, b 3 plus max of b 4 comma b 5 and that overlaps with b 2. So, if you replace the values as given here we really get 350 this is much more than the total space that is required by the program if we simply add up all the sizes of all the variables. So, you can do that here you know this is 30. So, 320 plus 30 is 350 then plus 50 is 400 plus 240 is a 640 plus 440 plus 440 plus 440 plus 100 would be 740. So, instead of that we are really using only 350 here. So, this is the advantage of you know recognizing the fact that the data blocks can you know overlap. So, this is just another explanation of the same phenomenon. So, we have b 1 30 and b 2 320 the space here overlaps with b 1. So, b 1 remains the same within that instead of b 2 equal to 320 we have b 3 and b 4 other possibilities we have b 1 b 3 and b 5 these actually happen at various points in time. So, for example, after b 1 begins you know its data area will always be present in memory the area of b 2 comes into existence when b 2 executes and it vanishes once b 2 terminates. The area for b 3 begins at the same offset here as b 2 and the same thing happens with b 4 and b 5. B 4 starts and then terminates so the same area is used by b 5 and finally, when b 3 terminates all the area would be released and then b 1 terminates the program terminates. So, now let us look at activation records with nested procedures. So, if there is no nesting of procedures for example, here let us assume that main R, Q and R are all at the same level as in C. So, the allocation of activation records and deallocation of activation records is very simple I already explained that as the call sequence progresses the activation records created and as the sequence strings and the procedures return the activation records are returned to the storage pool. Whereas, if we have nested procedures one language which has such nested procedures is Pascal it is necessary to know even though Pascal is not used in practice anymore it is definitely necessary to know the implications of nesting procedures within other procedures. So, for example, here is the main program RTSD within that we have declared a procedure P within P we have declared another procedure Q and this is the end of procedure Q Q and R are at the same level then we have the body for R here and this procedure P has its body here begin R end and finally we have the body for the main program RTSD begin P end. So, now the program control begins at the main program. So, P will be called and when P begins execution the body of P begins execution. So, in this R will be called. So, when procedure R is called it calls Q in turn and then when Q is called it calls R in turn and this recursion will go on for a while and finally you know this R will terminate without calling Q and that would make Q also terminate and finally P will terminate and the program ends. So, this is the call sequence that we have assumed for our example RTSD calls P P calls R Q calls R calls Q Q calls R again and then the recursion ends and entire sequence drops down. In such a scenario it is not enough to simply link the activation records and hope for the rest it is necessary to do something more than that. Activation records are created at procedure entry time and are destroyed at exit time as before, but the difficulty arises when we want to access the variables which are in the various procedures which have been invoked. So, let us understand the scope of the variables in such a scenario for the main program the variables would all be declared just after the program statement. So, the main program can access all the variables declared within itself, but it cannot access any variables which are hidden within the procedure P or Q or R. So, these are actually insulated from the program RTSD. So, we can only call the procedure P and when procedure P starts executing it will have its own variables just after the procedure statement, but again it cannot access the any variables of procedure Q or procedure R. The same thing holds as far as procedure Q and R it you know Q cannot access the variables of R and R cannot access the variables of Q, but when we are executing program the procedure P, we can access not only the variables of P, but also the variables of the main program. So, which is one level above it because P is nested within the program RTSD. Similarly, when Q is executing it can access the variables within Q, it can access the variables within P in which it is nested and of course, it can also access the main program variables in RTSD because P is nested within RTSD. The same is true for R as well variables of R variables of P and variables of program RTSD, but R cannot access the variables of Q and Q cannot access the variables of R. This must be remembered when we construct the activation records as we go along. So, we call the procedure P. So, an activation record for P is created. So, now let us understand how the variables are accessed from the procedure P. If the local variables of procedure P are being accessed, then the top of the activation record which is available in the register base can be used to access the variables within the data area or activation record of P. We know the offsets of the various variables and parameters within P within the activation record. So, base plus the top set will give us the address at which the variable or parameter is situated. But what about the variables of the main program RTSD? It is not possible to do that using the base pointer, but we need to maintain extra information on the previous enclosing procedures activation record. So, this is maintained in what is known as the static link chain SL chain. The DL chain simply you know chains all the activation records in order to maintain a stack structure nothing more than that really. So, when we want to access the variables of RTSD, the SL you know field of the activation record has to be put into a register and the contents of that activation of that register will now point to the beginning of the activation record for RTSD. So, we must now consider this particular value and then access the variables of RTSD using the offset. So, in other words we have we need an indirect addressing mode here. So, rather double indirection the first level of indirection we must move the contents of the static link into a register and then use the contents of that register as an address. So, we require two levels in order to access the variables of RTSD whereas, to access the variables of P we already know the activation record address in base. So, only one level of indirection will be required now P calls R. So, you can see that R is nested within the procedure P. So, we can access the variables of R the procedure that of the procedure P and also the program RTSD. So, as usual the variables of R can be accessed very easily using the base pointer and then using one level of indirection using the static link we can access the variables of P and using two levels of indirection we can access the variables of RTSD. Every time even though the pointer points to the middle of this activation record it is actually giving us the beginning of the activation record the address of the beginning of the activation record from where all the offsets are measured. So, we must go from here to this activation record access the static link in that activation record take that and go to this activation record and access the variables within RTSD. So, two levels of indirection will be required this is correct because I can access the variables of R and then P and also the RTSD. Now, Q calls R. So, we call P then R then R calls Q. So, the activation record for Q gets created, but from within Q I cannot access the variables of R I can only access the variables of Q variables of P and variables of RTSD. So, making the static link point to the activation record of R would be a mistake because we can now access the variables of R also using the static link available in Q. To be correct the static link of Q should point to the activation record of P just like the static link of R pointed to the activation record of P. So, now I can access the variables of Q directly using base variables of P using one level of indirection using the static link and using two static link indirections I can access the variables of RTSD also. So, all this static link traversal must also be translated to instructions in machine code. So, the at run time these instructions will be executed the static link fields will be moved into appropriate registers and then the variables will be accessed at run time. The last call in our chain Q calls R. So, R is created again we cannot link the static link of R to the activation record of Q and we cannot even link it to this R because these two R's are very different. There are two instances of the recursive invocations it should actually point to the activation record of P exactly like this pointed to the activation record of P. So, now we can access R and then one traversal will give us the variables of P and two traversals will give us the variables of RTSD. So, this is how the static link chain is used in order to access the variables which are global to this particular anyone of the procedures. So, we must also now observe rather we must also discuss how exactly we fill up the static link chains. So, as the call chain progresses you know see it is a fairly easy to understand that the creation of activation record takes place after the call assumes control because the exact size of the activation record will be known only to the callee function it will not be known to the caller callee functions can possibly be compiled even separately. So, the total area within the for the variables of the function its temporaries etcetera will not be known to the caller caller will only know the size of the parameter list and nothing else. So, the complete creation of the activation record really happens in the callee code. Now, something else must also happen during the callers while the callers code executes what exactly is that the level or the nesting level of the caller that information is lost once the control to the callee is actually handed over you know. So, if we hand over the control to the callee from where did we come and what was the nesting level of that particular procedure this information will not be available anymore the creation of the static link actually depends on both the caller and the callee. So, let us understand how this can be done. So, we have this call chain here let us consider somewhere in the middle you know p 2 calls p calls r the level of p 2 is indicated as 2 here p is indicated as 2 here level of r is indicated as 3 here. The formula which is used you know here is l 1 minus l 2 plus 1. So, what exactly does it show it says it says we must skip l 1 minus l 2 plus 1 records starting from the callers activation record and establish the static link to the activation record that is reached. So, let us understand what this is and then I will tell you what exactly is the code that is going to be generated. So, 2 minus 3 plus 1 is 0. So, this is just the formula l 1 minus l 2 plus 1. So, we are really here p calls r now we want to establish the static link of r the static link of p has already been filled let us assume that. So, this is the caller p is the caller and r is the callee starting from the callers activation record we must now skip 0 activation records because l 1 minus l 2 plus 1 is 0 that means, we stay at p. So, the activation record which is reached after we skip l 1 minus l 2 plus 1 records is p itself. Therefore, it is correct to establish the static link of r to point to p itself. Now, let us understand what happens when r calls q. So, the next level r calls q. So, this. So, the level of r is 3 the level of q is also 3. So, 3 minus 3 plus 1 is really 1. So, the formula tells us that starting from the caller which is r we must skip 1 activation record now we point to now we actually come to p and it says the static link of q must now be established. So, that it points to p. So, while the code generator is generating code the number of hops that must be done you know must also be translated into instructions. So, if we say we want to skip 1 link here it implies that you know we read the activation the static link of within the activation record of r and then take the contents of that. So, that will give us the beginning of the activation record and that is to be used as the activation rather the static link of this particular q. So, instructions must be generated to move this value into the static link field of the activation record the offsets for all these fields are already known. So, it is not they are all with respect to the base pointer. So, the base register will also be known and therefore, generating these instructions is quite straight forward. So, let me you know straight again. So, we really have to skip l 1 minus l 2 plus 1 records starting from the callers activation record go to that particular record and then you know make that as the value of the static link for the calling. So, from here we skip 1 and this is the static link value for q. Similarly, from the caller we skip once and that is the static link value for r etcetera. Now, the release of the activation records happens in the reverse order. So, we return from r. So, the activation record for r r is released to the storage pool then we return from q and the a r of q is returned. Similarly, for r and p as well once the main program terminates the storage required by the main program will also be returned to the storage pool. So, what we have used so far you know in our discussion was actually it will utilize the static link and the dynamic link. The static link was used to access the global variables in the various activation records and the dynamic link was used to maintain the stack of activation records. This task can also be carried out using another data structure called as the display stack of activation records. So, instead of you know using a static link what we do here is to maintain a list of you know a stack of pointers which point to the activation records of procedures which are right now executing. For the same program that we saw here the sequence is r t s t calls p, p calls r you know r calls q, q calls r. So, this was the sequence we trace there. So, let us trace the same sequence here as well. So, to begin with the display stack contains a pointer to the activation record of r t s t alone. Now, there is no need for the static link we have pointers of all the activation records maintained on the stack. However, the dynamic link is definitely necessary to maintain the stack structure do the allocation and deallocation etcetera. R t s t calls p. So, the activation record pointers of r t s t and p are both on the stack that of p is now pushed on to the stack p calls r. So, now we have three activation records which are present and r p and r t s t are also all three are on the stack. So, remember the most recent procedure which is activated its activation record pointer is on the top of the stack. Now, r calls q. So, situation changes here justifiably. So, because it is not correct to push the activation record pointer of q on top of r here. The implication of that would be the variables of all these would be accessed from all the other procedures as well. So, the display stack structure must reflect the scope of the various functions and procedures appropriately. So, when we say r p and r t s t here the implication is the where the control within r can access the variables of r the variables of p and also the variables of r t s t and this reflects correctly the scope structure of the nesting of the program. So, you can see here r p here then p here and r t s t here. So, when q is called from r we must replace the pointer of r with the pointer of q. So, we have only q p and r t s t which again reflects the nesting structure properly. So, q p and r t s t. So, then what happen to the pointer r the pointer r was actually stored within the activation record of q. So, it would be unsaved once we return from q. So, from q we call r. So, again the activation record of q is saved in the sorry the pointer to the activation record of q is popped from the stack it is saved in the activation record of r and the activation record pointer of r is pushed on to the stack. So, this is the stack structure which is very similar to the static link structure of the previous scheme. So, once we return the pointer of r is popped and the pointer of q is unsaved from the activation record of r. The same thing happens when we return from q q is popped and the pointer for r is unsaved. The same thing have you know once we come here there is nothing to unsave the pointer of r will be thrown away and here we return to the main program the pointer of p will be thrown away. So, and once r t s t completes the display stack becomes empty. Here also the formula which can be used to pop a certain number of pointers from the stack and then the display stack and you know save them in the activation record the formula is the same. Pop l 1 minus l 2 plus 1 records of the display of the caller and push the pointer to the activation record of the call l 1 is the caller and l 2 is the calling. So, let us do that here to here. So, this r and this is q. So, 3 minus 3 plus 1 is 1. So, we have popped one pointer from the activation from the display stack of at this stage. So, r goes away and we push the activation record pointer of q on to the stack this r will be saved. So, the same thing holds here as well both are at the same level. So, one pointer is popped here and other pointer is pushed on to the stack. So, the pop l pointers are stored in the activation record of the caller and are restored to the display after the call l returns. So, that brings us to the next concept in runtime environments. So, we so far we have studied you know activation records how the activation records are really you know allocated, deallocated etcetera. So, in the just to add one extra point when we have a C like structure for the programming language that is known as string of any procedures within another the situation is very simple because no procedure can access the variables of another procedure they are all similar to q and r. So, there is no need for you know the static link structure at all we access either the variables of the self procedure or the global variables. Global variables are all in a particular static area and the local variables of the currently active procedure are in the activation record. So, I do not need any static link I only need two links one to the beginning of the activation record and another to the static area containing the global variables. The dynamic link structure of course, will be required to take care of the stack allocation and deallocation. So, far what we have seen is actually the static scope for a programming language. So, let us understand the term static scope the languages which we have seen so far C C plus plus Pascal java they all have what is known as static scope. A global identifier refers to the identifier with the name that is declared in the closest enclosing scope of the program and it uses the static or unchanging relationship between the blocks in the program text. Static scope is also called as lexical scope. So, the nesting structure which is shown by the program like here this is the one which is used by the static scope you know scheme. So, procedure Q is nested within P procedure P is nested within R T S T. So, and as I already explained the variables are accessed from Q the variables which can be accessed from Q or itself and then those of procedure P and those of procedure program R T S T. So, this nesting structure which is fixed and does not change you know dictates which variables can be accessed at various points in time and that information since it does not change can be built into the code which is produced in the form of static links etcetera. There is another concept known as dynamic scope So, functional programming languages actually use dynamic scope quite routinely. A global identifier refers to the identifier associated with the most recent activation record and it uses the actual sequence of calls that are executed in the dynamic execution of the program and both schemes are identical as far as the local variables are concerned. Now it is time to take an example and understand what is dynamic scope because the text itself does not make it very clear. So, here is a concocted program which looks like a C program, but it is definitely not C because C does not have dynamic scoping. So, let us understand there are two variables X and Y then there is a function G which takes one parameter which takes one parameter and returns X plus Z and another function F which has a parameter Y another parameter another variable X X is Y plus 1 and it calls G Y star X and returns that as the value. So, here in the main program we call Y equal to F 3. So, let us understand what happens if this were to be a simple C program F is called. So, Y becomes 3 and then here is the local variable X. So, X equal to Y plus 1 will produce 4 Y was 3 now we call G with Y star X 4 into 3 is 12. So, we go to G Z is 12 and then we call and X which is here actually refers to the global variable X here. So, this is 12 and this is 1. So, we return 13 as the value and 13 is returned to the main program as well and that is assigned to Y. This is the normal scheme as far as static scope is concerned in C dynamics. So, this is the activation record structure here is the outer block main program X is 1 and Y is 0 to begin with then we call F with 3. So, the parameter Y has 3 value and the integer variable X will have value 4 at the time of calling G because its assignment is already over. We call G with 12. So, the variable Z gets the parameter Z gets value 12. Now, if we had assumed C like structure the X here always refers to the global variable right, but if we assume a dynamic scope a non-C like scheme the dynamic scope clearly says the global identifier refers to the identifier associated with the most recent activation record. So, in other words when we are in G here there is no problem when we are in G the global variable X is 1 of the occurrences of X and the local variable X within F is another occurrence of X. F has not terminated. So, this value is very much alive you know when we have created this activation record there is this instance of X within the activation record for F and this instance of X within the activation record for the main program. Dynamic scope says start from the current block keep going upwards in the this stuff activation records find the activation record which is very which is the closest to Z and contains an instance of the variable that we want. So, in this case as we go upwards it is the local variable of F X which is the local variable of F that is relevant to us this is called dynamic scope. So, the value of X which is relevant at this point here is 4 instead of being 1 because it is the variable X within the function F. So, this is 4 and this is 12. So, we really return the value 16 this is dynamic scope let us take another example here is a variable R global variable 0.25 then there is a procedure void show then there is a procedure void show which prints R then there is another function small which has a local variable R and assigned a value 0.125 and then show in the main program we have 2 sequences show small print F show small print F let us see what is printed show is called. So, within show the value of R is obviously the global variable because it has no local variables within itself and there is no other function which is active. So, 0.25 is printed out and then we call small. So, there is a local variable R here and then show is called, but static scope says look at the static structure of the program. So, this variable R is not visible within show it is again this 0.25 which is printed out then you know we come to the second line which is similar again 0.25 and 0.25 is printed out. If we assume dynamic scoping for show there is no difference because there is only one global variable which is visible, but once small is called this R becomes visible. So, where this show now has a choice of either this R or this R this is the most recent activation record containing the variable R. So, it is 0.125 which is relevant to this show as well. So, this R is printed out as 0.125 the same is true for the second one as well. So, in dynamic scoping when we have a choice the most recent activation record is used and it is the variable which is present in that record is actually utilized. So, let me stop here we will continue with the implementation of dynamic scope in the next lecture. Thank you.