Welcome back.
In this lecture, we're going to start implementing variables.
So just go to parse it out, see?
And in our past viable functional struct union just under the ignore in store abbreviations we made
in the last lecture we're going to say struck token name token equals token x.
So now if you imagine something like Integer ABC, you can see that we have our industry data type which
we parsed here and now.
What's next on the token stack is the name of the variable, right?
Which is why we do token next which will pop that off the ABC and we're going to check is the name token,
not an identifier.
If it's not an identifier, then someone's done something stupid like integer 49.
Right?
Well, we can't allow that.
Obviously it's not a valid a valid function, a valid variable name and see.
So we need to error out.
We're going to say compiler error, current process, expecting a valid name for the given variable
declaration.
And again, don't worry about line numbers and all that because we already deal with that.
Okay, we keep track of the line and column numbers, so this compiler error will output those out for
us.
So now here we would check for a function check.
If this is a function OC as a function declaration, we haven't got to that bit yet because someone
could do something like this, couldn't they?
You see what I mean?
And then suddenly it's no longer a variable declaration.
It's a function declaration to understand.
But we're not going to implement functions in this lecture.
We're going to implement variables.
So now we're just going to go parse variable, ampersand, D type, name token and history.
So now just go up here, we're going to say void parse, variable struct data type V type struct token
name, token struct history, history.
Now at this point in time, we have already parsed most of the variables.
So in it a we've currently parsed everything except the semicolon.
Okay?
However, if someone did in it B and they did an array bracket here, then obviously where the array
brackets.
So we need to check for array brackets here.
So we're just going to get a common for now check for array brackets and we're even going to do a compiler
warning to remind us.
Don't forget to check for array brackets.
Okay.
Because don't forget, we've we've currently parsed in it B for example, but there's still array brackets
here we need to check for.
We're not going to do that in this lecture, but we will need to do this soon.
So what we're now going to do, we're going to check if there's a value.
So imagine something like init c equals 50.
Well, obviously we've parsed in it c, so now there should be an equals, right?
So we're going to check for n equals.
So we're going to say f token.
Next is operator and we're just going to check for an equals operator here, then ignore the equals
operator and we're going to do that by doing token next.
So at this point when we've done token X, now we just see the 50 for this example input on line 510,
we just see the 50 now, right?
So now we're going to say parse expression, double root.
And I don't think we've implemented that function yet and we're just going to pass in the history and
now just appear, we're going to say struck node value node equals null.
And then by here we're going to say value node equals no pop.
Okay?
So now we're going to make pause expression by root.
So just go pause expression of all root struct history, history.
And we're just going to go pause expression level and we're going to go history and then we're just
going to go struck.
No result node equals no pop.
Now later in the course, we're going to have some sort of like literal evaluation at compile time.
So if someone was to do 50 plus 70 plus 30, they would essentially all be joined together.
They'll be summed and joined at compile time.
So we'd only see one number node with the result of those, but we're not going to worry about that
now because that's quite a large part of the of the parsing process.
So what we're going to do here is we're going to do no push result node.
So we're just going to push that result node to the stack solvency from the face of it, parse expression,
root and parse expression of all their just aliases of each other because they're not redoing anything.
But as I said later in the course, we're going to change this route function to do evaluation.
So that's why it's important that there's some separation to prepare for when we do that later in the
course.
Okay.
So we're now going to create a new function.
It's going to be called make variable node and register.
And it's going to take a history, it's going to take a data type, it's going to take a name token
and it's going to take a value node.
So that's everything you would expect in a variable declaration, right?
I was just going to make a new function called make variable node.
It's going to be data type name token and the value node.
Okay.
So we're just going to call make variable node
and we're going to say struck node, var node equals node pop.
And here we need to calculate the scope of set.
We need to push the variable node to the scope and we will come back to all of these.
And we're just going to put a warning here to remind us to come back, remember to calculate scope offsets
and push to the scope.
So what a scope offsets.
Well, like, if we have a scope, obviously they have an offset when they're loaded into memory, right.
Such as base pointer, minus for base pointer minus eight.
You will need to know assembly language to understand what I mean by that.
So look more into that.
Take a look at stack frames, just do some Googling around C stack frames because you are going to need
to understand that for this course.
I am going to show you the stack frames later on when they become applicable, but if you're curious
to know more about that now, that's what you would need to research to understand what I mean when
I say scope offset.
Okay.
But we will be discussing that later on when it's appropriate.
Okay.
So here we're just going to push the variable node to the stack.
Okay.
So again, these look like aliases of each other, but like I said, we will be implementing more functionality
later on for those.
So now we're going to work on this make variable node.
So we're going to go const char name string equals null and we're going to say if there was a name token,
then name string equals name token s file and we're just going to go no create ampersand struct node.
Type equals no type variable and I just need to go to compile that so we can actually make some substructures.
So just go to compile RH and we're going to find struct node.
You can control left click and Visual Studio code on the node data type and it'll take you straight
there.
And just in our union we're going to say struck va
va and just in here we're going to say strike data type type conjecture.
Name sets like the variable name.
Okay, struck.
No, Val.
So that's like a pointer to the value node.
And there will be some other variables in here, such as the offsets and padding information.
But we won't write that in this lecture because we're not using that functionality yet.
So just those three will do fine OC in in the node structure in this union.
So I'm back to parsed C now we should be able to say dot var dot name equals name token as val tovar
sub val equals value node OC and instead of name token asphalt, just change that to name string because
as we calculate that here, right, and there's a reason we check if the name token is null or not,
it's because the caller of make variable node, they might want to like pass in the node name token
and set the name later on.
But obviously if we do name token asphalt here, that will cause a segmentation fault.
So by checking that here, it ensures that people are allowed to pass null for the name token OC.
All right, nice.
All of these functions are subject to change later on down in the course we will even be changing make
variable node to work with structures a bit more efficiently.
But obviously I'm showing you the baby steps first and I'll take you into the deeper stuff as we go
through the course.
Okay.
So that that looks okay.
So back to parse variable, we're now going to say make variable node and register.
We're going to pass in the history, the D type, the name token and the value node just like that.
Now let's see who's calling POS variable.
We can see our functional struct calling that.
So yeah, everything should line up.
Okay now because we can see where pushing the node here.
So that later later on down the line.
It can be popped off here when we peak for the next node.
Okay.
So yeah, that's all.
All good.
So we're going to try and compile this, right?
You make clean to make and we can see that on compiler 292 is complaining about our data type.
So we just got a compiler 292.
So now that you are on line 292, let's just hold control and left click data type which will take us
to the data type.
Just copy and paste this and we're going to go back all the way to the top above struck node and we're
just going to paste it there and now just allow it to be seen before the node.
But now this access is the node.
So we also need to forward to Claire.
So we're going to say struct node just like that which will forward declare node, which will allow
us to access node pointers here.
So that's how that should look.
And now if we do a make clean and a make.
We can see that that now compiles absolutely fine.
So yeah, essentially just put the stroke data type above the stroke node.
But because we reference to struct no pointer, we also need to forward the clear stroke node above
struct data type, simple as that.
So I just wants to go back to parse.
See, we're going to keep scrolling until we find parse variable functional struct union and just in
our paths, variable make variable node and register make variable node.
We have forgotten to put our data type, so we're just going to go dot var dot type equals D type.
Just like that.
And I also want us to go to parse next function so you can just search for that.
We're going to have to begin searching for things because it's getting quite a large file and you'll
see parse queue for global just control left click to get to that and notice we pop the node off here.
I just want us to push the node back and again we're popping it off because we plan to do some stuff
with this node on line 632 later on in the course, but just push it back to the stack for now and we're
now just going to go to the terminal, we're going to go make, clean, make, and now we're just going
to head over to test C and we're going to we're going to let you put a global variable here and it X
equals 50.
And now let's just do main.
And we can see that it loops forever.
That's because I haven't implemented semicolons yet.
We haven't actually done that yet.
So just go to the semicolon, pest control C and run that again and we see everything compile file.
So everything's fine.
Cool.
So there's one more mistake we need to correct.
Go to parse the dot c back in parse variable parse variable, make variable node and register make variable
node.
You can see here we've done var type equals D type now D types of pointer, but the type here is not
a pointer, you see.
So what we need to do is we need to do asterisk type which will copy the memory from the pointer into
the variable because it's not a pointer.
Okay.
So now just do a make again and we're going to run main.
We can see everything still works fine.
Great.
And now we're going to actually test our functionality.
So impose keyword.
Buy here line 633 pass queue for global.
We're just going to do a breakpoint J to B main break parse that.
I'd see 633 and we're going to run now 633 is the line number, but that might be different for you,
right?
We're basically breaking by here.
Okay.
So whatever that line number is for you and we're just going to go print asterisk note after we after
we type run to run that program and look what we have.
We have our variable broken down into a variable node.
So we can now let you just do node var and what do we see?
We see the flags, the sign flag which is set.
We have our data type, type of three, which should be correct.
Yes, it is integer because we start from zero.
We have our secondary type, which is no.
We have our type string, which is in it.
Our variable size is four bytes a point.
The depth is zero because it's not a pointer structure and union nodes pointers and no, because this
is not a structure or union node union variable I should say.
And here our name is X and there's our values.
So if we have a look at our value and the the name we see 50.
So we've literally broken down our entire variable declaration into its own node.
And look how easy it is to parse that we know its size without even checking if it's an integer, because
we've calculated all of this and put it in this lovely little structure called struct note.
So should we store everything here?
And this data type structure is incredibly powerful because it allows us to calculate all those complicated
parsing expressions only once, and then we store all that information here so anyone can understand
what what sort of parsing went on when parsing that variable.
We know exactly that it's an integer.
We know that it's full bytes.
We know it's not a pointer and we don't have to parse it twice.
Right.
We've parsed it into into a single node that tells us all of this valuable information.
Okay.
So we're not finished parsing variables yet.
We will have to work more on that in this course and implement structure variables and stuff like that.
But yeah, we're going to keep working on that and yeah, in a few lectures time will be at.
I also have a semicolon here without causing an infinite loop because we'll have code that will deal
with semicolons.
Okay.
So thanks very much for watching.