 Give the second top. So it's going to be a different topic than just now, which was Haskell. This will be a talk about compilers. And this is some early days of compilers. This is 1965. And the work was done, I think, in 1962, early 60s. And this is the paper. They have very nicely done an HTML version of the original paper, which you can also find the PDF. But the HTML is actually much easier to read. So the paper is about this DSL, essentially, a domain-specific language for writing compilers. Because I think the historic context was at that time, they were inventing many languages, like Al Gore was one of the languages from the early 50s. And it was being implemented in the 60s. And they were writing compilers for all kinds of weird machines. So back then, they had many, many different types of machines with different assembly instructions. So writing compilers was taking up a lot of time. And one of the things people do was to see, can we have a more productive way of writing compilers? So just to explain, a compiler, essentially, we use it all the time. But it somehow seems a bit like a black box to many of us. But it's really just a program that takes in a program written in a source language and outputs a program in a target language. The target language could be, say, now we've heard of JavaScript compilers, compilers to JavaScript. So for example, you could compile from Elm to JavaScript. So that's a compiler. In this case, they're compiling from Al Gore to machine code at that time. So this paper introduced the concept of what's called a meta compiler. So meta compiler is also a compiler. But it takes in a special DSL for writing compilers. And outputs compilers. So again, just to recap, a compiler takes a source program, outputs a target program. A meta compiler outputs only a specific kind of target program, which is compilers. It doesn't output anything else. So it helps compiler writers, essentially. Or some people call it a compiler compiler. Because it's a compiler that produces a compiler. OK? All right. Cool. So let's look at what this DSL looks like. So I'll just go with examples. Because that's the easiest way. So let me just show you how it works, for example. Let me give you an example of a compiler first, just to set the stage. So let's say we have a, so this is like the hello world of compilers. So let's say we have an expression written in this infix notation. And we want to produce an expression in sort of this stack notation, assuming a programming for some kind of a stack machine. These are like the instruction codes. So you have push, which puts the operands on the stack. Then each of the operators pop the operands in needs and push the result back onto the stack. So this is a translation of the input, which is the infix expression into this sequence of stack operations. Is that OK? All right. So this is an example of a compiler. So this compiler takes in expressions and infix notation and outputs this machine instructions for a stack machine. So what does this look like now? So let me show you the compiler. Let's clear the screen because it's a very small compiler, actually. But the compiler is written in something called the meta language because this is a language that describes our input language and also describes the output language, essentially. So let me run through the lines. So we just sort of have two lines at the beginning and the end just to indicate the start and the end of the program. So like dot syntax, this is the notation popular in those days, the 60s. If you use TROF, you know about dot something, but never mind. So dot syntax, so this is the name of the type of input language. It's called the expression language, xper. And then at the end, and in between is a number of rules. And this is meant to look like the package now form, actually. So this is what, in fact, this was, algo60 was the first language, I think, formally specified in BNF. Before that, it was not formally specified. I don't know how they defined the language. But anyway, so this is in Decker's now form. So you have a sequence of rules. Each rule is terminated by a semicolon. You can see that. So here we have four rules, because you see four equal signs. That's kind of the trick. And then the rules have a left-hand side and the right-hand side. So the left-hand side is the thing we're defining. And the right-hand side is the definition of the thing. And then rules, so rules are, they are expressions with different kinds of symbols. But in particular, they have the vertical symbol, the vertical bar. So the vertical bar represents alternatives. So it's like A or B. So that's of the lowest priority. So let's look at the bottom. I think it's easier to go from the bottom up. So the last rule is called the number rule. So the number rule matches and is defined as, so there's a special construct. So the dot something is some keywords in the DSL. So one of the keywords is dot number. So dot number is a special expression that matches any number. So this dot number will match like a five, for example. And ignore the stuff in the curly brackets first. And then we can define expression three as a number. And then expression two is defined for the multiplication and division because they bind tighter. So expression two is defined as expression three. And then the asterisk is the regular expression, the zero or more of the stuff after it. So expression two is expression three followed by zero or more, the asterisk followed by another expression three, or a divide followed by an expression three. But it could be many of copies of these. And then the original definition expert is just the same as expert two except is for the plus and minus. And it's at the top level because plus and minus defines the weaker than plus, multiply and divide. OK? All right. OK, now talk about the stuff in the curly braces. That indicates what to output because the job of the compiler is to output the target language. So far the syntax is to express the language of the input. So now we look at the parentheses. Again, from the bottom, the number says push and then the dollar sign. The dollar sign is also a special symbol in the language. It outputs the token that was just matched by the dot number built in. So you output push followed by a space followed by the number. Let's say push five, for example. And then we don't see that in expert three. Expert three is to handle, of course, the parentheses because parentheses binds the tightest. So it's at the expert three level. And then the only other part is the times and divide. And they're quite simple, actually. So they just output the operator because all the operands have already been pushed onto the stack. So they just output the operator name. So again, just look at the example. It's metric in. Looks like this. And the output looks like this. So OK, in fact, this is quite nice. So on the same screen, we have all the components, right? So this is the definition of the compiler. This is the input to the compiler. And if you run it through this, you get back this output. Well, yes. You're not going to be satisfied until you show us the method file which defines the compiler. Of course, of course. Yes, yes, that's coming. That's coming. But the one is a little bit messy. So I have to go through a few examples first to understand the DSL. So yes, we will eventually show you the description of the compiler, actually, which is what is called the meta two compiler, right? Because it's two levels of meta. Anyway, OK, but let's go step by step. OK, so this is the first part. So this is important to understand the first part. What the DSL looks like, right? And then what does it do? So let's look at a more complicated example now. So second example. Second example is called AXP. So AXP is a language with assignments, I guess. That's why it's called AXP. And it's a language with just assignments. It doesn't do anything, actually. But it's language with just assignments. And you have also other operators like the unary miners and the exponentiation and so on. So it's sort of a step up from the previous language, which was just a single line. This is multiple lines, in fact, right? And we will also compile this. Let's see what it compiles to. Also to some kind of a stack machine, I think. So it compiles to also a kind of stack machine. But now we also have the ability to add and store, so have a reference, almost like the earlier talk talk about variable references. So in this case, we have a memory address. And we can store numbers there. And we can load the values back from that memory address. So this is what it looks like if you compile it to this particular machine. This stack machine enhanced with this address. And load. And I think it replaces the push with a literal. But sort of the concept is the same. OK, so now we know this. Let's look at the compiler, how we would describe this compiler in this DSL. AXP meta. OK. So it's written in a similar fashion. OK, so except maybe you can see at EX5, it has introduced some new syntax. I guess it's the dot ID, which is also built into the language. It matches any kind of identifier. Think of it like you're an identifier for a C variable. So the fern and whatever it was just now was the identifiers. So as you can see, if you explain the whole thing now. So when you see an identifier, you want to load, means you see it in the right-hand side, right? You want to load its value. So that's why it transforms into load, the name of the identifier. Number is the same except it's now called literal. And then parentheses is the same. Most of the rest are actually the same. OK, except at the top, you have the AS, the assignment statement, I think. So this is where we use the identifier on the left-hand side. Fern, colon equals is like Pascal, something. So you can see how it translates that. So first, it issues the address to say that we're going to have an identifier, and here's the address. And then it processors the EX1. And then after that, it outputs the store instruction. So the result of the body of the assignment is stored into that address because the address is on the stack. So after EX1 is done, the stack is empty. Then the stack has the value of EX1, whatever the expression is. So store will take the value of EX1 on the stack and the address of the identifier and sort of stick it in the memory. That's what store does. So OK, so this is the second example. Actually, the paper goes into more complicated examples, but I will skip the more complicated example because they compile to some very strange machine code. At the time, it was a different machine code, anyway. Yes, question. Can you show the output of meta2 for either this or the previous example? Yeah, I thought we saw it already. That's the lower. This one. Oh, the output. All right, you mean the compiler. OK, sure, sure. So in this case, this particular compiler generates a compiler in terms of Lua, but you could use C++ or whatever. Just Lua happened to be kind of simple. I'm not sure it would make much sense. We can look at it, I guess. Sure, sure, no problem. We can look at it. I don't know. It's kind of a lot of repeat, repeat, repeat. I mean, the reason is because we need some way to do localized blocks. And in Lua, repeat is apparently the way to do it. So this gives you a local scope. It's like the open and close parentheses in C. But in Lua, it's repeat and until. So it's a little bit the lots of repeat. And OK, you can see things like test string and so on, which checks whether you match the literal strings and so on. And then we define functions, of course. Unfortunately, there's no indentation. Yeah, it's a recursive descent parser. Yeah, so if you enter the parsing literature, it's actually generally a recursive descent parser. So what that means is, let's look at the definition again. So what that means is whenever we encounter a rule, we would sort of, a rule is translated as a function, basically, right? So a rule, each rule becomes one function. And whenever we encounter the rule, we would call that function to recursively consume the input stream. And then that rule will return to us. And then we can consume some more and then we can call other rules. So that's called a recursive descent parsing. OK, so now we come to the force of the talk, which is we're going to look at how to write the meta compiler itself. So far, I've been using the meta compiler, actually. If you saw when I make, no, I haven't been using it. So if I try to produce the compiler, xp.lua, it's up to date, of course, which is redo the whole thing. So OK, sorry, it's too low. So yeah, so the meta compiler is called meta.lua. So this is the program that translates the DSL into the Lua code that we saw, which is kind of horrendous looking. It wasn't meant for human consumption. So the interesting, really interesting bit about this paper really is that we can express this compiler, meta.lua, in that DSL. And now we're going to look at it. OK, but let me give you a caveat first. So the point of the paper really isn't to produce a production ready DSL for the compilers. It was really to give you a sort of a simple example that would have this property that we can express the compiler in its own DSL. So this is called bootstrapping, if you've not heard of that. And we'll see why this is useful. But the point is just to get something simple that bootstraps so that you can enhance it later on. Let's look at what that looks like now. So this would be the main part of the paper kind of. So let's look at, oh no, I didn't put it examples because look at meta.meta. OK, it's a little bit longer anyway. But so same thing, the syntax and so on. Let's start from the bottom again. So the top level now is a program because this is the. OK, so now we're going to think one level of meta. So this is the meta compiler. So the input to this compiler is the DSL. The input to this is the DSL. Previously we saw the input was expressions, the input was assignments. Now the input is the DSL itself. OK, all right, so the input is a DSL and we call that the program. That represents the entire input. And again, remember the DSL has, so this starts off with the literal dot syntax, which we know. And then it ends with the literal dot n. And the literal dot syntax is followed by the ID, which is kind of like the name of the language in this case. Well, OK, this is like some header code I need in Lua just to require some. We have a small runtime. I can show the library, actually, it's also very small. It's like three lines of Lua. So we have a little runtime library to do some things for us. And then so the bulk of the program really is a sequence of one or more rules. And that's what the star rule means. So it's a syntax followed by identifier, followed by one or more rules, followed by the n. Oh, OK, at the n what we do is quite interesting. At the n what we do is we invoke the function program, because this rule itself is transformed into a function. So at the very end of our Lua script, we need to have something that starts off the whole process, like the main, because all we've done is define functions. We actually got to start consuming the input. So here we actually call. So this will convert into, like in this case, program open-close parentheses, which calls the program itself. OK, so let's see what the rule is. A rule is some name, which is the name of the rule. In this case, the name of the rule is rule. This is very strange. So this block of code just to say, we create a function with that name. So function rule bracket, bracket. This creates the function, like a define a new function. And then the rule has an equal sign, which is the literal equal sign. And then followed by, let me recall a choice. Again, choice, I guess it means because we have multiple alternatives, A or B or C. So we call it a choice. OK, fine. And then followed by the n of the rule, which is the semicolon, which outputs n. And the function and the n together forms a block of, defines the body of the function. So the beginning function is function, some name, bracket. And then the end of the function is the word n. OK, so this is lower code, actually. But you don't have to really know. Lower code is like Python or Ruby. It's a dynamically-type language. OK, we're almost done. So what post-language did the original paper use? It wasn't Lua, it was 65. Machine code, machine code. Sort of like an assembly code, opcodes, which looks a little bit more horrible. So that's why I choose to use this example, actually. So the original paper doesn't use Lua, of course, because Lua didn't exist in 1965. But for the convenience of modern day sensibilities, we will use Lua. So I don't have to explain to you all the funny opcodes mean, because it's like three-letter codes and stuff. OK, so now we know choice. So choice, again, remember is to do the vertical lines, A or B or C. So we need this repeat until true business is just to create a block of context so that we have the ability to define local variables and so on. So that's what the whole repeat until true business really is. It's not really, we're not really doing any loops. So it's just a syntactical construct in Lua that lets us create a context. It's like your open-close curly brackets in C, OK? All right, so choice, we define as, so the things between the vertical bars, we call them sequences, because they're actually a sequence of things, like syntax followed by equal, followed by blah, blah, blah. It's actually a sequence of things. So it's a sequence followed by one or more vertical bars and more sequences. So sequence, vertical bar, sequence, vertical bar, sequence means first sequence, or second sequence, or third sequence, and so on, so forth. See, what happens? OK, and then the choice, OK, so there's an interesting decision here. So the way we do choices is, once we find one of the choices that works, we will just decide that's the one. We don't go on and try the others. So it's not really back us in our form in that sense. It's almost like today what we would call, well, not quite also, something called passing expression grammars, which also have a very similar effect, where it sort of sticks to the first sequence that worked. It doesn't go and try the others. It's something like a greedy, yeah. So the reason for this is to avoid sort of backtracking. We just sort of go down the tree. We don't go different branches. That's why we have this. So switch is just some kind of global variable that tells us if something worked or not. Something was matched or not. So we use switch everywhere, actually. OK, so this is just to say, well, we matched something. OK, we're done. We don't have to check all the other choices anymore. So we keep trying until we find the first one that worked. This is what this does, basically. All right, now we get to the easy things. OK, now let's get to the sequence. The sequence, as I say, is literally a sequence of expressions. So each of these expressions is called a primary. And it defines similarly to choice, except, of course, it's just separated by spaces, like this, like what's the example? Like this syntax, followed by ID, followed by. That's a sequence. In fact, this is one sequence. There's no choice here, actually. This is syntax, followed by ID, followed by asterisk, rule, followed by N. And we'll handle the asterisk on top. OK, and the real, true kind of the heart of the program really is the primary, which is where most of the constructs are handled. So we're done, we only have two more. So just sort of bear with me. OK, so primary is the thing that the sequence is made out of, a sequence is made of multiple primary expressions. And primary can be many things. Let's just go top down. A primary can be an ID. So primary is the right-hand side. Remember, we're on the right-hand side now, because the rule is handled at the early on. This is the right-hand side. So primary is in the right-hand side. ID means, like we see an expert, or EX-1, in the right-hand side. Means, as we say, we will call the function, because it's recursive descent. So when we see the name of a rule, this ID means it's the name of a rule, basically. We see the name of a rule, we will call the function. This is how we call a function. We stick the name down there, and we put it with the parentheses. So we call the function. Next thing, it could be a literal string, like the dot syntax. It could be a dot, like a dot syntax, a literal, so in the single quotes. That is what the dot string is. The stuff in the single quotes. And in that case, we run a little helper function which tests whether the next input sequence is indeed that particular string, like the string dot syntax. So when we see a string, we test it. Is that the string in the input? That's sort of natural, I guess. OK, and here it gets a bit weird, because now we're going to talk about ID and string again. Now, the thing about the third rule is the literal dot ID. It only matches these three characters, dot and ind, whereas the first rule matches any valid identifier. At first, I was very confused. Why does this ID appear so many times? But anyway, yeah, so that's the thing. So here is the literal string ID. And so how do we match an identifier? We sort of just turn to the regular expression. So identifier is an alphabet followed by one or more alphabets or numbers. That's the definition we use here. Like A15 is an identifier. And we just stick it into this input, because later we might be asked to produce it in the dollar sign. So we've got to save it somewhere so we can produce it later on when we're asked for it. Number and string goes the same way, so I wouldn't explain. We have something called empty, which matches nothing. So that always just sets the switch to true. So that's simple. And then we could have, or here's where things get messy. So a primary expression could itself be a choice. So let's just handle this way. Very nice. And of course, the key thing is here, is how we handle the clean star operator. So the last part is to do the clean star, which is, and here we actually do a loop, actually, because we need to match multiple one, zero, or more copies of this particular primary. The matching of the primary happens inside the primary, and then this part is just to do the loop to keep matching them until no more. And then we exit, because we only go as far as, we don't know how many copies there are, so we just keep matching until we're out of it. And the last bit I think is quite straightforward. So output is the bits in the curly brackets. So that's the bit that's supposed to produce the output to the, in fact, it just writes the standard output, actually, right? Like you saw the word literal. We just print the word literal on the standard output, or the word push, or whatever it is. So how it works is it's basically the curly brackets. And in between the curly brackets could be either strings or dollar signs, right? So that's why it's written like this. So it's a zero or more strings or dollar signs. It's quite a nifty way to write it, actually, right? It's a star bracket dollar sign or string, which exactly is what I just said, but in this DSL. So the three cases are, it is the dollar sign, right? Means we're asked for something we just read, and we always assign it to this local variable called input, so we just write the variable input, which prints it, basically, right? It is a string, so we just print whatever that was, because if it's the string like push, then we just print the word push, right? And finally, if it's the, so all the things in one parentheses goes, after the stuff you printed, we just print a new line just to have things on separate lines and you can read it. All right, that was the meta compiler. So what do I mean by this is the meta compiler? Let me just illustrate this. So we can use the compiler to produce a file, right? So we can, let me clear and then go to the top. So we can take this input meta dot meta, which is what we just saw, the not too many lines, hopefully, and then we run it through the compiler, which is meta, meta dot lua, right? Then we store it somewhere else, we call it meta2 dot lua, just not to bash our original file, right? So it turns out that, of course, this is also what we call a fixed point in that the process of running meta, the DSL, through the meta compiler produces the same source code as the meta compiler. So the meta dot lua and meta2 dot lua have exactly the same, which is what we were expecting. I think, can you actually do the talk on the talk? Safety in compilers, yes, right? So there's some familiarity there, because we're essentially doing this idea of moving the compilers forward through compiling the previous version on the next version from the previous version, right? But it didn't start like that, right? Yeah, yeah, yeah, yeah, yeah, yeah. Where did the first thing that happened? That's a good question, right? So this is like a circular definition, right? So that's why this thing is so amazing, right? So actually, all the code is just in what you saw, right? We can ignore the meta compiler code itself, which I can show you, it just looks like a lot of code. It's actually, how many codes? How many lines of code is there? I mean, I never tested it, actually. Meta2.lua is like, well, that's okay. 214, well, it's kind of repetitive code. Repeat, repeat until and so on, so on, so on. Whereas we will always work on the level of the DSL, right? Which is only, you know, 33 lines of DSL. Oh, okay, so I forgot to tell you how big is the runtime in case you think I was cheating and everything was in the runtime, right? Because there's a runtime, right? How big is the bootstrapping compiler? So the runtime, let me show you the runtime first. The runtime is, okay, slightly bigger, 48 lines of Lua code. Let me show you the runtime, just quickly show you. There's no magic really. The runtime is to do like input, you know, read all the stuff. Some ways to move around the input. Also, we handle white space implicitly. Notice we never code anything about white space. We just sort of skip all the white space. The real deal is the read function, really. The read function just skip all the white space and reads that token. That's basically, and checks the token against these, this thing called the finder. And the finder can actually either match a regular expression, sorry, this thing, match is to do regular expression, string not match, blah, blah, blah. And then this test prefix is to do the, matching the literal string. So basically, you can see it here, right? And yeah, unfortunately we had to do strings separately. We can't do it inside. Okay, but that's all, that's all. And this is just to export the, export the, JavaScript kind of, we return a module object back to the thing that required the runtime. So we only need three functions. Well, it's an exercise to the reader to get rid of the two. We just need, if we can only do one, that's better. But so far we need three, but just like this, okay. Sorry, what was the question? Oh, how did we get, sorry, how did we get the first one? Yes, the first one, you gotta write it by hand, basically. There's no escaping, I guess, because you gotta start somewhere. So the first one, but you can write it in anything, actually. You don't have to write it in Lua, actually. You don't have to write it in Lua. You can write it in whatever language you're most familiar with. You can write it in Python or C, or you could get it from somebody else, as long as it interprets the same DSL. Can you copy it from the paper? In theory? Kind of, yes, unfortunately the paper doesn't output something you can run directly. It outputs sort of machine code. You also got to write an emulator for that machine, which you can do because there are some people who did it this way, actually, you can also find it online. Some people actually did it the way the paper did, which was output the machine code, and then run the machine code on an emulator for the machine, which is doable, which works, which works. I mean, it's just a little bit tedious. What machine is it? It's actually its own virtual machine. He devised a custom virtual machine to do this job. Yeah. It's literally just enough power to write meta. Kind of, kind of, yeah. And so that each machine instruction is quite simple to implement by itself. And it's just literally one by one. There's no back and forth or whatever. It's just literally line by line machine instructions. OK, and? It's just a shame that method.meta uses all the features of meta, because if it's used less, you could just hand write a version which only influence those that use it, and then you can place it, and then you add it. I think that was the point of meta. It has to be the minimum possible, minimum viable medical product. Yes, in a sense, yes. It is sort of the minimum viable. If there was any other option, then like, why would you? Thing was a question? What's the model equivalent of this? Like, is there anything that's like this right now? Yes. And it's everything for passing to the project. Yes, yes, yes. I will cover that at the end. OK, so I want to tell you why bootstrapping is so important, right? So let's, let's, this is not in the paper, actually. So it's something I thought of. But it's not a very good example. But never mind, let's try. What we want to extend the DSL, right? That's really where the power of bootstrapping comes in. So let me try to show you how we can do that. So let's look at the meta compiler. Again, see, this is the sort of, I think this is also like, another analogy to today's could be that in a different world is something like the Lisp interpreter written in Lisp. But that's that's sort of lying because it doesn't implement the garbage collector and all that stuff. But anyway, this is this is like the real deal because this implements everything. Like what you see is really what is generated. There's no trickery behind the scenes. Literally, because the Lisp interpreter will reuse the reader of the host list, which is kind of like, Anyway, Oh, yes, yes, I use Lua, of course. But, you know, we have to bottom out somewhere, right? I mean, that there's some bottom level which you implement things in. What am I saying? Okay, yes. So we want to extend the DSL because you might say, well, you only give me three kinds of four kinds of sort of wildcard things, right? Can either be ID, number, actually only three, because empty is not really a thing. Empty is just nothing. So number and empty, sorry. No, numbers is not. Numbers is a specific kind of string, right? So no, but I mean, you can remove it because it's not used in methods of methods that didn't have numbers. I see you are correct, I think. But I think it's for the purpose of the paper. He implements a subset of lgol60 with this compiler. So I think lgol60 would need to have some kind of numbers. Yeah, that could be why he has numbers here. Okay, but let me back to my story was, I only give you sort of three kinds of wildcard. So what if I want a floating point number? How would you write that? Well, you could, actually, you could write it, right? How would you write it? You could say it's a number followed by an optional dot and some other, some more numbers, right? Okay, I mean, you can sort of wing it. But you can imagine there are some things you can't really express in this. If I want to give you four primitives, oh, okay, three actually, empty is not really a thing. So I want to give you three primitives, number, id, and string, right? Right? Okay, so, see, actually, you know, we use the power of regular expression in Lua. So can we expose that power to the DSL writer? So what if we could let the DSL writer use regular expression? In fact, this is now very common. Of course, Lexus very commonly lets you write a token matching as a regular expression. This doesn't, you can't. But, well, let's try and make it. You're already doing it, right? You're already using the power of the DSL. No, but you can't write a particular language definition which uses regular expressions to define a token either. So you want to implement regular expressions inside Meta itself? Yes, yes. So that the DSL writers can use a regular expression to define new kinds of tokens, not just the three that I have predefined. Yeah, like dot, r, e, graph, e. Yeah. Because this is quite limited, right? Number, id, and string is just sort of, you know, what if you want other things, right? I mean, you might want. You might want an alternative definition of id, for example, you don't like my definition, it's only alphabets, and you mean you want underscore, for example. Actually, I don't know how to underscore here in IDs, which most languages do these days. They allow underscores in the identifiers, right? So maybe you disagree with my meaning of identifier. So how will we do that, right? Extend Meta, you extend the Meta. Yes, yes, but how will we do it exactly? So we have to, so we have to edit this file now. So we have to extend Meta, yes, exactly. And how will we do it? So this is the interesting thing. We don't edit any lower code directly. Like we don't edit Meta dot lower, but we could, but that would be hard. So we try not to do that. So I did this file, actually. Yeah, yeah, the dollar sign. Yes, something to do the dollar sign, actually. So how do we do it? I've done it before, but it's been a while. So let's try. So let's put it after the string. It's okay. Because we will treat it differently from a string. So we will say a regular expression starts with a hash, because I think Pearl does that or something. I don't know, I mean, just for convenience. I will say it starts with a hash and then followed by a string, right? Because it's anything, right? Anything goes. So it's a hash followed by some string, okay? So hash then the small quotes and then regular expression inside, right? Okay, so what's the code, right? So well, it's gonna look like the rest of the lines below, right? Because it's gotta save some of the input, right? So local underscore input equal underscore. So we call the run, which is our runtime library, actually parse the double quotes, single quotes, because we use double quotes in the lower code. Otherwise we get confused between the quotes. So notice the lower code uses double quotes and not single quotes. I don't know if lower, yeah, just dollar, actually. Yes, that's right. Dollar, we will finish the quotes, close the code and single quote and close this. Okay, right, should be, right? Hopefully I got it correct. Looks correct to me, okay. All right, so now that we have this, all right. So how do we get the new compiler? This is not, this doesn't run, that's the thing. This is the description of the compiler, right? This is not a compiler, huh? If you use it to me all the way. Yes, yes, yes, exactly, right? That's the only thing you can do actually. We have not more things you can do. So we actually just did this now. So we just do it again, whatever, write it again. So meta.meta, which is the new one, right? This has the regular expression stuff. Then we pass it through the old one, which is this guy, meta.lua, which didn't have the regular expression stuff, which also means we can't use the regular expression in meta.meta yet, because the old one doesn't know about regular expressions. But it knows about hash and strings and so on. And then we output this to, we call it meta with regular expressions. Let's do, kind of not mess with the name. Okay, so. But now we need to go back to meta.meta and pre-place. Yeah, that's the part I haven't thought about that. Can we do that? Yeah, we should do. We can, we can. Pretty straightforward, because you already have the red. Oh, let's just check what is meta, what's the difference in the new code? Because that will be small actually. In the new code and the old code, because we only added one more rule actually, which means we added one more alternative, actually. Not one more rule. So there's one more repeat and until block, I think. This meta.lua, oops. Oh, sorry, this is a bit messy. Let's just look at that by itself. Ah, here we go. So yeah, basically you can see what it does, right? It tests for the string, the hex, because we wanted to see the hex. And then it does some stuff. And then we check for the parse string. We stick it to the input. And then we write the code, which is to this code input and so on parse, write input, this is the code, right? And so on and then repeat. Yes, so that works. What do we say? Oh, do you want to replace the... Oh, this is the thing I actually didn't try. Okay, let's see. No, but dot ID is the literal ID. That's the literal dot ID. No, no, I can never replace this. I can replace this actually, but I will still have the other one. So it would look more messy, right? It will actually be longer. No, it will actually be longer. I could replace this dot ID with the regular expression, but it's more characters than the word dot ID. No, because then you can remove the... No, I can't, because I still need to provide dot ID to the writers of the DSL. I cannot change the DSL to not provide the dot ID, right? Oh, right. Then I'm sort of... All the programs would break if you use dot ID, right? So that's why I said this is not the perfect example, but because of this reason, actually. But what we can do is we can write... We can write... We can update the program earlier to handle floating point numbers, as I said. Then let's just see how that would look like. So let's actually use the construct because we have never actually used it before. We just defined it, right? So then let's use it now. So unfortunately, we will go back to this example because... So basically, we will not use dot number because this only matches integers, right? So let's say we want to match the... I think we got to write it as... No, no, no. What am I doing? D plus or something? Oh, right. Percent, A, D, sorry. Plus, right? Sorry, let me just look at how it's done in meta. Sorry. Oh, sorry. Meta... Meta? No, number is... No, D plus, right? D plus. D plus. I think we need a quoted dot and... Oh, we need to put this in there. This is... Oh, you're saying you need three options? Percent the... This is D star, actually, right? Because, well... Star, maybe. It's kind of ugly. No? What? Oh, multiple dots, sorry, sorry. What did I do? Oh, got a question mark. That's a good idea, that's a good idea. No, you want the whole thing to be like... No? It's actually kind of complicated. We need to say when you have a dot, you must have... No, but... Then, you optionally have a dot and... Sorry. Yeah, regular expressions is too hard, so let's not... Okay, but in theory, you can write it. Let's just not write it now, because... Yeah, just put it there exactly. I'll read the question mark outside of France. What? Will the question mark outside of France? Yeah. Ah, right, right, okay, cool, cool, cool. Sorry. I think late. Okay, yes. You cannot have a star, you must have a plus. Oh, I must have a plus. It depends, because maybe... Yeah, it depends whether you allow one dot. Some languages allow one dot, like Python. Can you remove... Yes, yes, yes, yes, remove the dot. Sorry. Okay. Hope this works, fingers crossed. Okay. Do you need white space between the... Actually, no. White space doesn't matter. A lot of ideas, okay. So we make the examples, arithmetic.lua. Oh. Hmm. Oh, yeah, yeah, sorry. It's the wrong compiler, wrong compiler. So the old compiler says, what is this hash thing? Crashes, because no idea what this hash business is. It's lua. Lua, lua, right, right. Sorry. The new compiler, right? Hopefully that works. Let's see. Oh, okay. That means it didn't blow up. Let's change the example to use that, right? Otherwise, we don't know what it actually works on. So whatever. Put it somewhere inside just to make it hard. 3.5. Okay. Moment, okay. Let's clear the screen. Moment of truth. Examples arithmetic.in. Lua. Examples arithmetic.lua. Is that... Oh. Doesn't work. The dot. It seems like I think we messed up on the dot. Yeah, you want to pass the backslash to the right guy. Yeah, yes, yes, yes, yes. That makes sense, because now I'm passing a backslash dot, which doesn't mean anything, right? It's like c, right? Backslash n. Good point. Ah, okay. What are you going to do again? Yes, yes, yes, yes. No problem. Oh, right. I did this guy, right? And then we compile it again. This guy. Let me run it again. No! Doesn't work. Well, okay. Fill demo. So... I'm sorry. Yeah, I know. I'll debug it and figure it out. Any case, if you're interested in all this code and stuff, it is on... The URL is kind of small. I'll paste it into the Meetup group, Facebook. It's all available online. Maybe you can do the example with the regular expression. Yeah. Yep. Things happen. Okay. Okay, so I want to talk about the stuff we can use today. This is, I think, 65. It was a little bit old by now. But it's still quite amazing, right? I mean, it's old stuff, but it's pretty neat. We have method other languages. If you don't like Lua, if you like JavaScript, or if you like C. And today, the thing that is the closest to meta is old meta. You can see the illusion to meta. And it actually uses passing expression grammar, which I mentioned in passing, which allows for a limited form of backtracking. Whereas in meta, there's no backtracking at all. And then the guys who did old meta actually went on to do something called OM, which is fairly similar, except OM separates the actions, the semantic actions, which is the printing of the, in this case, was just printing of some strings into a separate thing from the parser. And they actually have quite a complicated example where they write a compiler from ES5 to ES6 in OM, basically in sort of old meta, which is pretty much like meta. But they have more predicates, actually. We don't have the plus predicates, if you recall. So we only have the star. So you have other predicates more commonly used like plus, and they even have things like negation, and you can write custom expressions in the host language. We can write a lower expression that if the lower expression returns true, then we continue the rest of the pars. So that's actually very powerful. You can do things like symbol tables and things like that with predicates. That's the sort of the evolution of meta. All right. That's all I have. Thanks. Any questions? How do you come across this paper? How do I come across this paper? This was mentioned on the ACM. That's the first place I come across in two years ago. It's been a while. OK. So if you're interested, you can read up on... My internet is very slow. But there's an ACM article in the ACMQ publication on meta where this person was... OK. This person was trying to... It says 1960. I think the actual work was done in 62, but the paper came out in 64. So he sort of went through the meta compile. Actually, the more interesting thing was the lower implementation, which is actually very interesting. So this one was still talking about the virtual machine and all that stuff, which is a bit... Oh, I can show you the virtual machine stuff if you want to see it. It's just for completeness sake, but it's really a little bit ugly. Blah, blah, blah, blah, blah. So let me just skip to the end. The meta compiler written in itself. This is the meta compiler. Figure 5 is the meta compiler written in itself. It looks like this. So the out is kind of like our... We just have default by out. Out is just print something. So we don't have to out. We just print. So these are the things that are out, like the GN1 and TST and so on. So these are like opcodes to sort of a virtual machine and the BT and so on. So it's a little bit unreadable, I think. This is the original meta in meta because it generates machine code. It's a little bit hard to read. What was I going to say? Ah, yes, there is the... The Lou implementation was not written by me originally. I sort of stole it from Lou Valiant, which is over here just to give credit where credit is due. So it's mostly from here except maybe the example of the regular expression, which is the part that I did actually. And he has some other things about... Well, he has something called NoMeta for Haskell. Since we have some Haskellers in the audience, you can check it out into this kind of stuff. Yep, that's it. Other questions? I really like this kind of, you know, something that outputs itself. So if you see more of that, let me know. I think I'll be pretty interested. Okay, so let's just close off the papers we left, I think. So I'm also the...