 Welcome to the lecture on syntax analysis part 4. So, in the previous lectures, we covered basics of syntax analysis, context free grammars, context free languages and top down parsing. Today, we will continue our discussion on parsing with recursive descent parsing and then move on to bottom up parsing. So, we looked at a transformation known as useless symbol elimination and now we also look at two more transformations one on left recursion elimination and another one known as left factoring. The left recursive grammars pose problems to LL1 parser generation. The problem is that left recursive grammars do not satisfy the LL1 condition. So, let us understand what exactly left recursive grammars are. So, if a grammar has a non-terminal a such that a in more than one application of the productions of a produces a alpha. So, you can see that the first symbol of this sentential form is also a. So, that means we can produce as many you know we can go on applying the productions of a as many times as we want and this is known as left recursion. So, our LL1 parsing method and also the one we are going to see the recursive descent parsing method cannot handle left recursive grammars. So, left recursion in grammars can be of course, eliminated in other words we can convert left recursion to right recursion and similarly right recursion can be converted to left recursion. So, first of all if you look at what is known as immediate left recursion then we need to handle productions of the form a going to a alpha. Remember left recursion implies a derives a alpha in one or more applications of productions of a whereas, here the production itself has non-terminal a on the left most in the left most position. So, if there is a production of the form a going to a alpha then the grammar is said to have immediate left recursion. So, let us see what we can do with it. So, assume that there are two productions a going to a alpha and a going to beta. The assumption is a going to beta will not have a in the left most position. So, if that is so then we can transform these two productions into these three productions first of all a going to beta a prime and then a prime going to alpha a prime or a prime going to epsilon. A prime is a new non-terminal which did not exist before. So, if you look at this you know this application produces exactly beta a prime and nothing else, but then a prime can be you know it has right recursion. So, we can use it as many times as we want. So, a prime going to alpha a prime can be used many times to produce many instances of a. So, if you look at this production we produce as many instances of alpha as we wanted and then a was replaced with beta. So, here also a prime produces as many instances of alpha as we want and finally, a prime goes to epsilon thereby producing nothing, but we have already produced a beta to begin with. So, we have produced beta followed by many alphas which is exactly the same as what a produced. So, this is immediate left recursion elimination, this grammar you know does not have left recursion. So, if we have a group of productions say a going to a alpha 1, a going to a alpha 2 etcetera, a going to a alpha m and then the other alternates without left recursion would be beta 1, beta 2 etcetera, beta n. So, if this is the case then we can transform these productions to in a very similar way to this a going to beta 1, a prime, beta 2, a prime etcetera, beta n, a prime and then the new non terminal a prime will have productions alpha 1, a prime, alpha 2, a prime etcetera, alpha m, a prime and then extra epsilon as well. So, this is just a generalization of this transformation and is sure to you know remove left recursion, immediate left recursion. Let us take an example. So, the rule is given here a going to a alpha or beta will be transform to a going to beta a prime, a prime going to alpha a prime or epsilon. So, this grammar has left recursion because e goes to e plus c or e, e or e star or parenthesis e parenthesis or a or b. So, in 1, 2 and 3 these 3 productions we have e as the most non terminal and therefore, there is left recursion. So, if we eliminate the left recursion, but remove the ambiguity as well this is ambiguous. So, if you want to eliminate the left recursion first of all let us try to write a left recursive, but unambiguous grammar because ambiguous grammars do not you know help us in parsing. So, this is the unambiguous version of that grammar e plus t or t, e goes to e plus t or t, t goes to t f or f, f goes to f star or p, p goes to parenthesis e parenthesis or a or b. So, this is the you know generates the same language as the previous one, but is unambiguous, but this is still left recursive. So, if we remove it you know the left recursion then we get e going to t e prime exactly like this you know beta a prime right. So, e going to t is the other production. So, we have e going to t e prime, e prime going to plus t e prime. So, this is the part plus t e and then r epsilon t going to f t prime, t prime going to f t prime r epsilon f going to p f prime, f prime going to star f prime r epsilon and p remains as it is of course, we could try eliminating left recursion from this grammar as well and see what happens. So, that I leave it you as homework. So, that was about left recursion elimination as I said left factoring is the other transformation that we want to study. If there are two alternatives beginning with the same string then the grammar is not a l 1 example is here. So, s going to 0 s 1 or 0 1. So, this is definitely not a l 1 grammar and the idea intuition behind left factoring is remove the common portion of the alternatives and then have a separate non-terminal for the rest of it. So, for example, here 0 is the common portion. So, that is factored out and for the rest of the portion we have a new non-terminal s prime. So, s prime goes to s 1 which is the rest of it here and r 1 which is the rest of it in the other alternate this grammar of course, is definitely l l 1. So, this transformation you know using this transformation it is possible sometimes to change a grammar which is not l l 1 to l l 1 form of course, left recursion was another as well. One method would be if there are two alternatives for a production a going to alpha beta 1 or alpha beta 2 of course, there could be many alternatives with the same prefix as well. So, the method remains similar. So, we remove alpha. So, a becomes alpha a prime and the new non-terminal a prime goes to beta 1 or beta 2. So, here is another example for logical expressions. So, e going to t or e or t, t going to f and f and f and t or f and f goes to not f or parenthesis e parenthesis true or false. So, this grammar of course, is definitely not l l 1, but because it starts with the same non-terminal t for both the options here also it starts with the same non-terminal f for both options. Once we do left factoring we get e going to t prime e prime going to r e r epsilon t going to f t prime t prime going to and t r epsilon f going to not f or parenthesis e parenthesis true or false. So, this definitely is l l 1. So, it is not as if these are hypothetical examples these you know this expression grammar of course, occurs in the programming language in the grammar for programming language c or similar languages. So, now an example to show that grammar transformations may not help every time. Here is our you know controversial if then else grammar we know that this is ambiguous. So, even if we do and of course, it has the same left side as well if i d s and if i d s because it is ambiguous even if we do left factoring. Let us say s prime going to s dollar s going to if i d s s 1 r a s 1 going to epsilon or else s. So, this is a factored grammar. So, there is no common part between the left side and the two right hand sides of s, but once we compute the direction symbol sets and try to fill up the table. We have seen this example before. So, I will not go into too many details again for the symbol s 1 and else we get two productions. So, the grammar does not happen to be l l 1. So, left factoring has not really helped in this case because the underlying grammar was ambiguous. Suppose you know practically if the grammar produces you know such a table and we have a problem with it. In such a case the programmer can be given a choice to choose the correct entry and you know eliminate the other entries correct in the sense intuitive entry. So, in this case if we choose s 1 going to else s instead of s 1 going to epsilon on the look ahead else this results the conflict because we have eliminated one of the productions here and this associates else with the innermost if then which is actually the correct choice so the matched statement grammar that I gave you couple of lectures ago does this as well. So, the choice of eliminating s 1 going to epsilon and retaining s 1 going to else s fills this table correctly makes this operatable as an l l 1 parser, but it will associate the else with the innermost if. So, let us move on to recursive descent parsing. Recursive descent parsing is a top down parsing strategy and basically instead of a table driven grammar you know table driven parser as in the case of l l 1 parser here this is a you know inlined program as such. So, we are going to have one function or procedure for each non-terminal. So, these are hard coded programs rather than table driven parsers the functions call each other recursively that is why this is called a recursive descent parser based on the grammar I will show you an example as well. The recursion stack handles the task of the l l 1 parser stack. So, there is no other stack necessary like in the case of l l 1 parser the programming language stack which handles recursion will also take care of the job of the l l 1 parser stack. The exactly the same l l 1 conditions need to be satisfied for the grammar here as well for the grammar to be eligible for recursive descent parsing just like the l l 1 parser we can generate recursive descent parsers also automatically from the grammar hand coding is also very easy even if we do not generate them automatically. The advantage of recursive descent parsers is that error recovery in such grammars such parsers is superior to that of l l 1 parsers. So, let us take an example and then move on to automatic generation of recursive descent parsers here is a very simple grammar s prime going to s dollar s going to a a s r c a going to b a r s b b going to b a r s. As I said there is one function for each non-terminal. So, this is the function for non-terminal s prime then we have a function for non-terminal s and then we are going to have a non-terminal you know function for non-terminal a and another one for non-terminal b as well. So, let us look at the function for non-terminal s prime. So, this is the main program because it corresponds to the start symbol of the grammar. So, on the right hand side we have the non-terminal s followed by the end of file symbol dollar. So, the flow within the program in the within the parser would be call the function f s corresponding to the non-terminal s and once it completes that the control comes here. So, the next token is checked whether it is E y f or not if it is E y f parsing is over. So, you accept otherwise you show an error message. So, this is for the non-terminal s prime which is very intuitive the whenever there is a non-terminal you call the function for the non-terminal and whenever there is a terminal check whether the next token actually corresponds to the terminal present in the production. So, let us take the function for the non-terminal s. So, the all the alternatives are combined in the function. So, we really have many you know cases of the switch statement one corresponding to each of the alternatives of the production. The first alternative is a s and it begins with little a the second alternative is little c. So, we have on the token a switch statement to check whether it is little a or little c and the grammar has been assured to be l l 1. So, these two alternatives will never begin with the same symbol. So, little a assures us that the production to be used for expansion in l l 1 parsing is s going to a s and. So, we are going to expand using the production s going to a s here as well. So, the token a is matched already because we came to case a we get the next token then here is a function here is a non-terminal a. So, we call the function f a the next one is a non-terminal s. So, we call the function f s then that case is completed. So, we have a break. So, that we get out of the case switch statement for the case c we already you know we have matched the c with this because we if we take case c the matching automatically happens. So, you get the next token and then get out of the switch statement any other symbol in the input implies an error. Then we have the function for the non-terminal a. So, again there are two alternatives one corresponds to b a the other one corresponds to s b. B a starts with little b. So, we have a case for little b if the token is little b then get the next token if the next token happens to be little a that is the symbol here again get the next token otherwise an error message is given and we then we get out for the symbol here is s. So, to take this particular alternative we must make sure that the input symbol that is the token is either a or c which corresponds to the first of capital S. So, in that case we call the function corresponding to the non-terminal s. Then we call f b the function corresponding to non-terminal b and then break for any other symbol it is an error. So, finally, the function for non-terminal b it again has two options b a and s. So, we again have a similar flow for b we get the next token and call f a and finally, break for the first of s which is a comma c we call f s and break for others it is an error. So, how do we generate recursive descent parsers automatically? Of course, the scheme is based on the structure of productions. So, the generator actually looks at the productions and generates the program we are going to look at some more details of this. The grammar must of course, satisfy the LL1 conditions. So, we are going to check the LL1 condition and then call the generator function get token obtains the next token from the lexical analyzer and places it in the global variable token this is the assumption function error prints out a suitable error message and now we are going to see the details. So, the weight is given here for if the you know right hand side happens to be epsilon of a if there is a production a going to epsilon and let us start with the last one first. So, there is a production a to alpha. So, then we are going to write a function f a which returns nothing and does not take any parameters and the body of the function corresponds to the program segment generated for alpha. So, now we are going to see various possibilities for alpha and then mention the code which can be generated. So, if alpha is epsilon then we just generate the skip that is semicolon if alpha is a single non terminal a. So, a single terminal a then we generate the program segment if token equal to a get token else error. So, this is intuitive we saw this in the program segment example before if a is a non terminal then we generate a call f a function call for the non terminal a. If alpha consists of several alternatives alpha 1 alpha 2 alpha 3 etcetera. Then we generate a switch on the token and for all the symbols in the direction symbol set of alpha 1 instead of first we use direction symbol because alpha 1 alpha 2 etcetera may also be epsilon and then the follow automatically kicks in if the symbols begin alpha 1 you know. So, that is direction symbol of alpha 1 all the symbols are listed here then the program segment corresponding to alpha 1 is generated and break is generated as well. Similarly, for alpha 2 alpha 3 etcetera and for any other symbols it is error. So, we saw an example of these two already the first one you know begins the first option and the second set begins the second option etcetera etcetera. If the you know string alpha is of the form alpha 1 alpha 2 alpha n then we generate the program segments for alpha 1 alpha 2 alpha n and concat them in the same order. So, this is the scheme for generating the program segments for you know recursive and parser. So, let us just go back and see one of the examples again. So, this is a production of the form a going to b a or s b. So, there is a function for the non terminal a and then because there are alternatives there are there is a switch as well and within the switch the direction symbol set of b a is b and the direction symbol set of s b is a comma c. So, that way we generate get token and then check the. So, this is the program segment generated for the string b a and this is the program segment generated for the string s b. So, within this this is of the form alpha 1 alpha 2 this is again of the form alpha 1 alpha 2. So, we go on applying the rules of generation and generate the appropriate program segments. So, now we move on to bottom up parsing. So, far we have discussed the top down parsing strategy in which the start symbol was expanded progressively and finally, we reach the leaves which correspond to the string to be parsed. In the case of bottom up parsing we begin at the leaves build the parse tree in small segments combine the small trees to make bigger trees until the root is reached. So, that is why this is called as a bottom up strategy. So, this process is called reduction of the sentence to the start symbol of the grammar. So, one of the ways of reducing a sentence is to follow the right most derivation of the sentence in reverse. So, let me give you examples to show how this works. So, and shift reducing shift reduce parsing implements one such strategy and it uses the concept of what is known as a handle to detect when to perform such reductions. So, let me show you some definitions and then we move on to examples. So, what exactly is a handle? A handle of a right sentential form gamma is a production A to beta and a position in gamma. So, let us take a derivation of this form S going to alpha A w. So, this is a right most derivation in many steps and now we replace alpha A by beta and the context in which we apply is alpha on the left side and w on the right side. So, now in this sentential form alpha beta w we say that A to beta in the right position following alpha is a handle of the string or sentential form alpha beta w. So, basically we want to locate the right hand side of the production which is applicable at this point. So, that is why that is the reason it is called as a handle. Handle of a right sentential form gamma is a production A to beta and a position in gamma where the string beta may be found and replaced by the non-terminal A to produce the previous right sentential form in a right most derivation of gamma. So, from here if we replace beta by A we get this particular sentential form. Similarly, we progressively replace handles by their left hand side non-terminals to reach the start symbol S. This is the strategy which is used in shift reduce parsing. So, handle will always eventually appear on the top of the stack and is never submerged inside the stack. This is a very important property what it says is this alpha is in the stack and this w is the rest of the input which is not yet parsed and now we have beta also just on the top of the stack. So, when we want to remove beta and replace it with A we just have to pop an appropriate number of symbols from the stack. What it really says is it is not mixed up with alpha, but it is at the top of the stack. So, in shift reduce parsing we locate the handle and reduce it by the left hand side of the production repeatedly to reach the start symbol. So, we are going to see examples of this these reductions. In fact, trace out a right most derivation of the sentence in reverse. So, this is known as handle pruning and L R parsing is a method of shift reduce parsing we are going to study that in some detail later. So, let us look at examples of what handles are and how they relate to right most derivation. Here is a grammar S going to A A C B E A going to A B or B B going to D. So, let us consider the string A B B C D E. So, the right most derivation is given here. So, for S we apply the production A A A C B E and then you know we apply the production B going to D to get the form A A C D E. Then you know we apply the production A going to A B to get the form A A B C D E and finally, we apply the production A going to B to get the form A B B C D E. So, this is a right most derivation of the string A B B C D E because every time we replace only the right most non-terminal you know we rather expand the right most non-terminal. So, now let us traverse this particular derivation in reverse. So, the right most derivation runs in this order the reverse of it would be this particular order. So, this is our given input string A B B C D E and the shift reduce parser let us not worry about the details of how it locates that this second B is the handle. So, it says let me now reduce that little b to capital A if it does that then we get this sentential form. In this it locates the handle as A B. So, the production applicable is A to A B A to A B you know is applied at this point. So, we replace A B by A and we get this sentential form. So, in this form it the shift reduce parser says D is the you know handle. So, and the production applicable at this point is determined to be B to D. So, this little D is replaced by B to get this sentential form. So, now it determines that this entire right hand side is the handle and the production applicable is S going to A A C B E. So, it replaces this entire right hand side by S and since we have reached the start symbol the parsing is completed. So, this is how you know the shift reduce parser works it starts from the inputs input string and reaches the start symbol. So, the handle is unique if the grammar is unambiguous if the grammar is ambiguous then you know it is not possible to use this strategy in a very simple way. Another example. So, we have S going to A A S or C A going to B A or S B B going to B A or S. So, let us take the string A C B B A C. So, the string is here and the right most derivation is in this order. So, you can observe that the non-terminal on the right most at the in the right most position has been expanded. So, S to C then B is expanded then A is expanded then S is expanded and finally, we get the string. So, the handles are handle is really underlined here C is the handle. So, the production is S to C. So, we replace C by S we get this non non this sentential form B A is the handle. So, it is replaced by A. So, we get this here again B A is the handle. So, we get B replace B A by B and we get this sentential form. S B is the handle. So, that is replaced by A to get this form C is the handle. So, that is replaced by S because S to C is the production to get this sentential form and this entire thing is the handle and that would be reduced to S using the production S going to A A S. So, third example this is the familiar expression grammar this is ambiguous. So, let us see what happens. So, the grammar is E to E plus E E to E star E E to parenthesis E parenthesis E going to I D. So, we know very well that I D plus I D star I D can be parsed in two ways because this is ambiguous we get two parse trees. So, the first interpretation says I D plus I D first and then star I D the second interpretation says I D star I D first and then added to I D. So, these are the two derivations. So, we let us see what happens you know we have I D here and that will be replaced by E because of this production I D is the handle the second I D is the handle here and that would be replaced by E again the third I D is the handle here and that would be replaced by E again. Now, E star E is the handle that gets replaced by E and E plus E is the handle and that gets replaced by E. Whereas, if we had used the other right most derivation we have the same string again I D plus I D star I D at this point the handle is unique. So, we get this sentential form again this handle is unique. So, we get E plus E star I D the third handle is also unique. So, we get this right sorry the third this is one step has been missed by mistake. So, this becomes E plus E star E. So, we get you know we replace E plus E star E by E to E plus E is replaced by E. So, this is what we get E star I D is what we get and then that becomes E star E and finally, this entire thing E star E is the handle and that gets reduced to E. So, E star E this becomes I D and this becomes E to E plus E star I D and now this E has been replaced by I D and finally, we get I D plus I D star I D. So, the thing is this is not the handle here you know. So, this is the handle there is a minor error in this slide. So, we get from E plus E we reduce it to E star I D and then finally, E star E and finally, E. So, the problem with this is when we have a particular step we really do not know whether this derivation sequence was followed or this derivation sequence was followed. So, locating the handle uniquely may not be possible. So, in this case if this was the derivation sequence the handle at this point in the third step was I D whereas, if we had used this derivation sequence the handle in the derivation sequence would be E plus E. So, with because this is because of the ambiguous nature of the grammar and the moral of the story is if the grammar is ambiguous then handles cannot be located uniquely. Here is an example to show how exactly the parsing happens with respect to parse trees. So, it is the same grammar again S going to A S R C A going to B A R S B B going to B A R S the right most derivation of the string A C B B A C is shown here and I have also underlined the handle. So, here this is the right most derivation very simply like this I am not going to discuss it in too much detail because it is a very simple thing whereas, what we discuss in detail is how exactly the parse tree is built up when we traverse the entire derivation in reverse. So, we start looking at the input symbol A to begin A C B B A C is the input string the first symbol is A and we can do no reductions here. So, we move on to the next step in which the little a remains as it is, but the next C gets replaced by S right. So, the second C replaced by S. So, this is the small parse tree which has been built here and this remains as it is. The third step you know the we have again replace this handle B A by A. So, the small parse tree corresponding to A going to B A has been added to this sequence. So, now we have A here S to C another small parse tree the symbol B remains as it is and there is another small parse tree which has been built. So, this progresses further and in the fourth step we have replaced B A by B. So, this is the parse tree which has been built here. So, this little B and this parse tree have been combined to produce B going to using the production B going to B A. So, here is a amalgamated parse tree and the other two remain as they are. Then step five we have S B being replaced by A. So, here is you know the tree for S to C and here is the tree for B going to something. So, this S and this B are combined now by A. So, we have a new parse tree in this form and the little A which remain before also stays. And then we have step C in which this C is replaced by S. So, we have little A a small parse tree hanging by A and another small parse tree hanging by S. And finally, all these A A and S. So, this A this entire parse tree rooted at A and this S which is the part of this parse tree are combined to produce this entire big parse tree and there is nothing more to do this is the root of the parse tree. So, the parsing strategy starts from input builds small parse trees combines them on the way and finally, reaches the start symbol. So, this is the big parse tree for this entire string. So, this is the process of bottom up parsing. Now, let us study the shift reduce parsing algorithm. So, so far we said we have handled and then replace the handled by the right hand side the by the left hand side non terminal of the production and so on and so forth. We have not answered the question of how exactly do we locate a handle in a right sentential form. In the case of L R parser which we are going to study later in detail it uses a deterministic finite state machine to detect the condition that a handle is now on the stack. So, how to do that is actually a fairly complicated process and we will study that later. The next question is which production to use in case there is more than one with the same right hand side that is possible, but the question is answered by the L R parser using a parsing table similar to an L L parsing table to choose the production which is applicable. It so happens that the state of the D F A tells us not only that it is a handle, but it also tells us the production which is applicable at that point. Then the third component is a stack. A stack is used to implement a shift reduce parser and the shift reduce parser is nothing but an augmented deterministic push down automaton. It has several actions four to be precise. There is a shift action which shifts the next input symbol to the top of the stack. Then there is a reduce action the right hand side of the handle is on the top of the stack. So, it locates the left end of the handle inside the stack by looking at the number of symbols the right hand side is made up of. Replaces the handle by the L H S of an appropriate production which is applicable at this point. So, you can observe that the reduction process consists of popping symbols from the stack and pushing some symbols on to the stack. So, again these moves can be coded in terms of an ordinary deterministic push down automaton. So, that is why I said this is an augmented version of the D P D A which is more amenable for programming. Then it has an accept action which says yes parsing is completed and is successful and of course, it may announce an error which says the input string is erroneous. So, an error recovery routine is called to make sure that parsing can be continued. So, let us take some examples to see how exactly the parser shift reduce parser works. So, we have the same A C B B A C input. So, in this case it shift the action is supposed to be shift. So, it shifts on to the stack and the next action is also shift. So, the parser shifts A C C also on to the stack. Now, the parser determines that reduction by S to C is in order. So, it replaces the top C by S. So, the next three symbols or the next three actions are shift. So, we get A S B B on the stack and A C in the input. Now, the reduction is called for A. So, because the stack has B A as the handle and the production applicable is A to B A. So, B A is replaced by A and the only symbol which remains in the input is C. So, now B A is again said to be a handle. So, the replacement by B application of B to B A happens and B A is replaced by B. Again there is a handle here S B. So, S B is replaced by A and we get A A. Now, there is a shift and C is pushed on to the stack. Again C is reduced to S and A S finally reduces to S and here the shift reduce parser accepts. So, these are exactly the same sequence of actions that were actually performed when we traverse the rightmost derivation in reverse. It is just that they are coded in the form of the actions of the parser. So, that a program can be written for it. Here is another example from our expression grammar and parser. So, I D 1 plus I D 2 plus I D 3 combined with plus and star that is the input. So, I D 1 is shifted on to the stack then a reduction to E happens then plus is pushed on to the stack and I D 2 is also pushed on to the stack. Again I D 2 is reduced to E star is pushed on to the stack I D 3 is also pushed on to the stack again I D 3 is reduced to E. Now, E star E is reduced to E and finally E plus E is reduced to E and the parser accepts. So, this is the second example of how the shift reduce parser really works. Let us move on to a specific type of shift reduce parser called the L R parser because these are the parsers which are of practical interest to us. Of course, I must mention that there were in the olden days other types of shift reduce parsers known as operator precedence parsers which were very popular at that time, but once the L R parsing strategy was proposed people found that this has much more much wider application than operator precedence grammars. And therefore, in the recent years the parsers are all L R parsers and the tools that we have are the ones which generate L R parsers automatically from the grammars. So, here again just like the L L k we have the L R k. So, left to right scanning with right most derivation in reverse k being the number of look ahead tokens. So, in the case of L L k it was left to right scanning with left most derivation. Here it is left to right scanning with right most derivation in reverse not just right most derivation and k as usual is the number of look ahead tokens. So, of practical significance are just L R 0 and L R 1 really speaking L R 1 is the most important. These parsers can be automatically generated using parser generators and Yacht is a an L R parser generator available under UNIX. L R grammars are a subset of context free grammars for which L R parsers can be constructed. So, remember just like the L L grammars the L R grammars are also subsets of general context free grammars. And a particular grammar for a language may not be L R 1 or L R 2 and we may be able to rewrite some of these grammars to become L R 1 or L R 2, but it does not mean that every grammar that is written for a language will pass the L R 1 or L R 2 test. We should be smart enough to write the grammar such that the test actually is completed successfully. So, L R 1 grammars fortunately can be written quite easily for practically all programming language constructs for which context free grammars can be written it just needs a little practice. And L R parsing happens to be the most general non backtracking shift reduce parsing method that is known today. So, these L L grammars are a strict subset of L R grammars. So, an L L K grammar is also L R K, but an L R K grammar is need not necessarily be L L K. So, you cannot that means you can always find L R K grammars which are not L L K. This is the block diagram of an L R parser generator. So, the grammar is input to a table generator this is the L R parsing table generator and out comes a parsing table. And when we use the parsing table there is also a driver routine this is the this thing is this block is the entire parser. So, the parser consists of a stack a driver routine and the parsing table which has generated automatically. So, when the input is given the driver routine reads the input manipulates the stack appropriately using the parsing table and generates some output in the form of either a parse tree or error messages etcetera etcetera. So, let us see what exactly is an L R parser configuration. So, the input you know is a 1 a 2 a 3 a n dollar and the starting state of the L R parser is assumed to be S 0. So, a configuration consists of you know a string of states and non terminals mixed here non terminals or terminals mixed here and unexpended or unused input is the second part of the configuration. So, S 0 S 1 S m etcetera are the states of the parser and X 1 X 2 X m are the grammar symbols terminals or non terminals. So, the starting configuration is always S 0 and then the rest the entire input unused. So, there are two parts in the parsing table the first part is called as the action part and the second part is called as the go to part I will show you an example. The action table can have four types of entries shift reduce accept and error which were which we have already seen and the go to table provides the next state information to be used after a reduce move. So, let me show you a parsing table just to get the feel for it. So, the parsing table is indexed by the state number on this side the action table action part is indexed by the tokens where as and of course, end of file and the go to part is indexed by the non terminals alone. So, for example, if you pick state 2 and the input symbol as b it says S 6 the interpretation of this is the action is shift action and the state to which we shift next is 6. So, the what is done is if the parser is in state 2 and the next input symbol is b it shifts it on to the stack and also shifts the state number 6 on to the stack. Similarly, suppose the state in which the parser is 7 and for all the input symbols a b and c it says the action is r 4 r stands for reduction and the number 4 is not a state number, but it is the production number. So, here it is a going to b a. So, the action which is done here is suppose the input symbol is a the action is reduce using production 4 the implication is the handle b a is available on the stack. So, pop the handle from the stack it exposes some particular state. So, what we do is use that state along with the go to table to determine which state we should really go to. So, that is why what is said here is the go to table provides the next state information to be used after a reduce move this becomes clear when we take up a complete example, but before that let us see how the L R parsing algorithm works. So, here is the parser it has a table it has a stack and it looks at the input as well it starts with the initial state 0 and the input is w dollar a is the first input symbol. So, the whole thing is repeated forever until we get out of it that s be the top of stack state a be the next input symbol. So, we look at s and a in the action part if it is a shift p push a and p on to the stack in that order advance the input pointer this is what I just now explain. If the action says reduce by a to alpha then pop 2 star alpha symbols of the stack the reason is the stack has a combination of both states and grammar symbols. So, there are 2 n symbols if we the right hand side of the if the handle is of the size n. So, we really pop 2 star alpha symbols of the stack now the state s prime is exposed on the stack. So, push a and go to of s prime comma a on to the stack in that order. So, this is how we determine the next state to be jumped into if the action is accept then we end otherwise we announce an error and get out you know either do an error a query or get out of the parser. So, we will stop at this point and continue in the next lecture. Thank you.