 Well here everybody it's the last day before the well last class before the midterm I guess Just The person that asked me the first question before class raise their hand and re-ask that question Yeah, our random person in the audience. Yes Right, so the question is on project three should we assume that the test cases are all single letter Terminals and non-terminals. No, they're strange. Why? How do you know? In the project description there's explicit definitions for what the tokens are what they're made of right and so The other way to think about this is to think like me Right, you're the professor. I have to evaluate these things you want to evaluate Not just can you code it but the main thing you try to evaluate is are you following the specification and implementing a program that does all of this specification, right, so if you think about you think about the specification says I want a program that looks like this Right, that's what the specification says and so test cases are really just points inside here Right, but I'm testing like some specific functionality So if the description says that tokens and non-terminals can be any length and the test cases that were given you are only of length one Probably safe to assume that other test cases are testing others. So like all those one unit test cases are all in here Right, so if your program is only doing this you're not doing the entire specification, right? So that's why we're going to test other things and if you think about it like this We may test things close to the border Right, what we know we're not gonna do is we're not gonna give you something outside So I'm not gonna be something that's invalid. That could be another way to test these things Right, so what you kind of want to think about are what are the bounds? What are So what could be what kind of things other than harping that you can like do wrong in your project freeze? Lexer. Yes Not modifying a Lexer Right, so we did modify the Lexer. What are some key words in the Lexer from project two if so, could you create a In our project three-grammer, can you create a non-terminal or a terminal that's called hit? Yeah, so that work Yes That's testing another point in this Specification what are some other things? What about when you calculate your first that's how should you calculate let's say first sets? What's our algorithm like at a super high level for calculating first sets? Take each rule. What are the things? Yeah initialize, so why do we initialize everything with empty set? That's possible that they're all empty What do we do? We want to write our first sets algorithm in a recursive way. Do we do that recursively? when we did it by hand Calculating first sets Interative iterative right we're iterating over all the rules in the grammar and then all the rules in our first set How are we thinking we're iterating over all non-terminals in our grammar then for each non-terminal? We iterate for every rule that that non-terminal for first sets appears on the left-hand side We're iterating to find all five of those rules that we have to see how that changes the first set What we're not doing is we're not saying the first of a is on the left-hand side Is the first of B so then we recursively call calculate first of B Because what if B is something like B goes to A? This is why we initialize everything that empty first sets did not have this problem Yes What is the condition Is there a way to keep that like in a program? So one way is to use a flag Okay, you can have a Boolean flag at the beginning you set change to zero and then anytime you make a change to a first set You set it to one Another way to do it would be to make complete copies of the first sets Right create a through whatever Non-terminal you have created copies so call it old A old B old C whatever old first sets Right calculate the new first sets and then compare them all right if you compare them all and they're all not They all have not changed then you know you're good Where's some other common problems? That maybe you can have like projects To what were the sum of bugs there? segmentation fault Is the silent killer of project 3s? right so That's actually hard because it's just our regular test and your program does this thing but crashes over on these inputs Right, and so when you're generating test cases if you're not generating test cases that could potentially crash your program But are still valid inputs Then you're not going to pass the test cases right So you have to be very careful while you should so when we say so one of the main causes of a segmentation Yeah, so no memory not allocated. So trying to do you usually it's trying to dereference a null value So what are the ways you can dereference something in C or C plus plus? Star operator so if I have some pointer And I have star pointer If this the address that's in here is zero or null It's going to cause a segmentation fault. What's the other way of accessing? Do you have to take a pointer? What's the difference between these two? Yeah, so this really means all this is is syntactic shorthand for pointer dot food Right, so actually in this case pointer to use the error syntax pointer The typing pointer must point to a struct Because you're accessing a specific field in that structure in C But really what you're doing is just dereferencing and accessing that field. This is the exact same syntax. So At any place in your code you are doing dereferencing of pointers You better make sure that you're pointing to the correct thing and that that thing exists There is something to point to if you're pointing to null then you have a problem So I could be test cases right you want to look at your program and see How like measure the code coverage of your own program on the test cases that you have maybe you're not Exercising all of your code and there's a bug in some parts of your code that are not being exercised So then you can think how can I make a test case that exercises that code? It's likely that our test cases are exercising that code right similarly between any pointer dereference Make sure it's not null. That's like the first thing you can do and think about why like proof to yourself Can it ever be null? Throughout all paths throughout the program from main to this point where you're dereferencing it could it ever be null? these are the Of like every project besides logic problems, so there could be a logic problem sometimes Especially what are some common logic problems? How do you compare character pointers in C? Yeah Right you have to use this function You cannot say if you have two character pointers and food and bar You can't say does food equal equal to bar? This is not going to work. You also may need to depending on how you're using sets If you're using a set library or using a list library, how does that set test for equality? Does it if you're using character pointers? Does it actually use string compare to compare strings or is it using the equality operator to compare strings? Okay, because you want to say it is epsilon in this set Well, how do you do that? I think there's a pretty much 90% of the errors and bugs that I've seen throughout the years of student brain coding. It's one of these cases Yes read the documentation. Oh, yes of your whatever reason for sets or lists. Yes, you need to figure out How does it compare your quality? So what if we want to change that through your own loader? Depends on the specific way Depends on the specific class that you're using. Sometimes you can define an equality operator Sometimes you may have to do it yourself. You may have to iterate over that set and use string compare to compare what you're preparing to Right, you can define a function called is it in this set Using string compare or whatever, right? So you can definitely help yourself out Well Another project three questions Keep these in mind These are the core problems and then back to scoping Okay, so it's a little weird because we're starting off mid execution of this program Yes Yes Okay Oh No, because they don't have actual blocks by default in C when you do a case You don't actually include the braces, right? I believe so I'm not 100% on that. You have to check the exact syntax Perfect See something you've learned in here helping programing projects amazing, right? Who knew this stuff was actually relevant? Cool. Okay so to refresh our memories to Revive this discussion of where we are So we've talked about static scoping which looks specifically at The scope in the program so a program C is valid this Declaration of this variable C is valid only in this block and any children of that block Statically and we can do this by looking at this. We don't have to execute the program We don't have to think about the execution. We can map each usage to a declaration and we can do that statically The flip side is dynamic scoping and that's what we're looking at here where as we've seen we step through this code we executed so this top-level box here is the symbol table that is being dynamically built as this program is executed and It's been dynamically built. So we have x bar foo bas The body of bar and then main and then we have the types of those variables and here in the third column So we see that x currently has an integer 10 and the arrows kind of show us where we where our execution went, right? So we First went up here. We set x to be 10 But when we saw this usage of x Right dynamically at runtime. We need to look it up and say what does this x refer to? So this x we look up in our symbol table from the most recent Block in our simple table to the oldest. So in this case, it's gonna be from the bottom to the top. Yes So with the name xoping then I can tell There's an x that's a char and a character. They can tell what you can tell which one is Being called No, so it cannot Is simply looking at name matching So it's not trying to say which x is this most likely because I'm pairing this x to an integer Which means it should also be an integer That's something actually completely different, which is type inference We'll look at later or you can actually do cool stuff like that Yep Then when it gets to that point in the program and said hey, I tried to use x It should be an integer because it's been used here, but it's actually a character pointer. So throw an exception If it see it will not throw an exception. I'll just do it, right, which is why I see is not great We'll just say sure. Yeah, I think the prayers those they're not equal good Okay, so we set this x to be 10 We saw that we went inside here when we went inside this block now we're creating a new block in our symbol table Where we have here x which is a character pointer which has the string testing or points to the string testing And then we print out x and here we have a usage of x Right and the reason why this x is not mapped to this integer is because we use this table Right. We don't care about statically what happens. We don't look at the code We look at the symbol table and we see looking from the bottom up. Where's the first instance of x? Right here So this is the x that we're printing out and that's what this x refers to and From this point, it's been exactly the same, right? This is the same behavior as statically the key is that this mapping is being done dynamically while the program is Executing whereas in static the compiler does it before it ever x before the program ever executed Okay, so now once we leave this block We no longer have that symbol table entry that's associated with that block It goes away the block is out of scope and now we're calling foo So now we jump into foo when we get to foo we start a new block and inside this block There's one character declaration of a variable C which has the character C inside of it Then foo is called and foo calls bar and now we're inside again another Another basic another block so a new scope So we create a new block entry in our symbol table and here we say there's an integer x that has value 100 and Then we call Baz so again we get into a new block, but here we have no Scope so we don't create we don't have to create a new Entry sorry, there's no declaration here and now I get to this line And I say what x is this which x does this refer to? What's the value of that x? 100 so this x Whereas before and this is the big difference where things start to change right before this x Referred to this declaration of x constantly Anytime this line is executed this x always referred to this global x But here in dynamic scoping because the path we took through this program One of those blocks declared a new x That x is then available to any function that gets called So now when we reference x, we're actually referencing this x inside bar So this x references bar. It's going to should print out a hundred and it's not going to reference this x, right? Even though statically that's what would happen. This is the key difference with dynamically and we can see that this would change if we didn't call Let's say we called Baz from food instead of bar Then this x would then refer to the global x and refer to 10 because there is no other x in essentially This represents basically the call stack right now, right we have As which has no Declaration so it's not on here. We have as then we have bar then we have food then we have the global scope So this represents the call chain that we're currently at Well, then we set x to 1337 Has to do the same thing right it has to resolve that usage of x to that declaration of x and say okay This x maps to this thing, so I'm going to change this to be 1337 So that when we leave this scope, right? We're going to return back to whoever called us and So when we return here, we clean up the scope associated with this in our simple table, but there is no scope associated here So then we get to bar we get to the end of bar and then what happens here? What how's our simple table change now? We remove the last one right now this x is no longer in scope All right, so it goes away We can never we can no longer access that variable x Went away now we get here and we say print out the values of x and c What x does it resolve to or see revolve to see? Right, so we look up. We see a name of C. We see the value C And we look up x and we see x is first in this global x of 10 So it should print out 10 C and then we get out from here This block goes away, and then finally get to the end And if we had any more we that would execute over at that So if we had a version of GCC that supported dynamic scoping which does not currently exist And so you have to make this up But if we were using a version of GCC that was exactly the same semantics except for dynamic scoping If we compiled this it would hopefully well I guess if I use the W all it should tell me that I don't have a return value for me So bad me warning, but It doesn't because it's not real and Then if we were to run this fake imaginary program it would say testing 100 and 10 C This is different from the static-scoping That should be right We would start screwing things up and not know why it was screwed up That's a disadvantage. What would be a clear advantage to this method, right? So I'll post that to everyone why what could be the use of something like this, right? So I guess I don't know. I guess it's a matter of preference Is it a disadvantage because you don't understand how to use it in the semantics and you're not used to it Maybe say that about anything right my list has a bunch of parentheses if you try to read this it just looks insane But over time that syntax goes away, and that's just a syntactic issue that you start to understand and feel with right Look at me some benefits of dynamic scoping or drawbacks Harder to read is actually harder to read or what is it harder to do? Mm-hmm Yeah, so that's a great point right so I decided to enter X here now If I print it out or use X after bass Right, I have absolutely no way of knowing what could be that value of X because Bass could change it anything that bass calls could change it anything that that library calls could change it Anything that that library calls could change it, right? It would be hundreds of calls Anybody that alters a variable X is going to alter my X Right, so yeah, I wouldn't I wouldn't say necessarily it's harder to read in the sense of light just mechanical Seeing what's going on. It's harder to reason about what is going to be the behavior of my program Right. I'll be a drawback. What else? Yeah, so this is actually in It's actually kind of funny so it's it's basically a way to kind of do global variables It's like a poor man's global variables Right because you can and actually and for configuration and that kind of stuff so maybe you have some configurations that You know you can have and they don't necessarily to me think about it, right? Let's say system a call system be called system C All right, and system C has some configuration parameters But you as a if you want to pass those parameters to see Then this intermediate library be better be able to take your parameters and then pass it to see to change the AC or C Right, it doesn't do that Then you have to change be yourself to do these past things and you have to change everything But if these are just Variables that C is reading from in dynamic scoping you can define those variables and set their values and C will pick them up And so you don't need to care about who's in in your intermediaries to pass your configuration options Ultimately to see Yeah, it would be that Shadowed the work copies of variables So yeah, you can think about like a library that's like it's a middleman library, but it's not doing much It's just kind of passing stuff around or like actually on emacs. It uses this a lot. So like dynamic variables are There's different each buffer is window you're looking at has like global variables like the number of you want double spaces after every period or What's the size of the window of text that you want or something like that? And so when you instantiate a new buffer, you can do that easily by just changing the values that you want Can you simulate this by passing anything by reference? No, well Could you yes the problem is is So for every function you have to basically take in this table Right every function needs to have the current symbol table to be able to read from it Right, you can't just change because bad as you can't just say it passes in a reference to x because bad Itself may not use an x and any function that bad calls may then modify x. So then you have to pass x along that way Well, actually look at pass by reference and pass by Value all that kind of stuff later So another benefit which may not be quite so so we're thinking a lot and the on the usage side right, but on the writing actually a compiler or an interpreter It's actually pretty easy. I mean You can do this you can interpret this line by line and build this symbol table as you're interpreting it There's just a hash table, right? I mean basically and then you have different scopes you create a nice table you create a lookup function And so it's actually really easy to write an interpreter So Diana token is actually easier to implement than static scoping I would say it's probably It's probably faster for compilation. It's slower for execution Because for every variable usage you have to look up what variable are you referring to now? Right, whereas in C it actually as we'll see eventually it assigns memory locations to all of these like for this global x It's going to sign a fixed address of 0804 005 a and then anytime here It says I know this extra version this global x. This means I set memory address 0804 005 a to 1 3 3 7 right that's one a set in assembly instruction Whereas here in dynamic scoping when it gets in this line It says okay, I need to look up in the table what who has the memory address of X the name and then it has to look this up in this table So it's a much more It's a slower process Before Yes The list the lists are The big example so in common list you actually can specify a per variable basis You can say this variable. I want this to be dynamically scope and other variables are statically scope emacs list which is a derivative of list that max is written in I think it's called you list It's all dynamic scoping so it's way different And so yeah, I believe I remember correctly like early versions of Your Python or Ruby of one of those scripting languages use dynamic scoping because it was way easier to implement Even like a printf and may be just change it to Correct unless the compiler was super smart and was able to analyze and say even though. I know I'm doing dynamic scoping I know that this x will always refer to this x because it's in the same scope Right so in this case it may be able to check it But in the general case like this x this x could be a character pointer right now, right? So that should be an error So yeah, so you do get more a little more benefits from static scoping in that you can Do type errors because you know the usage of every type When you see then a name, you know exactly what the type is of that name Where's the dynamic scoping the type of that name can depend on the path and execution No No semantics on the midterm up till syntax analysis Anything from syntax analysis any questions on this thing, okay so We've been talking about basically essentially right now. We've been talking about resolving variable names right and trying to say Actually, okay, so another cool thing we didn't talk about And I didn't actually include in here right but even here when we see a call to a function foo How do we know which function foo we're talking about in dynamic scoping? We have to look it up in the symbol table and map foo to the function on line for So this actually gives you then very powerful capabilities if I wanted to Overwrite or hook a function in a different library and say I really hate the way they're comparing strings I'm just going to define in my scope a string comparing function, and I know that library is going to use that function Right, so that's actually a pretty powerful primitive to be able to Hook other functions and say I want to execute my function instead of your Bring it back, although that's that's actually a very good question. That's more on Class and class hierarchy and like super classes and sub classes and being able to like hide your parent caller Yeah, it's very similar, but think about that apply to anything You could overwrite any function in any library or whatever to do what your specific program It's actually super handy sometimes So I keep that's all keep plugging list list also has super cool ways to like Like common list you can define all different types of You can like completely replace a function with your own function You can also they have like before or after hooks where you can say before this function runs I want to run this little some code that does something first. Maybe it translates Parameters or something or you can hook the after of a function so you can do stuff after a function's call. Anyways, it's really cool kind of like if you ever play with Can't remember the name of the Python Where you can augment functions with like an act symbol or something like you can have attributes of functions that do other things so you can Okay, so Okay, so we've been talking names right how do we resolve variable names to the instances of that variable, right? How do we resolve a usage to a declaration? That's what we've been looking at and we looked at two different types static and dynamic Now I want to think about when you write your programs. How does the compiler know when you call a function? How does that actually know which function to call? The whole point of this class is there's no magic involved just like we just looked at is when you write a variable name specifically how to compile it figure out what thing you mean Right, that's the scope in rules and the scope in strategy So now we want to see when you see a function call which function gets called So how does work in like C? So how does it how does it figure out? Almost yes, yeah, so but what is it looking for specifically? How is it? So is it does so Right so it function Yeah, so The key question is and think about your different programming languages that you use right when you write When you define a function or to find several functions and you're calling a function How how does the compiler and how do you because you're writing this? How do you know which function is going to get called? so With names, what would this be if we're just using the name? Yeah, wait So wait, so okay Okay, so in C. So how does C specifically do function resolution? Was it Name just the name doesn't matter You can't you actually can't define a function in the same scope that has a different number of arguments in C Because in C a function is its name that is it So when you see a function call the way you look up which function that maps to is just comparing the names So what else could you do? You're a language designer you could look at just the name. What are the pros and cons there only one name for a function? I mean is that well, but isn't that good that you want one name for a function? Do you want to call a function by multiple names? like have length and size and number of elements and Doesn't that be crazy when you're programming Java and like arrays are what is it dot length? But lists are dot size method I guess oh it is relevant because do you want like so do you want multiple names for the same function? What's probably more for them? So how so let's say you only have functions. We're not even considering objects right now, right? Take it back to simple C So what's the scope of functions? Can you define a function inside of a function in C? Could you I mean we'll talk about that later, right? But that would mean that a function would be local to only that scope, right? We can't do that in C. So all your functions have to be what scope? global They have global scope and Function resolution is just on names. What are the pros and cons? continuity in one sense you're working on it with Right, yeah, so when you're looking it helps it can help readability when you're looking at code and you see a function called You can go to the exact definition of that function, right? There's no ambiguity You know when you see string compare str cmp. It is the string compare function Of course assuming they actually included the string.h or whatever header file you need for that and didn't define their own string compare because otherwise You have major problems Right, so names can be so just doing names. We good. What's the downside? Why would you want to function the same name different parameters? That sounds confusing to me? So getting example yet in the back. Yeah, so let's say Like well, there's a couple ways you can go. Yeah, you can do comparison, right? So like you have str cmp string compare Do would you ever want to compare two integers? You don't ever want to know two integers or less than or equal to each other You can't use that function, right the string compare that name str cmp Well, let's say you wanted to write just a cmp function Right now we have to choose. What do we want to compare? Do we compare character pointers? Do we compare integers? What about doubles? What's the difference between comparing doubles and integers? Nothing, right? I mean to us as the program. We don't really care. I just want to compare these things right and So if I only use names to look up things then I cannot define a function So every function has to have a specific number of parameters and each of the prayers has to have the exact Same type so you cannot write a function or think about like a function like Maximum or something right that takes in let's say two integers and returns you the max integer That's kind of crappy because then you have to write a max three function That takes in three integers if you ever want to compare three integers and the max four function that takes in four integers as parameters Right now you start getting into this crazy nonsense. So then To solve this problem, what can we do for function resolution? What can we start looking at maybe then? Number of parameters, so we look at number of Okay, we look at the number of parameters. What else though would that help us in our cmp example? Compare the type of parameters. We're looking at the type of parameters Well Return value why would we want to look at the return value? Yeah, right, maybe we want two types of return one that returns Yes, so that's So if I have like void cmp and int cmp Right, and then I have a function called cmp Which one should get called? Why? Because it's not returning any value. But is this valid C code? Do you have to use the return value? No Maybe I don't want the return type in this specific instance Right, maybe I just want the side effects of calling the cmp function All right, so We'll look at it in C C like languages you don't use the return type, but you can or when we get into Type inference and being able to refer the types everywhere. You actually can use the return value to select the function So we use names we use names plus return types We use names plus parameter numbers, which is all the stuff we were talking about we use names parameter numbers parameter types and so really What this refers to and maybe for the term function signature before well, okay, you're learning of the term function signature so this These rules of what does it mean to actually like how do we refer to functions? If we're just referring to them by name and the signature is just the name Right, we know when we see SDR CMP it matched to one specific function And that's all we need to know when we look at the call to SDR CMP We don't need to care about how many parameters are being called We will have to do that to worry about if that matches Semantically with what we're trying to call but at least I know exactly which function should be called But if I'm using Names parameter number and parameter types that I had better have a way to Specify that right now would be the function signature. So for instance here Somebody dialing into a well Okay, awesome, let's do this function signatures. That's super cool All right Right, so here if we think about the function signature Right here for this CMP function. We have CMP usually we'll write it like this So the name of the function and then a vector of do I care that this is named x and this is named a No, I care that this is made why this name B No, so this is the name comparison and the parameter types are an integer and an integer and this one is CMP in Int int so these have the exact same function signature because in Let's say this line with we don't care about the return types But if I change this into a double right now this function signature changes to a double And now these are different functions Then the question is that when I invoke this function time map it back to the correct place Well, all right Okay, so for midterm on Friday try to come early So that and when you sit don't we have 230 people in a room for four hundred thirty eight So don't sit next to somebody spread out Come early, so you get the midterms the ta's will be procuring I don't have a lot of people watching everything. Don't make me