Math Expressions in C | Part 2

Brief Summary

This video is about continuing a C project named "proof," a simple language for proving math statements. The creator implemented the lexer and parser, enabling the parsing of defines, variables, functions, and operators. The language consists of statements that can be definitions, expressions, or equalities, including defining sets, functions, and operators with rules. The goal is to define statements and prove simple statements step by step. The video covers implementing the parse_equality function, handling operator precedence, and parsing different types of equalities such as sets and expressions.

  • Implemented lexer and parser for the "proof" language.
  • Parsing defines, variables, functions, and operators.
  • Implementing parse_equality function and handling operator precedence.

Intro and Project Overview

The creator is continuing with the C project, now named "proof," which is designed as a simple language for proving mathematical statements. The project has implemented the lexer and most of the parser, allowing it to parse definitions, variables, functions, and operators. The language is statement-based, where each statement can be a definition or an equality, and can include both. The language aims to define sets, functions, and operators, along with rules for these functions, to prove mathematical statements step by step.

Language Structure and Examples

The language consists of statements that can define sets, such as a set of numbers, or built-in infinite sets. It also includes defining functions and operators, and adding rules for these functions, which are treated as true axioms. For example, f(0) = 1 is considered an axiom. The goal is to define such statements and then prove simpler statements by randomly trying formulas until a solution is found.

Code Overview: Lexer, Parser, and Program

The C code includes the lexer, parser, and program components. The parse_program function uses parse_statement, which further uses parse_defines and parse_equality. The parse_equality function is responsible for parsing expressions involving an equal sign or an arrow. Currently, parse_equality contains a "to-do" item for implementation.

Implementing Parse Equality

The creator plans to implement parse_equality without operator precedence, parsing expressions from left to right. Parentheses will be used to define the order of operations. The function needs to handle different types of equalities, such as set definitions and expressions involving variables. The implementation will involve parsing expressions on both sides of the equal sign.

Parsing Expressions: Initial Token Analysis

The parse_expression function will determine the type of expression based on the initial token. It checks if the token is a number, set, or name. Numbers typically lead to operators, while names can indicate function calls or operators. Sets should be complete without additional elements. The function returns an error if the token doesn't match these expected types.

Handling Numbers in Expressions

If the token is a number, the next token must be an operator. The function checks the next token and sets the expression kind accordingly. If the next token is an equal sign, it's a number expression. If it's an operator, it's an operator expression. An error is thrown if neither is found. The function uses clitoral to create the number expression and reads the next token.

Creating Operator Expressions

For operator expressions, memory is allocated for the left and right hand sides. The left hand side is filled with the number, and the right hand side is parsed using parse_expression again. The function reads tokens to skip the number and the operator symbol before parsing the right hand side.

Testing the Implementation

The creator tests the implementation with an example: 1 + 1 = 2. The initial test reveals an error where the function expects an equal sign but finds a number. This is corrected by ensuring the function reads the current token without consuming it.

Handling Different Token Types

The function is modified to handle different token types, such as exists and for_all, which indicate the end of an expression. The first expression should end on an equal sign, while the second expression can end on various tokens. The function now correctly parses the example expression.

Dumping Expressions for Debugging

To better understand the parsed expressions, the creator adds a dump function to print the structure of the expressions. This involves creating functions to dump equalities, sets, numbers, functions, and operators. The dump function uses a switch statement to handle different expression kinds and prints the relevant information.

Parsing Names and Functions

The function is extended to handle names, which can be variables or function calls. If the next token is a left parenthesis, it's a function call; otherwise, it's a variable. The function initializes the expression kind and handles the arguments for function calls.

Handling Function Arguments

The creator considers allowing functions with only one argument and adds a "to-do" item to parse arguments. The function handles operators by allocating memory for the left and right hand sides and setting the token kind to function.

Parsing Parentheses

The function is updated to handle parentheses. If a left parenthesis is encountered, the function parses the expression inside the parentheses. The function reads the next token and recursively calls parse_expression to parse the inner expression.

Implementing Eval and Proof Statements

The creator adds support for eval and proof statements. The eval statement parses an expression, while the proof statement parses another statement. These are added to the parse_statement function to handle them correctly.

Final Adjustments and Testing

The code is adjusted to ensure that eval and proof statements are correctly parsed. The parse_expression function is modified to handle these statements. The implementation is tested to ensure it correctly evaluates expressions and proves statements.

Conclusion and Next Steps

The creator concludes that the parser is in a good state and expresses satisfaction with the progress. The next steps involve interpreting the abstract syntax tree (AST) and implementing type checking. The goal is to get the evaluation working and add a list of evaluations and proofs to the program. The creator also mentions potential command-line arguments using arc_parse.

Summarize any YouTube video in seconds

Get summaries like this one for any video, in your language, with the free Summ app.

Download on the App Store
Get it on Google Play

Transcript

YouTube Transcript Generator

0:00 All right. So, let's continue with our C project. Uh, from last time, I've decided to name the project as proof, mainly because it's like a combination between C and the word proof. And, uh, yeah, I know it's nerdy. Uh, we are all nerds, but uh, it's like a really simple language for proving math statements. And last time we implemented the lexer and most of the a like being able to parse an a and right now we are able to uh parse the defines like defining variables defining functions and the operators and uh if we like let's take a short look at uh how the language looks

0:46 like. we have a bunch of statements, right? That's the main idea. And uh each statement needs to have uh one of the followings, a definition or an um I call this one I think like an expression or like equality because it needs an equal sign, right? And it can have both. Obviously if you define something like a rule um like a theorem or something like that but u some of the statements are going to be defining sets. For instance, this is a set of a few numbers. Uh like it makes sense to have things like the set

1:32 called n which is going to be built in and it's going to be like an infinite set. I'm not sure how we could define infinite sets just like this. I don't think it's really I think it's pretty difficult to do that. So maybe we'll have some built-in sets that are infinite. Then we have things like defining functions, defining operators and um then adding rules for these functions. For instance, this uh this is like a statement that we take as true. It's more like an axiom if you think about it. It's like f of 0 is equal to one and that's you know it's a statement that we consider true. So then when we try to

2:21 prove a certain statement for instance here we use f of zero we can prove that uh a plus f of 0 is equal to a + one. So you know something like that. And um yeah, the idea would be to define a bunch of these kind of statements and then have really simple um like statements that we can actually prove and see step by step how they are being solved. Probably just randomly trying all the formulas until we get to the end. So you know that's that's usually how I solve math problems like uh try formulas until it works. So um yeah let's go to the C code and um let's

3:07 try to get back into it. So uh here we have defined the lexer the parser and the program which is the a right and here we initialize the uh parser and then we try to parse the program right and then we print the results. So if we go into parse program you'll see that we have this function called parse statement. If we go into parse statement we have it should be something like parse defines which parses this kind of defines that we have here. And then we should have a parse

3:55 equality check. And then we should go into parse equality. And parse equality is exactly this uh this part right here which should be like an equal or this one after the arrow. Right? So that's the idea. Okay. So instead of parse equality we have just a to-do and we said implement me. Okay. Nice. So how are we going to implement these kind of uh things? Well, I was thinking that we won't have operator precedence because it's kind of difficult to define the precedence of the operators. It's like how do you even define that?

4:41 So I'm just going to um have them from left to right. Like we're going to parse them from left to right. And in case you use parenthesis, that's when you apply precedence because at least we know that parentheses are um you know uh used to define the order of the operations. But if you have something like a * or a + a * b, I'm not going to do a a * b first because we don't know what these operators are. like we need some kind of definitions for them maybe. Not sure. We'll see how how we can get there uh in the end. But for now, we'll just need to

5:27 make sure that we use parenthesis, right? If you use parenthesis, that's uh when it's going to work. Okay. So, what should we do here? Well, I guess h there are some different types of uh equalities, right? It's it's like if you have a set, you expect a set definition. All right? So that's one thing we can have. If you have um I guess anything else if there is

6:15 anything else like a letter like a name or a number or some kind of value so anything that's like a variable then you know you have some kind of expression. Okay. Interesting. And uh if we go into equality we have yeah I mean we have expression t right and expression can be a set. So that's that's decent. Um okay let's let's see. So I would say here

7:07 probably that we are going to have some kind of obviously let's let's copy paste some some other function first because why not? Uh let me just zoom out a bit to fit the entire thing. So we'll have the result the token and I mean token doesn't really matter that much. I was thinking to have a function like parser parse expression. We parse in the parser and then here we need to parse quality arrow left hand side. I think left hand side yes that works.

7:52 So this thing obviously it can fail. So if it's not zero then we are going to return defer one and we can add a to-do recover from error right I don't really care about recovering from errors though so yeah it is what it is then we need to read a token and if the token is not token equal Then we need to show an error. So expected expected equal but found whatever right

8:39 that's the idea. Okay that's that's that. And then we need to parse the other expression. Okay. and we just parse it into right hand side. So now we need to figure out how to define parse expression. So let's go over here. Let's do expression expression. Oh, it's called parse expression. Right. So at this point let's just copy paste some stuff

9:25 again. Return result. Okay. So here as I said um earlier we want to look into you know what's the first thingy if we have a set a name or a number. So things that are interesting for us are numbers set names. Anything else should be an error. Okay. So um let's do token is equal to parser. We take the first token. If token kind is equal to

10:12 token let's do I guess let's do number first. Oops. If we have a number, but I mean if we have a number or a letter, it's just that um it's a numerical expression kind of like you you know what I mean? Um so because we can have a set a number a name an operator

11:06 operator. Yeah. Or a name which could be a function. H. Well, that's interesting. I mean, if it's a number, we clearly expect an operator probably, right? Like, it doesn't make sense to have anything else. So, that could be a thing. But if we have a name, um, we are kind of not sure if we have a function call or an operator. Like, we can have both. So for a number it's pretty obvious that uh the next thing is going to be an operator. All right. Next uh thing should be or I

11:53 guess has to be an operator. I mean should be it's a good word as well but whatever. Uh else if token kind is token [Music] name. Next thing can be open in parentheses or an operator. Right? We can have both of them or I guess any of them. else if token kind is equal to token set uh should be done right we shouldn't have anything

12:40 else if it's a set and uh anything else it's an error anything else we just got an error so let's copy paste this expected expected a number a name or a set but found something else expected a number name or a symbol maybe it's like a symbol represents uh value from a set kind of so Let's show that as an

13:26 error. And okay, so we have a number. Perfect. So I said this should be the first one. So, we have actually I mean I could just V split this to make it a bit but I think the text is going to be too small for you. This is enough. Hopefully. Okay. So, let's let's keep this stuff here somewhere because it's useful.

14:13 And if we go back to here, I don't know how useful it is though. I mean, we just know that we have an operator here, right? Just like that. We know what's the left hand side of this operator, but we don't really know what's the right hand side. So, what should we do at this point? I

14:58 guess I guess we should fill in the left hand side. I guess we should just fill in the left hand side and then parse the next token. If the next token is not an operator, we fail. Uh or maybe we want to have a different function static int parse operator right and here we're going to

15:45 have operator e or wait how is it called operator expression operator. Okay, I'm just going to close that because it's annoying. So, we are going to have something like that and then defer return. Okay. So, let's take the [Music] token. I mean, as I said, we kind of

16:30 already know what's the first thing, so it's kind of annoying. I mean does it though? Next thing has to be an operator or equal. Next thing can be or equal, right? And this means just that the next thing is equal. It doesn't have to be an operator. Exactly. We have to look at the next thing.

17:15 So what should we do in this case? Um I guess we have to look at the next token. So, yes. Well, I'm not sure yet if I if I'm going to need this function, though. So, let let's just keep everything inside of this single if. Let's not worry about you know code that much. So let's just

18:01 take a look at the next token. So if parser next token I'm is equal to token equal. We have a number expression, right? So we just have a number expression. Else if parser next token kind is token operator, we have we have an operator expression. And on the last else case,

18:49 it means we are kind of cooked. We expected expected um an operator or equal but found something else right so that's that okay so if we have token equal let's see what we need to do we have to say expression kind is expression kind of number. Simple enough, right? Makes sense. And then we need to set the expression

19:35 number uh as well. So the number element of the union, right? So expression number and here I guess we could use clitoral expression number D and the value is going to be token dot value right so that's that and um I think we need to do a read to skip the token so I think we need to do a read so It's

20:23 parser read parser and that should skip the thingy. Okay, nice. Otherwise, if we have an operator, right, we have an operator. What do we need to do? Well, we know we have an operator that on the left hand side has a number. [Music] Um, yeah, I guess it makes sense.

21:09 So let's try to create this uh expression kind is equal to expression kind operator right then expression we need to fill in the operator field which is expression operator now the problem with expression operator let's copy paste is that it needs references so I think we have to allocate these two fields the left hand side and right hand side. So expression operator I guess the easiest thing first is to use clitoral and have expression operator t

21:57 and the value of the operator is going to be parser next token value and then null and null just to initialize just to initialize it, right? I think that makes sense. Um but we also know uh we also know that the left hand side

22:43 expression needs to be a number. Mhm. Very interesting. So how can we do that? Can I just say expression operator dot left hand side is equal to ds maloc and then use size of

23:28 um expression t right when could as well. I could as well. I mean, I don't know if it's I guess it's simple enough. So, Here obviously I we could check if it's uh if it's null or not. So like

24:19 expression left hand side is equal to null. Then we can just spanic DS error out of memory. All right. Something like that. Did I use this one? I guess I used it. Okay. So we just panic there and otherwise we can just expression operator left hand side find is expression kind number and then expression operator left hand side number is

25:07 clal expression number T token value right something like that. So we filled in the left hand side and now we have to fill in the right hand side. Um, so we just have to parse expression again I guess. So parser parse expression maybe parser parse expression. And we have to not

25:53 forget we need to read twice because once we skip the number and the second time we skip the symbol for the operator, right? And then we go again with parse expression and Yeah, we do parse expression. I don't know. I was thinking that maybe we could somehow reuse some stuff,

26:40 but not sure. like uh what if you find token number? Yeah. Anyway, parse expression. But see like at this point you kind of expect a number or some other variable. You cannot really have a set. That would be weird. All right. Like that's the the only thing I'm I'm kind of meed

27:29 about. Um but uh anyway parse expression but yeah it's like recursive call to parse expression and we need to pass in the parser and expression operator dot right hand side and I mean right hand side is already it needs to be allocated basically. So let's go here. Let's do right hand side. Right hand

28:19 side. And I guess if this thing is not zero we return defer right I think that's how uh we are supposed to parse like numbers with operators and then we have an equal sign and Then uh another

29:05 expression right now we could just go into test tool and let's add an arrow here and let's do 1 + 1 is equal to 2. Something like that. And let's see what happens if we run this thing. Okay. So, expected equal but found the number at 2 34. Wait, what the Why did it actually print this stuff? That's kind of interesting though. 5

30:00 91 but then don't I have a if that happens and then parse statement if it's not Ah it it like returned. Okay. So if this thing is not zero, we returned it for one, right? Okay. So let's let's go again. So it's going to say expected equal but found the number at 234. All right. and 234. It's basically

30:48 here, excuse me. And the error happened 591 in the compiler or I guess you know here H. So I guess maybe this is just the current token parser talk without reading it. But then we have to read uh like token is equal to parser

31:33 read. I guess we have to read afterwards. Okay 560. Now the error is expected an operator or equal but found number So token kind was

32:20 number token kind was number. So it it had to look at the next token and problem [Music] is but I'm not sure why it says pound oh phone number I have to look at when I say but found I have to show the next token. So here I have to say

33:08 parser next token kind right I have to show the next token and here is fine that's what I was confused about so it's going to say end of file right and if we go into test two let me just put this one here maybe it's going to show it better if I run it it's going to say found exist lists. So problem is that uh in here we are looking for the equal. So we are saying if we find equal it's done. But I should also say that an

33:56 expression is done parsing if you find um exists or for all or some other kind of token that's not uh you know from an expression. [Music] But I mean the first expression should only end on token equal. That makes sense. But the second expression can end on multiple tokens, right? If you think about it, if you think about it, the first expression it's kind of like, okay, it's

34:43 the first bit of the expression. So if I do cat, it's like 1 plus one, you need to have an equal sign. But for two uh since we don't have uh you know semicolon at the end of the line, we need to look for exists for for all for end of file or uh I think we also have cat. We also have eval proof, right? we have all of these keywords. So if you find anything else, I mean we also have uh variables. So if you find anything else, you should just end the expression, not really

35:30 fail, right? I think that makes sense. So I guess what I'm going to change here is if I find an operator, we do operator. Otherwise, I'm just going to do uh number, right? So if you have an operator, we have an operator expression. If you have just a number, we do just a number. Can we maybe refactor this thing better? Don't think so. So, we also have

36:17 now name it does it looks weird. Look, but you know, now you can see that it works, right? it it parses the stuff correctly. So if we go to dump expression where is the dump program dump statement dump it dumps the defines. So now we have to statement uh equality equality dump. Let's do equality dump. We don't have equality dump. So, let's

37:05 add that. Equality dump like that. Oh, equality is already a pointer. What? Nice. It's already a pointer. Okay. So I guess it has left hand side and right hand side. So I'm going to do and those are expressions. Oops. I'm going to do expression dump. Uh left hand side. I think this

37:52 one needs to be referenced. Let's do print f equals. Why not? And then expression dump equality right inside. And let's add expression dump expression expression. So I mean if I just run this thing it should we should see an equal. Interesting that we see two of

38:37 them. Well, I mean, yeah, it makes sense because um if statement equality is not null, uh that's when we dump it. So now we see it only for the first one. Okay, nice. So expression dump switch expression kind oops. So if we have a

39:24 set expression set dump and then we're going to do expression set maybe I'm just going to return it so that it's uh simpler return expression number dump expression number expression function dump. Oh, expression name I guess.

40:10 Expression operator [Music] dump operator and then return expression bar dump like that. So we can just copy paste expression set the pointer set. So here set is just the name of the set. So I'm just going to copy paste this thing.

41:01 Maybe just I don't know set just so we see that it's something interesting set value set value. Okay. Interesting. Let's copy paste the next one which is number. I mean we are interested only in number at this point but uh you know what I mean number should be similar. It only has value. So I'm just going

41:49 to do that number. We have the function one which is expression I think name right let's just not do anything and then we have operator And the operator is called operator

42:40 obviously. Operator let's keep that as well for now. And the last one is parentheses. I guess this one right there. Okay. For operator, we have left hand side and right hand side. So I'm going to do something like expression. We need to define this one first like this. So we need to call expression dump

43:27 on operator left hand side. Right? And then we need to do space. All right. And then the right hand side. So now if we run this thing we should see number one operator plus number one equal number two. So we are able to parse the given expression. That's pretty cool. Okay. For a function, I think it's

44:13 kind of straightforward. We have to print the name. All right. and then four unsigned int i is equal to zero. I is with the name uh arms count i ++ we need something like expression I think args was uh an array of expressions. the expression to pointer

44:59 arg i rg. Okay, this unreachable obviously this dynamic array get ref. So the dynamic array is name args index is i and this thing is weapon pointer ar i and I'm just going to dump it like that. Okay. And for the parenthesis,

45:45 uh not sure we just have to dump the inner expression. So pon expert but um would be nice to have something maybe something like pattern space and then closing would So these are these are dumping all the expressions. Nice. Now we can get back to actually finishing the

46:30 parser. So we were here we were we were able to parse the numbers. So let's see about the names. So as I said here we can have by equal I mean and right like anything else. So we can have a parenthesis an operator or anything else. Let's check the next token. So if the next token is token left parenthesis we do something else. If we have token operator, we do

47:16 something and on the else case it means it's just a variable. So we can just do something like this. Um what should we do here though? So it's just a name. I mean we already know that the kind is a expression kind function right like h sure it is a function right so name is for the function

48:06 So, I need to put that here. But what's interesting is the array. I'm just going to do zero for the array because we don't really care. Like if the array is initialized with zero, it's going to have the count zero. So, um, no items basically. So, it's it's just a variable and we skip we skip it. That's cool. Okay. What should we do in case we have a function? So, if we have a function, we set the expression kind to function as

48:52 well. Then we need to initialize it like this like we did here. Then we need to initialize the array. We have to not forget to initialize the array. So we need to do this dynamic array in it. The dynamic array is expression name dot args. Let's put the reference and the size of is expression t. So this is how we are going to initialize the array. We can do it also

49:38 here but I think it's fine. So we initialize the array, right? And after we initialize the array, we need to parse until we find a closing parenthesis. That's kind of the idea. We need to parse all the arguments. So I was just thinking like what if we

50:24 allow functions with only one argument? That's something. Uh, that's kind of not sure. What if we have functions with only one argument? That's a good point. Not because I'm lazy and I don't want to parse it, but I was just uh thinking like would that make sense? Anyway, uh we'll come back to this one to do parse args, right? But let's look into the

51:10 operator because the operator is the other easy one which is just going to be copy pasting this. So it's an operator, right? We know the value of the operator. We allocate the left hand side. If it fails, it fails. But now the left hand side is token kind function. Right? So function token. But see, it's like interesting. We don't really know this

51:57 stuff. We need to think about it better with the L parenthesis. We need to parse args first and then decide on what's the kind of the uh then decide what the type is because we can have a plus after the last parenthesis and then it's an operator. So we have to make sure that we we parse all the arguments. I guess what we

52:46 could do is I'm not sure. Let's let's leave it as it is and we'll you know I'll refactor it if I see the need to refactor it but for now I think it's fine to keep it like this. So anyway, so if we have an operator as the next token, then we need to set the token kind to function for the left hand side. Then we're going to set the

53:36 name as an expression name. This thing has a zero. I guess okay let's let's do it like this. So expression name t is going to be a name literal expression name t token do value and zero. I guess we

54:25 can still make it like this. Then we have to initialize the dynamic array. So this dynamic array in it then name arrow args and is going to be size of expression t what we want. Okay. So, we also initialize it. That's good. Then the next step is if we

55:11 find open parenthesis, we're going to do something. We don't know yet what that's going to be, but we're going to do something. Okay. Then what I would like to do here is call to read parser read. I would like to call parser read. So we basically looked at the token we used it and generated this name expression. Then we are going to parse what's inside the parenthesis. Then we are going to skip the current token which you know is going to be the name and we are going to look at the current

55:59 the new current token and if we have an operator it means that the expression kind is an operator otherwise it's just the function and for the name we are just going to set name Right. And then we call to read I guess. So I guess here we need to say parser token. Uh let's think. No no it's it's fine. Parser read parser and we have to read the parser.

56:46 Uh so here we don't need to to skip it. We look at the current token. The current token is not operator. We don't have to do anything. If it is an operator, then we initialize this thing. We allocate the expression. We set the kind to function. And here we also assign name. Then we have to skip the the the operator token here. I need to use token value. So if if you think about it, that's what it does, right? It's just token

57:32 operator. It allocates the memory. It says the kind of function. We already have this defined. We don't need to worry about it. We skip the operator symbol. Then we have right hand side. We allocate it. Right? We allocate it and we parse the right hand side expression. Okay, makes sense. I was like, can I do that here as well? I don't know.

58:22 probably I can like I can do something like um expression number is critical expression number T token value then we can say token is equal to parser read parser token find and then here we have the token we allocate we just set the number we read only once and here we don't need to read and here we just set the

59:10 number. So again we know that we have to read a single number. So we just set the number thingy. Then we uh get the next token. If the next token is an operator we know we have an operator otherwise it's just a single number. And similarly here we just initialize the name. Then you know close your eyes don't look at this thing. We read the next token. If the next token after the name is an operator, we have an operator. Otherwise, it's just a name like a function. The only difference here is that we have these parenthesis which are optional. So if we encounter left parenthesis, we have to do something here. We don't have

59:56 parenthesis for a number. So that's the only difference I would say. Okay. So if I compile this thing, it should still work hopefully. Yeah, it still works for the operators. Let's go back to test two. Let me just add another plus one. Let's see what happens. Okay, it does plus one. What if I do a variable? We have a name. Nice. Uh B have a name. We have two names. That's perfect. And here I would like to have okay that doesn't matter. I would like to have exists f

1:00:43 mm and let's do f is equal to zero first because uh why not? But let's try to make it work with uh the iso dump. I'm unhappy with one thing and that is we need two new lines. Well, I guess no, we need only one new line. The only problem is that we need to do a print f new line here. All right. So, we can see it better. Okay. Nice. Okay. Okay,

1:01:31 so let's ignore the set for now. So let's see how we are going to parse the inside of the parenthesis. I mean I should call that here and then if token kind then what are we going to do? I have another idea. Hold on. Anyway, so if we have a left parenthesis, right, we expect an expression. We expect an expression.

1:02:16 That's fair. So I'm going to do, let's just pretend that we do each iteration by hand. So I need to say parser parse expression and we are going to pass in the thingy and some kind of arg. All right, we don't have arg. I think it's fine if we just define it on the step. I don't see any issues. And we're going to pass it like this. I mean if this thing fails we just uh return for one. Okay. So we have we parse one

1:03:04 argument or like one expression and let's parser read parser. Not really. We don't need to do that. We can just say token is equal to parser doc. If token is equal to token, we need to do this thing again. So I see here something like uh do while loop Am I

1:03:50 right? So the current token is uh left parenthesis. I assume we need to do something like parser read parser if token kind is equal to air parenthesis then we break If it's not right parenthesis, then we parse a new expression. And then at the end if we have a comma

1:04:43 I mean if we have a comma we have to parse another expression. That's kind of the logic that I'm going for. Mhm. Because if we do it like this, you can have comma and then immediately after parenthesis. I don't know if that's a problem. I don't really [Music]

1:05:30 care, but it's kind of annoying. So, we parse one expression, but if you have a closing parenthesis immediately, I mean, it's kind of weird to have closing like we you need to have at least one argument if you have parenthesis. Let's do it like that. So you need at least one argu like it doesn't make sense to have a a function with a no argument like what what language is that? Okay. So we have one argument at least. Then if you find a comma then we don't do anything. Uh that's good. That's a good case.

1:06:20 else if you find a parenthesis you break and I guess on the else case it's a bit of a problem because uh while while true it might be one problem if so you parse one expression then you find a comma you go Again, if you don't find a comma, but you find the right parenthesis, you stop the iteration. But if you find anything else, I would say expected, comma, or right parenthesis, but found

1:07:08 whatever I think that's fine, right? or function calls. So let's run it again. It shouldn't change anything. But if we go here and we do one, two, three, we should have expected a symbol a name 670. Whoa. What? So we have token kind

1:07:54 name. Let's visualize what the current token is. So we found was the current token. We found operator equals and parentheses. Uh what left Wait, left parenthesis. Yeah, left parenthesis is

1:08:41 good. So, it's going to go into this thing. Um, okay. What I mean, we obviously get here. Wait, what? We don't The Yeah, we found parenthesis. Ah, Um, token is equal to parser. I don't know if I have to read here or what. Do I have to read where? maybe in the beginning of the dow while

1:09:29 loop because when I do continue I don't read token but even when I do the right parenthesis I don't So, do I also need to read once here? Okay, fair enough. It did something now for the arguments. Why don't I print arguments? Did I forget

1:10:15 that statement dump? So function dump I forgot to append the argument. Okay. So here after we parse the expression we need to this let's do this unreachable obviously this dynamic array append and we're going to append into name args the arc you Okay. 1 2 3 Name and then one, two, three. It's kind of uh kind of

1:11:02 ugly. Let's go into the dump. Put a function. Let's put I guess if name args do count is greater than zero, we're going to print f a parenthesis, right? We're also going to print it. Oops. Print it here. And if I + 1 is less than name args. I'm going to print f a

1:11:48 comma. Right. That's how it's supposed to work. Yeah. So we also parse the function calls. That's cool. The last thing we have to parse is wait where is it parse the set. So if we find the set token if we find the set token

1:12:36 expression set I guess the only thing that we missed but the expression. So we have set we don't have that we can skip it. We are going to say expression find set set.

1:13:22 So yeah, it's like if you find a number, if you find a token name, and if you find a token set, but we missed some things. If we take a look here, we will also have squirly braces or the symbols. Uh, that kind of sucks. Let's Let's add it though. So, it's going to be similar to set. Let's call it expression kinds. Maybe that's a good name. I mean, it's like an expanded set somehow. I don't know how it

1:14:10 symbols symbols T and what it's going to contain is it's an array of expressions though because it can be like anything inside of a set. I don't know. You know, ideally it's just numbers, but you can actually have anything there. So, yeah, why not? Let's let's just leave it as uh uh that. So, here is more like set.

1:15:14 I guess symbols is fine. I I don't know. Let's just leave it as symbols. Okay. So if we go into here, we can just say expression symbols [Music] symbols because maybe I want to rename this thing into function because it's a function. Was it in? All right. Now it's a

1:16:04 function. Maybe even here it needs to be function. here [Music] function and maybe here function here for instance could be function Right. Function works function function.

1:16:50 And then what if we rename this thing into name because it's like a set name or something. All right. And here we have a name and then it's a new name expression name. We have

1:17:41 name expression kind is going to be replaced to name expected a symbol of function or a name. Okay, fair enough. And we can rename this thing to set now expression set. And now this becomes a set

1:18:27 of elements, right? or I guess items it's shorter. Okay. So now we have this set right here. Type dump. And now we can do a dump or a set expression. Set dump set. Uh, the set doesn't really have anything

1:19:14 there. So, it's going to be similar to the parentheses thingy. The only difference is we need a while loop or I guess a for loop. Okay, so we have the set print f this thingy and that should be it. So here we have set items. Nice. So that's going to be the

1:20:02 set. I could even add uh some squirrelies just to show it better. Okay, nice. So we are able to dump a set. Let's have in set expression set expression set. Okay, so it should still work the same. Nothing changed, right? Uh I guess we just change this thing to be function instead of uh name and the set that we change to be like if

1:20:48 we go to test two we can say m is equal to one for now it doesn't make sense but you know name m is equal to number one. And now if you go to parse expression we have token number token name token operator token set. I would like to add else if token kind is equal to token l brace. So if you find an L brace that's also kind of part of

1:21:34 a thingy. So let's copy paste something from here. We initialize a set with zero. Then we initialize the items. They are expressions. We skip the first token. However, I think we just need to copy paste this dow while loop. I think that's all we need to

1:22:21 do. Wait, where did I go? Here. So we are going to do a dual loop. We skip the first thing. Then we pass an expression. Then we append that uh you know element. I could call it item just for uh consistency. So this is an item from the set. Then if we find the comma it's fine. We continue. If we find R brace we break. And then expecting this or this but found whatever. And then we skip the

1:23:06 last thingy. And at the end we have to add this stuff. We have to not forget about the expression kind set and so this would allow us to write things like this right we generate a set I mean obviously Um, I would say it's not perfect. Oops.

1:24:00 Because Okay. Um, you can use sets like with addition and stuff. So that's doesn't make sense, but that's more for the type checker to solve, right? I think I mean, obviously, we could have done a better parser, but I think it's good enough. Um yeah like maybe I don't know if you find a name to yeah it's it depends right we could have done like it's mainly because

1:24:47 we have only one parse expression if you think about it left hand side and right hand side are kind of different right they are not uh you don't parse them the name exactly the same like like uh on the left hand side you can have sets like these names but on the right hand side you cannot have them. So that's the idea but um no that's it is what it is. We are not going to misuse the language like that's the that's the point. So we just added this thing.

1:25:34 So next thing would be parenthesis. else if something token kind is equal to L parenthesis. We should parse an expression until we find the right parenthesis which I think it's kind of Okay, because it's just going to stop when it finds something unreachable. You know what I mean? So, I think it should

1:26:19 be fine with parenthesis. So, what do we have to do? Maybe something similar to this. Let's create a parentheses. Oops. A parenthesis thingy. So it has an expression. Uh let's initialize it with null. Let's find the malo around here. So let's copy paste it. Let's do parent

1:27:05 expression. What parent do expression or is it expert? We initialize the the malo. I don't think I want to do that. I think I want to do expression dot parent expression. Although it's the same thing. It's exactly the same thing, right? We allocate it. Then we need to do parser

1:27:50 read parser, right? Then I guess token is equal to, but we don't really care. Then we need [Music] to do something like this. We need to call to parser parse expression of parser and parent.export. If this thing is not zero, we return the for one. We fail it basically. And here is going to be a parenthesized

1:28:38 expression par is equal to parent. And then after we finish parsing it, token is equal to parser doc. If token kind is not equal to token air parenthesis expected parenthesis but found whatever it fails, right? It dies basically. And then we need to skip

1:29:26 it. I think that should be good. And if we go to test two, can I say something like 0 + 1 + two? Is that a thing? 753. So expected a symbol, a function, a name. Um I mean you can also have this one and this

1:30:11 one but found operator 340. So it didn't skip the what? But I mean it did parser read. Oh Yeah, because for parenthesis we finished reading the parenthesis, right? What the should we do

1:30:59 here? We finished doing the parenthesis. uh we read that and then if we find an operator as usual we need this if statement. If we find an operator we need to set the expression to operator is is no longer a parenthesis right? it becomes an operator and the left hand side gets allocated. What not? Left hand side is parenthesis. So parent is equal to

1:31:44 parent and then we parse the right hand side and otherwise if we have if we don't have an operator parent is equal to parent right it's it's just parenthesis. So now so stutter but let's pretend that it's fine. So it does the parenthesis. Perfect. Wait, it was No. Oh, it was it was the compiler. Uh a bit slower. Let's go to test two. Let's do one plus. Wait, why did it

1:32:32 rebuild? No idea. So, you can see it doing parting correctly. That's cool. Obviously, you can have stupid stuff like like this. There's nothing stopping you from doing this, but um yeah, you know, I guess it makes sense to have things like this like allowing them, but they are not correct. So, you know, it is what it is. So let's see if it works on our no

1:33:19 because we have Eval and uh Okay. So let's let's delete this two because we don't don't need it anymore. So let's add a and proof inside of the parser. So this is going to be interesting. Let's do if token kind is equal to token a valal we're going to do something and if it is proof we're going to do something else. So if it's evaluation we need to parse an expression and that's

1:34:04 it. So if it's eval, we are going to skip the eval token and then we are just going to parse an expression. Where is it? I will we don't have really like expression t ever. Uh this log info is not done yet, right? So yeah, and for uh for the proof, we need to

1:34:52 parse a statement. So we need to skip the proof token. We know it's proof and we need a statement d [Music] statement and we need to parse a full statement. So a parser parse statement and because statement is lower is like below we need to move it as well to the top. The is the parser? The was this par

1:35:43 expression? Oh, interesting. Yeah. So, we need parse statement in inside of parse expression, right? Parse statement and parse statements uh requires parser and statement. And if obviously if this thing is not equal to zero return before one and then we are going to log a to-do but uh but found

1:36:28 proof. Found [Music] proof. Wait wait wait wait wait. Why did it require an equal? 1812. But it's not an equality. What the So, it showed to do. That's good. I guess for the proof

1:37:24 90 the is this? So at least for eval it worked. Dump expression dump. Let's Let's just dump a val and see. So at least we can see what the is this

1:38:10 error parse statement. That's kind of annoying. expected equal but found proof 83. So this happens in parse equality. Did they make some mistake in here? Don't think so. Just copy paste

1:38:56 this one. Just going to test and let's just define it. Let's see if uh I don't know. What the Oh, wait. What? So, it reaches the to-do expected equal but found end of a Um, my bad. I think that's

1:39:42 because it shouldn't be inside of parse expression. Those shouldn't be in parse expression. They should be in parse statement. So parse statement parse statement. I guess here we can do something like if parser talk kind is equal to token eval we are going to do something you know what I

1:40:31 mean like Yes. Let's just define it. Token kind tok. If token kind is token eval then we are just doing this stuff. If we find token proof, we're doing this. And on the else case, we are doing the

1:41:17 statement, right? So, it's uh it's supposed to work now. Let's do it like this. Maybe it's going to be cooler. And here I can do statement dump.

1:42:03 Right. And I don't think I need to define this here anymore. Yeah, perfect. So, it's going to need to evaluate the Why so many weird things? I I typed Eval in both of them. um roof. Maybe I'm going to do back slash N just for uh

1:42:49 convenience. So, it's going to need to evaluate this. Okay. Two new lines, right? So, it's going to need to evaluate this uh this expression. It's going to need to prove this statement. This one as well. and it has this like knowledge base, right? So that's us being able to build the SD for this thing. So I think that's pretty

1:43:35 cool. Pretty good start for now, I would say. So yeah, I mean I'm now I'm curious how it's how is it going to work like because at this point we have the a we might want to add some typeing but we'll do that uh some other time you know know what I mean. We'll uh we'll just try to get some type checking at some point and probably the next step would be to just try to interpret this uh now at this

1:44:22 point like trying to do some uh at least the evaluation would be kind of interesting to solve. So I guess next step would be inside of the program to add a list of evaluations that we are going to generate here and maybe a list of proofs or like statements for proofs that we need to prove. So, uh yeah, I guess we'll uh we'll try to do that. But I mean, for now, for today, I think uh I'm done with uh this

1:45:10 thingy. But uh yeah, I mean, at least it looks interesting to be honest. Might not work. That's uh if it doesn't work, that's another thing. But, you know, at least we did some parsing lexing, which is kind of nice. It's always cool to do that in C, I would say. Uh, so yeah, again, maybe the parse expression function is kind of meh. It's uh you know bit too long for my taste but uh you know at the at the end of the day if it works it works and uh

1:45:59 honestly like to be fair I think that's uh that's the more important thing like if it does what it's supposed to do that's enough and uh you know like you will learn that maybe the hard way who knows But um yeah, pretty happy with the results. It looks it looks promising, not going to lie. I mean, obviously, we could have gone in the direction of doing just pattern like reax pattern matching, finding for instance, how do you prove this one, right? You just look in your database. You find this sequence of symbols. You

1:46:44 find this sequence of symbols and you just replace it, right? But there's no AD there. There's no like doesn't feel like it's working language, you know? Uh like we can do that in Vim. We can just do something like inside of test we can just uh highlight like the proof right and then do the wait how do you do that it's um like that star I think I need a dot

1:47:35 Mhm. I mean F cuz I don't know how to replace to be honest. So I think it's F, but I I'm pretty sure I'm missing something like an S or something. wait maybe I don't okay I don't need so you would just you know replace it and you can do that in Vim but uh

1:48:20 again it's like bit cooler if you use a compiler like I mean compiler this kind parser, right? So maybe some some changes that I'm going to do on my own. Maybe I'm going to add some uh command line arguments using the arc parse thingy. But other than that, yeah, I don't think I'm going to touch this code like the parser code. Thinking I and I think it's complete for now. I don't think it's missing anything. So yeah, I mean, and it's what? Jesus, 1,000 lines of code. That's

1:49:07 insane. Maybe only here the token symbols. If we find any new symbols that we can add, that's welcomed. Anyway, so uh yeah, this should be all for now. And in the next one, we'll try to like interpret the ASD, run some kind of inferences between like at least getting evaluation to somehow work. That would be really cool. So, uh yeah, let's see each other in the next one. So, see you.

Share

YouTube Video Summaries