 Morning everyone, thanks for, I hope you all had a very restful, nice, calm spring break. Some people? Yeah, so now we get right back to it. So as you can see on the screen, Project 4 is out. I don't have the links up on the website, but it is up on the website if you go to project-4. Right after class I'll post all that. So the idea here for Project 4, it's going to do April 1st. It's not an April Fool's joke. Are you sure? I am sure. Just make it April 2nd so we don't have it. We can go back to March 31st, whatever it is. It's not going to be any confusion. No. Okay, so the idea is for Project 4, there's basically two parts of Project 4. The first part, you have to finish an incomplete parser. We're going to give you some code, some parsing code for a language, and the grammar of this language we're going to see right here. Some parts of this language are not actually specified, so you have to complete the parser and write those parts. I highly, highly recommend you do this part first. So if you do the rest of it, type-checking, whatever, but you didn't finish the parser or do the parsing correctly, then it's really no point. Okay, and then, while this project is really cool, you're going to be given an input language, and you're going to do type-checking on that language. So the input is going to be a program, and the output is either going to be like a compiler, so what does your compiler spit out if there's type errors? For his? Yeah, what the error is, a little bit of information, right? But this is all you're doing. You're not executing the program, you're just checking for type errors. So you're going to output if there's an error, you're going to output the error message, and if it's correct, if it's a correctly typed program, then you're going to output all of the equivalent types in the program so we know that you know it was done correctly. And so this document basically, the project description describes the input grammar, the language, and all of the type rules that you're going to need to successfully do this project. Any questions on a high level before we get kind of more into it? It seems kind of pretty good. Do I have to change that? No. Okay, so... Is that online? It will be right after class. I think it technically is online, but there's no links to it. Okay, so this is the grammar description. Anybody? Well, okay, I'll rephrase that to not out yourself. You should know how to read this grammar description, right? I've been talking about context-free grammars all class. So, self-check. Do I understand how to read this grammar description? The basic idea is your program is going to be first a set of declarations, and then the body of the program. And this defines how types you can define in the declaration. You can define types, and then you can define variables that are of that type. And we'll see examples of this. So, obviously, you'll need to go through this and understand exactly what's happening here. So, I won't go into it in a lot of detail, but I want to hit the high notes right now. You can see it's kind of long, right? Okay, these are the tokens. So, just so that that's very clear. So, you won't need to worry about tokenizing. So, the parser that we're going to give you already handles all the tokenization. So, you won't have to deal with that. So, all right, we're going to give you an example. Okay, perfect. All right, so this is an example of a program written in our language. So, we have first, so this whole top declaration before the braces, this is the declaration section. And then inside in here, we're defining the type section. So, this defines, okay, so the way to read this on the left is a name, and on the right is the definition of that type. So, here we're saying that type A is an integer type, and here we're saying type B is an A type. So, what type is type B? Int. Int, yay. Success. See, you're already going to do awesome with this. Okay, then in the variable section, here we just declare the variables that we're going to use. So, here on the left is a list of variable names, and on the right of the colon is the type of that variable name. So, if this is variable name B, then what does that mean the type of X is? Int. Okay, we also have a variable Y. Y is the type C. It is undefined. But, based on this, so this is the body of the program, this is Y is assigned to X. So, given this, no, Y is assigned to X, right? Y gets the value of X, yeah. But, from this assignment statement, what do we know here, for this program to type check, what do we know about the types here of X and Y? Y has to be the same. It has to be the same, exactly. So, can you tell what should be the type of C? Int. It has to be an int in order for this program to compile. So, this is actually one of the really cool things about this language as opposed to other languages. We can have implicit types and implicit variables. So, here we can define a variable with some type that we actually have never declared, right? Based on the usage in the program, we can infer, hey, is there a possible way for this to type check, and if so, what is the type, what is actually the type of C, right? And so, here we can see that it's int, yeah. But, that must be taken care of in the global part, not the body. What taken care of? All the type, types. So, this is what we're getting into. Sorry. These are explicit types. So, here are explicitly defining. Type A is an integer, and type B is a type A. This is an implicit type because it doesn't have a definition of, it's not explicitly defined in the type section. So, actually the program goes through itself, it starts to define itself? Yes. Well, the types of the program are defined based on the usage. And that's, this is really the key of what you're doing here is how do you do this type inference? And we'll see exactly how to do that later in the class. But this is your goal, this is where you're trying to get to. So, we can go up, we can see that, so we have five built-in types, int, reels, booleans, strings, and longs. Types are either explicit or implicitly declared. So, we saw explicit types are type names, we have to go through all the semantics here. So, this is defining all the semantics of exactly what we mean here. So, explicit types and implicit types. So, that's exactly what this means. So, this type C here is never declared as a type. And so, its actual type depends on the usage. The same thing with variables. This is another cool thing. Any program in Python or some other Ruby, I think JavaScript does. No, you have to declare things with var, otherwise it's considered global. I guess it kind of has it, but anyways. So, variables can be either declared explicitly, so what does it mean to be declared explicitly in general? Yeah, you define it, right? There's a declaration that says, okay, I'm going to use some variable foo. Implicit just means that when the program sees the usage of some variable foo that hasn't been declared, then it creates a new variable for that, right? It assumes that that is a new declaration of a new variable. And so, that's what this says. So, explicit variables are declared specifically here. Otherwise, it's implicit. If it's not declared explicitly, but it appears in the program body. For instance, in this program, very similar, type section, what's the type of type A? Int. And the type of type B? Int. Int as well. And so, the type of X is? Int. Int and Y is? Int. When we get to here, we don't know yet, right? When we see this, we see that Y is some type C. And we don't know what type C is in our built-in types. So, when we see Y is equal to X, what does this say about the types of Y and the type of X? They have to be the same. They have to be the same for this to type check, right? So, this is how we're able to essentially infer that, okay, C must be an int for this to type check. If C was anything other than an int, this won't type check. What if we miss that? What do you mean miss that? What if that's missing from the program? Does it throw an error? No. So, it doesn't know what C is. All you're doing is type checking. Yeah, exactly. You know, type C could be never declared as a concrete type, and that's fine. Never defined. It's fine. Exactly. Yeah. So, we're only checking the type rules. Yeah. So, the program would still work if you, like, under type, you switched A into B, A, right? Like, you switched them. So, B, A was first. Yes. So, if you switched them, you would be declaring, so if you switched them, A would be an implicit type, right, because it hasn't been defined yet, but it's been used, and then in the next line, you'd be declaring that A is type integer. And then B would also know that it's... Exactly. Yes. Yeah. So, under the hood, when this is all running, when it figures out what kind of type C is, does it then, like, mark that? It says, now type C is always, will always be an int. Yes. So, for your program to correctly type check, every... So, we saw y equals x implies a constraint on the types, right? It says that type of x must be the same as the type of y. And the only way to satisfy that constraint is if type of C is an int, right? And that has to hold and be true throughout the entire program. Okay. So, if at any other point you see type C is a real... It blows up. That blows up, and that's a type error. So, you have to declare, you have to say that that's a type error. Okay. Yeah. So, this is a simplified version of type, of this kind of inference type checking. It's a Hindley-Milder, which we'll see later, but it's a lot more reduced, so it's a lot easier to do. The colon means what? The colon is our way of declaring. So, it means the thing on the left is the variable name, and the thing on the right is the type of that variable name. Okay. So, we see y is equal to x, and then we see z is equal to 10. So, is z declared as a declared variable? Nope. No. I'm going to say that there's an undefined variable usage. No. Variables can be implicitly defined. Yeah, variables can be implicitly defined, right? So, then what about this assignment? What do we know then about the types, the type of z? So, when we first see z, do we have a type for z? No. No, it's some new implicit type that we haven't seen yet. But what do we know about this relation here based on this assignment statement? It's the same as w. Yeah, so 10 is an int, right? So, the type of z must be an int, right? So, this assignment statement to hold. So, we don't know what z is, but essentially from the usage here, we infer that z has to be an int. So, what about this line? What do we see here? We're assuming w is an int. Our w, is w declared? Nope. Nope. So, we're going to create a new implicit variable w with an implicit type. So, here in z times five, does this imply any constraints about the types here? Yeah, well, kind of the answer is it depends, right? Because in some crazy languages, you can multiply integers by strings, like Python is one of my least favorite parts. It doesn't make any sense, but for our language, we'll see for every single operator in assignments, operators, we have type constraints associated with that. So, the types of our language is, hey, any type times any other type can work, but they both have to be the same, and they return that same type. So, here z, this statement means that the type of z must be the same as the type of five. So, it's the type of five? Int. And what's the type of z? Int. Int, because we established that on the other line. So, is that consistent? So, are instant longs ever going to mix? Nope. There's no type convergence in our language, which also makes it a lot easier, so you don't have to worry about all that. So, yeah, that's why all the types, ints, longs, reels, they're just n strings. You can consider them distinct types. It doesn't matter at all what they actually are. Okay, then we have the type of w is equal to the return of z times five. So, then what's the type of w? Yeah, it's got to be an int, right, for this to type check, because an int times an int returns an int, and so we're assigning that to w, so that means that must be an int. Great. See, look at this. There's like 90% of the way there. Something must be missing. More like 10. Okay. That's good. This is, I mean, this is, you need to be able to look at this program and understand exactly what the types are in the program. So, this is definitely, definitely useful and important. But you really have to dig in so that you can read these programs, write new programs, right, your own test cases in this language, and be able to understand how all the rules apply here. Good. So, yeah, so this is more kind of semantics that you'll get into. So, talks about the difference between declarations and uses, right? So, here a is declared. Here b is declared and a is used, right? Because a, we're saying b, we're declaring a new type b that has the type a, right, so this is a use of a. Here we're declaring x and we're using the, here we're declaring y and using c, and you can go through this exact thing. We'll step you through all of this. So, the type system is where we get to the interesting part. So, we really don't care what the operators necessarily are. All we care about is the types for this, right, because we're only considering checking the types. So, these, there are five type rules and they should follow pretty easily from our intuition we just built up looking at the examples, right? So, c1, this first type rule says that the left-hand side of the assignment must have the same type of the right-hand side of the assignment. Which makes sense. You can't assign between different types. This rule says that operands, we have four operands in this language, plus, minus, multiply and divide, must have the same type. And it can be any type, right, including string and boolean. We can add booleans, minus booleans, times booleans, right? For our purposes we don't care. All we care is that we can do this for the types. Okay, the operands of a relational operator, the reloth and the grammar, must be the same type. We'll see that. So, any type. Condition needs to be of type boolean. The variable. So, in the switch statement, switch in C, right? You're switching on a variable, and then you go to one of the cases, depending on the value of that variable. So, here this says that that type of that variable must be an int. If we're going to switch on something, it's got to be an int. So, these are all the type rules, and then these are essentially clarifications. So, saying that an expression returns the same type as both of its operands, right? Yeah. It says real number constants are type real. Yes. What's real? It is this one there? Yeah. What's real? It's a deep question. Real is real. Real is real. Yeah, this is one of the five types. So, what this is saying is that there's in our grammar, right? There are real nums where real num is a number followed by a dot followed by digits, right? So, this is essentially the thing of this real num here is a token that defines a literal real number. And we're saying that this is just clarifying that, hey, when you see like a num, the token num has type int. And the token real num has type real. So, that's what those lines just clarify. So, this clarifies that whenever you have an expression, right? The result of the expression is the same type of the operators. So, if you have int plus int, that returns an int, right? String times a string is a string. So, p1, relational operator. So, relational operator is less than greater than equal to, not equal to. The result of that is a type Boolean, right? Yeah, so this says that the number constants, so number tokens have type int and real num tokens are type real. Yeah, this just clarifies that, like, hey, if we can't, if this ever breaks, then we know that the types have to be different, which means we have a type error. So, your parser is missing these statements. While statements, conditions, do statements, switch statements, case statements, and case. So, for regular, yeah. Just a quick question about relational operators. Yes. If you have an, like, unassigned type and then, like, I say a is greater than 5, does it assign it to an int? What's the type of a and what's the type of... Oh, a is like an implicit type. Exactly, so that means, so these rules mean that this rule, c2 says that, or no, c3 says if we have anything, something, relationship operator, something else, right? So, a less than 5, right? C3 says a and 5 must have the same type. So, if the type of a is implicit, now we know that the type of a must be an int. Right, yeah. What if you're either an expression or a relation operator? What if you don't know either of the types? Ah, you don't know either type. Let's say they're both implicit. So, you have a less than b. But what do you know about... So, before you get to that, right? Let's say you have two implicit types, two implicit variables, a and b, right? What's the type of a? Unknown. It's unknown, but is it the same necessarily as the type of b or type of c? Well, I imagine we would assume that it would be the same type. Well, just like, before we get there, right? So, okay, let's see. So, let's assume we have... So, we actually don't have any type declaration, so this could be a valid program in our language. So, we can... Well, okay. Equal to d plus c times d. Right? Okay. So, I'm going to parse this expression. So, one thing you should do to check yourself is what is the parse tree of this going to look like? It's going to look something like this, more or less. I think that does the order of operations and the parentheses. So, when we're parsing this, right, we're going to parse down here and we're going to check this semantically. We're going to say, okay, for this multiply operator, right? So, here I have a new variable. What's the type of this variable? Right? So, if I'm cute. So, one thing, right? So, let's say I have some variable list of variables I've seen so far. Right? So, I hadn't seen any variables. There's no declaration of variables. So, this list is empty. So, I see c. I look c up in my variable list. I say, okay, there's nothing there. So, this must be an implicit variable. Right? So, I create a new variable c in here. And what do I give as the type of this variable c? Yeah, exactly. A placeholder. But do I just use, like, I don't know, placeholder alpha? And then when I see d, I'll give it also alpha. D, I don't know. Well, as long as... Let's look at one example. Actually, that's a good point. We don't know if they're the same. Exactly. Yes. That's a key point. Okay. So, if I see this, like, a is equal to b. And then I see c is equal to d. Right? So, my variable list here is going to say, okay, the type of a is something. Right? So, if I just said they're the same. Right? They're just some unknown quantity. But I use the same symbol. What does this say about the types of a, b, c, and d? They're all the same. They're all the same. Are the types all the same based on here? Not necessarily. Exactly. We don't know that they're actually the same. So, what we do is we want to create a new type here called, let's say, the type of c. Right? So, we have to create some brand new type. Because we don't know what it is. It could be one of the types we know. It could be something else. But for now, all we know is that it's some type c. And then we do type d. Then we say the type of d. Great. Okay. So, here the type here is type c. Here the type here is type d. So, on this multiply operator, what does this mean about the types of c and d? You must be the same. They've got to be the same. Yeah, exactly. With our rules. So, we change type d to type c. In our program. Exactly. So, we need to, you kind of, this is where you have to, this gets in the kind of nuts and bolts of how you do this. Right? But you have to essentially go through, replace every variable that has type d with type c. Right? So, you know those are the same types. And we will not have a problem. We will not have where they're not the same type. If you do then you have a type error. We'll see examples of that in a second. So, what's the type of this multiply operator? Type c. Type c. And then here we get to a plus. So, we are here. We say, okay, what's the type of this d? Type d. Right? Type d. We don't actually know what it is yet. So, we have to create a new variable in our type list. Type d. And then we see, okay, what's the, what does our type system say about these types? Type c. They have to be the same. So, what am I going to change in my variable list? A little b to c. Yeah. So, I'm going to change every type d to type c now. Right? So, what is this plus return? Type c. Type c. And this equal operator, I go to this side and say, what's this type? I look up a in here. A. I say a. And it has type a when we first see it. And I say, are these two equal? No. Or what constraint? They must be equal. They must be equal. Right? This is my type systems. That's exactly. So, type a must be equal to type c. So, I replace every instance of type a in here with type c. And so, after this line executes, I know that, I don't know exactly what their type is, right? But I know that based on this statement, they all have to be the same type. So, if later on at any other point, we find out that b is an int and c is a real, then we know that there's a type error. Right? So, this was the program. Let's say c is equal to 10. Right? So, what would this mean about all the types here? That they're all ints. Yeah, exactly. So, this means that these types have to be the same. The type of 10 is an int. The type of c is type c. This means that type c has to be ints. And then if we go here and we say now d is a 10.10. Right? So, what's the type of this? Real. So, we have real is equal to int. Right? That's a problem. We can't assign a real to an int. So, we have a type error. Yeah, we have to handle type errors. Oh, yeah. That's the fun part. Okay. Okay. So, back to the parsing. So, you only have to implement for regular credit while statements condition and do statements. If you want a little bit of extra credit, you got to do switch statements and case statements. But, if you're going to, you must do all the type checking on switch statements, case statements in the case. You can't just do those and then think that the parsing is the extra credit. Yeah. How much extra credit? It's down at the bottom. It's like five points. It's more about what you want to do it. Points are points, but this is the cool stuff. Okay. Yeah. Recommendation. Finish your incomplete parser before you do anything else. Right? This is, and the submission system will tell you how many syntax errors you fail. So, you should absolutely know that your parser is 100% correct for while statements, conditions, and do statements. Right? So, do that first and you should look at what we give you and how that maps to the grammar so you can think about what you need to do and how you should be writing a parser. Okay. The output. So, this is when we get to exactly what happens. So, what should be output? So, there'll be only one error per test case. Right? So, what does this mean when you're writing your program? Exactly. Once you find an error, you can stop. Right? You don't have to do any more parsing, which is nice. Right? Yeah. Thank you. Okay. So, there are many different types of errors. We've categorized them here. So, these are errors that either involve programmer defined types and types that are declared more than once. So, if you try to an explicitly declared type, it can be. This should be. Okay. I may have to change this wording. The idea is if you declare a type again. Right? That's an error. Redeclaring it. Yeah. Redeclaring it. You can't. So, if you have something like... C equals 10. C equals 20. Yeah. At the top, you would have a type. If you have A is an int. And then you have A is also an int. The real. Oh. Right? This is an explicit declaration. So, you're declaring this twice. So, you're redeclaring the type A. Even though they're the same. Oh, so it's even if it's the same. Yes. Yeah. That's easier. You don't have to worry about it. So, we must store all the different types somehow somewhere. Yes. Absolutely. Yeah. You need a variable list and a type list. Okay. An implicit type redeclared explicitly. Right? So, how do we explicitly declare a type? We say A is a type B. Right? So, here we don't know what type B is. It's been implicitly declared. So, then if we later try to say, well, B... Oh. I guess this doesn't answer the earlier question. This is an error. Okay. Yeah. So, swapping these two is fine. Right? If it's this way, it's fine. But like this, it's breaking this type rule. Implicit type redeclared explicitly. Elaborate on that. Yeah. So, here type B is implicitly. So, this is an implicit. Right? And here we're trying to explicitly declare type B. So, this is a type error. You can't retroactively declare. Exactly. Yeah. Okay. Yeah. This clarifies by uses and declarations. Okay. Declaring a type as a variable. Right? Seems like a bad thing. You probably don't do. Right? These are kind of easy things. So, if we had type, let's say A is an int. And then in our variable declarations, we say, oh, I want a variable A that's a string. So, this is a type name. This is a variable name. Right? So, we want to re-declare variables as names. All right? That's pretty straightforward. So, yeah, that throws an error. Okay. Yes. And using a type as a variable name. Right? That would be, that's an error code as well. Right? So, if you're in your program, you're using a type as a variable name. That's another error. Right? So, how do you define new types in C and C++? Type def, kind of. Struct. Struct. Yeah, more. So, type def is actually just a renaming operation, basically. It does, I mean, it's good for defining essentially new types for the programmer. Right? Because when I read it, I can see that, oh, you mean this is integer. Oh, this is centimeters and not just an int. Right? So, I can know more semantic meaning about that. But, yeah, so, structs are kind of how you define new types or combinations of types. Right? You give them new names. And I forgot the question. What were you talking about? Type versus types. Type versus variables. Ah, ah, ah, ah. Okay. Good, good, good. Okay. It would be like trying to, well, one thing would be like in C, trying to declare, so, if we have an int, say I want to call my int car. Right? Airward. Yeah, right. This would air, because this is a type. Now, in C, this is an explicit type. Or this is a built-in type, right? So, yeah, I don't even think this would, I don't know. So, I don't think this would, yeah, this would be actually be a syntax error. But if we define, so if we just find the struct foo, right? And we did all that stuff. And then later on, we tried to declare an int called foo. So I think this would also fail. So we'd have to use a type def to define it from a struct fruit of a foo. But anyways, the point is, right, you don't want to use variables types as variable names. So that way we know whenever we see a reference what it actually refers to. Does this refer, because otherwise it would be confusing. Does this foo refer to the type foo or the variable foo? Right? Or if we later on in the program said, I don't know, foo is equal to 10, what does this even mean? Right? Because foo is a type. And there's errors involving variable declarations. I should fix this. That's fine. Variables declare more than once, right? So we can't declare a variable more than once. Makes sense. Just like normal programming. Trying to use a variable as a type, also a problem. Yeah. So this is where he said, so just like in C, if you try to use a built-in type in the body of the program or in the int real string, it's going to cause a syntax error. Okay. So this is what you have to output. So you're outputting error code, right? The constant string error code. And then the code, which is replaced by one of these 2.2, 1.1, whatever the type is. And then the symbol name is the type or the variable that's related to that error. And so there's tons of, yeah. So you can see here, like this example. So here I'm defining a type called A. And then later on here, I'm defining a variable called A, right? So I'm redeclaring a type as a variable name. So I output error code 1.3 and A, yeah. Is that A, the built-in type? Okay. There's only 5 built-in types. Now I'm going to forget them all. Int, real, strings, Boolean, and long. Okay. If there's a type mismatch, right? So that would be any of those type constraints are violated. Then you need to say that there's a type mismatch. You put the line number that this type mismatch occurred on. And you put the constraint where the constraints are values either C1 through C5, right? One of those 5 constraints. And you can assume that violations are only going to happen on a single line, right? So you're actually using, the lexer is the same API as the lexer that we gave you in Project 2. So you can get the line exactly from there like you did in Project 2. We need total errors or other to wait to check. All of them on this list? 30? I don't, I mean, 40. How do you want to count it? Like these 5 plus all of these? Yeah, total everything. We're not going to have to check them all, right? Yeah. Okay, so if there are no semantic errors in your program, right? So we're not actually executing the program yet. So we don't care about that. But we want to show that, okay, because if we just say that like, I don't know, if you just output like, yay, everything's good. Then it's really easy to not actually be correct. Yeah. Awesome. So we're only worrying about type checking errors. There's not going to be any parsing errors thrown in or lexing errors. There will be parsing errors to make sure that you implement those parsing things correctly. So there are test cases that are checking that you implement those correctly. But yeah, there's no anything else really. I mean, the lexing we're kind of giving you, so we're not going to test that. Okay. So if there's no semantic errors, then you're going to output the list of types and variables that are type equivalent, right? So this shows that you actually know how to do this type constraints and understand the type equivalence. So you basically, so we have some pseudo code. So this should actually help you kind of decide how to write this and do this output. Basically, where's the example? The basic idea is, let's see, these are all type mismatches. I'm not going to go through all these. So here we can see a large, large-ish quote-quote program. And then we're going to out, so this program type checks. So this is a good example to walk through exactly what's going on here. One of the types are the fact that there are no type errors. Then when we get here, the output should be, so you're going to output each of the built-in types. So the built-in types here are Boolean, int, long, real string. And you're going to output each of the variables and types that are equivalent here. So we have like a, b, c, y, a1, b1, and foo are all ints in this program. There are no longs, reels. There's one string, type b, and the variable test. So these are all strings. And then we have i's. So we have the x, right, is an implicit variable here. So x has the same type as e and h. So e is the type here, and h is this implicit variable here. So the output is in the order that it appears in the program, which is what you've been doing for the other assignments. So yeah, all of these outputs here are just in the order that they appear. So you said you only output if there's no error? Correct. Correct. Yeah, you don't have to do this. As soon as you detect an error, you output that error message and stop. Okay. Any questions on, so obviously I'm expecting you to kind of dig in and figure this out, right? But I thought it would be helpful to go over it now. We output the variables in the order that they appear. Variables and types in the order that they appear. Exactly. Yeah. So this is about project theory, but was there any extra credit? It's like 105, that's 100. Yeah. Okay. So what was that? I didn't think there was any extra credit. There was. The total added up to 105. Oh, okay. That's like, so yeah. Yeah, so that's how it was. So all right, on this project, so evaluation. So same thing, test cases. We're going to give you some test cases, right? There'll be more test cases on the server. 25 points for the 1.x error codes, 15 points for the 2.x error codes, right? These are pretty simple kind of checks. The main bulk of the project is tight mismatch errors, right? So the tight mismatch errors and the no semantic error cases. So that's where the bulk of the points are. That's where the bulk of the work is too. And then five points extra credit for doing parsing and type checking for case, case list, and switch statement. So the other very important thing, so you'll notice that on here there's no points for implementing the parser, right? Because that's kind of what you have to do. So there's, you know, you have to implement the parser. Your part's the parser, correct? There's only three parts, right? And this shows that you know how to implement a parser based on a grammar, right? Especially because we're giving you all the rest of the parser. So it's actually, you should look at that to help guide you of what you should do for your part. So there's a big penalty for not doing that, so do it. I don't know how else to incentivize that. Because really, you can't really get the other ones correct if you're not parsing it correctly, right? Because you're going to fail those test cases. So you need to do it correctly. So I highly recommend do the parser first. Submit it so that you pass all the test cases. That way everything's great. And then that should be good. Just like before, I don't think this is a surprise to anyone. All your outputs kind of match exactly, right? It doesn't match exactly. It's wrong submitting the project here. Any questions? I'm assuming that we could try to submit it to see what type of errors we're passing on. It's not going to tell us. It will tell you based on the category. It will just tell you how much you pass. It's not going to tell you exactly which things you're failing or not failing in. What did you mean by lexing errors? By lexing errors? Did I say lexing errors? You said no testing lexing errors. Yeah, because we give you the lexer. So we're not going to throw weird characters at you. We wrote the lexer, so you don't have to worry about it. Cool. Are we excited? They'll also be, so we have, what, midterm? What is it next Friday? Maybe you forgot. So let me have homework. I'll sign it later today. So that way you'll have some practice. And then I think by the end of the week, I'll submit or I'll send out a practice midterm so that we can go over it next Wednesday. So we'll all be very prepared. Through all this semantic stuff so that we can actually get to more type-checking stuff which is what you're doing for the project, right? So we want to get through all this so that we can get to type-checking so that we can, but I think, I mean, it's pretty, I don't know, maybe you can tell me if it was or was not, but I think it should be fairly clear the project, right? I don't think it's too outlandish or crazy. But hopefully as you get into it, you'll see when we do type-checking and automated type-checking, we'll see how those match up. Yeah. For the test cases that will be online, should we be expecting to see at least one of every, one of every type of error? That's a good question. I don't know. That would be nice to help us out. So we're not guessing. Wow. There's a whole document. There's like a, I'm going to be framed out as a pget. It's like 15 pages with a bunch of examples. So there's also a lot of examples on there too. Cool. Okay. So we've talked about semantics. You know, pointers. If you sacrifice this class to finish project three, I highly recommend you go through and review all of the pointer semantics that we went through. So that's definitely going to be on midterms. And it's really cool stuff that you have to know so that that way you understand how pointers work, right? I mean, I think that's kind of a fundamental computer science concept. And so I don't want you to leave this class because I'm knowing how pointers work. Okay. So we talked about with a little bit with pointers. We talked about malloc, right? So malloc creates some new thing in memory for us and returns the address of that new box in memory. And so now we're going to look at a little bit more specifically about memory allocation, what it means semantically and what are some of the errors that can occur here. So basically, memory allocation is all about if we think about circle box diagrams, right? How do we create new locations, right? What is the location in the circle box diagram? It's literally two, 50-50, the box. Yes, the box. So memory allocation creates new boxes and reserves that address that's associated with them. And so what malloc will do, right, kind of heap allocation malloc is going to try to find memory that's not currently reserved and return that memory. And so it's either going to automatic, so we'll get into this, but memory allocation is going to either try to associate memory with a variable, right, where it's going to actually find that name to some memory location, or it's going to not give it a name and return that address, right, which is what we saw in the malloc. So what is the deallocation? Clearing the, basically saying that this is not, this bit of memory is not reserved and then nothing else. Yeah, exactly, right? So we're releasing that location and saying that this address can be reused by somebody else later, right? We're saying that, okay, we're going to release this location back into the world, and so now this program can use it again at some later point. So how can memory be allocated? So what are all the ways that you allocate memory on the C++ program? Using the new. Using new, but where does that actually, where does that go? Where does it come from? It's dynamic. So what type, what, like, so where does that actually live? On the heap? Yeah, so you can allocate memory on the heap. What else, is that it? Stack. So how do you allocate memory on the stack? Just declare it into your stack. Declaring it where? Anywhere you declare it going to be on the stack? Locally. Yeah, local variables and function parameters are going to be on the stack. So we have the heap, the stack, is that it? Global variables. So yeah, we have global variables and actually constants. I guess more depends on the compiler exactly where those are stored. So in general, how many times has global allocation done? Once. It's global, the program. The program allocates memory or allocates locations and gives those locations a address for each of the global variables. And when is it deallocated? When the program terminates? Yeah, never almost. From the program's perspective, it's never deallocated. After the program terminates, does the program care what memory is allocated or deallocated? No. Okay, so stack allocations. So when are variables locations allocated on the stack? Yeah, when a function starts, right? When they're declared, it's more of how they appear in the source code, right? But it's really at each function invocation that that memory gets created on the stack. We're actually going to look at how that actually happens, because I think it's really cool. So when is that memory free? What was it? I'm exiting that code block. Yeah, when you exit that function invocation, right? That's when that memory is deallocated. So do you have to do anything as a programmer to automatically deallocate variables on the stack? No, right? You don't have to do anything. It happens automatically. So how is out-of-scope defined? Access that chat variable for that particular piece of code or data, excuse me, when something that's not declared what it's already been deallocated. Yeah, but what is out-of-scope? How do we know what's out-of-scope or in-scope? See, it's the block structure. Who defines why the block structure? See, it's not on the language. It's part of the semantics of the language, which is what we've been studying, right? So the scoping rules, right, are all done that's part of the semantics of the language, right? So you can see the scoping rules are actually influencing when stack memory can be deallocated, right? That's why it can be automatically deallocated, because in C we know okay, I can only ever reference this variable inside this block. So after I leave this block, I can automatically deallocate that variable, right? Nobody else could ever reference that variable. So what about heap allocation? So is it done automatically? No. No, right? So who does heap allocation? We do. We do. Yeah, so we as programmers, right? The programmer explicitly does the allocation and then how is our things deallocated automatically on the heap? No, right? We have to explicitly deallocate memory. Okay, this is good. Keep thinking about this. Start on this project 4. Alright, thanks. See you all on Wednesday.