字幕表 動画を再生する 英語字幕をプリント Last time we looked at the problem - or the great advantage, if you like - of using intermediate codes as a staging point in our compilers. And we spent a lot of effort talking about how to improve your compiler, but still on the same machine, but with an intermediate code step. I would strongly advise you to watch that video first because what we're now going to find, in this next one we're doing, is we're just changing the rules slightly. instead of B* (improved binary) we're moving from B' to B''. We are generating a different binary for a completely different architecture. But we are using the front ends that we've already established that get us as far as intermediate code. What we're now talking about is: "How can I produce a new back end?" And you will find that the diagrams I draw are remarkably similar to the ones on a single machine, for improving yourself. So do watch that one first unless you're absolutely sure that you've taken every single thing it said(!) And then we can go on the adventure of just how intermediate codes are pretty well vital for porting compilers. In the last video we used this as our home base - if you like - our master referral point for everything that we were trying to do. We had source codes for two vital pieces and then compiled versions of them over here. What we're going to find with this one is, yes, we'll still be having an H compiler written in H producing intermediate code the thing that's going to change this time is instead of saying things like: "Take my intermediate code and write a compiler for it that produces B' I'll be saying: Take that, write it in high-level language of your choice but make the binary it produces be for a brand new machine - that we can't wait to get some software working on. So, that B' will start becoming B''. And whereas, in the previous episode, we were obsessed with getting really high quality B', and [then] we got to B'* even better! We're not going to be as obsessed this time with improving the quality of any binary - although that's possible in the end - what we are concerned with is this time saying: "I don't want better binary for the old machine I want some brand new binary B'', for the new machine, and I don't care how rubbish it is initially, I just want to get some binary for the new machine working and established. What we can say about any cross compiler is it's going to look like this. It's going to be a chosen higher-level language; it is going to originally be written in B' but it's going to produce B''. And if you want an actual example - referring back to previous episodes - for this: we were in a situation where our H was 'C'. The original binary it was running on - on a PDP 11 - and our B'', over here, was Z80 binaary. So, there you are then, that's a generic form of any cross-compiler. There's my actual example of my first encounter with cross-compilation. The bigger question is how does this help you? If you start saying: "Well, instead of just sending boatloads of code across to that new machine - and having no real control over it - what happens if I want to, sort of, you know ... yeah, I did think of it in those terms, send an Expeditionary Force onto the foreign machine, set up a few outposts, do a little bit more on the foreign land than just unload the binary that's been sent on a boat. Actually set up a 'binary factory' on your newly conquered land, you see? Well, yes, and actually, I mean, intermediate code helps that. This is the one new piece of software you need to write, since everything is working to intermediate code now. It's a non-optional intermediate stage. Your front end of your compiler will quite cheerfully be producing 'I'. All you need to do, to get something started on your new machine, is to write something in a high-level language which takes intermediate code but produces B'' at the other side. So, that's your intervention point. Let me say again it is a worthwhile step to do. Because the difference in detail between a PDP-11 binary and a Z80 binary is pretty considerable. And if you don't use intermediate codes you have to go right back to square one and think: "Oh! I've got to create a binary from scratch, all over again". But I've got to get in there - in that code generator trying to throw the old one away" You say is there anything I can learn from this? And just out of nowhere bridge the gap between your high-level language and your new B'' which you've got. What we're saying is, it's a lot simpler if you break it into two parts. Leave the front end as it is, on the other machine, for the moment and it's producing I at you, like mad. What you need is a new back end. So, we're in a situation, now, that as I've made clear ... any cross-compiler is going to be running on your old machine, to start with, producing binary code for some other new machine. So what we've now got to do is revisit all we did before. We said: "Here's how the transformation chain works with intermediate codes." If all you want to do is to improve the quality of the coding for your home machine B'. This is "similar but different" now. We're going to say: "Instead of producing better quality binary for this home machine we want to produce brand-new binary, but for a foreign and different machine." And we want to know exactly what processes we're going to have to go through. Similar to before, but a little bit different in detail. So, hold tight this is what we have to do. We've got this new piece of software something that takes an intermediate code we know the spec of that. We can write it in H, our chosen high-level language. It's always a good thing. But we know that, eventually, that thing has got to be compiled out, down to binary, but it's going to produce B''. We take our new piece of software and we compile it. Now notice that is my original 'H-to-Intermediate compiler' that runs on the old machine, but I'm using it to compile this new thing. We know what we're going to get and I write it out up here. H gets translated into I, via this. So, we are going to end up with I, B''- but the H has gone through to I. So, we've now got a piece of software that takes in I, is running on I, but produces B''. Don't forget that there is - as the fourth component in our chain, always available to us - an intermediate code compiler that takes it down to binary. Now we want, back from the beginnings of time, the original component number 4, which is that. So, I've written an I interpreter, in I, that produces B'' But, from work on the old machine, I've got something that takes I runs on B' [and] produces B'. net result of all of that what do we end up with? We end up with I, B'', B'. So, that is the result, if you like, of compiling the intermediate code right down to binary. We've now got a really - well it's close to being wonderful but not quite (!) - it's an Intermediate Code Compiler. It produces super duper new B'' for the new machine. [The] slight drawback is it runs on the binary for the old machine [B']. So we're almost there. We've established our bridgehead but we've not quite invaded yet because what we'd love to do is to get this thing down here saying B''. It's just a question again of feeding the right thing back into itself. We've got I, written in I, producing B''. We've compiled that with an I, B', B' and we've ended up with this: Intermediate Code producing B'' written in B'. What do you do now that you've got this executable answer? Final stage: feed it back to itself. Take the original thing and do it one more time If you take this look: I, I, B'' and feed it into your newly created binary I running on B prime .... hurrah! let trumpets sound! You have finally achieved what you wanted to achieve - which is that goes through there and you end up with I, B'', B''. In my original set-out of pieces of componentry you need, I had 1, 2, 3 and 4. And, looking back at it now, what we have got is that this is the equivalent of [piece] 4. Look, back in the early days when we only had one machine, you had needed an I compiler, to take I into B' ... B' there. What we've now done with all this jiggery-pokery with T diagrams is: we have produced ourselves an I, B'', B'' It is totally on the new machine now. It doesn't rely on B' at all. Now. those of you who have soldiered - how should we say? - really soldiered hard on the previous episodes of this, will now recognize that this is the same old story. You want to have the binary you are running on being of the same quality as the best binary you can produce. Except now it's not so much 'best binary', it's 'new binary'. Rather than generating new binary for the new machine off the old hardware can you "feed yourself back to yourself" enough so that eventually you end up with something that is totally happy on the new machine and doesn't need old machine support in terms of B' at all, any more. So, that's been a bit of a marathon folks. We've mounted our galleys, we've invaded the distant shore. We finally had enough cold compresses on our head that we think we're clear what we've done. But if you just go over this carefully, for yourself, and draw yourself lots of T-diagrams - or better still make yourself some T-diagram shapes - and just experiment with them until you're quite happy with with what you're doing. And I hope it's been convincing that although it is messy at times it is so much easier when you move to a new machine to say: "All I need to write, to get myself going, is an intermediate code compiler". I don't need to redo the whole chain. That can be back-filled as we go along. But I could take the existing front-end and port it into being a new front-end simply if I've got the back-end tools that can produce B'' for me. It's as simple as that really!