Earlier today, somebody asked about parsing. There's much overlap with my answer to that (http://news.ycombinator.com/item?id=1820858), though I would doubly recommend getting one of the Appel books.
I'm Not A Fan of the old Dragon book. I haven't read the new one or _Engineering a Compiler_ (yet), though.
I highly recommend _Essentials of Programming Languages_, though it focuses on interpreters rather than compilers. There's a chapter at the end of the first printing (they cut it from the second and third editions, le sigh) about taking a CPS-based interpreter and turning it into a compiler, too. Very cool.
_Lisp in Small Pieces_ has good content about compiling "dynamic" languages (with a Lisp-y flavor, of course). The Rabbit and Orbit papers at http://library.readscheme.org/page8.html are good, too.
Also, since you seem to have the same quirky, self-taught background I do - I found tinkering with low-level implementations of Forth to be very helpful in understanding virtual machines. Read the source to jonesforth (http://www.annexia.org/forth) and/or write a Forth in C, it will teach you quite a bit. Also, read about Lua's virtual machine - it's small, clean, and very well engineered.
:) That is actually what I did last month. (The assembler source doesn't always translate well to C, so it required a lot of careful thinking about what is going on and how to expres it in C.) I think I ended up writing three Forths, and I did indeed learn a lot.
I did some of the other things too... used to have LiSP, worked through the first few chapters of EOPL, did the Crenshaw tutorial too back in the day.
I still feel that the way I do things are, well, hackish, and incomplete, and suboptimal. I was kind of hoping that there would be a Book that would solve these problems...