2009-08-10 21 views
1

Dans Bison J'ai un syndicatComment initialiser la valeur d'union de Bison%?

%union 
{ 
    std::string* sval; 
} 

Et je veux l'utiliser comme ceci

En Lex:

*(yylval->sval) = "ABCD"; 

Plutôt que

yylval->sval = new std::string("ABCD"); 

Pour éviter les fuites de mémoire facilement

Cependant, j'ai besoin d'un moyen d'allouer une chaîne std :: à sval pour commencer.

Comment puis-je faire cela?

Répondre

0

Je ne suis pas entièrement clair pourquoi vous voulez faire cela mais je peux voir pourquoi ce que vous avez ne fonctionne pas. C'est parce que "ABCD" est un const char *, pas un std::string.

Je sais avec YACC que la première section "%{ ... %}" vous permet de définir des choses C en dehors du contrôle de Yacc (et il semble Bison a une fonction similaire, basée sur sa demande de compatibilité ascendante et la documentation here, 2.1.1). Pourquoi ne pas mettre:

std::string *strABCD = new std::string("ABCD"); 

dans cette section et utilisez:

yylval->sval = strABCD; 

plus tard à chaque fois que vous avez besoin d'un pointeur sur cette chaîne?

Cela me semble être le moyen le plus facile de réaliser ce que je veux.

Si vous craignez que les attributions dans l'analyseur Bison ne soient pas libérées (et elles devraient l'être), mon conseil est de ne pas les faire. Vous pouvez configurer votre chaîne avant d'appeler le yyparse() puis le libérer après le retour.

Mise à jour:

Voici comment je le ferais pour éviter l'allocation/libération de cette valeur fixée dans l'analyseur Bison. Réglez-le comme un global qui vit pour la durée du programme.

Code principal:

std::string *strABCD = new std::string ("ABCD"); 

int main(...) { 
    // Do some stuff. 
    : : : 
    yyparse(); 
    : : : 
    // Do some other stuff. 
} 

Bison source d'analyseur:

%{ 
    extern std::string *strABCD; 
%} 
: : : 
yylval->sval = strABCD; 

qui renvoie le pointeur fixe à votre chaîne ABCD avec aucune allocation ou libérant le code Bison du tout (et précieux peu même dans le code principal).

+0

Parce que maintenant vous avez une fuite de mémoire à moins que vous libérez vos entrées à Yacc pour toutes les règles. – DevDevDev

+0

D'accord, mais si vous allez allouer de la mémoire, vous devez le libérer. Si vous ne le souhaitez pas, n'allouez pas - changez votre union pour qu'elle soit un char * à la place. La plupart des parsers que j'ai écrits étaient des one-shots donc le code prélude "fuite" d'une chaîne std :: serait sans importance. Votre architecture peut être différente. Vous pouvez également le configurer avant d'appeler l'analyseur et le déchirer par la suite. Voir la mise à jour. – paxdiablo

+0

Votre code perdra une chaîne pour chaque règle correspondant à un type de retour. – DevDevDev

2

Vous ne pouvez pas mettre en sécurité des types avec des constructeurs ou des destructeurs (tels que std :: string) dans une union, cela ne fonctionnera donc pas.

Qu'est-ce que vous pouvez faire à la place est pas utiliser% l'union du tout - plutôt utiliser une macro pour carte YYSTYPE directement à un autre type:

%{ 
#define YYSTYPE std::string 
%} 

alors yylval sera ce type (tout comme tous $ n options dans le code grammatical)

+0

Où est-ce que je fais cela? Comment puis-je définir les types de mes règles? comme % Type règle – DevDevDev

+0

Je l'ai essayé et maintenant je suis en train de « ne peut pas convertir char * à semantic_type * » – DevDevDev

+0

Je ne pense pas que votre code fonctionne. – DevDevDev