Over the past few days, I've been busily hacking away at one of the assignments I've got for Uni: implementing programming language (new and/or familiar) features on top of a basic (read: primitive) language's parser/compiler.
Although the base code we got was initially quite hard to read (go out and have a taste of K&R C, with multiple statements on the same line as each other, hardly much indention or whitespace to be found, and use of integer constants all over, and you might be somewhat close to seeing what the code was like), I can say that I now understand most of it. That is, of course, after going through and coding a cleaned up version from scratch, only to have it backfire with a weirdo error I couldn't debug in time, and then cleaning up a second version of that source code.
Doing this, I started getting a very good feel for design/coding patterns in use. While cleaning things up, and again and again started, the patterns became quite well engrained; to read an xyz statement, you firstly grab a symbol and interpret it, validating it and displaying and error if not appropriate, and then going on to process more of the input.
I remember feeling quite enlightened the day I finally got my own failed parser recode attempt completed, ready to run. Aha! I now understand how to code parsers (of one sort). But... this is really no match for understanding code generation, and being able to implement the sorts of language features that you really always wanted...
Following the resumption of lectures after the spring break (and subsequent earthquake-break), the very first lecture of the term (at 9am), was a lecture on the subject of code generation. Specifically, generation of machine instructions. Now, for many years, I've kind of shied away from dealing with "the low level instructions" (things like manually loading and saving values to and from stack registers, etc.). You see, such low-level instruction sets are quite intimidating, but also tedious to program in for more than trivial tasks. But finally seeing instructions like jmp, lod, sto, etc. and friends described, and to understand what it is they do, was suddenly extra enlightening.
Soon afterwards, I was loading that cleaned up code up in my text editor, and browsing through the complete parser+compiler code, and looking to figure out how to implement some of the stuff I'd been wanting to. Although the lecturer said that he was giving full marks for certain features, less for others, and that we only needed to implement a 1 or 2 features, I quickly decided that to really understand this stuff (and be able to tackle some of those big-ticket items), I'd be much better off implementing a bunch of easy stuff first, and working my way up.
This strategy seems to be paying off.
Within a matter of minutes of investigation, and quick coding, I had added the modulo operator. Yipee! Now we can implement Pseudo-Random Number Generators, something that I'm sure would qualify as "a useful computation".
Turning my sights a bit bigger, and with a little bit more trial and error, I managed to implement "augmented assignment" (i.e. a += b or c *= (d+e)). This is something I'll admit to not being able to stand coding without. Writing "x := x + y" just seems so dorky, verbose, and ick! Admittedly, I still haven't totally got it working smoothly, since the current way it works ends up making order-dependent operators return the wrong results (though I've got ideas of some hacks around it!).
With these features pretty much under my belt, it soon came time to work on some more useful constructs: the missing "else" statements (for if...then..else...), comments, nicer looper constructs, and a few others things. Also, the work on the augmented assignment operators also paved the way for getting rid of some of the 'odd' symbol choices, which were quite unlike those for C and most common languages, and were starting to drive me nuts.
With each added feature (fully working), I became increasingly inspired to code some more. It was really great fun: as much as running around with a camera chasing fast moving targets. In fact, I reckon this compiler implementation is actually quite addictive! No wonder there are so many programming languages out there ;)