Hello and welcome, everybody.
And in this lecture we're going to create some structures for our Lexa.
So I just want you to just scroll down just under here.
We're going to go struct lex process that's going to contain a position, a vector of tokens
and a pointer to the compile process it's a part of and we're still not done.
We need to create some more variables in this Lex process structure, which will basically hold temporary
information during lexical analysis.
So we're going to go in it current expression count.
So essentially an expression count will basically be how many brackets are there?
At the moment.
So for example, one 251, we're about to pass this 50 token.
It will be an expression of two because we have two of those brackets.
Right.
Does that make sense?
So you don't need to worry about why we're going to use this until later on.
We're just getting the structures all nice and done now, so they're ready for it.
So we're going to go struct buffer.
Parentheses buffer.
Struct lacks process functions.
Functions.
We'll explain all of this as we go through the course.
And there should be function, not functions.
And finally, we're going to have a void pointer to private.
So this will allow people to point private data that only they understand in a particular lacks process.
So that's a simple explanation.
This will be private data that Alexa does not understand, but the person using the Alexa does understand
so they can later go go into this private data.
Right, and pull back, pull back out, whatever they stored in there.
So that's what this is about.
So we're now going to create the Lacks process functions.
So we're just going to go struct lex process functions just like that.
And we're going to go struck lex process.
We need to forward declare that and we're just going to go type def char lex process next char.
Struct lacks process process.
So it basically just making a bunch of function pointers here guys that'll do things like read the next
char, peek to the next char and push the next char.
And that allows kind of a form of abstraction, a little like how in Java or something you have inheritance,
you know, and see we have to rely on, you know, function pointers and stuff like that to deal with
things like inheritance, right?
So this is a similar sort of thing we're doing.
We're abstracting out the problem rather than making a Lexa that can only do this.
Instead, we we have function pointers.
So essentially we're going to have a function point of a next char picture chart and push char and it
basically allows people to implement these process functions and manipulate the way characters are read
or pushed to the Lexa.
Right?
So that'll be more explained on that later on.
But that's a brief overview of what we're doing here.
We're abstracting out the problem.
We should always be abstracting out code, and that's exactly what we're doing here.
So we're going to go type def char lacks process, peak char struct lacks process.
And then finally we're going to go type def void and this is going to be a lax process push char and
that's going to take a struct lacks process and a char to push.
Okay.
All right.
Let's now fill this structure.
So we're going to go let's process next char.
Next char lacks process peak char picture lacks process.
Push char, push char.
So now you can see how that's lining up.
So we have a lexical analysis process that has particular functions, those functions of a next char
picture and push char.
So someone who is making Alexa, well, using Alexa can implement these functions.
They can set the lacks process functions and manipulate how this works.
Okay.
Then everyone, we're now going to implement these these function pointers that we've created here,
right?
Some sort of default ones that that these get set as as a default.
So we're going to go to C process, start C and just by here we're going to say char, compile process
next char.
And that's going to accept a less process.
And you know what?
We should actually call it lax process as well.
So we're now going to go straight compile process.
Compiler equals less process compiler.
And then we're then going to go back to compiler stage and we're just going to scroll down to compile
process and we're going to put a pass in there because we kind of want to know the line and column that
the current lecture is on, right?
So we'll just put it in the compile process like that and head back to C process and we're going to
say compiler Pascal plus equals one.
So when we read a next char from the Lex process, we increment that by one and then we're going to
say char C equals compiler C file dot FP and we're just going to do a get C on that thing, which will
get one character from the file stream.
So now we're going to say if C is equal to the new line character, then compiler Pascaline plus equals
one compiler, Pascal equals zero.
So obviously, you know one when it goes to a new line, the column should be reset and the line should
be added by one.
And now we're just going to do return C.
So as you can see, that is basically fulfilling our Lex process next char and we haven't set the next
char process function yet which is writing them and we'll set them later.
So whenever there is a read of a char from a Lex process, it will come in here and it will call this
function.
It'll pull a character from the file stream from the file, and then it will perform this logic and
then return the character that it read.
Simple.
So we're now going to implement peak char.
So do char compile process peak char struck.
Lex process.
And just as before, we're going to go struct compile process compiler equals lex process compiler and
we're just going to go char C equals get C compiler C files at FP.
This time, we're not going to check if there's a new line because we're just peaking.
We don't want to actually just anything.
And now we're going to go and get C and we're going to put in C there and then we're going to go compiler.
See for AFP.
So what NGC will do is that it will push the character back to the file stream, as if we never even
bothered to pop it off with Gatsby.
Okay.
Does that make sense?
And we're just going to return, see?
So that's our picture.
Done.
We're now going to do push cha.
So we're going to go voi compile process, push cha stroke lax process, lax process cha see.
And we're just going to go struct compile process.
Compiler equals lax process compiler.
And push char is going to be very simple.
It's just an unjust C and that will basically push the character that they've provided here straight
to the file string.
So yeah, these functions will essentially go into the lax process functions and we'll set these function
pointers to point to these functions as a default.
As the default, you know, it can still be changed, but as the default low point here, which allows
our compiler to have a rough idea of what's going on during last call analysis and it allows us to,
you know, adjust things like the column and line that's currently being processed.
So this is pretty handy feature, right?
Because of the abstraction, we can create more efficient code.
Always break the problem down.
Let's use function pointers.
It makes sense.
So yeah, we've now implemented those functions.
Let's just put copy and paste them into the header file.
Okay.
Because we do want a a way to see that.
Okay.
So obviously we only want the prototypes.
So just get rid of the bodies, okay?
Because we want to be able to access those outside of C process.
Start to see.
Okay.
Nice.
So we've now put prototypes in the header files so we can access them out of C process dot c.
I just want us to go to compiler dot C now because we're going to create the lacks process functions
structure.
So just up here, we're going to say struct lacks process functions, compiler lacks functions equals.
And we're just going to open up an initialize here and we're going to say next char equals compile process,
next char dot peak char equals compile process picture dot push char equals compile process posture.
So that just defines those functions because we're going to set them in a moment.
Okay.
So all we're going to do is we're going to go struct lacks process, lacks process equals lacks process
create.
And I know we haven't created this function yet.
We're going to pass in the compiler process the address of the lacks process functions.
And we're just going to pass in Node by here.
So we're just going to create this little function here first now before we continue.
So this is going to be created in a file called Let's Process Dot C.
So just create that file and that file is going to include compiler dot hedge and we're just going to
create a few functions in here, right?
So we're going to start with the function we just called and compiler dot C, the one we have in created
yet lacks process create.
So we're going to say struct lacks process lacks process create struct compile process process.
And you know what, let's call that compiler just to keep it cleaner.
So it's more understandable.
And then here we're going to have our process functions.
And then finally, this will be a private data void, private pointer.
Okay.
So here there's the process.
There's the compiler lacks functions and we pass in null here for the private data.
So that's all fine.
So now we're just going to go struct lacks process.
Process equals calc one size of struct lacks process.
We're going to have to include some headers for this guy.
So include stalybridge.
And we're also going to need our vector as well.
So include our vector just like that.
So now we're just going to go process function equals functions and now we're just going to go process
token vec equals vec to create size of struct token.
And yeah, if we go to compiler hedge.
We can see the token vec there.
Right?
So we're essentially just initializing everything in this process, guys, so that we can pass it back
to the caller.
And that's what we're doing here.
Okay.
So everything in this structure will initialize in the process, create function.
So let's continue.
We're going to go process compiler equals compiler.
Process private equals private.
So we now just need to set the line and column number.
So we're going to say process.
Pass line equals one process.
Pascal equals one.
And now we're just going to return process.
And I just noticed a minor mistake.
If we just go to C process dot C, you'll see we set the pass column to zero.
Just change that to one for the next char.
That makes more sense.
Okay.
So let's create another function here for free in the next process.
So we're just going to go void lacks process, free stroke lacks process process and we're just going
to go vec to free process token vec and then we're going to go free process just like that.
Now before we continue any further, I just want to let you know throughout this compiler course, we're
not going to worry too much about freeing memory.
Compiler development is already difficult enough.
I'd rather not overwhelm you with having to keep track of which memory we freed and which memory we
haven't since.
The compiler cycle is basically from less analysis all the way to code generation and then the program
terminates.
We don't have to worry so much about memory management in this project.
If you wanted a compiler to run on like a web server or something, something that needs to stay running,
then you would have to definitely worry about memory management a lot more.
But for this project where you learn how to create a compiler that compiles a subset of C, we don't
really have to worry too much about memory, so we won't be cleaning up all of the memory in this project,
just the stuff that's essential.
So what we're going to do here, we're going to go for a pointer lacks process, private struct like
process, and this is just going to return the private data of the process and now we're going to go
struct factor lacks process tokens, struct lacks process and this is going to return the actual token
vector of this lexical analysis process.
Okay.
So that's all the functions we care about for the actual process.
Start C file, it's just copy and paste these into the header file as we did the other stuff just like
that.
We're just going to make the prototypes.
That's perfect.
So now all we're going to do is we're going to create a file called Lexus C, and this will be responsible
for our Alexa.
Okay.
So the lax process starts.
C file is responsible for lax process and LAX adopt C or be responsible for the actual lexical analysis.
So in this lecture, we're just going to create the core function for lexical analysis here, and we'll
fill it in in future lectures.
So here we're just going to say N at LAX and it's going to take a lax process.
And we're just going to return zero for now.
And it's also going to include compiler.
So we're going to copy and paste LAX into composer H just by there.
So we're just going to go back to compose C and we can see that now this lax process create function
we made earlier is now resolving correctly.
We need to actually check it succeeded in creating a lax process.
So we're just going to say if lax process makes you use the explanation mark that and it's negated.
So if if lax processes is false return null.
Simple as that.
So now we're also going to call our lax function.
So just go f lax.
LAX process does not equal lexical analysis all OC and we haven't created that yet.
We'll create that in a moment.
Then return null.
So if the lexicon s is failed, we'll return null.
So what I want you to do, I want you to go to compact.
Just scroll up.
And just above the token enumeration, we're going to create a new enumeration.
Lexical Analysis All OC and Lexical Analysis Input Error.
So this is just a way for us to bring back errors to the callers, you know?
I'd much rather have definitions and enumerations than passing back raw integers.
Right.
We don't want to say if it equals three.
Well, what does three mean?
So always use enumerations and definitions in any project.
So yeah, we go back to compact so we can see that's now resolve the problem.
So now let's just add let's process and lexa to our Makefile and that will conclude this lecture.
So we're just going to copy and paste C process to C and we're going to change that to Lexa.
Oh, Lexa dot C, just change the whole thing to Lexa.
I'm going to copy and paste that again and we're going to change that to Lex process
just like that, guys.
And now just by here, we're going to go build Lexa, build Lex process.
And now we're just going to try to build the project.
So open up the terminal and we're just going to go make clean, make.
Now we can see here there's a minor issue.
It's returning null, but it says that there's a problem with the cast.
So just go to compiler dot C.
Okay, guys, that was my mistake.
Was supposed to return.
Compiler failed with errors, not null.
My mistake with that.
So just replace all that with compiler failed with errors for compile file.
And if we try that again, you can see it compiles absolutely fine.
So yeah, that was a simple mistake.
Change it to this enumeration value and everything will work fine.
So that concludes this lecture.
Thank you for watching.