Much of the frontend is pretty much the same: parsing, semantic analysis, type checking. LLLVM mostly comes into play when generating the code. Instead of generating assembbler or opcodes directly, you call into LLVM to create data structures that represent low-level code and then a final call to gen machine code or JIT.
There are several versions of the LLVM Kaleidoscope language tutorial where you build a compiler that supports numeric operations, it is often based on Pratt parsers (at least the official C++ version[1]), but there's a C version on github [2].
In my opinion, you could get pretty far by reading the "Compiler design in C" or "Modern compiler implementation in C" up to the point of optimization and then applying the code generation from kaleidoscope tutorials. LLVM takes care of many optimizations.
There are several versions of the LLVM Kaleidoscope language tutorial where you build a compiler that supports numeric operations, it is often based on Pratt parsers (at least the official C++ version[1]), but there's a C version on github [2].
In my opinion, you could get pretty far by reading the "Compiler design in C" or "Modern compiler implementation in C" up to the point of optimization and then applying the code generation from kaleidoscope tutorials. LLVM takes care of many optimizations.
[1] http://llvm.org/docs/tutorial/LangImpl1.html [2] https://github.com/benbjohnson/llvm-c-kaleidoscope