I learned just about everything I needed to know about compilers in only a few hours at CSRI.
I subscribed to Dr. Dobb's Journal of Computer Calisthenics & Orthodontia.
In it was published the source code to Small C (Ron Cain). This was before open source existed. Finding the source code to anything was a delight.
My friend was an MSc student and I was but a lowly undergrad. My friend invited me to CSRI for the evening and we typed in all of the source code for the C compiler into the Unix V7 system.
Around 2am in the morning, we were finished and I typed in my first line of C code.
I knew 8080 (nee Z80) assembler at the time.
I typed something like:
a = b + c;
and SmallC responded with something like:
; a = b + c;
MOV L,(name of b)
MOV C,(name of c)
MOV (name of a),L
MOV (name of a + 1),H
from this, I could see what "a = b + c" compiled into.
This basically says:
(and, it says, to do the steps in the given sequence (not, say, in parallel)).
The code above is quite simple — it is raw 8080 code. It avoids all details, such as startup and shutdown,
It was easy to see what the compiler was doing for me.
Basically, the compiler was like an editor macro.
I went on to do a 6-month project for one of my courses.
I was intending to install a better parser, but I ended up rewriting the whole thing.
At the end of the course, my compiler was running, but needed testing.
I, carefully, applied one test after another.
My friend asked me to send him the source code. On Friday, before the weekend.
On Sunday, he sent me a list of about 100 bugs.
I was astounded. I fixed the bugs and the compiler quickly took shape.
I asked my friend how he found so many bugs in only 2 days.
He replied that he simply poured the compiler source code into itself.
In EE, this is called a "smoke test". You build the alpha version of a circuit, turn on the power and watch for smoke.
If there's no smoke, you do more careful testing.
Software testing could benefit from using this same technique for divide-and-conquer:
The smoke test — a lot of tests all at once — can be used to find blunders and typos. It is not worth running unit tests until the blunders have been cleared away.
 Computing Systems Research Facility at the University of Toronto
 Chris Lewis
 My memory is hazy. Someone will correct me…
 Note that K&R was more forgiving at the time — I didn't need to declare a, b, and c before asking the compiler to give me code.
Note that the 8080 was little-endian, the low-byte ended up in the lower (numerically) address and the high byte ended up in the address+1.
 The compiler was written in C for Unix V7 running on a PDP-11. My compiler emitted code for the 8080, running CP/M