Welcome back. In this video, we're going to take a little digression and talk about formal languages. A formal language has played a big role in theoretical computer science but they're also very important in compilers because inside of the compiler, we typically have several different formal languages that we're manipulating. A regular expressions are one example of a formal language but it's actually helpful I think in understanding regular languages and all the formal languages we'll see later on in later videos to talk about what the formal languages in general, So, let's begin with the definition. A formal language has an alphabet, So, some set of letter sigma. And then a language over that alphabet is just a set of strings of the characters drawn from the alphabet. So in the case or regular languages, we had certain ways of building up sets of strings of characters but other kinds of languages would have different sets of strings. And in general, a formal language is just any set of strings over some alphabet. An example of a language that you're familiar with is a form from the alphabet of English characters and it is just the set of English sentences. Now, This is not quite a formal language and that we might disagree in which string of English characters are in fact valid English sentences but one could imagine that we could define some rules that we would say the certain strings are English sentences and others aren't. And if we could come to this on agreement this would be a fully formal language. Now a much more rigorous formal language would be something like the following; we could pick our alphabet to be the asking character set and the language to be the set of all Valid C program. So this is definitely a very well defined language. This is exactly the set of inputs that C compilers will accept. And the, the important contrast I want to draw here is that the alphabet is actually interesting. So, different formal languages, you know? Have a very, very different alphabets and we can't really talk a bout what the formal language is or what sort of strings we're interested in unless to find that alphabet. Another important concept for many formal languages is a meaning function. Typically we have one of the strings in our language and let's call that some expression e and the expression e by itself is just a piece of syntax. It's a program in some sense or it represents something else that we're, Which is the thing we're actually interested in. And so we have a Function L that maps the strings in the language to their meanings. And so for example in the case of the regular expressions, this would be a regular expression. And that would be map to a set of strings. The regular language that, that regular expression to notes and we saw an example where we wrote out the meeting function for regular expression last time so let's use regular expressions as an example and I'm gonna first write down the meaning of the regular expressions. The way I wrote it down in the last video so if you recall we had a regular expression epsilon and that denoted a set, Which contain just one string, namely the empty string. And then we had a regular expression C for every character in the alphabet which also do need a socketing just one string namely the single character C. And then, we had a bunch of compound expressions. So for example, A + B. That was equal to the union of the sets A and B and we had the concatenation so I could, I could [inaudible] A and B and that was equal to a cross product where I selected a string from each set in order and concatenated them together. And finally there was iteration so I could write a star and that was the union over I. Greater than zero of all the sets A to the I, I ends. An interesting thing about this definition is you can see that they were mapping, over we have expressions and let me switch colors here, over here we have expressions and over here we have the sets. But there's something kind of odd about the way this is written and not quite right cuz you can see here we clearly, we have an expression. We have a piece of syntax A + B and then somehow on the other side this, this A, this A and this B have magically turned into sets that we're taking the union of and similarly down here we're choosing an element from this set but this set is also an expression and what does that mean? Somehow we're conflating the sets in the expressions and this is what. The meaning function is intended to fix and this what they, or, or, or intended to make clear. So we, what we really wanted to say is that there's some mapping, That the language L epsilon is the set so the, so L maps from expressions into sets of strings. Okay, It's a function that maps one to the other and it you haven't seen this notation before, this is a standard notation for describing functions. It does says that L is a function from things in the domain, in this domain to this range, okay. And similarly the language of this expression is the set and it becomes really useful for the compound expressions cuz here we say the language of this expression. Is equal to the language of a union with the language of B and now you can see the recursion. First we interpret A and B using L and we take the union of the result. Okay, so now it's clear what's asset and what's an expression and similarly here the language of a concatenated with B, we are going to select elements from the language of these two expressions and then we're going to form another set from those two sets. And finally for iteration, The language of a star is equal to the union over the meaning of a bunch of expressions, A to the I is an expression. This is a, a piece of syntax and we have to convert it to A set N order to take the union. And so about this, is. The proper definition of the meaning of regular expressions where we've made the meaning function L explicit and we've shown exactly how recursively we apply L to decompose the compound expressions into several expressions that we compute the meaning of and then computed the sets from those from those separate smaller s ets. So, there's other reasons for using a meeting function. We just saw one of them which is to make clear. What is syntax and what is semantics in our definitions. Some parts of the definition are expression and some parts are the, the meanings or the sets and the using L makes it clear that the arguments to L are the, the programs or the expressions and the results Are the, the sets. The outputs are the sets, But there are a couple of other reasons for separating syntax and semantics. One, is that it allows us to consider notation as a separate issue. That is if we have syntax and semantics being different, then we can vary the syntax while we keep the semantics the same and we might discover. That there, that some kinds of syntax are better than others for the problems that we're interested in, for the languages that we're interested in. And another reason for separating the two is because of expressions and meanings because syntax and semantics are not in one to one correspondents. And I actually illustrated this with regular expressions in the previous video but I want to iterate here that, that there are generally many more expressions than there are meanings so that means there maybe multiple way. To write an expression that means the same thing. I'd like to take a moment to illustrate why separating syntax from semantics is beneficial for a notation. So, everybody's familiar with the, the r number system so I can write numbers like zero, one. 42 and 107 and there are very nice algorithms for describing how you add and subtract and multiply such numbers but there are older systems of notation for numbers. Things like the Roman numerals. I could have the number one. I could have the number four, the number ten and say the number 40 I think is written like that and. And an issue with this number system, first of all, let me stress that these two have the same meaning. So the, the meanings of expressions in this language are. Are the integers and it's exactly the same in this language. So the idea, the mean ing of these two systems are just the numbers but the notation is extremely different. The number written in Roman numerals was completely different from a number written in Arabic numerals. And the fact is that the Roman numerals are really painfully to do addition and subtraction and multiplication and in fact. Back in ancient times when this was a common system was not very well known how to do it and very few people were actually good at doing arithmetic with, with the system because of, because the algorithms were kind of complicated. And, when we moved to the, the Arabic system, later, That it was a big improvement because people, it was easier for people to learn how to do basic arithmetic with these kinds of numbers. And the only thing that changed between one system and the other was the system of notation. And so, notation is extremely important because it governs how you think and it governs the kinds of things you can say and the sort of procedures that you will use. So don't underestimate the importance of notation and this is one reason for separating syntax from semantics because we can leave the idea of what we're trying to do than numbers alone. And play with, with different ways of representing them and we might discover that some ways are better than others. The third reason I gave for separating syntax and semantics is that in many interesting languages, multiple expressions, multiple pieces of syntax will have the same semantics. Now going back again to regular expressions, let's consider the regular expression zero. Now there are many ways to write the same language which is the language of all strings of zeroes so string of zeroes of any length. So for example I could also write that as zero + zero. Another way to write it is as epsilon + zero, zero and here you can see that, that this expression is all the strings of 0s of at least link one and then we get the empty string for epsilon so that is = zero and then just, you know? Any combination of these things would also amount to an eq uivalent language for example that one and so on. So there's actually an unbounded, unlimited number of way I could write this language but all of these mean exactly the same thing and if you think about it. What this means is that in general, if I draw the two domains differently, I think about different expressions over here and different distinct meanings over here and the function L that maps between them. The function L is many to one. So there are. Yeah. There are points in the space that where many different expressions or pieces of syntax map to the same meaning. And this is just a general characteristic of Interesting formal languages and this is actually extremely important in compilers because this is the basis of optimization. The fact that there are many different programs that are actually functionally equivalent, that's what allows us to substitute one program that runs faster than another, that's what allows us to replace one program with another if it runs faster and does exactly the same thing. So we couldn't do optimization and, you know the reason we can do optimization as precisely because the meaning function is many to one. So meaning is many to one and keep in mind, important point here it's never one to many. We don't want the opposite situation. If we have the opposite situation, Where L could map a single point to two different meanings. Well first of all, this would no longer be a function but, but also it would mean that the meaning of certain expressions say in our programming language was not well defined. That's that when you wrote a program was actually ambiguous whether it meant this or it meant that and that's a situation we don't like. So, we expect meaning functions to be many to one for nontrivial languages and we don't want them ever to be one too many. And that concludes today's video. Next time, Going to go back and continue with our discussion of lexical analysis.