Modern Compiler Implementation in ML (I'm not a fan of the C/Java versions)
If you are fluent in a mainstream OO language - Java, C#, Ruby etc
Programming Language Processors in Java: Compilers and Interpreters
( the code is in Java but can be trivially ported into any OO language )
Most compiler programming books use lex/yacc versions for lexing and parsing. Imo, this isn't a good way to learn lexing/parsing, and using recursive descent or combinator parsing approaches is (imho) the right way to begin.
If you want to know how tools like lex and yacc are built, then Holub's "Compiler Construction in C" is very comprehensive and goes into great detail about the required CS theory- (automata DFA, NFA etc).
The book seems to be out of print, but used copies are worth buying (imho)
Compiler Design in C (1990)
EDIT: Adding some extra remarks I think might also be interesting to share.
Another approach, that I really like, is to output bytecodes that are mapped directly to macros in typical macro assemblers like NASM/MASM/TASM. Those macro assemblers provide very powerful macro systems.
Then map those macros to the corresponding assembly code.
Sure it gives a bit more work, but I find it more fun.
Get dozens of book recommendations delivered straight to your inbox every Thursday.