[antlr-interest] pretty printing in the c target

Jim Idle jimi at temporal-wave.com
Mon Dec 15 18:37:43 PST 2008


On Mon, 15 Dec 2008 17:09:19 -0800, Robert Soule <robert.soule at gmail.com>  
wrote:

> Hi,
>
> I am trying to write a pretty printer for my input language. In java,
> I read in the source, convert to the AST, then use a tree grammar
> to call the StringTemplates, and everything works fine. However,
> I need to use C as the target language, and there isn't a StringTemplate
> implementation in C.
>
> I looked at the examples that are available on the antlr.org website,
> but the only ones that pretty print are toy examples, and simple append
> the character strings to the text contained in the token literals. This
> isn't really a feasible approach in my language. So, what I've ended up
> doing is following a pattern more or less like the following:
>
> someRule
> returns [pANTLR3_STRING result]
> @init {result = factory->newRaw(factory);}
> : ^(SOMETOKEN anotherRule thirdRule)
> {
>   $result->append($result, "Start\n");
>   $result->appendS($result, $anotherRule.result);
>   factory->destroy(factory, $aotherRule.result);
>   $result->appendS($result, $thirdRule.result);
>   factory->destroy(factory, $thirdRule.result);
>   $result->append($result, "\n\n");
> }
>
> However, I've encountered a few problems with this approach. First,
> when I call factory->close(..) at the end of my program, I get a double
> free problem,


You should not be calling the factory->destroy. Just close the factory,  
and if you use the
parsers factory, you don't need to do that. When you are done, just memcpy  
(or strdup) the
chars pointer from teh final string. All the other memory will be  
discarded for you. If you
are just going to write out the result, then fwrite the chars pointer and  
close as normal - all memmory
will be freed for you. You are trying to do too much:

>   $result->append($result, "Start\n");
>   $result->appendS($result, $anotherRule.result);;
>   $result->appendS($result, $thirdRule.result);
>   $result->append($result, "\n\n");
     fwrite(... $result->chars ...);
     factory->close(factory); // But only if this is your own factory,  
which there is no need for really.




  and I don't see in the API where I can call remove on
> the string from the factory. However, more troubling is that when the
> return of one of the rules like anotherRule is composed of only
> small literal strings (like "()"),  then calling destroy on the result  
> sometimes
> frees too much memory,

You don't use destroy() like this, so next time you try to use it, you have
already corrupted the memory.

so that I cause problems for "thirdRule".
> Moreover, this just seems like an awkward way to build up my output
> string.

That is because you are sassuming that you have to do oall the management.  
You don't do that,
you just let the factory take care of it all. When you close, it has  
trcked all the mmemory and
it frees it all for you. You just use teh strings and forget about them as  
if they were Java
objects. Use the factory in the parser (see C examples for poly for  
instance), and you don't even
need to close your own factory.

>
> Since this seems like a pretty common task, I was wondering if
> there is a common, recommended way of doing this?

Read the API docs for more info :-) However, not that you do not NEED to  
use teh string factory stuff
it is really just a convenience. You can copy the input text yourself  
suign teh token supplied offests.

Jim


More information about the antlr-interest mailing list