With all due respect to GCC, that's hardly a new concept. In 1986, I had a deal with Lattice (remember when other companies besides Microsoft sold DOS C compilers?). I'd ported the AT&T C++ translator to run as a preprocessor to their Amiga C compiler, but we wanted tighter integration, so they gave me the specs for the workfile that their frontend passed to their backend. Like GCC, Lattice C had common code for the lext/parse/AST part of the compiler and target-specific code for the code generator part.
We were planning on replacing their C frontend with a C++ frontend. Alas, it came to naught, since I was never able to define a reliable function overloading subsystem. C++ is a real horror on overloading, since unlike
Java, you can implicitly invoke constructors and conversion operators as part of the overloaded method call, which can result in some major ambiguities.
Layered compilers in general go back to almost the beginning. The old IBM mainframe COBOL ran in 6 or 7 distinct passes. It had to. Memory back then meant the logic for each pass had to be able to fit in something like 16KB RAM.
Speaking of IBM mainframes, there has been a fair amount of work done on getting gcc to run in IBM's OS/MVS 3.8 - a free ancestor of the modern z/OS that runs in the Hercules mainframe emulator environment. I looked at the gcc internal logic docs as part of this project and was quite impressed.
Gcc frontends exist for C, C++, and Ada that I can list offhand. I believer there's been work on a COBOL, and I'm pretty sure it's at the core of the Linux FORTRAN. I'm sure there are others. So the docs are pretty good for that sort of effort.