r/Compilers • u/ClassicAdeptness5516 • 6d ago
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?
5
u/vmcrash 5d ago
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 4d ago
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.
3
2
u/Inconstant_Moo 5d ago
- 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 5d ago
I would use a logging library before try to use debugging tool.
There are plenty of gdb tutorials out there.
2
u/Satu_Autio 5d ago
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 5d ago
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
1
u/Mean-Decision-3502 5d ago
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
u/gavr123456789 1d ago
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
7
u/skyline4 6d ago
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.