What I wrote about wrapping a C++ class with a C API is essentially C++ with POD types/functions. But instead of calling C from ANTLR's C++ code (which is actually your C++ listener code called by ANTLR since you don't modify ANTLR itself) you would have a separate C++ class wrapped in C functions. Your legacy code would then call those C functions. Please check the examples I listed to see how this can be done, not specifically for this case, but for wrapping C++ classes in C functions in general.
This is the proposed flow of code/data:
ANTLR C++ target --> custom listener functions --> C++ AST class --> C types/functions wrapper --> Legacy C code
1. ANTLR C++ target will call custom functions that are implemented.
2. Custom listener functions build up an AST in a C++ class.
3. C functions access the AST C++ class and return data in C types.
4. Legacy C code calls the wrapper C functions.
Jason