So we're now going to implement operators in Alexa.
So go to compiler dot hedge.
Scroll up to numeric case and we're going to make a case for operators now.
So I just want you to go hash tag define operator case excluding division.
And just to the backslash there.
Case plus, just do another backslash.
Case subtraction.
Operator.
Case multiplication.
Operator.
Case right.
Arrow.
You know, is that a greater than the.
Greater than.
Operator.
Case left.
Arrow below then.
Operator case.
We just do this for all the operators, right?
So we've got a modulus there.
And you'll notice that we're actually using characters here.
So we can't just do like two right hours here.
But if you remember in the Lexical Analysis Lecture, I explained how the operators can be joined together
at a later stage.
So that's absolutely fine.
One of these can be joined with another one to form the the shift, right.
So here we're going to say case explanation, Mark.
Case equals
case
bitwise, not case bitwise.
All case bitwise end.
And obviously those two ends can be joined together to make a logical end.
And so so can we use the these two to create a logical
case?
Left parentheses bracket.
Case left array bracket case comma.
So you can see we have quite a lot of operators, right?
Case full stop.
So that'll be used for things like structures, right?
So A, B, C equals 50.
Believe it or not, the DOT is an operator.
Not everyone knows that, but it is.
So the DOT is actually an operator.
Case question mark.
So the question mark will be used for for tenaris.
So yeah, that's actually it.
So just remove that colon there and remove that.
And now we can go back to our lexicon c.
And we can just say Operator Case excluding division, and you'll see why we exclude division later
on.
So we're going to say token equals token, make operator or string.
And we're just going to break.
We're just going to right click format document just like that.
So we now need to make this function token, make operator or string.
So just above here, we're going to say static struct token, token, make, operator or string.
And we're just going to return null for now and we'll fill that later.
Just above here, I want us to make a read operator function.
So we're just going to go const char read up.
Just like that.
So this read up function will basically read an operator from the input stream.
It is more complicated than it sounds, so just bear with me.
So with for first going to say bool single operator equals true.
Now we're going to say char arp equals next.
Next C to read the next character.
And now we're just going to create a buffer
and we're just going to write that operator to that buffer.
And now, before we continue this, we need to create some more functions.
So just above read up, we're going to say static ball op treated as one and it's going to accept a
operator character.
And we're just going to say return up equals equals left bracket or up equals equals left array bracket.
Or OP equals equals comma.
Yes, commas are actually operators in our lexa.
Okay.
So 50, 30, 20.
That is an expression or op equals equals full stop or OP equals equals multiplication or arp equals
equals.
Question mark.
So what we've done here O and the C should be named OP.
The variable here should be named OP.
So what this function will tell us is if we can only use operator once.
So in other words, if they can't be merged together to make to make a joint operator.
Okay.
I know you can do something like this indirection and C, but we handle that differently, which is
why it's here.
Okay.
So back to our read up function.
We're going to say if the operator cannot be treated as one.
In other words, if it can be just one operator or multiple like plus plus, for example, then we'll
peek ahead to see if there's anything we can join it with.
Okay.
Maybe someone did.
Plus.
Plus, maybe someone did.
Minus, minus.
We've only read one character, so we now need to read the other plus or the other minus.
Does that make sense?
So now we're going to say if it's single operator and we haven't created this yet, we'll make this
in a second.
And now let's create the single operator function.
So we're going to say static ball is single operator.
And what this function will do, it will basically return true if the the char you provided is an operator.
The word single comes from the fact that we are only going to check here for single operators, i.e.
one left bracket rather than a bit shift left.
So yeah, let's write this function.
We're going to say return up is equal to plus or up is equal to minus or OP is equal to divide or OP
is equal to multiply, multiply or OP is equal to equals or OP is equal to above above or OP is equal
to left arrow or OP is equal to or or OP is equal to ampersand or OP is equal to up arrow or OP is equal
to modulus or OP is equal to bitwise not or OP is equal to logical not or OP is equal to left bracket
or OP is equal to left or right bracket,
comma or OP.
Is equal to full stop or OP is equal to this character.
Oh, and we've actually written that character twice.
Okay, just remove that one.
Or OP is equal to.
Question mark.
Okay.
There you go.
So if we just right click from a document, so it tidies that up a little bit so we can see a single
operator as if the is if the character we provided is any of these OC.
So that way, if someone provides us something that isn't, that we know that it's a separate token,
it shouldn't be joint.
We're only looking for these single operators.
So back to our read up function here.
We're going to say buffer, write, buffer up and then we're going to pop off the character that we
peaked.
So here we peaked and we didn't change anything because we confirmed it was a single operator.
Then we pop it off with an XY after we've written it to the buffer.
And of course it's not a single operator if we got this far.
So just set that to false.
So simply put, what's going on then?
Let's imagine we have the operator in the file plus.
Plus.
So it comes in here, reads the first character.
So it gets plus it goes here and it says, is the operator treated as one and that returns false.
So we know that it's possible to stack these together.
So we then go going here.
We peak for the next character in the file and we get another plus.
Is that a single operator?
While we can see that it is.
So this F statement will run and we'll write the second plus to the buffer.
So now there's two pluses in the buffer.
And yeah, so that's how that works.
And that allows us to read multiple single operators and make them into one.
So we now need to get the buffer data.
So just go char pointer equals buffer pointer buffer.
And of course we also need to write the note terminate to this thing.
So just write it here.
Okay, perfect.
So we're now going to say if it's not a single operator, then we need to check that the operator they've
given us is valid because someone could have provided us plus minus or plus multiplication.
Right?
So we need to check that this is not the case and that the the operator pair that we've received is
valid.
So to do that, we need to create a new function.
So we're going to say pull up valid and this time is going to accept a const char pointer.
Okay, so we can read a string.
And essentially what we're going to be doing is we're going to be making a string.
Compare the checks for things like plus, plus, minus, minus and all that sort of stuff.
And then obviously if the OP doesn't match any of these valid strings, then we return false.
And that's, that's how this function is going to work.
But before we continue doing something like string, compare every single time, right?
It's going to be very tedious, right?
I mean, that's really ugly, right?
So let's create a macro which will allow us to do something like this.
Is the operator equal to plus plus?
Look how cleaner that is.
So we're going to make a macro that does that now.
So what we're going to do, we're going to go to compiler.
He's just going to scroll up.
Just by here, we're going to say hashtag define as equal str str two and we're just going to go string
and string two.
So this first checks that they're both not.
No.
We're going to have another brackets here with another and end.
And we're just going to say str compare, string compare.
And we're going to have to include string H here as well guys str compare string string two and we're
just going to say equals equals zero.
Just like that.
So now this macro will allow us to do things like s equals.
Hello.
And they'll return true if they match.
So there's a lot more cleaner than having to check if both of them are not.
No.
And then calling this function and check if it's equal to zero.
Right.
So a lot cleaner just do s equal like that.
So back to the Lexa when I'm going to fill in the OP valid.
Okay.
So what we're going to say is we're going to say return s equal op plus or s equal op minus or as equal
op
multiply or as equal op divide or as equal op explanation mark or as equal op up arrow or as equal op
plus equals or as equal op minus equals or as equal op times equals.
So as you can see, this basically just compares that the operator you've provided is valid.
So it checks all the possible combinations that doesn't include indirection such as pointer access.
Okay.
That's handled differently.
So we'll get to that when we get to it.
So here then we're going to say as equal op divide equals.
So you're just going to fill all of these in all the possible combinations.
So there's our above, our equal, and I sort of allow our compiler to parse all of these operators.
Whoops,
we got our plus plus,
minus, minus.
Just make sure you don't make any Sanctus errors like I did.
Okay.
So that looks like it's well, we'll we'll definitely come back and add more to this if we've missed
any, but that looks correct to me.
So it's right click format document.
So yeah, that will only return true if the operator you provided is valid.
So that's that's very useful.
So now we can continue our read up function.
So just by here we're going to say if the OP is not valid, then we'll have to push all of the operators
except the first one back to the input stream.
And the reason for that is because plus a multiply are both valid operators, but they're not valid
together.
So by pushing the multiplication back to the stream, we are left with only plus two paths as an operator
and a multiply will be parsed later on.
So that's the idea.
So when the operator is not valid, we have to push it back to the stream.
So how we're going to do that, we're going to call a function, read up, flush back, but keep first
and just get rid of the but just have it as keep first read flashback heap first and we're going to
provide the buffer.
I do like my descriptive functions, you know, lets people know exactly what's going on.
So we're just going to create this function now.
So just scroll up and we're going to say void read op flush back, keep first struck buffer buffer cons
char data equals buffer pointer buffer in it lan equals buffer len for h i equals len minus one i above
or equal one i minus minus f data i equals null.
Then we're just going to ignore it and continue.
Otherwise we're going to push that character back to the stream.
Okay, so let's imagine a scenario where the buffer contains plus and multiply, set it to the buffer
length.
We go through it backwards, we ignore any null terminate as we encounter and we push that character
back to the stack and it'll leave only one, only one character, which would be the first operator,
which in our case would be plus in this example.
So that's how that works, guys.
Okay.
So after we've done that, we need to actually add another null terminator after we've flushed everything.
This is because we've actually also discarded our null terminator.
So we're just going to say pointer one equals Z is zero.
And this is valid because we've only pushed the data back.
We haven't actually adjusted the buffer at this point in time at all.
We've just pushed all the characters back.
The buffer is the same, right?
So by attaching an old Terminator at this position, it'll mean that the rest of the buffer won't be
able to be read, because when we read it, we'll encounter the null Terminator as soon as we've read
the first operator character.
So although the other operators might still be there, we can't actually see them because as soon as
you read the string, the null terminator here at index, one will be seen and it will just think that
that's it.
Think that's the end of the string, right?
So now what if it is a normal operator?
Well, we need to account for that.
So we're going to say elseif OP is valid is not valid.
I mean
then compiler error lacks process compiler the operator is not valid and here we'll just put in the
pointer.
Finally we just return the pointer by here.
And as I said, we're not going to care much for memory management in this project because it's already
quite difficult to make a compiler and anyone with eight gigabytes of RAM will have absolutely no problem
with this course.
Even for gigabytes, you're not going to run out of memory really for a project like this.
We'll be lucky to use more than 20 meg maybe when compiling programs.
So our read up function is now done so we can continue with our tokamak operator or string.
So just in here we're going to say char arp equals PQ c.
If the operator is the left bracket, then we need to check if this is an included statement because
somebody could do something like this, like that, right?
And the lexa would make an operator here, identify here operator here at the H would be another identifier
in the right bracket.
It makes more sense to detect that here and just make ABC a string.
So instead we see symbol, hashtag, keyword include and string ABC H because that'd be a lot easier
to parse right later on.
So we're going to deal with that problem here where this gets seen as an operator.
Okay.
So struct.
Token, less token equals Lex, less token.
And now we're going to say if token is keyword, which we haven't actually created yet, we're going
to do that now.
Last token include.
Then return token, make string and the start delimiter will be the left bracket and the end delimiter
be the right bracket.
So now you can see why we abstracted out those strings when we made them right.
So then that'll give us a nice, tidy token output.
Well, no longer have something like symbol.
Keyword.
Operator identifier.
Operator.
Identifier.
Operator.
Look how stupid that is.
Right?
Instead, we'll just have symbol, include and string.
Look how much easier that is to work with.
Right.
So that's why we handle this here at such an early stage in the compiler development.
So just by here, we're now going to say struct token token equals token create.
And we're just going to make that.
So the token type will be token type of operator.
And what are operators?
Well, they have asphalt string values, right?
So we're going to say asphalt equals read up and yeah, that's it for that token creation.
So read off will obviously be called and it will find that operator for us.
So we're going to return token here.
But it's also possible that the operator is actually an expression.
So we're going to have to check for that.
Just get rid of that floating semicolon there.
We only want one.
So we're going to say if OP is equal to the left bracket, then that's something we must deal with.
Okay.
So we'll deal with that in a moment.
But first, let's create the token as keyword function, and we're going to create that function in
a new file called Token dot C, which will basically contain generic token information.
So here we're going to say include compiler H and we're just going to say bool token is keyword
struct token const char value.
So this is nice and simple.
We just go return token type is equal to a keyword and the value is equal to the value they provided.
So that's how we prove that something is a keyword, right?
So someone says token is keyword and they pass in the token, they might pass in int for integer.
And then if the token is a keyword and it has that value, it is the token you're asking for.
So let's just put that in compiler dot h the prototype for that space that in.
And yeah, that should now work.
So now just for our new expressions here, we're going to say static void lacks new expression.
So now we're just going to go let's process current expression, count plus plus f lacks process.
Current expression count is equal to one.
Then let's process parenthesis buffer equals buffer create.
So what we're doing here is we're creating the parenthesis buffer as soon as they enter an expression
and it's the start of an expression.
So it's the very first one.
So if we have nested expressions, obviously this will make it equal one, which is where it creates
the buffer.
And then everything in this buffer will be shown to you here on every bit of input in between these
brackets that gets tokenized.
Okay.
We'll point to this parentheses buffer.
Like we explained earlier in a previous lecture when we first made the parenthesis buffer in the structure.
While we're here, we're also going to check if we're in an expression.
So we're going to say, Bull Lex is in expression, we're just going to return lex process can expression
count above zero.
And that's how we know that we're in an expression, right?
Okay.
So don't worry about dealing with closing the expression because we'll deal with that in another lecture.
Let's just finish the tokenization of the operators.
So here we're now going to say Lex, new expression and there we go.
That will make that happen.
And obviously, in a in a later lecture, we'll check to see if the symbol is the right bracket and
then we'll know that we need to close that expression.
But we'll do that later on.
Okay, guys, so we're soon going to test this, but we just need to go to our Makefile and add the
token C file before we do that.
So just go build token.
Oh, all right.
And that's in the object's just after the lexa and I'll copy and paste the lexa here.
Try to keep things organized next to things they're related to.
It'll make your life so much easier later on.
So we're going to say token auto token C token dot C token.
Oh, just like that, guys.
Okay, now let's do a full build, make clean, make.
We see that compiles without issues.
So yeah, now it's time to actually test the software.
So let's perform a make on it, go to test, start, see and here we're just going to say 50 plus 20
and that should work.
Okay.
Because we've implemented numbers, operators and spaces, so everything should be fine now.
So just go to here and just do dot for such main and it says everything compiled.
Fine, right.
Everything compiled.
File.
My grandma's not so good in this sentence, but you get the idea.
Everything was compiled absolutely fine.
So, yeah, we can do that.
We can.
We can add a lot of different things to this with no issues at all.
Yeah.
So try that and run it.
We can see that that's two plus plus.
That should work fine.
Everything compile fine.
Good.
Yeah.
So congratulations.
You've implemented operators.