[antlr-interest] Problem with C target output on example C grammar

Kamil Burzynski nopik at data.pl
Wed Apr 2 11:14:41 PDT 2008


Hello,

>> Well, the thing is that it is natural way of doing in C++. In pure C
>> returning struct by value is rarely used, I agree. But in C++ (and Java
>> in fact), returning objects by value is much more common. Especially in
>> my case - when the object was smart pointer itself. These entities are
>> *meant* to be passed as value. And since they point to (usually)
>> non-trivial class, you cannot reduce them away by returning a bunch of
>> struct members at once.

> If they are pointers, then they can be assign NULL so it should not

They are smart pointers, not pointers. It means, that they are (rather
complex) template objects mimicking pointer behavior. They are very
useful when it comes to memory management and avoiding memleaks, for
example. And their version taken from boost library do not allow
assigning raw pointer (or int) unfortunately (which is reasonable, and
would be dangerous if enabled). More info at
http://en.wikipedia.org/wiki/Smart_pointers or at boost.org.

> be an issue, but as I said, if you use more than one element then you
> won't get the issue, so at worst, you could add a dummy int to the
> returns clause. Can you give me an example, other than struct, which

Hm, thats interesting idea. I did not tried returning 2 values.. this
workaround will be safer and easier than mine.

> you do not need to return, of something that you cannot because it
> cannot be assigned to NULL?

Smart pointer is the example ;) The idea is something like this (though
full understanding requires some C++ and template knowledge):

class Foo
{
public:
       void do_something();
};

template<typename T> class SmartPtr
{
public:
 SmartPtr( T *t ) { my_t = t; };
 T &operator->() { return *t; };
private:
 T *t;
};

typedef SmartPtr<Foo> SmartFooPtr;

void bar()
{
  SmartFooPtr foo_ptr( new Foo() );
  foo_ptr->do_something(); //smart pointer is used like regular pointer
}

The trick is that you can add extra functionality to you pointer-like
object (namely SmartPtr template above). 99% of smart pointers do
reference count their objects and call delete when last reference is
destroyed. For example:

void foo()
{
     Foo *foo_ptr = new Foo();
     Foo *foo_ptr2 = foo_ptr;

     //memory leak at the end of function, since nobody called delete
}

and their smart version:

void foo()
{
     SmartPtr<Foo> foo_ptr( new Foo() );   //SmartPtr may create
     //reference counter and set it to 1

     SmartPtr<Foo> foo_ptr2( foo_ptr ); //Reference counter bumped to 2

     //No memory leak. At the end of function 2 destructors will be
     //called, one will decrement reference counter to 1, second
     //will do the same, and once counter reaches 0, SmartPtr will call
     //delete automatically.
}

Of course this is very simple case, but when you pass your pointers
around complex methods, it is sometimes awkward to call delete properly.
Java have garbage collector, smart pointers are just C++-ish way of
doing the same.

> I think, after a bit of looking, that I
> can avoid initializing the single return element, but something nags
> at the back of my mind about this. I would like to have an example of
> something that cannot be done that a user actually wants to do, so I
> can see if I can make it work. Thanks.

Well, just as you, I do not want to have dangerous C target at antlr ;)
So, if removal of NULL here is dangerous, just do not do it. C++ people
will have to do workarounds, but it still will be safer.

> Best thing is to just buy yourself a copy of the reference book:
> http://www.pragprog.com/titles/tpantlr

> There is a lot of great information in there on how to do all sorts of things.

Yeah, I was considering it already.. and made the purchase minute ago :D

>> But if you have object as in Java, you cannot return all its members
>> separately, that would make no sense.

> Would you want to return an object by value? Surely it will be by
> reference? However, as I said, if this really is the case, then add a
> dummy flag to the return for the moment, while I look in to it.

No, I indeed wanted to return by value. Thats why used nasty case of
returning plain C struct by value, too ;) Smart pointers described above
are just example of returning by value (just like regular pointers are,
in this case). Till now I have created ugly workaround, but dummy return
value seems to be much cleaner than my solution.

>> Not so easy ;) There is one grammar error indeed. I do not know which
>> problem you are thinking about my error,

> The fact that you did not relink your main program with a new .so

Ah yes. Today I have also checked on the other machine, main.o was not
rebuild, indeed. I have tweaked my makefile so it wont happen again :D

> and therefore got a segmentation violation when trying to run the
> binary with it. I explained that i n a previous eamil.

>> In my other email I also indicated other error which are purely related
>> to
>> C runtime, I think: when rule uses 2 scopes, first of them is not
>> accessible.

> This was just that you did not relink the main executable with your
> library I believe. If not, then can you provide an example as I did
> not see anything in the prior emails. It might be there of course, but
> I didn't see anything else?

Sure, here you go (my mailer may wrap lines, watch out):

11854 20:12:06 nopigentoo ~/Warsztat/antlr/scope$ cat main.c
#include    <scope1Lexer.h>
#include    <scope1Parser.h>

int ANTLR3_CDECL
main    (int argc, char *argv[])
{
    pANTLR3_UINT8           fName;
    pANTLR3_INPUT_STREAM    input;
    pscope1Lexer                    lxr;
    pANTLR3_COMMON_TOKEN_STREAM     tstream;
    pscope1Parser                               psr;
    if (argc < 2 || argv[1] == NULL)
    {
                        fName   =(pANTLR3_UINT8)"./input"; // Note in VS2005 debug, working directory must be configured
    }
    else
    {
                        fName   = (pANTLR3_UINT8)argv[1];
    }
    input       = antlr3AsciiFileStreamNew(fName);
    lxr     = scope1LexerNew(input);        // CLexerNew is generated by ANTLR
                tstream = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(lxr));
    psr     = scope1ParserNew(tstream);  // CParserNew is generated by ANTLR3

    psr->evaluate(psr);

    psr     ->free  (psr);          psr = NULL;
    tstream ->free  (tstream);      tstream = NULL;
    lxr     ->free  (lxr);          lxr = NULL;
    input   ->close (input);        input = NULL;

    return 0;
}

11855 20:12:09 nopigentoo ~/Warsztat/antlr/scope$ cat scope1.g
grammar scope1;

options {
  language = C;
}

scope A
{
        int a;
}

scope B
{
        int b;
}

scope C
{
        int c;
}

evaluate
scope A;
scope B;
scope C;
@init
{
        printf("\%p \%p \%p\n", SCOPE_TOP(A), SCOPE_TOP(B), SCOPE_TOP(C) );
        $A::a = 42;
        $B::b = 42;
        $C::c = 42;
}
: 'foo';

11856 20:12:14 nopigentoo ~/Warsztat/antlr/scope$ java org.antlr.Tool scope1.g
ANTLR Parser Generator  Version 3.1b1 (??)  1989-2007
Generating scope1Parser.c
Generating scope1Parser.h
Generating scope1Lexer.c
Generating scope1Lexer.h
11857 20:12:26 nopigentoo ~/Warsztat/antlr/scope$ gcc *.c -o main -I. -lantlr3c
11858 20:12:35 nopigentoo ~/Warsztat/antlr/scope$ ./main
(nil) (nil) 0x52d390
Segmentation fault
11859 20:12:37 nopigentoo ~/Warsztat/antlr/scope$

As you see, only last scope (C) was initialized.

-- 
Best regards from
Kamil Burzynski



More information about the antlr-interest mailing list