|> It occurs to me that inheritance should be especially useful in the
|> construction of a parse tree. ...
|> A better way to do this, it seems to me, is to define an abstract class
|> for parse tree nodes, and then subclass specific node types from the
|> abstract base class. I envision member functions like SanityCheck(),
|> Optimize(), and GenerateCode() which take very different (though
|> conceptually identical) actions for each node subclass.

I have a feeling this only works well for simple compilers. On my current
project I am writing a compiler that does so many transformation of the
original parse tree that the idea of storing each different type of node
in a different class (the work is in C++) is simply not practical.
Instead I use the OO properties of C++ to manipulate generic LISP like
data structures with smart pointers to manage the garbage collection. I
can then have pattern matching rules to do the optimization and code
generation. Granted this philosophy might make the compiler slow but this
is acceptable for our purposes.

|> It also seems to me that something other than yacc and lex should be used
|> for the parser. This venerable old tools have served us well, but their
|> design is beginning to show its age. Upgrades like yacc++ and lex++ don't
|> seem to help much since it is the basic design of the tools, not their
|> implementations, which seems to be at fault.