 All right. Good morning. Let's get started today. Thanks. Thanks. Thanks for coming. You know, Monday morning at 9am, always a lot of fun to be in class for both of us. Okay, so in case you missed the email, homework two was sent out and assigned last night, so there's four problems. Going over, first question has to deal with how we decide if a grammar is ambiguous or not in two different ways. The second problem is about computing first sets, which we're going to go over in depth. We're going to see an example of doing that today, but it's just applying the rules that we actually all derived on Wednesday. Then the third problem is doing first sets and follow sets for grammar, and we'll start follow today. Hopefully we'll get into it, so you'll have an idea, and then we'll go into an in-depth example on probably Monday. And then for more regular expressions stuff, because I want you to know, regular expressions are a really important part, so you basically have to, oh, it shouldn't be called text. That's cool. Copy, paste, error. Yeah, basically you want to create a regular expression to that deals with that English string, so you want to translate the English description into a regular expression. Any questions? I looked at your website and there was a lot of text for the homework, but there was no link for it. Or is it just a link to Blackboard? Oh, it's on Blackboard. Okay. Those links, I took the link directly into the Blackboard class for some reason, so yeah, it just links to Blackboard in general. As long as I can get this on Blackboard. Yes, you should be able to. Cool. Any other questions on homework stuff? Midterm in a week. So on Wednesday we'll do a review, so I think probably today or tomorrow I'll release like a practice midterm, and on Wednesday that's what we'll be going over is we'll be doing the practice midterm and then you can ask any questions and that kind of stuff. So the best way to prepare for the midterm is to do this on work, right? Do the practice midterm beforehand, before Wednesday, and then come on Wednesday so we can talk about how you thought about things, if you made some mistakes, we can try and correct them before the midterm on Friday. Are we going to get as far as lexical analysis for the midterm or are we just going to be covering up to essentially what we're going to be covering up to today. Lexical analysis? Yeah, the stuff we covered three weeks ago. Syntax analysis is what we're doing now. So everything up till next Monday will be a fair game. Are we going to get one back? Yes, it'll be graded next week. Any other questions? Lots of heads trying to exist. We haven't covered it in a minute. Okay, today we looked at first sets and we tried to figure out, okay, how to calculate the first sets, right? So we kind of derived from using examples. We took the examples and we derived kind of general rules for how to calculate the first set. So let's kind of regroup here. So what is, you know, what is the first set or first function? What is this function? What does it take in? What does it return? It takes in a string and returns the first character. It takes in a string and returns the first character. You need to be more specific. A string of what? A string of characters? A string of, yeah. Grammar symbols, which would be terminals, non-terminals, or epsilons? Yeah, so a string of grammar symbols, right? So that's what the epsilon or the alpha here represents, right? So we have terminals, non-terminals, and epsilons, right? So a sequence, so a string is a sequence, so a sequence of any of those, yeah. So what does it return then? Somebody else? Say it again? Set of possible terminals are tokened. Perfect, yeah. The set of possible terminals that this alpha strings that that alpha generates starts with, exactly. Cool. So the way to think about this, so the way, so what we're going to do is we're actually going to try to think about this as an algorithm, right? So we've generated some rules and now we want to think about how to use these rules to compute, right? And to be able to compute this first set for any grammar that you give us, we can calculate the first sets of any grammar in a simple set. So first returns a set containing tokens or terminals. For this, since we're talking about context-free grammars, we'll just talk about terminals, but the tokens helps us remind us why we're doing this, right? Because they are tokens in parsing. But context-free grammars are general, you know, general concepts. So important things. Okay, so actually, so I guess we took back my terminals and epsilon, right? So we're going to meet epsilon in first sets, right? But no non-terminals. If you have any non-terminals in your first set, you've done something horribly wrong. Okay, so usually when we talk about first sets, we want to calculate the first set for every non-terminal in our grammar, right, just like we saw. Because that'll help us differentiate between the rules, right? So what we're doing is we're trying to say, hey, if we can calculate this beforehand, then when we write our parser, we know that if I can determine between two rules just based on one character, then I can do a predictive parser that's very efficient and can create these parseries. So we're going to first start out with, we're going to say the first set of every non-terminal is the empty set. So this is our base case, this is how we start. So we say, so for example, you know, homework's midterms, right? So if we say, okay, calculate the first sets of this grammar, your first step is, so when we say calculate the first sets, we mean the first sets of all the non-terminals, right? So for every non-terminal in your grammar, you're going to say the first set of that is the empty set. Then you just apply the following, the five rules, right, that we derive, you're going to apply these rules over and over until what we'll see nothing changes, where you can't, they don't change any of our current definitions of the first sets. So what was the first rule that we derived? Yeah. The first of x is the set containing x, if it only if x is a terminal? Yeah, right. So we say, hey, the first set of any terminal is the second containing that terminal, right? So then what was the second case? Yeah, first of the empty set is the second containing the empty string, right? What's the empty string called? Epsilon, yeah, good. So yeah, so the first of epsilon is the second containing epsilon, right? So why are these, why do we have these two rules? Why don't they just one? Because epsilon is special, yeah, because epsilon is not a terminal, I mean, right, it's not necessarily a terminal, just like maybe a book copy of myself. What happens when you forget your copy mug? I think I forgot it in my other class or something, I don't know, I don't know where it is, this is not it. I had to leave early to make sure I got coffee, otherwise we would have a terrible class today. All right, if we have a terrible class anyway, I'm sorry. Okay, so what was our next rule? What did our next rule have to deal with? What was the intuition behind the next rule, right? These are kind of, so if you think about, this is a recursive definition, right, these are the base cases. So when you break everything down, you're going to get just a terminal or an epsilon, right? So what is, what did the next rule deal with? Yeah. Our next, our next rule dealt with removing epsilon from something that epsilon could not be the first of. Correct, so, but what did it apply to? So what were we looking at? So for a terminal, so we did terminals, we did epsilons, right? So what's kind of left? Not terminals. Yeah, yeah, right? That's the third of the grammar symbols, right? So we're taking care of this case, the two cases, and we take care of the third. So we basically derived the rule and we showed ourselves that, hey, if we have a rule in the form of a produces b alpha, right? So here, so what, what type of grammar symbol is capital A here? Non-terminal, right? And so how do you know that? It's capitalized, yes, but also it has a rule. Yeah, it's on the left-hand side of the grammar production rule, right? So only non-terminals on the left-hand side, that's how you know that. Okay, great. What's alpha represent? Everything after b. Yeah, everything, all symbols, terminals, non-terminals, epsilon, a sequence of, of symbols. What's b? So it doesn't have to be a non-terminal, so I may change this to beta. I think I changed it back because it was annoying using all the Greek characters, but now that I kind of look at it now, I can see that it's a little confusing. But that b just means whatever symbol is there, terminal, non-terminal, epsilon, whatever. Wouldn't it, because it's, it's, because we were going to say the first of b minus the second containing epsilon, wouldn't have to be some kind of non-terminal? Because it has to contain more than one character. Not necessarily, actually. We can look at that in a bit. Oh, because it could just be, it could be epsilon, it could be just a, it could be just the terminal a, little a. Exactly, yes. And then the fifth rule applies, then you add it back. Cool. Right, so this, all this rule says, so this is complicated, but it says for every production rule, right, I can take, I can calculate the first set of the left-hand side, right, by adding the first symbol on the right-hand side, right, in this case b, taking that, calculating its first set, subtracting epsilon and adding that to the first of a. So before we had equals here, right, we'd say, well the first of a is equal to this. Why don't we kind of add, that's sense. It's kind of, yeah, right? So we're saying union that into it, right? So add those, add the first of b minus epsilon to the first of a. Right, but why isn't it equal? Why aren't we saying equality here? We don't want to overwrite the value. Yeah, there may be multiple rules, right? This, if there's multiple production rules for a, right, when we have the bar, that means two different rules. We have a goes to something or a goes to something else, right? And because both of those rules are possible, we have, we can apply this by adding each of their first symbols to a, right? So this just operates on each rule in isolation, but we want to add them, right? We're trying to build up these first sets. So what happens if b has an, and so we saw that specifically when we just look at this, right, we want to subtract out the epsilon because we don't know what else is left in alpha, right? Just because that the first symbol on the left hand side here produces an epsilon doesn't mean that a has to go to epsilon. It depends on the rest of the symbols in that rule, right? So that's why we subtract and remove epsilon here. So what kind of the next rule deal with at a high level? We're not going to describe it exactly, but what was the intuition behind there? Why do we need more rules? Are we done? The next rule is basically if you have a bunch of different either non-terminals or terminals that all contain epsilon, then you take the very last one, remove that, and add it to the first set away. Yeah, so kind of at a high level, right? We now have to deal with the question, well, what if this b has an epsilon in its first set, right? That means there's some possible combination of rules or applications of b, where b is going to go to nothing, which means that the first of a is going to be whatever the first of alpha is here, right? And so that's what this incredibly complicated looking rule does, but at a high level, it's doing something very simple. It's saying that, okay, if b is zero, if there's whatever number of symbols here, right, here we have b's, or you can think of them as beta as if that helps disassociate the non-terminal, not necessarily non-terminals, right? So if we have, basically we say that there's however many starting symbols that have epsilon in their first sets, we can add the next one after that, first set minus epsilon to a, right? So it says if epsilon is in the first set of b0, b1, b2, all the way up to bi, then I can add the next one's first set. But the important thing to note here is this is a recursive definition that applies for any i, right? So in this example, it would also apply for i as zero, right? There's a first in b0, which means I add the first of b1 minus epsilon to the first of a. And then I check, is there an epsilon in the first of b1? If there is, then I add the first b2 minus epsilon to the first of a. And I keep going until I have to stop when there is the first of epsilon, there is something that epsilon is not in the first of one of those symbols. And then I stop, I don't add any more because I know that those strings have to start with at least that symbol. And so the last case just deals with the situation of what happens if I go all the way through, right? If I can go all the way through all the symbols on the right hand side can produce epsilon, then there's one possible combination of trees and paths where every single symbol is going to produce epsilon, which means that it's going to be the empty string, right? Epsilon, which means that a can also produce epsilon. So that's all that this case says. It says, hey, if I go through every single symbol, terminal, non-terminal, whatever, and I got all the way to the end, then I can add epsilon back to the first of a. But only in that case, right? So does it make sense? Exactly, yes. So three always applies. So this is the thing, right? One always is our base case, two always applies, three also always applies, right? Every single rule is going to have some a goes to b, right? a goes to beta. It's going to have some leftmost symbol. If it's just the one symbol, then this rule will apply, right? All these other rules say, hey, what happens if epsilon is in those symbols? What do I do? So the idea is, well, if epsilon's in b here, then I go to the next one, the next symbol, and then I always add the one after it, and then I check that one. Hey, was epsilon in the first of that? Then I go to the next one, yeah. So what's this testing? What's this operation? It's just set membership, yeah. So saying, is epsilon in this set? Exactly. So yeah, it's just saying, is it one of the elements in this set? So it doesn't have to be exactly epsilon, and that's kind of, it's an important thing because, remember, the first sets are all possible. Strings that that terminal, non-terminal generates, what are the first terminals that it could possibly start with? So if there's some combination that it starts with the empty string, then there's going to be an epsilon in it. So that's what we start calculating. So let's say we have this grammar. S goes to A, B, C, D. A goes to C, D, or little i big A. B goes to little b. C goes to small c, big c, or epsilon, and D goes to little d, big d, or epsilon. So it's the fact that this is more complicated than what we've done, changed what we do, and we do the rules, we apply the rules just as we have them to this. We can do it if you give me or I give you, or however you want to think about it, like 20, you know, 20 of these rules with a lot of symbols, you can just do it, it's just applying the rules over and over. So the way I like to do this, and the way to help you make sure you're doing it correctly, and you know when to stop applying these rules, I build a table. So on the left-hand side, I have each of the first sets. So I have at the top the initial state, and then I'm going to put each transition of applying these rules to each of the non-terminals, what happens when I apply those rules, right? So I start them off, my initial condition is all of them are the empty set. Now this is really important because one thing that you're going to be tempted to do, right, this is a recursive definition. So when you go to program this, or when you go to write it, you'll say, okay, this is easy, right? So I calculate the first set of S, which means I have to calculate the first set of A, which means that I recursively go to A, try to calculate the first set of A. Well, the first set of A is either little A or the first of C. So now I've got to go calculate the first set of C, and you get stuck in this recursive hellhole in some sense. And because there can be loops, if you program it like that, you're never going to stop. You're going to keep trying indefinitely to calculate first sets, and your program is going to crash. So this is why we do this in steps, and we precalculate essentially the values. So when we say, on our first go around, we say, okay, I want to calculate the first set of S. So when I say, okay, my rule says I apply the first of A minus epsilon 2, add that to the first of S. Well, what's the first of A? It's right there on the board, standing in the face. No, it's the empty set. Yeah, this is why we start with, it's the empty set. We'll see that everything propagates correctly by continually applying these rules. But this is actually a very important point that will help you not get too far ahead of yourself when you're doing this, right? This is why we precalculate it when I say, what's the first of A? I don't have to look at anything else. All I look at is my table here, and I say, well, currently A is the first of A is the empty set. So that's what I'm going to use. I take the empty set, I subtract epsilon from it, I remove epsilon, there's still the empty set, and I add that to the first of S. So it's the first of S there. So now I'm going to move this out of the way, and we'll put the rules here. So which rule did I just try to apply by calculating the first of S? Which rule? So take rule three, so add the first of A right to the first of S, the first of A minus epsilon, where you said the first of A is empty set. So that's going to be the empty set, right? So now when I calculate, now I calculate the first of A, right? So which of these rules do I look at when trying to calculate the first of A? The production rules. These grammar rules. We'll number them. One, two, three, four, five. Which rules do I look at? Do I look at one? Do I look at two? Do I look at three? Do I look at four? Do I look at five? Do I look at all of them? So rule two doesn't apply currently because- Not rules. Not rules. I don't think about that. We're calculating the first of A, so we kind of know what we want to go to. So which production rules do we look at? Of these production rules. Do we look at this? Do we look at this? Exactly. So we only look at- We're interested in calculating the first of A. We only look at rules where A is on the left-hand side, right? Because our rules, that's the only way we add first sets. Each of those rules says, hey, if there's- To calculate the first set for a left-hand side symbol, check these things on the right-hand side and do these things, right? But that's the way we update. So we can completely forget. We don't have to look at anything else except for that the rule that has A on the left-hand side. Now once I get here, right, how many rules are there of A goes to something? Two. Two. Two, right? That's an important thing. So we're using the bar here but there's really two rules here. So let's take the first rule. A goes to CD. So which of my five rules, my first set rules do I apply? Three. So which one here is the left-most symbol? C? Big C? What's the first set of big C? Empty set. Empty set. Empty set. Yeah. So we take that, subtract it, epsilon from it and add it to the first of A which is still the empty set, right? So do any of the other rules apply? Three still applies a little way. Yeah. So three still applies to little A but just looking at CD, right? So those other rules don't apply because there's not an epsilon in the first of C, right? If there was an epsilon in the first of C I would try to add, I would add the first of D minus epsilon to the first of A but there's no epsilon in the first of C so I'm not going to do that. So that's the only rule that applies. So then let's look at this next rule, right? So applying rule three to the next rule, which of these symbols is matches to our V or our beta in our rule? Little A? Yeah. So what's the first set of little A? Little A. That's but how do you know it's not in any of these? It's rule one. Rule one. Yes. Right. So rule one says, hey, the first set of little A is big is the second containing little A and so we take little A and we subtract epsilon from it, right, which is the second containing little A and we add that to the first of A. So after applying this we have the first of A here, right? So hopefully part of the thing that you should kind of be seeing and start to, right, is before when we tried to calculate the first of S we used the first of A as the empty set, right? But next time when we go through again we're going to use this set that contains A, right? So this is how our values are going to propagate through. So quick question for you. So the reason why we didn't, so you're saying we went over big C and big D, right, for the first of A but then the reason we didn't choose any elements from those from their first set is because their first set is the empty set, right? Exactly. We did. We still perform the calculation. Yeah, so this is what gets you, right? So algorithmically when you write this as a program, right, you just take whatever's in the first of C that you've calculated, you subtract epsilon from it and you add it to that, right? You're just doing set unions so you can do that with the empty set and it doesn't change. So based off of that if we would have pretty much computed first of C or first of D first and then first of A, it would have been, for example, little c. Exactly, yes. But we haven't got, we haven't, yeah, you can actually do these rules in any order. You just keep applying them and we'll look at the condition of when you stop when one column is exactly the same as the other column. So when you've gone through, applied all the rules to all the non-terminals and there's no changes, that's when you stop. Why are you subtracting epsilon from c? Like how come you're not looking at little c yet? Here? Like, you know how you looked at the first of big C? Yes. And then you said, yeah, you used to correct epsilon. Correct. So what's the first of, so with the first of C? Oh, okay, I got you. Yeah, so you got to use these values, right? And this makes it simpler, right? So you can, at every step of this, uh-oh. Oh no, there's actually still a copy, I don't know if I should. Consider floor copy, if the copy was going in, I think it's fine. I'm going to drink it, so it doesn't get me too much. That's weird, but actually, it's about half full still. All right, that's cool. I blame the questions. Just kidding. All right, okay, so one horrible, horrible accident today. All right, so what was the question? I just got it. You didn't get to do it. Okay, cool. At least I'll do it in this mode. All right, perfect. Okay, so now I want to calculate the first of B. Right, so then which rule do we apply? B's rule? Rule three first, right? We apply rule three. So what's the leftmost symbol of the rule B goes to little b? Little b? Little b, right? So what's the first set of little b? The second containing b, right? So we take the second containing b, we subtract epsilon from it, and then we add that to the first set of big b. Yeah. So you're saying you always apply rule three because I thought it was only if it's like two similar? Alpha is a sequence, a sequence can be zero, right? Oh, okay. Exactly, yeah. So that's the other trick. That's why you only look at that symbol. So it just means you don't have to special case any rules for anything like that. You always take the leftmost symbol even if there's only one symbol. Kind of when we talk about leftmost derivations and rightmost derivations, right? If there's only one, it's both leftmost and rightmost. Right, so then we get the first set of b is the second containing little b. Then we want to calculate the first set of c. Right, so how many rules do we look at here? Or which, which of these production rules do we look at? The rule three. Morse? Three. Yeah, c. Which production rule? The one that has the c. One that has c on the left hand side. Yeah, that's the important thing. Keep it getting right. Production rules. Production rules, first set of rules, I know. Kind of realized that as I said it. Okay, then we have, oh thank you. It's very nice. So now we want to calculate the first set of c. So what is the first set? So we look at the first rule, right? Big c goes to little c, big c. And then we take the, so which rule do we apply then? We take the little c. One, two, three. Rule three, right? So which of these symbols do we want to take the first set of? Big c or little c? Big c, little c. Little c, right? And so the first set of little c is? Little c, little c. Little c, we add that there, right? So we get the set containing little c. And then what about the next rule? We do the epsilon. So it's actually a tricky one. So this gets back into precisely applying these rules, right? So let's see if we can actually precisely apply these rules here in this case. So we have c goes to epsilon, right? Which rule do we apply? Rule three, right? We always apply to rule three, right? So we're trying to calculate the first set of c, right? And we say, okay, then we take the first set of the leftmost symbol. So what's the leftmost symbol here? Epsilon. Yeah, so what's the first set of epsilon? How do you know? Rule two, right? Epsilon. But what does rule three say that we add to the first set of c? Yeah, the first set of the leftmost symbol minus epsilon. So what's the second containing epsilon minus epsilon? The empty set. The empty set. So then we add the empty set to c, right? But, so we just applied rule three, right? Does rule four apply? Let's think about that. When would rule four apply? If epsilon is in the first of b, zero, etc., etc., then essentially it's saying that for all b of n, if epsilon is in b of n, then you check the first of epsilon b of n plus one. You don't check, you add it always. Yeah, that's good. The fourth rule, if we have to reply to the first of little c in this case, what about the next one? It would have for the other rule, right? But we're looking at the second rule here of epsilon, right? So, okay, the first thing to ask yourself for a question for number four, right, is is there an epsilon in the first set of the leftmost symbol? We just computed that. It definitely is. So then rule four says, okay, then you can add the next symbol to the first set of a. Is there a symbol? No. Yeah, so we can't add anything, right? So that rule four doesn't apply because we can't add anything after the epsilon. But what does rule five say? Epsilon still counts. Add it back in. Right. Well, so rule five says, right, if there's an epsilon in every single one of the symbols, then add epsilon to the first of c. So does that rule apply here? Yeah, we have one symbol on the right-hand side. Is epsilon in the first set of that symbol? Right. So then we can add, then we add epsilon to the first set of c. So take epsilon out and add it back in. Yes. So this is a, so obviously when you're looking at this, when you have c goes to epsilon, you know you can add epsilon to c, right? So you don't have to go over all of this rigmarole. But this is showing you that the rules are consistent. And if you, and this is how your program should work, right? So you don't have to special case epsilon at all. You just apply these rules over and over again, right? So you have a fifth rule that checks, hey, is there epsilon in the first set of all these symbols? If so, then add the second containing epsilon. So that's what actually propagates this. That was an important point I wanted to make, yeah. So how do you know it'll apply to the third rule instead of the second rule when you're checking c there? Because I'm trying to calculate the first set of big c, right? The first rule only applies to terminals. Is big c a terminal? No. And then the second rule applies to just epsilon. Is big c epsilon? No. No. So I know I have to start with rule three. Because rule three always applies to any non-terminal. Okay, because it has the or symbol that means that you have to apply rule three essentially. The or symbol just means that there's another rule. So I could write this as c goes to little c, big c. And I can have a new line and have another rule that says big c goes to epsilon. That's exactly the same. So it'd be the same thing if you have, if you got rid of this and just had c goes to epsilon. So you first have to apply rule three. And then by applying that, you apply rule two, right? To say, okay, what is the first set of the leftmost symbol? Well, in this case, it's clear, it's epsilon. Then you actually remove it and don't add it until you apply rule five. I'm hoping this will help on programming, right? That's why we want to talk about this and think about this as mechanically applying these basic operations. Okay. So that's the first set of d. What we can do a little bit of. It's going to have d and epsilon. d and epsilon, right? Yeah. So applying this to the, this rule, we take the leftmost symbol, right? Rule three says we take the leftmost symbol and then rule one says, well, that first of that symbol is the second painting d. We add that to big d. And then we do this exact same thing we did with epsilon. So we're going to get epsilon in here. Cool. So the question we have to ask ourselves, we've gone through all of the non-terminals here. So are we done? Can we stop and say these are the first sets? We've calculated it. We're done. Let's go home. No, because things have changed. Yeah. Right. That's how we know we're done. When two of these columns are identical, right? Are these columns identical? Well, we made a change, right? So we have to do it again. We apply these rules over again. So calculate the first of s. Which of these grammar rules do I look at? One through five. One. Yeah. Only one because I'm just looking at the first of s. And then which rule do I apply? Rule three. So I add the first of what to what? First of a. First of a to the first of s. The first of a minus epsilon to the first of s. Yeah, exactly. Which is going to be what? A. Little a. Little a. The second containing a. Yeah. Cool. Now I take first of a, right? I want to calculate the first of a, right? So I take, so I look at this rule first, right? A goes to big C, big D. So I'm going to add which symbol here? So which am I, so I'm going to apply this rule, right? So which do I try to calculate? First of C. The first of big C, right? And so what's the first of C? C epsilon, right? Yeah, we got it right here. This is where we look, right? We don't even have to, we don't look at the rules. We don't have to look at anything except for this table that we've created to say, okay, last time we did it, the latest value is C epsilon, right? We don't want to use this value, right? This is an old value. The empty set is an old value, right? We want to use the new value. Okay. So when I say, okay, so what, by applying rule three, what do I add to the first of A? Little C. Little C. Yeah, so right now the first of A is going to be the second taking A and C, right? Little A, little C. I specifically don't have epsilon, even though epsilon is in the first of C because they're, I'm subtracting it out, right? Cool. So do any of the other rules apply? Yeah, the A, the little A. The fifth one, maybe. The fifth one, you only go, wow. Isn't it because, because that first contained at the end, an epsilon, so you would add it back in, right? Or am I not understanding that correctly? The rule is, the rule is correct. Okay, so these are, there's two different things, right? There's the mathematical rules, which we can apply in any order. And as long as we apply them all correctly, we'll get the right answer. So we can't actually apply rule five. So what does rule five say? Well, the first sets. Yeah, so how do I actually calculate that here? What are the conditions here? How do I know if that applies? C and D, what do I look at for C and D? They can both be epsilon. Yeah, so if all of the grammar symbols in this rule, right? So do I look at little A big A? No, no. No, because I'm not even considering that right now. Only focus on this rule, right? So I can say, hey, is there an epsilon in all of the, all of these symbols in their first sets? So what's the answer? Yes. Yes, so yes, I can add an epsilon there. So yeah, we can definitely do that. That's something we can do now. For me, I like to think about it a little bit algorithmically, right? Like, so how am I going to actually compute that? So that's, so I just added the first of S to the first of A, right? So the first of, sorry, I added the first of C minus epsilon to the first of A by applying rule three, right? But I haven't actually gone through and looked at each of the symbols yet, right? So I wouldn't really apply rule five now. What I think about is, does rule four apply? Yes. So what does this mean? How do I apply this to this rule, this production rule? This means if this first of C contained epsilon, then we wanted to use the first of C. So if the first of C contains an epsilon, that's it? Yes. Yeah. Then I add the first of D minus epsilon to the first of A. So what's the first of D minus epsilon? D. The second D. The second containing D. So A now has A, C, and D if we did it in this order, right? And then if there was a symbol after D, then I would say, hey, is epsilon in the first of D? Yeah. Then add the first of whatever comes after it to the first of A, right? But there's nothing after it. And then this is when I do my check, okay, did I go through all the way? Is there epsilon in all of these first sets? Yeah. Then I would, which is yes, right? And then I add epsilon there, right? So now this rule applies rule five. And so I add epsilon in here. So now I know the first of A is ABCD epsilon. We computed the first of A just now. Say it again. So we computed rule three on the first of A, right? So then how do we have an epsilon if we minus the epsilon from the first of C? Right. So we applied rule three. Yeah, and then we took out the epsilon. Then we took out the epsilon. Then we just added C, exactly. Yes, so the first of C doesn't have an epsilon. Correct. So we added, this is where we got the C from. So, yeah, no, I understand where you got the C from. Got it, got it, got it. I'll take it. You got an epsilon. You don't change the first of C. You just add the first of C by itself. Ah, yeah. Yes. So we only add and we're only changing A because we're only looking at that rule A. So yeah, so yeah, that's a good point. So we call, you think of it like a function call, right? We call the first of C. It returns something. And then we take out epsilon from that set without actually changing the first of C. OK. That's a good question. Cool. Yeah. Did we touch that? Did you get it? Yeah, the second. Ah, yes. OK, great. So actually, yeah, so we would apply this. So we actually didn't do that. I kind of skipped over it. That's a good point. But before we're done here, right, we say, OK, we finished with this rule, this production rule. A goes to C, D. But then I got to look at the next rule, right? So which one of my five rules applies to this, my five first-end rules? Three. Three. Right? So I do the same thing I did. I do three. And then I say, OK, add the first of little A to the first of big A. And I know by rule one that the first of A is the second-taining A. So I add that. A is already in there. So sets, right? So sets are just, order doesn't matter. And you can only have one of each element. So if you add A to a second-taining A, right? You still have? Doesn't matter. Yeah, it doesn't change it. But once again, algorithmically, you would just do that, right? You just apply all these rules as many times as you can for each of these non-terminals. Yeah. For the project where we're going to be programming, this does order matter? No, it shouldn't. If it does, you're doing it wrong. OK. So yeah, no, and that's the nice thing about this. You can just apply these. You can go over these non-terminals in any order. You can apply the rules as long as you're always grabbing the latest first set from here and not trying to recursively calculate it. That's when people get into trouble. OK. So the first set of B, change to rule one. Oh, yeah. Rule three, then rule one, right? So you add B back into there. There's already B in there. Mess to that. So that doesn't change. Then we do C. Same thing, doesn't change. And we do D. No change. So that actually gets into a good point about the question about do we take out epsilon from C, right? So this is another way you can self-check while you're doing this. So think about it this way, right? We're only ever adding things into sets. Every time we apply rules, we're only adding things. So all of these sets should only ever be growing. They should never be shrinking. So if you ever have a step where you've gotten rid of something, you've done something horribly wrong. And then you should go back and re-look at the rules or something, right? So that's another good way to check. So am I done? I want to know what the way is through. I'm not done. We've got to do it again. Do it again. OK, so we do S. So which of our rules do we apply to try to calculate the first of S? Three. So what's the first of A? A, C, D, and epsilon. So do I add A, C, D, epsilon to the first of S? Yeah, C, D. A, C, D, and then subtract epsilon. Right, A, C, D. So I take out epsilon, right? So now the first of S contains A, C, and D. So am I done? Because that set contained epsilon, you're now going to be. Yes, right? That's the important rule. So rule four, right? Rule four says, hey, do I add the first of the next one? And I know I add the first of the next one when the current one, the one I'm looking at, the leftmost one, has epsilon in it. So is epsilon in the first of A? Yes, yes. Yeah, then I add the first of big B there, right? Minus epsilon to the first of A. So my set for the first of S is A, C, D, B. So then do I add the first of C to the first of S? Yeah. Because the set rule four apply again? Because the first of B did not use your epsilon. Yeah, so B does not have an epsilon, so I don't add the first of C, right? That's the important point. That's when I stop. So there's rule five applied? No, right? We didn't reach the end. There's not an epsilon in all of these symbols just in the first one, right? Which kind of makes sense with the intuition of the first sets, right? So S, all the strings that S could possibly generate, A could go to nothing, the mg string, right, epsilon. But B is always going to be a single B, right? So it's not possible for S to generate a string that is empty. There has to be always a little B in there. So when I calculate the first of A, how does my set change? It doesn't change. Doesn't change, right? We have the first of C. We have the first of D. We take an epsilon, then we add it back in, because we went all the way through. Then we add the first of A. And none of that changes. B first of B? First of C? Nope. First of D? Oh, did I stop? Am I done? No, one more time is real. One more time, well, you only know it's one more time, because of the columns. Yes. We've reached the end of the PowerPoint slide, so we know we're done. That's nice, good. So first of S, right? When I calculate the first of S, what's the first thing I do? What do I add to the first of S? The first of A minus epsilon, right? A, C, D. No change. And then I, do I add the first of B? Yes, yeah. Yes, because there's an epsilon in the first of A, so I add the first of B minus epsilon. Do I add the first of C? Nope. Nope. So I stop, there, this one stops, this one stops, this one stops, this one stops. Now they're all the same, so we stop. Now we're all, now the sets are all the same. We've applied all the rules, so now it stops. And it kind of makes sense. If you think about why do we keep doing it until it doesn't change, right? So every time we apply the rules, we're adding something to the sets, right? The sets are always growing, and each of the rules depends on the first set of the other rules. So you keep on going until you don't change anything? Yes, it's called the fixed point, but we won't, we don't have to know that or anything, but in general, in the future, when they talk about theory stuff or fixed point or whatever, this is what it means is you've reached a point where you're applying all these rules, doing all these things, and you're not actually changing the sets or anything. And you know that you're done because, hey, every time I add these rules, I better be adding something to a first set, and all the rules depend on the other rules' first sets. So if I never change anything by correctly applying all the rules, then I know I'm done, right? And you can even, this doesn't mean that you actually, you know, you have to stop here if you wanna do a self-check and do it one more time by applying all those rules. You know, better make sure it stops there. All right, one thing, what if I change this A over here to be A, big A, big D right here on this left-hand side? Would I be able to do that? Or would everything, when I start here, right? I say, when I calculate the, I calculate the first of S, I calculate the first of A. So this C, big C is an A. When I calculate the first, when I try to calculate the first of big A, which rule do I apply? The term like it's epsilon? It's what you do with rule three, right? Rule three? Yeah. Wouldn't actually craft, you could do the first of A minus epsilon and then the first of A could be small A, big A, and then you would just take A. So it would be the same thing, right? Yeah, close. What do we use? So here we have basically A goes to A alpha, right? We add the first of A minus epsilon to the first of A. So do we get an affordable recursive call? We have multiple rules in A, so you just try the other rule. But I already know the first of A, right? The first of A is the empty set. The empty set A. Exactly. So when we see this, we say, hey, the first of A, I just look it up here. It's the empty set. I say empty set minus epsilon. Boom, done. What would you do on the next iteration? On the next iteration, there'll be an A in there, right? Because there's an A here. And so I'll just add in the second painting A minus epsilon to the second painting A. I mean, it's not going to change, right? If you union a set with itself, it doesn't change, right? But the critical thing is this is why you can't do this recursively when you program it, right? The important thing is there's no special case that it's the fact that it's the same, right? Whatever this symbol is that you're trying to calculate here, the first of B, right? You just look it up in the table. So though these rules are recursive, to apply them recursively is not the best program. Yes, absolutely. So you can think about this as like, what's the last scene value of the first of B? So that's what's important to yourself.