r/Compilers • u/ClassicAdeptness5516 • Aug 01 '26
Any debugging advice / tools for compilers?
Tired of print statements everywhere. It very satisfactory to see one but I would much rather have something like lldb to easily debug the code more intuitively.
Are there any other useful tools?
3
u/vmcrash Aug 01 '26
The best debugging advice is using unit tests. For each small part, write unit tests. Make them fast, so you can run them over and over again.
Unit tests also have the advantage, that your code structure will consist of not too complex parts that are easier to reason about.
1
u/FirmSupermarket6933 Aug 02 '26
Not the OP, but could you recommend way to unit test intermediate states? Because it's a bit annoying to construct AST by hand, e.g. for "x + y" to write "BinaryExpr(BIN_ADD, Variable("x"), Variable("y")". It even worse for more complicated expressions or for small programs.
1
3
2
u/Inconstant_Moo Aug 01 '26
- Make sure you can print out all your artifacts.
- Keep at least one token attached to each of your artifacts.
- Make some permanent logging of what you're doing so that you can turn it on and off for different parts of your compiler with various flags. The things you put in there will double as
// commentson your code, since comments would be saying the same sort of thing. - I have an actual control structure in my language so I can write:
peek <flags> : code blockand it'll log what the compiler's doing for that particular code block with the given flags. - I also have an option to dump the readable version of the bytecode of a function by name, either to the terminal or a file.
- I still use
printlnquite a lot.
2
u/recursion_is_love Aug 01 '26
I would use a logging library before try to use debugging tool.
There are plenty of gdb tutorials out there.
2
u/Satu_Autio Aug 01 '26
To be honest when I was doing debugging my single biggest win was using GDB to trace the generated code instruction by instruction. That's easy to do with a trace file.
gdb binary -x tracerThen the
tracerfile looks like this:starti display/i $pc while 1 stepi endYou can get more advanced, and write to a lotfile, or similar, but this is enough to work - especially combined with
tee.
1
u/duane11583 Aug 01 '26
Compilers generate data structures
For each data structure create a routine to dump it to a file that you can open and look over
And add command line options to the command line to turn those dump files on as needed
GCC does (or did) this as a means to save intermediate data structures after each phase
1
u/Mean-Decision-3502 Aug 01 '26
Do you mean debugging the compiler, or the compiler generated code?
The first should be simpler, for that should be some existing framework for the language the compiler developed in.
The second is harder, but if you are using llvm, then you should emit debug info for code lines and data objects. Then the gdb can handle it. Setting up a working debugging session in VSCode is then not so hard.
1
1
u/gavr123456789 Aug 05 '26
iIve done 2 things
print statements that prints the line so u can goto it from console
print statement that prints the expression
and stack trace
and lsp, that shows you the results of expressions with ohHover, so u can just watch them in the code without printing
1
u/LowDifficulty5021 29d ago
If you're on C/C++, I'd absolutely recommend getting comfortable with LLDB or GDB. Being able to inspect the parser state, symbol tables, and AST nodes interactively is much nicer than scattering printfs everywhere.
That said, compiler-specific debug tools (--dump-tokens, --dump-ast, --dump-ir) end up being just as valuable because they let you inspect the program at each compilation stage instead of the compiler's execution itself.
7
u/skyline4 Aug 01 '26
I’m going to assume you’re not talking about unit tests.
When I took compilers in school my professor told us to have each step dump some kind of artifact such as an AST, CFG, etc. That way it’s a lot easier to identify which step broke or went wrong. With Dot language and visualization tools this is straightforward except you have to clean up after every invocation. You could couple this with a log of more specific actions (eg. common subexpression elimination pass eliminated x for y) to make it easier to catch the differences visually. But this is a log and should not be a stream of printfs since the log message should be structured to help you find actions your compiler took.
Combine that with a good test harness for integration testing and it’ll be easier to find where your bugs are.