Hello and welcome back, everyone.
Before we can continue implementing structures, we need to implement bodies.
So what our bodies, while anything between these brackets and obviously we have to implement bodies
because structures have bodies.
Functions have bodies if statements have bodies.
So we need to implement the body node in this lecture before we can continue working on the structures.
Okay.
So let's start by going to compilers h.
And just under the strict declaration, we're going to say struct body
body.
So what the bodies have, well, they have statements, you know, functions have statements.
Right.
The actual body between the brackets are statements.
So what are we going to do?
Well, we're actually going to create a vector of statements, and this will be a vector containing
struct node.
So if I had something like X equals 50, that would be stored as one element in the statements vector
we then had in it.
Y equals 30 that will be stored as an element in the statements vector.
Does that make sense?
So now we're going to say size, tw size.
So this will be the size of all the statements sum together.
So when I refer to size, I mean like variable declarations.
So this will be the sum of the size of all variable declaration statements inside of this body, the
size of combined variables inside this body.
There you go.
So we're going to have a building called padded.
So this will be true if we had to pad the size.
True if the variable size had to be increased due to padding in the body.
More will be explained on padded when we go to implement it.
So now we're going to say struck node largest via node.
So this is a pointer to the largest variable node inside the statement vector.
A pointer to the largest variable node in the statements factor.
So when I say the largest, I mean the largest in size.
So, you know, a structure that's I don't know, 200 bytes long is bigger than a variable, right?
So obviously, if there's no variable declarations in the statements, then this will be null.
So that's what our body structure looks like.
And we're going to go back to parse it out, see.
And we're just going to create here void powers, body
parts, body function.
So what is pass body going to do?
Well, it's going to create a new scope to begin with.
And we're going to finish the scope by here.
And we basically need to read all the statements into memory.
So what we're going to do is we're going to say size t, temp size equals zero zero.
And our positive body is also going to have a pointer of size t called variable size.
And it's going to accept a struct history.
So this variable size is basically going to be set as we pause and it's essentially going to be set
to the sum of all variables we come across when parsing the body.
Okay, so we should probably make that clear, shouldn't we?
Set to the sum of all variables encountered in the past body variable sizes, I should say, simple
as that.
So back to the body.
We're going to say if there is no variable size, basically, if they provide an old pointer which is
valid, then we'll just set the variable size to the temp size.
So that guarantees we always have a variable size set even if they pass null in here.
They were passing all if they don't care about what the variable size is.
So now we're going to create a vector for our statements.
We'll just call it body vec equals vector create size of struct node.
Now just head to test C, I want to show you some things so it's possible to have if statements inside
functions where we just go stuff like that where there's no curly braces in our parser.
We will call this a parsing of a single statement and anything with brackets like this will be parsed
as parsing a body of multiple statements.
So there's a separation between those two.
So I just let you know that while we implement this now, so back to positive, see, we're going to
check for a left curly.
And if there's no left Curly, then we're parsing a single statement.
So we say parse body single statement and we haven't created that function yet.
We're just going to pass in the variable size, the body VEC and the history.
So now we're going to create that function which is in charge for just parsing a single statement.
So we're going to say void parse body, single statement, size RT variable size, stroke vector body
vec struct history, history.
And once we parse the single statement here, we then want to finish the scope and return.
So now just head over to Node C.
And just to make bracket no, we're going to say void make body note and that's going to take the body
vector statements.
It's going to take a size it's going to take a padded variable and it's going to take the largest far
note.
So we're just going to say no, create struct node.
So type equals node type body.
Top body top statement sequence body vec top body size equal size top body top padded equals padded
top body largest final equals large fan note nice.
Okay, so as you know, that will create a node on the stack with those properties and then it will
return the address and pass the address straight into Node Create.
So it can copy that node into the new malloc memory.
So we're going to copy and paste that into compile H.
And I hope depositors see.
And we're going to start by making a blank body note.
So I can go no for the body vec zero for the size false for the padded and no for the largest variable
node.
Now we're going to pop off that body note that we just created
and we're going to scroll to the top of this file.
We're just going to say extern, struc, node, positive current body.
So this is the current body node that we're aware of that we're currently in is external because we'll
define this somewhere else in a moment.
So just head over to nodes, see?
Scroll up.
We're just going to say struct node positive current body equals null.
So at defining the actual memory and node dot C, but we're allowing ourselves to reference it and pass
a dot C.
Okay, so now head back to parse body and we're just going to say body node bind it dot owner equals
parse the current body so.
Yeah.
Essentially, every every body node kind of has a parent unless there's no parent above it.
So what we're saying here is the body.
No, we're just creating now as a parent, which is equal to the positive current body, and then we
change the current body.
That's another important thing.
We change it to ourselves because now we're a step down.
I want we're done with this function.
We're then going to set it back to what it was.
So we're going to say body node by the owner.
And obviously everything in between here, the the body node will be set correctly.
We need to always return it back to the previous one because imagine the scenario of something like
this where we have multiple scopes and then we have something going on here.
Okay?
So obviously if we don't set it back, it will it will cause problems for when we finally pause in it.
Why?
Okay.
So that's the reason.
So now what we have to do, we have to parse the single statement because remember, this function is
called for things like this.
If X, y equals 30 where there's no brackets, but between them, that's when this single function gets
called.
So I only expect in one statement.
So there's going to be no while loop here.
We're just going to parse the statement right away.
So we're just going to save y parse statement struct history, history
we're going to say token peak.
Next type is keyword.
Then parse the keyword
return because statements can be keywords, can't they like return 56 return is a keyword, right?
So we need to be able to parse that situation.
So we've just done that here.
If it's not a keyword, we can assume it's an expression such as X equals 50.
So we're just going to say parse expression, ball root history, and then we're going to check for
an actual symbol.
So we're going to say token peak next type is equal to token type symbol, and the symbol is not a semicolon
because it's normal to end statements with a semicolon, as you know.
Then we're going to pause the symbol, which we haven't yet done.
So we're just going to create a dummy function for that.
That will do nothing for now.
And we'll fill that function in later on.
And we want to return if if we successfully parse that symbol.
And we're just going to put a little message here for us in case we end up accidentally calling it.
We're going to say symbols are not yet supported just in case we end up ever meeting the criteria for
parsing symbols.
So what to all statements expect a semicolon expects semicolon all statements and with semicolons when
they're on the lines on their own, that is okay.
Nice.
So that that should work.
Okay.
So we're now going to say on past body single statement struck nodes statement node equals no pause
statement history down history history flags.
So that will pause the statement.
So what do we need to do?
We need to pop off the statement that was parsed.
Okay.
Because when we go to parse key words, you know, it's going to it's going to parse through here and
it's going to be pushing to the stack and stuff like that.
Yeah.
So we need to be able to pop that off.
I don't expect you to understand all of this now.
Obviously, it's complicated.
We're jumping from through lots of different hoops, but that's because making a compiler is difficult.
So just stick with this, even if it's difficult and it will all make sense soon when all these systems
start working together properly.
And if you do have any questions, just ask me.
So the node we popped off, we have to put it in the body of X.
So we're going to say vector push body vec ampersand statement node.
So that'll push the power statement into the body vector.
Okay.
So what we're going to do now is we're going to create some dummy functions.
So we're going to say voi parser append size for node struct history history size t variable size struc
node node.
And we'll literally just going to do a compiler warning, not an error, just a warning and we're just
going to say pause the size tracking is not yet implemented and this lets us know, you know what I
mean?
So we can come back to it because I don't want to give you too much to deal with it once.
So all this function will be responsible for be responsible for looking at the nodes you provide it
and try to extract some sort of variable size from that node.
And then it will add it to the sum of the variable size here, variable size pointer.
So that's what that function is supposed to do when we finish implementing it.
So just by here we're going to say parse, append size for node.
We're going to pass in the history, the variable size, and then we're going to say the statement node,
okay, change it, change the variable size variable by the size of the statement node.
Perfect.
So now we're going to say struct node largest file node equals null.
If the statement node type is of no type variable, then the largest file node will equal the statement.
No.
Now that makes sense, right?
Because this is a single statement.
So of course if there's a variable, it's going to be the largest variable node because there's only
one of them.
So now we're going to say void parse of finalized body and this is a very complicated function.
So again, we're not going to fill it in in this lecture.
We're just going to make a placeholder for this and we're going to say struct history, history
struc node body node stroke vector body vec size tw variable size struct node largest align eligible
var node struck node largest possible var node.
So let me go back to that with you because it's quite long.
We have our history variable, our body node variable, our body vector, our variable size variable,
our node to the largest assignable variable node and I know to the largest possible variable node.
You don't have to understand all these concepts right now.
They will make sense as we go through the course.
So this function will essentially be responsible of computing padding for this body and it will also
be responsible for taking in all of these arguments that we've provided here and setting them in our
actual body node.
Okay.
So we will fill in the basics here today.
We'll go body node.
Body dot largest file node equals largest align eligible var node body node body dot padding equals
false body node body dot size equals asterisk variable size body node body statements equals body vec.
Okay, so this is basically what the finalized body does.
It'll take all of those arguments.
It will compute padding, which we haven't yet done, and then it will set all of those variables and
we haven't really discussed padding in detail yet.
We will discuss padding soon because you need to be aware of this.
This function later on will become a lot larger because.
We'll be responsible for going through all the statements and essentially computing the correct padding
for them.
We'll discuss more padding when it's appropriate.
So back to parse body single statement above, parse the current body, we're going to say pause a finalized
body and we're going to pass in the history the body node, the body vector, the variable size, largest
FA node and the largest possible varner will be largest file node because we only have one variable,
right?
So that's all we have to worry about.
The final thing to do is push our completed body node to the stack.
Okay.
Feel free to compare your code with the one on the commit log for this lecture.
For every coding lecture there's a link, a hyperlink to a GitHub repository.
And I put this here on purpose because I understand people make mistakes, they make typing errors,
and it's always a good place to go if you if you're a bit confused or if something doesn't work for
you.
But it works for me.
And if you do have problems, you can always reach out.
So we're going to continue implementing these bodies later.
I think this is been quite a long lecture, so I'm going to give you all a break and rather continue
this now in this lecture.
We'll continue this as we go through the course.