 So, somebody would please remind me at 4.45 to stop and then discuss about mode of exam. Next week we have first lecture exam, because there was some discussion in the evening about open book, open notes, closed book, whatever. So, we discussed that in the finalized because then I need to explain it. So, somebody please remind me at 4.45. So, we started looking at semantic analysis state of the compilation. We looked at the models, how we are going to create the semantic analyzer and what was coming over that we want to have certain properties associated with each of the grammar symbols and we are going to call that as an execute grammar. So, let us look at what is the framework for execute grammar and how we are going to then have an implementation. So, this is really, now I mean after syntax analysis everybody is familiar with property grammar. So, basically what I want to do now is that once we have a context to grammar and we have the grammar symbols, these grammar symbols I want to associate certain properties. At this point of time, let us not worry about what these properties are. Depending on what we are trying to do, these properties could be different. So, for example, if I am trying to do type checking. So, what I am talking about is now a more general framework. If I am trying to do type checking then maybe I want to have some type information. At some point of time when I start doing code generation in the later part of the compilation then you will find that with certain attributes, with certain grammar symbols I would like to associate information about where these symbols are stored. So, I may say that I want to associate a register with this expression. I want to store this particular expression into a register or I want to store a variable into certain register. So, attribute is really a generalized property which I am going to associate with each of the grammar symbols and remember that each grammar symbol can have more than one attribute. So, it can have several properties not just one. So, this is really a generalization of context to grammar. Where each symbol will have certain properties associated and as far as type checking is concerned I would like to do certain computations. So, in the previous class you recall and I was giving an example that if I am trying to parse say type declaration and I want to then create a parse for the type declaration then how do I compute that when I encounter C the type of the C is int and the kind of tree we created for this class that I will have an int here and then I may have. So, my rule may look something like saying that a type name followed by a list. This may be a rule and then I may say the list is nothing but it could be let us because it is a rule. So, it is list followed by let us say identify a separated by com. So, I could get something like this that I can say this is my type name this is my list. So, this is what my declaration is and type name could be type which is integer this could be a list followed by form of followed by an ID which I say C here and then this again will be list followed by form of followed by ID and list could be. So, let me have another rule which will say that list could be ID and list could be ID here. So, this could be a parse before this type of declaration. And now when I am looking at say this particular node I want to associate this type here. Now, how do I carry this type here? I need to do certain computations could be a simple copy or it could be certain computations. So, with this node, this node and this node these are the three nodes that I encounter I want to make and please in the symbol table corresponding to these variables saying that type of this will be. And another example we had was that if we have let us say some expression where I want to associate again certain type values with it. So, if I have an expression like this where I say that e goes to let us say t plus e and this is my type expression. Let us say that ID 1 and ID 2 have already been declared. So, when they declared their values their type information is available in the symbol table. Now, what is the type of e? They do not want to do that computation because I do not know whether this is going to be a valid type. So, remember that somewhere I gave you an example where we said that a is assigned d plus say or 2 where this was in and this was string. Now, I want to find out whether this is a valid assignment or not. So, first I must know that for a valid assignment both the types must be same or I should be able to automatically type last it. But if the types have to be same then type of d plus 2 must be same as n for this assignment to be valid. Now, how do I know type of b plus 2? So, I know type of b from symbol table I know type of 2. And then I will have to do this computation to say that type of this particular operator may not be allowed on these kind of attributes. So, this is how we are going to sort of build a type system where I am saying that I am now associating a value where I will say that ID will have a type information with it. Similarly, ID 2 will have a type and then this type information will be carried up in the tree. Similarly, I may say that type information here will be carried across the nodes. So, it may be carried from one part of the tree to another part or it may be carried from the child nodes to parent nodes. So, values of attributes are going to be computed by the semantic rules. And now you can see that semantic rules for this and semantic rules for this are going to be different. So, you have to design these semantic rules. And there are two notations which are generally used. One is called synthesized attributes. Another is called inherited attributes. So, synthesized attributes as the name suggests is a situation where you say that attribute of a node in the parse tree depends upon the attributes of its children. So, if I know attributes of the children node, then I can do this computation. That is called synthesized means. And inherited attribute is a situation where we say that an attribute depends upon either the attribute of the parent or attribute of the siblings. So, in this case, for example, I may say that attribute of this part of the tree depends upon attributes of this part of the tree which happens to be sibling there. And attribute of this will depend upon attribute of this which is coming from the parent. So, we will have two kinds of attributes associated synthesized attributes and inherited attributes. And also, we have two notations associated with us. One is going to be pure specification which we are going to call as syntax directed definitions. In short here, I will show you what these specifications are. So, these are only specifications and do not give you any details about how to implement it. So, this is just here that I have some specifications. And then I want to implement it and implementation is going to be slightly different. Versus we have something known as translation themes. We are not only we give specifications, but we also give any evaluation order. So, for example, I may say here that in this case, if I say I have an attribute type, then I can always say. So, let me now put some symbols on this. And now when I say e1 and e2, I am not saying these are two different non-terminals. I am saying these are two different occurrences of the same non-terminals. My non-terminal is still e. So, I may write the rule like saying that whenever I do or you do it on this part. So, whenever I say that I have a rule which says e goes to id, I have an attribute equation which says e type is nothing but id type. And how do I know the id type? How will I find out the id type? In the declaration. So, here actually id type is nothing, but I may say look up type information for id type. This is what id type is because id has already been declared. The type information has already been entered in the symbol table. And when I am trying to pass this expression, that time I will say e type is nothing but look up this. And then if I write something like this which says e goes to e1 plus e or e goes to e1 plus e2. Now, the reason I am writing 1 and 2 are so that I can say that I am talking about an attribute of this, this and this. These are three occurrences of the same symbol. So, I may say that I may write some complex rule like saying that if e1 type is int and e2 type is int, then e type is int. So, this is saying that if both the types are integer, then this is integer type. And then I can enumerate it saying what are the possible combinations and I may also have a situation where I say that e type is an incorrect type. It is an erroneous type. So, for example, if I say e1 type is string and e2 type is const, then I will say that it is an error. Then I will say e type is an error type. So, that is how I will be able to flag errors in my type. So, these are really attribute situations I am writing. Now, this does not tell you if I look at these kind of specifications, this is not telling you in which order I am doing evaluation. It is just saying that I have certain specifications. And at some point of time, we will have to worry about evaluation of this. So, we will convert those into translation schemes and then use a parser to not only verify that the grammar is correct, but also to see that your types are correct. Same method can be used for code generation and so forth. They need to make sense. And I gave you an example again from YAK in the previous class showing you that you have already done this. So, if I go back to YAK, you have certain dollar symbols associated with each of the grammar symbols here. So, if I have dollar symbols, then what are the dollar symbols associated with these? So, I have dollar dollar with this, dollar 1, dollar 2 and dollar 3 with this. So, I can always add what are these dollar symbols? What is the type of this? What are the type of dollar? We define in the YAK file that it is x1 to x4 to x5 to x6. No. Have you ever seen the code of Y dot 5 dot c? Structure. This is structure. And what is the type of the structure? It is a union as a member of different data. It is a union. It is a union. So, you can like pass 22 more. You just cannot say two structures. Good. So, next time you ask a question, you must be directed. That is the DNS, right? Just do the look up. So, it is actually a union. So, you can like ask it to anything. So, if you recall now, that sometimes when you try to associate, say, integer values with this, it actually gives you a warning. Saying that you are associating a wrong type. So, unless you type pass first dollar-dollar, to eliminate those warnings, it will keep giving you those warnings. In C, I mean it is not an error. But you must know in terms of your implementation also. So, conceptually, both are really the same. Only implementation are different. But the intention is that as I am. So, conceptually, one way to look at this is that first I want to pass my expression or pass my program. And once I have constructed the pass field, then I want to traverse the pass field and compute this information. So, for example, here I will say that my pass field is going to be something like this. And once I have created this pass field, then I will say that if I now traverse it, and it does not matter in which order, I can let us say traverse it in any order. And multiple times. Then I will say that if I know type of this, if I know type of this, what is the rule of computation of type of this. So, I will have these kind of rules associated. It is not giving me any evaluation order. It is not giving me any order in which I want to translate. But ultimately, the goal is going to be that ideally, if I can construct parse tree and at the same time, I keep on computing my attributes, that will save me multiple passes. So, I try to write my attributes in a fashion that I can do it as I am parsing. And then we should be able to see that that will immediately lead to translation scheme. Because then I am saying that this is the order in which I build my parse tree and therefore, this is the order in which I should compute my attributes. So, we want to now traverse the parse tree to evaluate these semantic rules. But please also remember that that is only a way it is possible in some situations that I may not be able to do it in as I am computing my parse tree, as I am building my parse tree. It is also possible that I may have to have multiple passes over this parse tree before I can do this computation. So, all those situations are possible. So, evaluation of these attribute equations, it can either generate code, it can save information in the symbol table. So, for example, if I am parsing this, I am trying to save information in the symbol table. If I am parsing this and I find the types are not same, so I may issue an error message. I can perform any other activity. So, basically what we are talking about is now a framework on top of context tree numbers which is going to be used for implementation of rest of the field of computation. Any questions? So, let us move on. So, here is a small example. So, what I am showing you is a grammar. And what is this grammar? This is only saying that I have a number and the number is can be a sign number and sign could be plus or minus, nothing else. And then followed by a list and list is nothing but a list of zero symbols. I have a binary number which is either plus or minus. And what do I want to do? I want to now write some attribute grammar which is going to annotate number with value represents. So, for example, if I write something like, so if I say a number is minus 101. Then if I pass this using the grammar here, I will get the pass fee like this. You will say number is nothing but a sign and list and sign is going to be minus and list you can see this is a left recursive rule. So, this is giving list as list forward by a bit and this bit will be one. This will be again a list forward by a bit. This bit will be zero and this list will give me a bit which will be one. This is how the pass fee is going to be. And now what I want to do is I want to associate value saying if I look at this particular node, then what is the value of the tree below it? And finally, I want to find the value of this particular number. Let's say in decimal. Now, if I ask you to convert this binary to decimal, how will you do it? What is the algorithm you use? Place value. So, we say this is the rightmost bit. So, the place value associated with this is 2.2 to power 0. 2 is 2 to power 1, 2 to power 2 and then add up everything. So, I must know position of each bit before I can compute this. Now, same thing I must compute here. I must know positions of each bit. How will I do that? So, now let's see that can I write rules such that somehow given this parse tree and given certain rules which are associated with each of the nodes, I can find out the decimal value of this. So, it is intent clear for what I am trying to do. So, if I say that this number I have let's say an attribute associated value. And finally, I want to say value is minus 5. Is this what it is? 2 to power 0, 1 and 4. So, that we say 5. So, this is what I want. Now, tell me what are the rules I should write. So, that I can do this computation that when I finish this, when I do this, when I evaluate all my rules, the value of this particular variable will be minus 5. So, think about it. So, let's say what is the position of this bit? This position 0. Now, how do I get this position 0? So, if I say that to begin with whenever I am parsing and as I said that this point of time I don't care about the order of evaluation, I just want to write pure attribute equations. I can say that whenever I start creating this tree and it doesn't matter now whether I am creating it top down or bottom up because I can have multiple passes over it. That as soon as I start reading this number, I say that when position let's say position is defined as so position is now an attribute which is initialized to 0. And if I say that I have this attribute with number which is position, then I can say that list is a position. So, list position is so the way I am going to do it now, I will say that for attribute of this name list, I will have the grammar symbol followed by the attribute name because I can have multiple attributes. So, I will now say that list position is nothing but let's say number position. So, this will get me value of this value which is 0. Now, I can say bit position is let's say list position. That will also take me 0 and then I can say that this gives me position 0. And then once I know the position what will I do? Then I know standard technique I will multiply it with power of 2 to power of that position. But here I must take this position as 1 and here this position should be 2. So, now I can write a rule here which says that when I am looking at this list position, I can say list position is nothing but so let me call this attribute and this attribute, but a different name so let me call it list 1. So, that I can say now list 1 position is nothing but list position plus 1. And then if I now look at this so bit position is nothing but list position so it will get value 1 here. And what about this? Again the same rule will apply here which will take now value 2 and then I can say that this bit takes value 2. So, by starting this I can write rules. Now, you can see that if I take this subtree or this subtree as long as my grammar rule is the same, my attribute equation is the same. Some people are not in their heads, but I can see a lot of blank faces also and it is not clear. Are you understanding what I am doing here or not? Somebody who does not understand what I have done there. So, let me write this slightly differently. Let me write this grammar and here I am saying number is find list and find is plus or minus and list is followed by bit or list is followed by bit. And then I say bit is either 0 or 1, this is what my grammar is. Now, suppose I say that so let us not worry about sign for the time being. Sign I will read later. Suppose I say to begin with here, I say that now I am writing certain rules with this. So, this is my grammar and I am going to add rules to this. So, if I say my rule is something like this, where I say that list P is let us say initialized to 0 or I can say it is number dot position, but let me say it is initialized to 0. That is the rule which is associated with this particular grammar rule. So, this is an attribute equation associated with this grammar. And then I say when it comes to this particular grammar rule, I say that bit position so let me now differentiate between this list and this list by saying this is list 1. So, now I say that bit position is list position and list 1 position is list position plus 1. This is the rule I have. And here I say that bit position is nothing but then I say that when I am coming to this, let me say that bit value, now I have to compute the value. What is the bit value here? 0 will always give me 0, does not matter where it occurs. So, position is not important. Only when the bit is 1, then the position is important. So, I can always say bit value is 0 and here I can say that bit value is 2 to power bit position. So, now this is telling me that if I reach the bit which is at the leaf level, then I can look at contribution of each other. If it is 0, it does not contribute anything. If it is 1, then it contributes corresponding to where it occurs. But then I need to know what is the value of the number. So, I need to take this information back. And that is where I say that if I am reducing by this rule, then I can say what is the list value? It is nothing but bit value. Whatever is coming, whatever is the value of this bit, that is going to be the value which is copied here. So, this is bit value. What about this? When I have a rule like this, what is the value of the list? Now, to compute this value, I must know this value and this value. And I just need to add the rule. So, I can now say that list value is nothing but list 1 dot value plus bit value. And if I now find out what is the number value, as I said, let us ignore sign for the time being. So, what is the number value? List value. You can see that what I have are really specifications which is telling me that how do I compute value of this number? I do not know in which order I am going to do the computation, but I will find out. Now, let us do this. Suppose now I am also worried about the sign. So, now I can say that in this case, so let me write now, it is slightly different. So, I have two signs. So, now I can say that this is either positive or this is negative. So, I can just use a Boolean here and I can say that this is saying that sign value is true and this saying that sign value is false. I can use any attributes I wish. And now this rule is going to change slightly and now I will say that number value, what is number value? Now I can say if sign value is true, then what is the number value? Then I will say number value is let us say sign this one as minus this. So, I know that if I ever create a parse tree using these grammar rules and then I evaluate all these rules on my parse tree, I will get value of the number. And as I said at this point of time, I only have specifications. I do not care about in which order I am evaluating these specifications. That we are going to do at some later point. List one or new? No, no. So, please once again. So, list is the non-terminal I have. List one is just another occurrence of the same thing. I want to differentiate between attribute of this list and this list. Now, when it comes to implementation, I already have a method which says that this attribute is dollar-dollar and this is dollar-dollar. So, I will be able to differentiate. When notationally I use here, I need some mechanism. So, I am putting some subscripts. But this is not a new non-terminal. It is the same non-terminal. Similarly, when I wrote E going to E plus E, I said E going to E1 plus M because there were three E's and I want to have different E's. But non-terminal is still the same. Is this now beginning to make sense? So, now if I use all these rules on this parse tree, you can see that in one top-down parse, I am going to get all the bit values, bit positions and then in the bottom-up parse, I am going to get the bit values. So, I can immediately see that this one is, if I start traversing from top, I will take this value 0, this value will reach here and then this 1 will reach here and 2 will reach here. And then when I start traversing upwards from bottom-up, this will say that value is 4 here, this will say value is 0, this will say value is 1 and when I add this, this will say that value is 4, this will say value is 1 and when I come here, this will say value is 5 and therefore this will say value is minus 5 because of this sign. So, these are the symbols I am using just to reconstruct what we did, that we have a number which is value sign is negative then I have position and value with list and bits and this is how the parse tree will look, but if I put now rules in this, this will say that this negative is true, so here I took positive as true in the example I have negative as true, does not matter just a Boolean value. And here this says position is 0 and this will copy the position here, which will say that in this case position becomes 1 because I am now using a rule which says list close to list followed by bit which is this rule and then this position 1 will get carried to this and then this position 2 will get carried to this and this will also then get position 2 and now I will start constructing the value, so this will give me value 4 looking at the bit value at the position this gives me 4 and this 4 is then carried upwards and then for this part again value will be 0 because of this position is immaterial this gives me value 0 and this therefore says that value associated with this list is going to be this plus this value which is 4 and on this part value will be 1 and then this list will get value 5 and number therefore will get value minus 1. Now instead of these numbers I could have a type information, so as I said this is a general matter which says that if I have certain properties with these nodes then how do I compute certain other properties of some other nodes and what I am using here I am using a combination of synthesized activity groups and inherited activity groups. In some cases I can see that this value whatever I have put in green is actually a synthesized activity group because it is defined in terms of its parent children nodes and whatever you see in red is actually coming from the parent and these are the inherited activity groups. You can inherit certain properties or you can synthesize certain properties. So now there are two things one is the parse tree which you see in black color and then you have all this blue green red which is the dependence graph which is saying that this evaluation must be done in certain order. Now the orders of construction of parse tree and evaluation of all these activity equations may not match at this point of time. When I say at this point of time I do not even care about it because I am only writing certain properties and not worried about the evaluation of it. But at some point of time I will have to worry about this. So if this is what my grammar is this is how my rules are going to be that list position is going to be 0. So this is just replication of that. This says sign negative is false this says sign negative is true and this says bit position is nothing but list position is saying list position is nothing but list 0 position plus 1 and this saying bit position is nothing but list 0 position. And here bit value is 0 and here bit value is 2 to power bit position. And then I start taking these values up so here I will say that list value is nothing but list 1 value plus bit value and this will say list value is nothing but So, you can see that I already have some kind of attribute grammar and at least a way of evaluation of attitude equations. Now, let us take another example. So, attributes I already discussed this they fall in two classes one is synthesized by attribute and another is inherited by attribute and synthesized by attribute is something which is computed from value of the children nodes and inherited by attribute which are computed in thumbs of the attributes of the sibling and the family. That is something what is the heritage standard English words. So, now we will start putting this in slightly formal notation. So, what we are saying now is that suppose I have a production of the form A goes to L form and then with this I can associate a set of semantics. Now, I need not have just one rule I can have multiple rules. So, you can see that for example, here with this particular grammar rule I have two rules associated or three rules which says which position is list position this says list position is list position plus one and this says list value is list value plus with value. So, I have three rules associated with the same grammar rule. So, in general I can say that my rule is going to be of this form where I say I am trying to compute this B which is a function of attributes C1 to CK. Now, it does not matter whether it is synthesized or inherited if it is synthesized attribute. So, if this is synthesized attribute then C1 to CK are attributes of the children node of B or if this is inherited attribute of the grammar symbol on the right hand side then what it means is that C1 to CK are attributes of the parent node and the siblings. So, attributes what we have to remember here is that this attribute depends upon attributes C1 to CK. So, I cannot compute B before I have computed C1 to CK. So, looking at this I for example, cannot compute with position without knowing the list position I cannot compute list one position without knowing the list one value and bit value. So, I need to make sure that as far as my dependence graph is concerned that is a directed graph and I only computes my attributes in the order that no none of the edges get violated. And I will also assume at this point of time that we do not have cyclic dependence. So, that makes life a lot simpler if you do not have cyclic dependence is that then what is going to be the property of the dependence graph you have. Then you for example, on a dependence graph it does not have cyclic. So, you do a sorting on that and you sort that graph and find out the evaluation order it will not give you a total order but it will give you a partial order. So, if I do a topological sort on that then I know what my partial order of the evaluation is. So, for example, again once going back to that figure once again. So, if I know that I can compute these in certain order then you know that if every time I am computing something where all it depends upon have already been computed then I have no problem the order within that is not important. So, for example, whether I compute this value first or this value first that is not important as long as before this computation I have computed both of them. So, they like saying that if e goes to e 1 plus or e 1 plus e 2 does not matter whether I compute e 1 first or e 2 first as long as I have computed both of them that I can compute e 2. Of course, at some point of time we are going to impose certain constraints on that and say that I want to evaluate it in certain order because I am constructing my pastry from left to right I am scanning from my input from left to right and therefore, I am going to put certain constraints on that. So, continuing on this we have two kind of attributes and so let us look at a synthesized attribute and synthesized attribute are actually much simpler. So, these are also called asset attributed definitions if we say that all my attribute equations are such that I use only synthesized attributes then these are asset attributed definitions and a pastry can be annotated by just looking at the semantic rules and then I can say that for each node I can annotate it with one of the semantic rules and what will be the natural parsing method for construction of a dependence law for a synthesized attribute, bottom of parser. If I construct a bottom of parser and I have only synthesized attributes then I know that as I am constructing my nodes the nodes below it have already been constructed and I can keep on computing and finally when I reach the root node by then I have completed it. So, here is an example which is coming from the best calculator example. Now, there are many calculators this is actually a program in C you can use binary calculator, but then there were also calculators like here I could type an expression and when I finish typing an expression it gives me the value of the expression. This is I mean if you take any calculator what do you type you are typing an infix expression right and when you press return it gives you the value of that expression in terms of how does it work internally what it is doing is nothing but parsing your input. So, suppose this is a grammar I am using for parsing my input which says that when I press return. So, n is saying new line of return then l gives me the value of this expression and my expression grammar still remains it goes to plus t e goes to t e goes to p star f t goes to f f is bracketed expression or f is a digit. So, what kind of rules I am going to write for this. So, suppose I say that I just want to make sure that when I finish typing my expression and press return value of this expression is printed on this screen. So, as I see digits and as I see operators I must be able to compute all the values which are associated with each of the expression. So, for example, if I take now some expression which is passed by this particular language. So, let us say that I am trying to compute say 4 star 5 plus 3 some random expression what is the kind of parse tree I will construct for this. So, you say that l is nothing but an expression followed by new line and then I want to clearly say that l well here is nothing but even that is what I want to print or I can simply write it in terms of saying that here instead of the copying it and I can just say that print at all that. But if I now look at this part and now you can see that what kind of parse tree I will get from this. What is this giving me 4 star 5 this will give me t star f. t star f will get reduced to t and t will get reduced to e. So, this is how it will come. So, I think I am assuming our numbers here this part of the parse tree will look something like this and this part of the parse tree will look is going to be. So, t and actually I should have had one more e here basically e plus t and this t is going to f and f going to id which means 3. Now, if I have to write all these rules what is if I say my value or attribute that is associated with this just the value attribute only one attribute that will be grammar removal. Then what will I say what is the value here 4, but I need to write a rule I cannot just say that when I reduce by saying f goes to digit it is 4. So, what is the rule I write which is a more general rule. So, whatever is the value of the digit. So, I can say that value is nothing but here digit value that becomes my general rule. So, same rule will apply here and here it will say that value of f is nothing but digit well and when this rule is used which says t goes to f then I will say that what is t well f well. So, it is just talking. So, whenever I do a reduction by this rule this says that t well is nothing but f well and what is the rule I write for this when this says t goes to t star f. So, what is t well? t well is equal to t well star f well only one small problem that I do not know what this t well is because these are two t well suffering. So, I need to make sure that I use some subsets here to differentiate between them and therefore, I say that this is t 1 and therefore, this is t 1. Similarly, I can now say that when t goes to t I will say that e well is t well and so on. So, this way I can very quickly create all my rules and what I am saying here is that f well is nothing but whatever is value of the digit then f well is e well and t well is f well and this is saying t well is t well plus f well and this is saying e well is t well and e well is this and terminals which are associated have only since I have a value which are supplied by a lexical analyzers. So, for example, this is a terminal this is a terminal this is a terminal these values are going to come only from the lexical analyzers. So, this is how my parse tree will look and then I can do all computations of these values and so I have different expression here. So, basically what has to be clear to you is that given a grammar I have given a problem to be solved now. So, now I am posing several problems one problem I posed was that given a binary number a sign binary number how do I find the equivalent decimal number or given an expression how do I find value of the expression or given a type how do I find type of each of the variables these are different problems and for each problem I should know how to write my activity and my grammar will remain the same. So, using the same grammar same parsing technique I can solve different problems.