help-bison
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Token types with constructor


From: Hans Aberg
Subject: Re: Token types with constructor
Date: Thu, 2 Sep 2004 19:34:52 +0200

At 22:22 +0200 2004/09/01, Wolfgang Wieser wrote:
>On Tuesday 31 August 2004 22:03, you wrote:
>> [...lots of text about token types...]
>>
>So I don't really see why you seem to make things so difficult...
>Especially since it is really easy to quickly call the C++ constructors and
>destructors from an (otherwise plain C) [parser] code:

You are essentially saying that, by certain assumptions on how the C-parser
is implemented, you can write a proper C++-stack, which does what a proper
sequence container would do.

This is a quick-and-dirty implementation, as there is no guarantee that
future Bison versions uses the same stack implementation. For example,
Bison uses up to three stacks, for semantic, state and locations values,
but these can, if one so wants, be merged into a single stack.

So, if it works for you now, that is fine. But it is not a Bison standard
C++ solution that you have come up with.

If one just wants a working C++ parser, then I found it not difficult to
write a one in proper C++ code. Then my C++ classes need nothing special,
like customized allocators. If one wants to write a Bison officially
distributed C++ parser, then there are many more considerations to take
into account.

>I assume the parser allocates a stack of token elements using:
>
>  Tok *stack = (Tok*)malloc(N*sizeof(Tok));
>
>Okay, so when we need a token, then let's use one of the array elements
>but don't forget to call the constructor before. This could be done from
>within the push (shift) operation:
>
>  Tok *t = new(&stack[stack_top_index]) Tok();
>
>(operator new with placement syntax, see Stroustroup!)
>
>This requires that the token type used inside bison (i.e. not the
>user-supplied one), has a custom operator new:
>
>  struct Tok
>  {
>    short yyss;
>    YYSTYPE yyvs;
>    void *operator new(unsigned int /*size*/,void *ptr)
>      {  return(ptr);  }
>  };
>
>And when the token is no longer used, "delete" it again, i.e. call the
>destructor:
>
>  t->Tok::~Tok();
>
>Okay, and the rest of the memory management is as usual:
>
>  free(stack);
>
>In case the stack needs to be enlarged, we simply do:
>
>  Tok *newstack = (Tok*)malloc(newsize*sizeof());
>  for(int i=0; i<oldsize; i++)
>  {
>    new(&newstack[i]) Tok();   // constructor
>    newstack[i] = oldstack[i];  // copy
>    oldstack[i].Tok::~Tok();  // destructor
>  }
>  free(oldstack);
>
>I've been doing things like that several times and it worked well.
>Just write two #defines which do the ugly tasks for us. For normal C
>parsers, these #defines are no-ops (making sure that the C compiler does
>not stumble over operator new, etc) and for C++, we use the implementations
>above. What do you think? (It's teaching C code C++ behaviour :)
>
>Regards,
>Wolfgang







reply via email to

[Prev in Thread] Current Thread [Next in Thread]