In this lecture, we are going to start setting up our project, so I'm going to open up Visual Studio
code.
This is the text editor I'll be using.
I recommend you use this text editor to also write your compiler because it has some very nice extensions
that you can install by here.
So we're going to go and open a folder and we're going to create a new folder here called Peach Compiler.
That is what we're going to call our compiler, Peach compiler and we're going to press the K here.
So it opens the folder.
And yeah, we're going to start creating the source files now for for the base of our project.
So we're going to create a file called Main C, and I'm just going to zoom in for you guys.
So you can see the code a little better.
So in our main C file, we're going to create a main function
and we're just going to return zero and we're going to create a Makefile here.
So it's going to be called make file with a capital M.
Okay, now this will be our Makefile for compiling our project.
So we're going to go object's equals and we won't put anything there for now.
We're going to go includes equals dash i dot forward slash which will make the include directory relative
to us.
Now we're going to make an all label and a clean label and the all label will depend on the objects.
And in here we're going to go GC main dot C dash show forward slash main ack.
We're going to apply a dash G for debugging symbols.
We're going to have our includes by here and that should be enough.
So we compile mean C with the following include instructions dash g for debugging symbols.
There's our output file and we also need to have our objects as well just like that.
So that should work.
Okay.
So we're just going to include a file here, include sd de std io h print f hello world.
So we're just going to check that that works.
All right.
So we're going to have to open a terminal and compile that.
Okay.
So we compile that by doing make.
And there we go.
That works perfect.
Now we do main.
We see.
Hello world.
We do make clean.
We can see.
Nothing can be done.
So let's just add that.
So make clean.
We'll remove the main file and it will remove all of the object files as well.
Be very careful with this dash ref.
Don't put a forward slash or anything or your whole system will be deleted.
Right?
Just be careful with that.
So yeah, we can do make make clean.
Nice.
So that works.
That that works very well.
Good.
So that's now set up correctly.
We're going to create a build directory here and I tend to make a dot keep file because I use Git repositories
and we obviously want the build directory to still be there.
You don't have to do that.
So yeah, we have our main file Makefile build directory and that is our project set up.
So going forward now we can use this project as a base for creating our compiler.
I also suggest installing some C extensions.
So I'm going to just search for C and you'll see C, C++ there.
I'm just going to install that because these extensions really do really do help.
Guys are right.
So down there in the tab at the bottom left and there you go is installed.
Nice.
Okay, guys, what we're now going to do is we're going to create some essential functions for our compiler
to actually work.
So what we're going to do is we're going to go to the Explorer and we just create a new file and we're
going to call it compiler dot C.
So this will contain some core compiler routines.
So in compiler C, we're just going to create a new function.
It's going to return an integer and it's called compile file and it's going to take a file name and
an output file name and also some flags and we'll make these flags later.
It's just have the actual variable set for now.
So essentially once someone wants to compile test dot C, they'll call the compile file function, they'll
pass test dot C in the file name here.
And the file name will be what you want to compile it to.
So test X, for example, if you were on windows and obviously these flags determine how it should compile
it, are we creating an object file or we create an executable, you know, things like that, right?
So just in here, we're going to return the zero.
And now what I want you to do is I want to create a new file called Compiler Dot RH and we're just going
to go hash tag if and Def Peach compiler RH to find Peach compiler RH and obviously it needs to be the
same case and it's going to hash tag endif there.
We're going to paste that prototype in there.
So compiler will contain all prototypes for functions that need to be accessed throughout our compiler.
All of them, it's going to be over 1000 lines long when we're done right by having one header file
that shares all the routines, we won't have to worry about having many header files and showing we
include them all.
Compiler development difficult enough, so we want to make it as simple as possible for us to build
this.
Other things will be going here, such as structures related to the compiler structures for tokens,
nodes, stuff like that, right?
So we now need to create a new file called C Process dot C and this stands for compiler process.
And essentially we're going to have a function here, a couple of functions for dealing with compiler
process operations such as creating the actual compile process itself, which will be a structure.
So just go to compiler H and we're going to go struct compile process.
And if we go back to C process, start C, we're going to create a new function that returns a compile
process pointer.
I'm just going to call it compile process create.
So this will create a new compile process, right?
And we're going to go const char file name, const char file name out and it flags
just like that.
And I can just zoom out for you guys.
So we're just going to include a header file studio and here we're going to actually open the file now.
So we're going to say file f open file name, right?
So if the file is null, we're just going to return null.
Right, simple.
So if we fail to open it, we're return null because we can't create a compile process.
So now we're going to make an out file name.
And that's just going to be the.
Same thing.
It's going to open it.
But the file name out and it's going to be a write.
Just like that.
And again, if we fail to create it, we'll return null.
However, the file name is optional.
Right?
So we want to check that it exists first before we do this.
So we'll go out file equals null by that.
And just like that, right mean right click format document.
So yeah.
So if they do not provide a file name out, then we will not open anything for writing because sometimes
you might want to compile something just to show on the terminal.
You might not want to actually pass it out to a file, right?
So that's what this is for.
So now we're going to actually create our compile process.
So we're going to go straight compile process, process equals calc and we need to include STD lib for
that guys.
And it's going to be one member size of struct compile process.
So I'll just declare the memory and set the memory to null for us complete zeros and it says incomplete
type not allowed.
That's because we need to include compiler H as well just like that.
So we're going to go process flags equals flags and we're going to have to create that actual variable.
So go back to compiler dot, we're going to go in at flags
and you know, just kind of put a bit of a comment here for you guys.
The flags in regards to how this file should be compiled, comments are good.
So now we want to create a sub structure for the input file.
So we're going to go struct compile process input file and we're just going to call that a C file,
compile a file and that's going to take a file pointer and an absolute path.
And we're also going to include Studio Page.
So you can see here my ID complains about zero.
Just ignore this for now.
It's probably because we haven't actually put the compiler dot C in the makefile yet.
So so it can't resolve that header file.
Okay.
So now we're going to create a new file called file o file.
And this is the output file where we're, where we're taking the input file.
What is the output file we are writing to.
Okay.
So that should do for now.
Let's go back to C process, start C and now we're going to go process C file PHP equals file and we're
going to go process O file equals out file.
Okay.
There's a lot more to initialize in regards to our compile process, but we'll add to it as we go along.
Right now, I'm just trying to get us the bare minimum required before we can actually start writing
the project properly.
So here we're just going to return the process and now we're going to copy and paste this prototype
into compiler dot hedge just like that.
Okay.
So now we just have back to compiler dot C and we're going to continue our compile file.
So we're going to go struct compile process process equals compile process, create file name out file
name and flags.
And I need you guys to include compiler dot H as well, guys.
All right.
And in the event there's an error, we're just going to return.
Compiler failed with errors and we're going to have to go to compiler C to create that enumeration.
So if we just go up here, we're going to go enum
compiler file, compile the compiler file compiler failed with errors just like that.
And now you can see that we have that resolved correctly and here we're just going to go compiler compiled.
Okay.
Rather than return zero.
So by here we're just going to say perform lexical analysis, perform parsing, perform code generation.
And we can add to this as we get as we come along.
But this is essentially what it's going to do.
When you call compile file, it will pass your input file through lexical analysis, through our Alexa
and it will pass it through parsing to produce an abstract syntax, tree, code generation and so on,
and validation as well, of course.
So this is the root this is the root function for compiling any file and it breaks it down by calling
all the sub processes.
Okay, so that's what will happen.
So we're now going to add composites, see and see process, start, see to our Makefile.
So go to the Makefile.
So we're just going to go by here and we're going to type dot forward slash build compiler dot zero
colon dot forward slash compiler dot C and then here we're just going to go DCC compiler dot C, dash
show dot fourth slash build compiler dot dash G, dash C and I do expect you guys to know make for this
course.
I know that not all of you are going to know make if you have a IDE that creates the make files for
you, you're more than welcome to follow the course on that.
But I always make the make files manually.
So if you are confused here having problems with this makefile, you should look that up.
So you must use tab in make no spaces or that will cause a problem.
So we're still not actually done here.
We need to actually also have include the includes which will include this here.
So let's copy and paste that and we're going to change this to C process
just like that.
And now for our objects, it's going to do it's going to be dot forward slash build compiler .0.4 slash
build C process dot zero.
So now we're just going to go to our terminal and we're going to go make and we can see it builds and
links those successfully.
So that's perfect.
That works absolutely fine.
I was just going to make clean to delete them.
Okay, guys, we're now going to create some helpers and the helpers will be things like vectors and
stuff like that, buffers that can change size when you write to them.
So create a new folder called Helpers.
And when I'm actually going to write this code because it's very generic, okay, we're going to go
to my GitHub and we're going to download those files.
So just open up file Firefox.
And I'd also like to say guys that I'll also put a direct link in the lecture description here.
Okay.
So we're going to go to GitHub dot com and we're going to search for drag and compiler because drag
and compiler was the project I made originally my first C compiler where a lot of these files are present.
So okay, once this is loaded, you want to look for nibble bits for slash drag and compiler.
That's the official drag and compiler that that I've written before.
And we're just going to go to the helpers and here you can see so many helpful things.
You see vector dot C vector page, these are vectors and stuff like that that will really make the whole
compiler process simpler.
So we're actually going to just create these files.
So let's copy and paste vector dot C.
And we're going to create that file in the helpers.
I'm just going to paste it in.
You're welcome to have a look and see what it's all about.
But there's no point in me teaching you how to write this because it's unrelated to compiler development.
And we're going to go.
Back to the helpers factor that h.
And we're going to copy and paste that.
We won't be copy and pasting anything else.
Just these helper things.
Everything related to actual compiler development will be shown to you from scratch.
And we don't need hash map.
We don't use that in our compiler.
And you also don't need file dot C or for that guy, so you can ignore that to just take the buffer.
So we're going to go backwards, see.
We're going to copy and paste that buffer dot C or some.
Prophet H.
Copy and paste that.
Where we go.
Nice.
So yeah, essentially Guy's Dragon compiler was the original C compiler I wrote in preparation for this
course, so you can find a lot of help for resources on the Dragon compiler repository.
Although you'll notice that I also have a.
Peach compiler repository, which is the repository directly related to this course.
So if you want actual direct source code on a per lecture basis, check the peach compiler if you want
to see the project I created prior to this course.
Dragon compiler.
Awesome.
So now we've got those vectors, buffers and stuff like that.
Let's add them to the Makefile.
So we're going to go to the Makefile, we're going to go to our forward slash build buffer top forward
slash helpers, buffer dot C, we're going to copy and paste that.
Help us buffer c build for such helpers.
Buffalo.
And we're going to create in the bill directory here another directory called helpers.
Okay.
I'm going to create a dot.
Keep file there as well.
It's just so because I'm using Git and we're going to copy and paste that and do the same for Vector.
And there we go.
So let me just go over these for you.
We'll go over the buffer.
Essentially, buffers are one you want when you have a string that you don't actually know what the
size is.
It doesn't have to be a string.
It can be any sort of data, but it will typically be used for strings in our compiler project.
So Buffer Create creates a new buffer.
We can use buffer read buffer peak to look into the buffer and we can call this to extend the buffer
or we can write straight to it with printf or rape.
If it exceeds the buffer boundary, it will increase the buffer for us automatically.
So it's very handy feature, right?
So we can write to this as much as we want.
It won't breach any buffer because the buffer will resize when you when you use these functions, if
it's needed, the vector will be basically store things.
So you'll say you'll say something like, I want a vector of integers and then you'll be able to push
or add integers to this vector.
So that's what that's about.
So we're just going to see this compiles.
We're going to go make clean, make.
And we can see there's compile issue.
So back to the Makefile and yeah, I can actually see the problem.
We haven't added the objects here, so we're going to go build helpers, buffer data, build helpers,
vector dot and you'll notice we also have adjusted it here as well.
So it should be like that.
Yeah.
Helpers buffer dodo helpers vector doll.
So it should look like that.
We try that again.
Make can see that.
Now compile is absolutely fine
with no issues perfect.
So I'm now going to show you the vector a little bit because we're going to be using it a lot and you
need to understand how it works really.
Right.
So go to mean dot C and I'm going to show you that here.
So we're just going to go include helpers factor dot C, factor dot, I mean, and we're going to say
struct vector vector equals vector create.
So what does it ask for?
It asks for a size.
So if we're creating a vector of integers would do size of in it.
So that makes sense.
So now what we're going to do is we're going to go integer x equals 50 and we're going to go vector
push and we're going to do Vec and then we're going to go ampersand x, which is the address of x.
Okay?
So it's going to push that integer to this vector.
Okay.
So now if we push, if we change the value of X to 20 and we push again,
you will see that we have 50 and 20 on the vector.
Okay.
And now let's set a peak pointer.
So what's the peak pointer?
Well, essentially, we can peak at any point on the vector and read from there.
So we're going to go vector set, peak pointer effect zero and then we're going to go in it.
Peter equals vector peak vec so that will return a pointer to the value we push to the stack.
Because if we look a vector push here, it essentially copies the memory from the address here into
the vector position.
Okay.
And if we look at vector peak, we can see that cause vector at which basically just gives us a pointer
to the vector position.
So that's why that is why we are doing vector peak and it returns a pointer.
Okay.
So now you can see why I wanted to show you this because it is a bit of there's a bit of logic going
on here you need to understand.
So we're going to go well pointer pointer equals vector peak vec.
Okay.
So now what we're going to do is we're going to say print F sent I and we're going to print that pointer
value.
So now let's just, let's just test that we're going to make and we're going to go main and we can see
5020 OC So you can see it's gone through the vector with the elements we push in and now outputs them.
OC If you want to pop from the vector, then you just do vector pop OC and you pass in the vector.
So then we should only see 50 on the stack there, right?
So let's try make again mean and now we only see 50 because we popped off the 20 OC.
So that's a brief introduction to the vector.
There's other functions that are part of this vector that I created.
However, I hope you can see why we won't be writing all that functionality ourself because it's it's
so a five, it's 500 lines long and it's unrelated to compiler development.
So, so yeah.
So our vector will be used for storing things like tokens in memory and nodes in memory and stuff like
that.
Right.
So that's an introduction to the vector there.
Okay.
So before we wrap this lecture up, let's just call our function we created.
So our compile file function.
So we're just going to say compile file, we're going to have to include compile our here guys as well.
Right?
And then it's going to ask for the file name.
We're going to do test C and then our alt file name will be test top for such test.
And we're going to have zero flags and we're going to have a response here.
We're going to say if the rest is all okay.
And I say print f everything compiled fine.
I'll say F rare equals failed, print f, compile failed.
Here, we could be a bit cleaner with this error system, but this.
His all just template stuff for now.
Right.
So we're going to say unknown response for compile file.
Nice.
Okay.
You know, maybe a switch and some function to handle that error would be more appropriate.
Right.
But this is just template code for now.
So we're going to make clean make.
Okay.
We're going to go main and we can see compile failed because there's no test file.
So we're now going to do we're going to create a test C file by here and we're just going to make a
stupid function that returns zero.
And now if we try that again, we can see everything compile fine because it managed to open the test
C file.
So the test dot C file will be where we're testing all of our C code that we want to compile.
So test C will be compiled into test executable.
That's that's how this is going to work, guys.
And yeah, so we've got the template sorted.
So in the next few lectures we'll create lexical analysis and we'll go from there to parsing and then
eventually cogeneration.
So this wasn't too much for you.
There is source code related to this lecture in the lecture description.
So yeah, you can see that we're breaking down the problem before we've even started writing any logic.
And that's very important when you're developing compilers because they, they do get complicated.
So we can see going forward we're going to perform lexical analysis, parsing and co-generation, and
there will also be validation here as well.
So thanks so much for watching.