 Hi, welcome back to part two of this lecture on operational semantics in the program analysis course. So what we'll do in this second part is to now define the abstract syntax of a language, which is called SIP for simple imperative language. And this will be the basis of eventually defining the semantics of this language. But before going into the semantics, we first have to define the syntax so that you know what kinds of programs are actually part of the language. So SIP is a toy language. It's not a real programming language that people have implemented and use, but it's just a simple imperative language that has been created for the purpose of showing how you can define the meaning of a language. It nevertheless has a couple of features that you'll know from normal programming languages. In particular, it does have assignments. So you can assign some values to some variables. It supports sequencing, which essentially just means that you can have one statement followed by another. It also has conditionals, which means you can have branches and depending on the outcome of some conditional expression either go this way or that way. It'll also have loops, so you can execute things many, many times. And in terms of types and variables, the only real variable that we have are integer variables. So everything is about integers and performing operations on these integers. Now in order to define what is part of this language, we're going to define its abstract syntax. So we are not going to define a concrete syntax. I will use a concrete syntax on some of the slides, but what we'll define here is just the abstract syntax and the concrete syntax. You can derive it from the way I'm using that language. So looking at the abstract syntax, we can say that a program has what we call a program P and each of these syntax rules is defined using one of these rules that you see here. We're saying a program can be one of three things. So either it's a command and we'll define what this command C is or it is an expression and we'll also define that or it's a boolean expression. So the expressions E are integer expressions. They do evaluate to an integer number, whereas the expressions B are boolean expressions, which means they evaluate to either true or false. So let's look more into these three ingredients of programs, commands, expressions and boolean expressions and let's start with the commands. So one kind of command is a command that consists of two other commands. And this is what you'll use to have not just one single command in your program, but chain them together. And this is therefore called a sequence. So you essentially take a command C1, put a semicolon in between and then have another command C2. Another kind of command is about assignments, where we have some location into which we are assigning, let's call this L, and we are assigning the value of some integer expression E. So what this is, is an assignment of an expression E to some label or location L. Then I also said we have conditionals in our language and the abstract syntax for this is that we have a node in the abstract syntax tree called if, which has three children. One for a boolean expression that determines whether we go left or right. And then two commands C1 and C2 that I executed depending on whether the condition is evaluated to true or false. So this is very similar to an if statement that you probably know from every programming language. So this is called also a two-way selector. Next, simp also supports loops. More specifically, it has while loops. So those are trees in the abstract syntax tree that have a while node with two children, one for the boolean expression that determines whether we go left or right. And that determines whether we go into the loop and then a command C, which is essentially the body of this loop. And then finally, we have the most simple kind of command in this language, which is called skip. And skip does exactly what the name suggests, which is that it's doing nothing. And now you may wonder why on earth do we really need this command called skip. And the reason is simply that we'll use this while defining the semantics of this language to say that nothing has to be done anymore. Instead of drawing all these nice syntax trees, I can also use a textual notation, which I'll just write down here. And as you'll see, it's much more compact than the notation where I'm explicitly drawing the trees. And I'm using this textual notation for the rest of the syntax. So in the textual notation, we will say that a command consists of either one command followed by a semicolon and then another command or by some label, which gets assigned the value of an expression or an if statement where we have an if followed by a boolean expression. And then and then branch where we execute C1 and then else branch where we execute C2. Or a command can also be a while loop where we have while some boolean expression do some command C. And finally, a command can also just be a skip command. So now remember, we said a program can either be a command and integer expression or a boolean expression. So let's also define the two kinds of commands that we have not yet defined here. And let's start with the integer expressions. So an integer expression is denoted with E. And now we use the textual syntax to define what kinds of integer expressions our language supports. One of them is this exclamation mark followed by L, which essentially means we are loading the value stored at some location or denoted with some label. Or we can have an integer expression that is simply a number. Or we can have a more complex integer expression by taking some expression and combining it through an operator with another expression. Now let's also look at what these different symbols mean. So first of all, this op can be one of the following operators. It could be a plus or a minus or multiplication or division. And then I'm using some more symbols here. So N is just any integer. L is a label or also called location within a set of memory locations L. So this is a set of locations L1, L2, sorry, L0, L1 and so on of memory locations. And then I was using this notation with the exclamation mark, exclamation mark L. And this is a way to express that we are retrieving a value that is stored at a location L. So we're basically reading a value from memory. And finally our language also has boolean expressions. So let's also define how they look like. So a boolean expression is denoted by capital B and it can either be true or false. So this is probably what you've expected. And then of course you can also evaluate more complex expressions to either true or false by taking some integer expression E and combining it with a boolean operator with some other integer expression. Or you can also negate a boolean expression or you can take the logical end of two boolean expressions. And now I still need to tell you what these boolean operators are and in the simple language there are three of them. One is greater than, the other is less than and then we also have equals. So just note that for equals we just use the single equals here and for assignment we actually use the column equals. So just make sure that you do not confuse these two. So now that we've defined the syntax of the language let's have a look at some programs written in this language. So let's have a look at some examples. So one program is the following where we say there's a variable Z and we are assigning the value of X to it and then have a semicolon. So we have some statements that follow afterwards and these will be two statements which just to show how this is passed into the abstract syntax tree. So I put parentheses around and the first of those is taking the value that is currently stored in Y and assigns it to X. And then the second statement is taking the value that is currently stored in Z and assigns it to Y. So now you can stop the video for a second and maybe think about what this program is actually doing. And what it is doing is to swap the values that are in X and Y by using Z just as a temporary variable. So now this uses a concrete syntax to write down a specific program and once we have a program we can represent it using our abstract syntax by drawing an abstract syntax tree. So let's just do this. The top level element here will be the semicolon which is the first semicolon in the program. It has two children for the two commands that are chained together using this semicolon. And the first of them is this assignment that you see at the beginning where we have on the left side the variable Z and on the right side this read of the variable X. And on the right side of this first sequence put together through a semicolon we have two more commands that each happen to be another assignment. One that assigns the value of Y to X and another one that assigns the value of Z to Y. So this here now is the complete AST for this little simp program. As a second slightly more complex example let's have a look at a program that contains a loop. And in the second example we are using then our while construct where we define some condition which here happens to be that the value of L needs to be larger than zero. And while this is the case we want to do the following. So first of all we want to assign something to variable or label F where we take the old value of F and then multiply it with the current value of L. And then after that we are also updating L by taking the old value of L minus one. Now if you look at this code you'll probably see that this is the factorial function. Let's now have a look at how this is represented in our abstract syntax. And again this is a point in the lecture where you may want to stop the video and just try it yourself and really draw it to double check that you've understood these ideas. So the AST for this piece of code will have a while loop node at the very top because that's the outermost structural element here. And then as you've seen while nodes have two children one for the condition and one for the body. So one for the condition happens to be a Boolean expression which uses this Boolean operator greater than which has two children namely the integer expression that will return the value of L and this other integer expression that returns just a number zero. And then in the while loop we have a command and this command happens to be a sequence of two commands. So we have the semicolon and each of these commands is an assignment one that assigns to F and on the right side we have some integer expression that evaluates to value that is then assigned to F. So the integer expression uses this operator for multiplication which takes two operands namely the value of F and the value of L. And now let's have a look at the remaining part of the tree so this other assignment which is writing into location L. And what it is writing is also the result of an integer expression where we take the minus operator and apply it to the value of L and two one. All right so this is already the end of the second part of the lecture on operational semantics. You now know the syntax of our little simple language and in the next parts of the lecture we'll actually assign some semantics some meaning to the syntax so that we can also say what these programs really mean. So we've only defined how programs look like and the next step is to define their meaning. Thank you very much for listening and see you next time.