 Good morning. Good morning. So you should have seen on the mailing list that Project 5 was posted. So we'll briefly go over through it today, try to answer any questions you have on it. High level. So the basic idea of this project is you are designing the front end of a compiler. So you're going to give it an input language, you have to do the lexing, the parsing for this language, and then there's already a back end that's written that takes in a certain structure and will execute it. So your goal is to create that data structure. So from parsing the program you have to create this data structure. So it's incredibly important that you actually go through and understand how this back end works, because you can't change the back end. So you've got to think about it, you're on a software development team, your job is to do the front end, the back end has already been designed and inspected and implemented, so you can't change that back end. Actually is exactly what a compiler has to do normally. So the compiler itself isn't executing your code, it's generating x86 code that the CPU actually executes. So a similar thing here, right? You're generating some data structure in the normal GCC compiler's case, that's x86 code. In our case it's this intermediate representation that something else is going to execute. So not only do you have to understand the input language and how the input language works, you have to understand the semantics of this intermediate representation language. So this project is very similar to the project for parsing. Finish the functions, but you have to write all the functions. Yeah, instead of like two. Yeah. Yay. Yay indeed. The language is similar-ish. The language is similar-ish. It's similar but different. Look at the grammar to understand the language. So yeah, this is the basic idea, so you're going to feed into, you're creating this blue box here. So you're creating the compiler to generate the data structures. And then this intermediate representation, which is a graph data structure, that's going to be fed into the back end. So this compiler already exists. You don't have to do this part, all you have to do is that first blue box. So this is the grammar of the language. You'll have to read through this just like you do all the grammars to figure out how it goes. I won't spend too much time talking about it right now. I'd say it's a simplified version of the project for grammar. So there's no type declarations, all variables are assumed to be integers, and they have the default value zero to start. So this makes some things easier. Tokens are all here. Yes. I noticed there was like, this has something about an ID list, but there's no ID list in like the compile. So is that like something we create? In the intermediate representation? So we'll have like our own ID list we use in our own... You should have a variable list. Yeah. Some type of variables. Exactly. So we'll store that in ours, and we'll use that when we're parsing stuff. Yes. Yeah. So this is part of the translation process, right? It's not a one-to-one mapping. It's not like you're just doing a simple translation, right? You're just interpreting this input language and outputting in this intermediate representation what it needs to execute. Also, expressions are not recursive, which makes things easier. No-type declaration section. We have if statements, which I don't think we had in the other language. Do we have those statements? We did not. We did not. In condition stuff. Right? Yeah. We have if statements. We have print statements. There's one ID list of global variables, so there's only one declaration of global variables. That also makes things a little bit easier. All variables are integers. There we go. So that's pretty much it. The idea is you need to know what this language does and what the semantics of this language are so that you can properly create the intermediate representation so that the back end will properly execute it in the same way. Right? The programmer doesn't know that it's running in this weird compiler or it's running in x86 code. They don't care. They just care that they're writing their program in our language and it should execute the same and have the same semantics. Okay. These things are pretty straightforward. Booleans, right? We all know it. Booleans are the condition statements. If statements have valid semantics, you will have problems with nested if statements. They can be recursively nested. There's actually further on in the document that talks about how to handle that, so make sure you pay attention to that because it's going to trick you up. While statements are very similar. So, if we look, I actually have the code to look at, put that h file. So, all of these structures in here for compiler.h, these are all the data structures of the intermediate representation. This is what you have to be creating. Right? So we have a value node, a go-to statement, an assignment statement, a print statement, if statement, a state general statement node, and that's it. So, if you notice, we have, so a statement is going to be either an assignment statement, a print statement, an if statement, and a go-to statement. But, if we go back to our language, let's see, a statement can either be an assignment statement, a print statement, a while statement, an if statement, or a switch statement. So, which of these don't we have in our intermediate representation? Which one? We do have print. We don't have a while statement and we don't have a switch statement. Right? So you have to emulate those semantics in our input language using the data structures given to you in the intermediate representation. Just like there is no x86 while instruction. When it writes that code out, it writes code, and actually we'll see exactly how it does it. It does something that it jumps to the top. Yeah. So no modifications of the compiler.c? Yes, you cannot change compiler.c or compiler.h. Do we upload those? No. No. You don't just upload your own code up. I think we did in... Two. Two. Yeah, one of the other projects. I can't remember the numbers. One. Okay. So, for instance, the semantics in our language of a while statement are the normal semantics. Right? So evaluate the condition and then if the condition is true, evaluate the body and then go back to step one. So evaluate the condition then evaluate the body. And evaluate the condition then evaluate the body. If the condition is false, then you skip the body. Right? You go on to the next statement. So we can actually completely write this. We can actually completely emulate these... this behavior just using ifs and go-tos. So we can say that if we say this is some label, we say if condition, then execute the body and the last thing there go to the label. Right? So it's going to jump up here. It's going to evaluate the condition. If that condition is true, it's going to execute the body and then it's going to go to the label again. So this is actually exactly how that K-6 code is written to do while loops. It's exactly this code. So this is essentially what you're creating using these data structures. And so you're essentially introducing these go-to statements into the generated intermediate representation because we have a go-to statement there, but we don't have a go-to statement in our program. So you can't actually write this program in our input language. There is no go-to in our input language. Does that make sense? Yes. But there will be like while loops. Yes. Is that label actually there and input? No. It just looks like this. Oh, okay. We're saying this is equivalent to this, right? If we had labels and we had go-tos. Okay. You have go-to statements in the input language so you can, sorry, in the intermediate representation language. So you can represent these. Okay. Switch similarly, right? We don't have a switch. What are the semantics of the switch statement? Labels. Yeah. So execute. Check that variable, right? If that variable is the first case, then do that case body. If it's the second case, then do that case body. The third case, do that case body. So it's just a go-to. Yeah. So we just have an if. Well, actually, yeah, it kind of translates into a bunch of if statements. But there's an important, yeah. Is it a bunch of ifs or is it? Yeah. So there's a couple ways to do it. The easy way to do this is to add, transform every case statement into a statement like this and add a go-to at the end of there to after all of these. And this will help simplify things if you do it this way. Not just because I say it, it's going to make implementation easier when you implement these things. Okay. We also have switch statements with a default case, which is if it does not match any of those, right? So we can transform this equivalently. If the variable is n1, then do statement list one, go to label, all the way up to nk. Otherwise, execute that statement list default. Right? I see that default one. Yes. So do we assume that every case has a break at the end? Yes. Yes. In our language, every case implicitly has a break in it. But these statement lists, right, these statement lists can contain if statements, case statements. Yeah. Everything there. Those can contain if statements, files. It's going to be the tough part. Yes. Print, prints out the value of the variable. You all know where the submission site is. I'm just trying to emphasize. So yes, this is, I think, the key to this project, to be successful in this project, you have to understand the intermediate representation. Because this is what you're generating, right? At this point, I think you all have got, first, follow grammars generating recursive descent parsers, right? So you can do that code, plus you can follow kind of along with what we did in project four, right? Which is part of what you did. So that part shouldn't be too difficult, but you have to do it and make sure that's rock solid. But this is the key, is making sure you understand these data structures, right? Because, as we can see, so for instance, so statements are basically a linked list of statements, right? Do this statement, then do this next statement, then this next statement, right? Which makes sense. That's how the compiler's going to, the back end is going to do it sequentially. Execution, right? Exceed this, then this, then this. The tricky part, but this isn't a linked list. It's a graph, right? So we have, for instance, as long as there's stuff there, you can keep branching out. Oh, not the assignment statement. Yeah. I wanted to do it. Yeah. So, it has conditions, and then it has a true branch or a false branch, right? So you think of it linked list-wise, right? Link, link, link, link, and then it splits off into two, so there's two possibilities of where it could go to, right? The true branch or a false branch. Similarly, a go-to statement can go anywhere. It can point to any statement node, so it can even go back, right? So you can have loops in your graph, which is how you want to do it. If you want something to continue to happen and you want a branch that will branch outside of that loop. Yes. Do you have to worry about L-sif? What? L-sif. Or is it just true or false for all of your statements? Let's see. Say that again? Do we have to worry about like an L-sif? Let's look at the if statement, whatever the statement says. I don't think there's any else clauses to our if statement. Let's see. Okay, yeah, this is one of the things. There is no else in our language, but there is an else branch in the input language, or sorry, in the intermediate representation. Yes. So there is no else in the if statement in our input language, but the intermediate representation has an else, right? Which we want to use when we're doing, which we could want to use when we're doing implementing wiles and switches. So another important concept, everything to the everything in the all the variables to the intermediate representation to the back end are represented using this value node structure. So this is going to be some name and the current value of that the name of that variable. And so, for instance, an assignment statement says, hey, it has some operator, right? So what are the operators plus, minus, multiplier, divide? So this is going to be the left and right operand on the right hand side. It's either going to add them together minus whatever the operation is, then it's going to copy that result into left hand side's value. But, the really important thing is these are all pointers, right? So you need to make sure these actually point to the same object. Every reference to variable A needs to point to the same value node A, right? If you have just looked inside that this value node to see what the current value is. So that's part of understanding what the back end does and seeing how it deals with assignment statements. Kind of let you read through these things. Print statement's pretty easy. You give it an ID here. The statement node structure is a union, so it can be either an assignment statement, a print statement, a if statement, or a go-to statement. And you'll know that it is based on this type. Yeah, we have some code here to kind of help you out. If and while. Okay, this is the key. I mean, I think at this point, it may be a premature to go over all of these in detail because you have to really start implementing this and going through it and reading this section. This is one of the key sections is how to do if and while statements. Especially with like I mentioned with the recursion. So the key to remember is this is how you do it. So that it will work recursively. As far as the literature, we want to find the one from the previous assignment or is that given? Is it a question? Looks like we do provide it for you, so. Great. You should. I mean, this would be hard. This is what we did at the start of the semester. Exactly. I wanted to create it for the third time. Exactly. Okay. Yeah, so this is all about how to handle this. Handling a wall statement is very similar. Your code, your structure should look like this. You should be able to sit down, look at your code for parsing a wall statement and draw this diagram based on what are happening to the pointers and all the structures that you're creating. Alright. The execution is actually incredibly simple if, well, okay, I don't want. That makes it sound really easier than it actually is. Essentially, what it's doing here, so it's starting with the statement node as a list of a linked list. Well, it's a graph, but the start node is a linked list and the next one is going to be the next node to be executed. So it's going to put it in the program counter just like x86 has a program counter. While this program counter's not equal to null, it checks the type of that statement. If that statement is a no-op, it just goes to the next one. So this is how you need to do a no-op statement and a go-to, maybe. A print statement, it checks the print statement. It makes sure it does some sanity-checking to make sure that there is a print statement and that there is an ID in that print statement. If it is, it just prints out the value that's inside that print statement. So a print statement is the current print statement. ID is the current, is the node, what's it called, a node that's in there and then you're printing out the value in that value node. Then we're setting the program counter equal to the next instruction. Assignment statement does sanity-checking, checks the operator if the op is does more sanity-checking and then it switches based on the operator. If it's a plus, it gets the values out of the two operands of their value nodes, adds them together into a result. Otherwise, it subtracts, otherwise it multiplies, otherwise it divides. In the case of zero, when the operator is null, it means you're just doing an A equals B assignment with no operation and then it sets the left-hand side's value to the result. So this is where you can see this is how values get propagated with the assignment structure and then it goes to the next program statement. Yes. For, are you going to, okay, so for the input, are you going to be declaring? Yes. Are you ever going to do it inside the body? No. The variable dimensions are all just one ID list at the top of the program. Any test? That's probably not where it goes. So like here you declare variables A and B and so these variables are the only global variables that you have through the entire execution of this program. And then there you have all the statements. You have ifs and additions and assignments. Yeah. So, dude, why is this to start with, you know, like decorations and then to assignment statements and... I would, let's hold that so we get to the end. Maybe, I think we're almost there. So that's basically how the back end works. Compiler. If statements, right, are exactly what you would think. It evaluates the operand depending on what operator it is, greater than, less than, not equal to. So what are the, so some of you remember what are the three operators are back end supports? Less than, not equal. Right here. Is that normal? Why not? What are you missing? Less than or equal to, yeah, so if we look at our back to the grammar, we need scrolling a bunch. Right, if statement and condition is a primary, real-op primary where a real-op is greater than, less than, greater than, less than, not equal to. Okay, that's good. But, yes, but for an ifs, for, what am I thinking about? I know this comes up at some point and I'm going to remember which part it is. Right, when you do, right, when you do a switch statement, what is this saying? This is saying if variable is equal equal to and one. Yeah. Right? Do you have an equals equals operator? No. Can you add it to compiler.c? No, no, absolutely not. That would be too easy. It's not. Yes, so you have to think about the data structure you're creating and what's here, right, you can only compare with a branch, right? So, does it make the false branch or true branch? Exactly, if you make the false branch or true branch in this case, then you get around that. When you get stuck on these things, you should come back and watch this video because I think it would be helpful. Okay, go through statement, then we just set our program counter equal to the target that I go to statement and that is the entire compiler back in here. Do we also have to implement less than or equal to or was it just the equal statement that's not in there? You have to fully support the input language. Okay. So, you have to look at the input language, see what operators you need in there. Think about default as if and while those conditions that are in there are the same ones that are in here. But, for instance, if you want to extend the language to support greater than or equal to or less than or equal to or even just change the way you write out using only these three base operating methods. We can still do it. Okay. I think we've covered all the tricky things. Okay. We did that. So, you have to the input, the the interface to the code that you write, you must implement this method, parse, generate, intermediate representation. That's going to return a pointer to a statement node structure. That's going to be the first statement in this list, right? That gets passed to that execute function we just saw and everything happens. So, you have to implement this in a different file, right? You implement that correctly and everything's good. So, the way you do that is totally up to you. Do it the way we did it like in project four of recursive or parsing to build up this thing. That's going to be the easiest way that's going to not drive you crazy. So, that's kind of synonymous with the program? Yes. Like parse program is kind of that. In that case, we're building up a data structure that represents the parse tree of that program. Here we only care about returning this statement node structure, this graph that represents the program. It's not just a one-to-one mapping like it was before. Yeah. So, I'm assuming you would suggest that we implement everything that allows us to parse the entire input language first and then go back and then translate it to this intermediate just to make sure that we can get through the whole language, being able to parse through it properly, then go through and systematically translate it. I don't know that I would agree with that. I mean, would you offer a counter? Yeah, the counter is you parse what you do. We'll have to parse the whole language. Right. But you need to parse it for a purpose. Right. I mean, I don't parse the language, but what I don't think you need to do is to parse it in the sense that you create a whole parse tree from it. I'm not saying that. I'm saying create the setup so that it can be parsed all the way through. So, you do that without causing some time there? Yes. That would be very good. You know in the project for how to not just, you know, parse everything and then figure out what you're going to do with the values of the variables and stuff. In fact, just do inline parsing while you're parsing to have other lists and things that you would store the variables and update them. Yes. So that's exactly how I do this part. Yes. I would start from here and figure out what parsing functions you need, right? Like for that variable declaration list at the start, right? This is somehow you need to parse that list into a sequence of IDs and then you need to create essentially a mapping or a list of that ID and a new value node so that every time you reference that ID later on in the program, you provide a pointer to the same value node. So that's what you have to do first and then, yeah, that's kind of your global variable, right? All right. More questions? You got to use your C++ for this assignment, sent to S67. Or use Java. Yeah. You don't have to use Java. I want to see your Python. Yeah. Why use Java? So, the other section, so they, okay, so they, the other section has decided you can use Java, but you don't get the back end so you have to do everything. I would much, I want you to do C and or C++ because that's how we've been going in this course. It's going to save you some work too because you don't have to do the back end. So, I'm taking that option off the table for you. Thank you. I mean, I would be very helpful. Okay. Yeah. Submit your own code. Don't submit your compiler.C. Grading. So, this is when we get back to the question about what do we do when. So, how do I suggest to tackle this? So, the points are broken down in different categories, assignment statements. So, programs with only assignment statements, programs with only if statements, programs with only while statements, programs with only switch statements, and finally, programs that contain all types of statements. But, so I mean, you say that it's a program that only contains if statements, but don't those if statements have to have, you know, something in there in the body of that if statement, so wouldn't it contain other? So that's, so, well, okay, that's true. Or would it be just Yes, there's one way up here. So, okay, I guess I should have clarified. That's not exactly. So, so for us to even test anything, right, we have to see what your program probably looks like. Right. Well, as we can never test your code. Right. Then, so if, while and switch, all depend on assignment statements. Right. We need to be able to assign things and test if you're going properly in the right branch. So, print, do assignment, get those down a hundred percent, and then move on to if, while, switch statements. Cool. Okay. Questions on that? Okay. I'll just reiterate one of three things. So, you can, actually you can do one of four things. You can do nothing. Right. Totally not good. You actually have a lot of choices. I guess you could drop the class or do. You have a lot of things. You can, okay, so you can resubmit project three, and this will replace your project three grade, but you have a 30 percent reduction on whatever you submit. So, for instance, here, if your project three grade, you've got a 20 on project three, and you've coded up project three to get a 90, right? You'll be reduced, 90 will be reduced by 30 percent to 63, so your greater project three will go up from a 20 to a 63. You can also choose to resubmit project four. Okay. Same thing. You can resubmit project four, penalty of 30 percent. Questions on those options? Yes. What if you resubmit project four? It's not going to go down. Okay. No. I mean, that would be hilarious. That'd be too mean, I think. That's like, it's like less of a bonus and more of a gamble, I guess. Your third option, so this option comes with no penalty, so you can replace the lowest grade on either project three or project four, but you have to do this entire new bonus project that extends project five and does the same thing. Oh, yeah. Can I use it to replace project five? No. Just do project five. I was saying if your project five grade is bad enough to be worth replacing, I would not do that. Right. So here's the grammar for your language, just to go over this, tokens in this language. So basically we've extended it such that we have arrays. So you can declare that you have array accesses in very well-accessed ID, left bracket, expression, right bracket. So we have size and we specify the size in the variable section after an array. So in this one you actually have to mod compiler.h and compiler.c to support this, so you have to submit everything. And okay, there's a project five section. What? Would this be related with project five? No, there's a bonus on the CSE site. Right. I don't have my login on this. About the bonus project, but project five itself. Yes. So you said new print statements before assignment statements kind of went out in order to get the points. Not kind of, print statements. Is there any specific format you want to do? No. All you have to do is create a print statement node and pass that to the back end and the back end will print. So that's a self-check. You should never have any print statements in the code that you write. Except your debugging stuff, right. You should never write any print statements in the code you submit. All of the printing, everything is done by the back end. So you already have that set up for us. Yes. We know how to do it in the back end so we can link your print statement. Yes. Exactly. You should create a super simple example that has one variable and just prints out that variable and it should print out the zero. Excellent. That's what that program should do. But without that, it's not a good way to do it. It's a really good program. And it's a great program. It's a great program. So it's a really good program. We can link our print statement in the code in the code that you write. You can That's including project five and anything. Yes, everything. Everything here. Project five, all the bonuses. Everything here. No extension. Yeah. The next one gets 100. Yeah. Why would you want an extension? I don't know. Extension is actually bad, but they can force you to like work on it for another day. Trust me. I've been in that situation. They do that same thing for conferences. You're like trying to submit a research paper and you're like working on it. You can work out like two or three days straight. And then like, oh, the deadline's been extended by a day. And you're like, oh my God, I've been working on this. I just want to be done. Take a nap. That's like a breath. I understand. Functions. Okay. So we've seen, we've been looking at the runtime environment because we're trying to understand what actually happens when we execute our code, right? We want to understand where is the compiler place thing? Why does it place things there? Right? So we've seen that the compiler places global variables in just a static fixed memory location, right? And we saw that the compiler will put local variables on the stack with an offset of the base pointer. So we'll put it inside the function frame of that function. So now I want to study functions a little bit more. We haven't really gone into depth. We've gone into semantics, right, of pointers and assignment statements, right? Do you feel that we went into enough depth and of assignment semantics? Oh yeah. We're good to see you. Yes. We're good to hear. Cool. So let's do a similar thing with lungions so we can understand everything. Okay. So what's so special about functions? They can do stuff. They can do stuff. I can do stuff. Am I special? Yeah. We're all specials in a place. We're all specials in a place. Yes. But specifically in code, why are functions special? Yeah. You get to build a subroutine that will do a task that you expect to do more than one. Yeah. So we can kind of declare something, right? And it's some sense parameterized and it will execute maybe changes behavior based on its parameters, but it allows us to kind of specify some repeatable process. It allows you to give things functionality. Yeah. Can we not call functions? So how do you actually, like, what are the mechanics of a function? How do you actually go about creating one or using one? Some type of process that takes in some type of input. When you're coding, when you're coding. Oh. Declare. Yeah. You have the first declare function and then what? Define it. Define it and then what? Use it. Use it. Yeah. Right. If you just declare to define the function and it's never used, right? Does it even exist? Right. So what do we need to declare a function? What are the things that goes into defining a function? Return type. Return type. Name. The name. Parameters. The parameters. The parameters types. The body. The actual function itself. Stuff that knows. I thought that was the definition. Right. So there are, I don't know, we're going to go to two sets of concepts. Right. So we need to define the name. Why do we need to define the name? Think about the why. So we can use it later, right? We can find it. Right. Just declaring it, we don't really care what the name is. Well, maybe we do. We need to recursive. We don't care what the name is. Right. Exactly. Then we're going to call. Okay. So we're going to separate the, we need to have some terms to talk about the parameters that are in the definition of the function and the parameters that we pass into the function. Right. Because those are actually two separate concepts, right? The parameters inside the function and the parameters that we pass to the function when we call it. So we're going to call these formal parameters. So I don't know. Whatever helps you think about it. Think about like a parameter and like a suit and tie. Maybe a top hat. You know, it's formal. Okay. Cool. And the types. We also need another return type of the function. Right. I guess. So now, okay, so we talked about why did, why did we just talk about a difference between declarations and definitions? Because you can declare a function without defining it. Why? So that you can use it without having it defined and then define it later. Yeah. Right. And that actually helps us in C or it may not even be our code that defines that function. Right. So this kind of gets back to encapsulation. Right. If I want to call some other person's function. Right. Maybe I don't want to know how their function is actually written. I just want to know how, what that signature looks like. Right. I need to know how to invoke that function. Yeah. Exactly. When you call libraries, all that kind of stuff. Right. So we're going to separate decorations from the invocation. So invoking a function. Right. We all know the syntax, what it syntactically looks like. Right. Here we're invoking a function called what? Passing in parameters f1, f2 all the way to x. Sorry. That's the x. x1, x2 all the way to xk. Where x1, x2, and xk are all expressions. Right. Do you have to always pass variables into functions? No. You don't know. You don't know. No. You can pass foo x plus one. Right. And it means at runtime evaluate x, add one to it and pass it in as the first parameter of this function. Right. So we're going to call, so this is when we separate. We're going to call x1, x2, xk. These are going to be the actual parameters of the function. So when we invoke a function, we're passing, we are setting actual parameters. And the definition, the declaration of that function, we have the formal parameter. So going back to what we knew. Right. So when we talked about function frame, we talked about the function frame on the stack of the local variables. Right. So how do we actually call a function? You go to the, where the code is? We go to where the code is. Yeah. We go to the code is. Where do these parameters live? Think about now what we've been talking about. Are they global variables? No. They're local variables to that function. Right. So they also need to be inside that function frame. Right. Every function needs to be able to access the parameters that it was called with. Right. But who puts those parameters there onto the stack? Where do those parameters come from when the function is invoked? Where is calling that function? Yeah. The calling function. Right. So when we invoke a function, we are responsible for copying those values, the x1, x2, xk onto the stack so that they can go to that function. So that's actually the job of the calling function. And this actually goes back to why, part of the reason why in C, you need to know the exact signature of the function. Right. Because you need to know when you invoke that function, how much space do I put on the stack and where do I put these variables on the stack that the function can find those parameters. So the function frames of this, right, we've seen we can move the stack down. We can put values on the stack. Right. But what other information when we call a function, what other information do we need? Right. So when you're calling a function, why are you calling a function? It wants to do something for us. So how do we get the result back? Return value usually. Right. We need that function to return some value. So where does that return value live? We also need to put all the parameters onto the stack to that function. Right. But I think I should talk about this on Wednesday. Right. So we call this new function. The new function completely takes over the CPU, can do whatever it wants. And we saw that actually the very first thing that it does is it changes the base pointer. It sets up its new base pointer based on the stack pointer, which completely gets rid of our function's base pointer and our function's base pointer. So where our frame lives on the stack is completely gone. So we need to actually store this. Right. We need to save our base pointer so that we know how to get back. So, but, okay, let's think about this. Right. So what we're executing, the CPU, the program counter or the instruction pointer on X86, right, is executing our function. We call some other function. Now, what happens when it's done executing? Where do we want it to go? Right back to where we are now. Well, to the next line, not to. Back to the next line after the call. But. You save it for your PC. You update the PC to the function. Then the function executes it back to your PC. But where do you put your PC? Yeah, you need to save it somewhere. Right. You have to have it saved somewhere because fundamentally when you call a function, the new program counter is going to be that function. Right. And that function is going to start executing. So we need to actually save the return address is what it's called. Right. Or where we want this function to go back and start executing when the invoke function stops. And then we saw we need local variables and temporary variables. So the question is, so essentially all of these things are going to need to be saved somehow. And need to live somewhere when we call a function. But the question is who does what? And where do these things live? Do I put the return value on the stack? Do I put parameters and registers? Do I put, I don't know, a frame pointer on the stack? Who puts it there? Right. Maybe the caller, the function that gets called, right, the call e, maybe, you know, does it create its space for its local variables? Should a calling function create space for local variables on the stack before functions call? So this is actually just, honestly, the specifics don't matter except for the fact that you have to have some kind of convention. Right. So if you're going to call some function that somebody else wrote, then your compiler needs to know how to create that call and that code without knowing what that function actually does. So we need some sort of convention so that we can call functions that different people write with different code. So all this information needs to be stored on the stack. So in what order are the things stored on the stack? Or are they put in parameters and if so, or sorry, in registers? You're trying to pass a parameter that's not 32 bits and so it can't fit in a register. Right. What do you do then? So the question is always who can store this and what's the order. So we need a precise convention that explicitly says if you want to call a function, you have to do x, y, z in this order. And if you get called as a function, your responsibility is a, b, c. But actually the crazy thing, well maybe, I don't know how long you've been working with computers, this convention completely varies based on processors. So different arm is different from x86. Operating systems, so Windows calling convention is different than the Linux calling convention. It could be based on the compiler, different compilers can do this different. And even the type of call. So calling a normal function versus calling a syscall, I know some of you are in the OS class. So calling a syscall, you have to put parameters and registers to call a syscall. Where in a normal x86 Linux call, you put the values on the stack. So it completely changes. But these are all specified and defined. So the Linux, the C-deckle calling convention for Linux. Let me go over this so you know that there is a standard. I won't expect you to memorize this. But the caller first pushes all arguments onto the stack from right to left order. So the rightmost and then the next to rightmost, all the way to the leftmost parameter, the actual parameter. Then it's going to push the address of the instruction after the call. So this is that return address. And this is all the caller has to do. And then the function starts to execute. Now the called function or the call e function has to save the previous base pointer. This frame pointer from that function that called it. That's its responsibility. Then it has to create space on the stack for local variables. Then it has to ensure, this is actually a key. So we're using the stack. If you call a function and it changes the stack, you're going to be completely messed up because you're going to try to look for variables based on that stack location and they're going to be in the wrong place. So it's up to every function to ensure that the stack is consistent when it returns. And finally, just to make things even more confusing, the return value is put into the EAX registers. The return value actually doesn't use the stack, which makes it incredibly frustrating. Cool. So on Monday we're going to go over a cool, I'm going to preview this a little bit. We're going to go over exactly what this code does when we execute it and how the stack frames look like so that we can understand how function frames live and look like on the stack.