Speaking of compiler classes flunked, and command parsers, and such,
there were a couple things I did aside my compiler class that I found
particularly useful for building an understanding of such things.

One was learning about the FORTH language.  Aside from other strengths and
weaknesses, FORTH has an extremely trivial parser, andd it's very
instructional.  (learning how to operate an RPN based calculator, or program
postscript, is probably equivilent.)  I'm led to believe that LISP is
similarly trivial to parse.  (This is why lisp dialects are such common
extension languages for editors (like emacs and clones) - not much effort
needs to go into the interpretter itself.)

The second was an article in (showing my age) "Best of Byte Volume 1" on the
"My Deat Aunt Sally" algorithm for parsing arithmatic expressions and
getting the precedence right (Multiply Divide Add Subtract.)

I actually went so far as to write a function compiler that you could call
from a fortran program.  This was for the classic 3-d function plot code
that was around at the time - since it was a big pain to keep recompiling
and linking the thing every time you wanted to draw a new picture, I wrote
some neat-o assembler that parsed a numeric expression (including fortran
functions) and built up rather less neat-o machine code that looked like a
fortran function, and did your basic FP math (calling the real fortran
library for all the functions, of course.)  Worked great.  Since this was FP
math, and generally with pretty complex functions, the fact that the
equation code itself was, um, a forth-like implementation of a calculator
with not very optimal code was dwarfed by the time spent doing the math
itself anyway.  (gee, I wonder if it would have counted as the final project
in the compiler class.)

BillW