[Résolu] [lex & Yacc] Segmentation fault

Segmentation fault [Résolu] [lex & Yacc] - C - Programmation

Marsh Posté le 20-12-2007 à 13:23:16    

Bonjour,  
 
Je suis entrain de me familiariser avec lex et yacc, en lisant un bouquin dessus, j'ai à faire l'exercise suivant.
 
1) sauvegarder des mots dans une liste chainee en fonction de leur type (verbe, nom...)
 
exemple
 
taper ^verb love : le lexer chercher si le verbe existe déjà, sinon il l'ajoute en début de la liste chainee avec son type VERBE.
 
2) après avoir mémoriser des verbes, des sujets, des pronoms, je dois taper une phrase genre exhortae needs help et le parser doit me dire si c'est une phrase simple ou composée ou si il y a erreur.
 
 
je compile, fait l'édition de lien... et lorsque je lance mon ./a.out j'ai une segmentation fault, j'ai tout revu mais j'arrive pas à voir ou est le problème.
 
 
voilà le .lex
 

Code :
  1. %{
  2. /* Analyseur lexical pouvant etre utiliser par un analyseur syntaxique
  3. */
  4. #include "y.tab.h"
  5. #define LOOKUP 0
  6. int state;
  7. int ajouter_mot (int type, char *word);
  8. int rechercher_mot (char *word);
  9. %}
  10. %%
  11. /* Fin de ligne retour a l'etat par defaut */
  12. \n {state = LOOKUP;}
  13. /* Fin de phrase */
  14. \.\n {state = LOOKUP;
  15.  return 0;
  16. }
  17. /* A chaque fois que la ligne commence par un nom reserve du langage */
  18. /* On va definir les mots de ce type */
  19. ^verb  {state = VERBE;}
  20. ^adj  {state = ADJECTIF;}
  21. ^adv  {state = ADVERBE;}
  22. ^nom  {state = NOM;}
  23. ^prep  {state = PREPOSITION;}
  24. ^pron  {state = PRONOM;}
  25. ^conj  {state = CONJONCTION;}
  26. /* un mot normal , on le defini ou on le recherche */
  27. [a-zA-Z]+ {
  28.  if (state != LOOKUP)
  29.  {
  30.   ajouter_mot (state, yytext);
  31.  }
  32.  else
  33.  {
  34.   switch (rechercher_mot (yytext))
  35.   {
  36.    case VERBE:
  37.     return VERBE;
  38.    case ADJECTIF:
  39.     return ADJECTIF;
  40.    case ADVERBE:
  41.     return ADVERBE;
  42.    case NOM:
  43.     return NOM;
  44.    case PREPOSITION:
  45.     return PREPOSITION;
  46.    case PRONOM:
  47.     return PRONOM;
  48.    case CONJONCTION:
  49.     return CONJONCTION;
  50.    default:
  51.     /* ne rien retourner, ignorer le mot */
  52.     printf ("%s : inconnu\n", yytext);
  53.   }
  54.  }
  55.  }
  56. . ; /* Ignorer le reste */
  57. %%
  58. /* On defini une liste chainee de mots et types */
  59. struct word
  60. {
  61. char *word_name;
  62. int type;
  63. struct word *p_suivant;
  64. };
  65. /* On declare le premier element de la liste */
  66. struct word *p_word_list = NULL;
  67. extern void *malloc ();
  68. /* -----------------------------------------------------------------------
  69. ajouter_mot ()
  70. -----------------------------------------------------------------------
  71. Role : ajoute un mot dans la liste (seulement si il n'y est pas deja)
  72. -----------------------------------------------------------------------
  73. */
  74. int ajouter_mot (int type, char *word)
  75. {
  76. struct word *p_word = NULL;
  77. /* On verifie d'abord que le mot ne se trouve pas deja dans la liste */
  78. if (rechercher_mot (word) != LOOKUP)
  79. {
  80.  printf ("!!! WARNING %s existe deja \n", word);
  81.  return 0;
  82. }
  83. /* On alloue un espace memoire */
  84.  p_word = malloc (sizeof *p_word);
  85.  if (p_word != NULL)
  86.  {
  87.   p_word->p_suivant = p_word_list;
  88.   p_word->type = type;
  89.   /* On alloue l'espace memoire pour la chaine de caractere */
  90.   p_word->word_name = malloc ((strlen (word) + 1) * sizeof (char));
  91.   if (p_word->word_name != NULL)
  92.   {
  93.    strcpy (p_word->word_name, word);
  94.   }
  95.   p_word_list = p_word;
  96.  }
  97. return 1;
  98. }
  99. /* ------------------------------------------------------------------------
  100. rechercher_mot ()
  101. ------------------------------------------------------------------------
  102. Role : Retourne le type du mot dans une liste chainne (LOOKUP si le mot
  103. n'existe pas)
  104. ------------------------------------------------------------------------
  105. */
  106. int rechercher_mot (char *word)
  107. {
  108. struct word *p_tmp = p_word_list;
  109. while (p_tmp != NULL)
  110. {
  111.  if (strcmp (p_tmp->word_name, word) == 0)
  112.  {
  113.   return p_tmp->type;
  114.  }
  115.  p_tmp = p_tmp->p_suivant;
  116. }
  117. return LOOKUP;
  118. }


 
et voilà le .y
 

Code :
  1. %{
  2. #include <stdio.h>
  3. %}
  4. %token NOM PRONOM VERBE ADVERBE ADJECTIF PREPOSITION CONJONCTION
  5. %%
  6. phrase : phrase_simple {printf ("Phrase simple\n" );}
  7. | phrase_composee {printf ("Phrase composee\n" );}
  8. ;
  9. phrase_simple : sujet verbe objet
  10. | sujet verbe objet phrase_preposition
  11. ;
  12. phrase_composee : phrase_simple CONJONCTION phrase_simple
  13. | phrase_composee CONJONCTION phrase_simple
  14. ;
  15. sujet : NOM
  16. | PRONOM
  17. | ADJECTIF sujet
  18. ;
  19. verbe : VERBE
  20. | ADVERBE VERBE
  21. |verbe VERBE
  22. ;
  23. objet : NOM
  24. | ADJECTIF objet
  25. ;
  26. phrase_preposition : PREPOSITION NOM
  27. ;
  28. %%
  29. extern FILE *yyin;
  30. main ()
  31. {
  32. while (!feof (yyin))
  33. {
  34.  yyparse ();
  35. }
  36. }
  37. yyerror (s)
  38. char *s;
  39. {
  40. fprintf (stderr, "%s\n", s);
  41. }


 
si quelqu'un pouvait me filer un coup de main, merci


Message édité par exhortae le 29-12-2007 à 18:05:22
Reply

Marsh Posté le 20-12-2007 à 13:23:16   

Reply

Marsh Posté le 21-12-2007 à 11:38:21    

Et bien compile en debug (gcc -g) et lance ton exécutable avec gdb :
 
gdb a.out
> run
 
Quand ça plante, essaye la commande bt pour voir la pile d'appel.
 
vw

Reply

Marsh Posté le 21-12-2007 à 13:28:38    

Bonjour
 
voilà ce que j'obtiens,
 

Code :
  1. [exhortae@localhost 5]$ gdb a.out
  2. GNU gdb 6.2-2mdk (Mandrakelinux)
  3. Copyright 2004 Free Software Foundation, Inc.
  4. GDB is free software, covered by the GNU General Public License, and you are
  5. welcome to change it and/or distribute copies of it under certain conditions.
  6. Type "show copying" to see the conditions.
  7. There is absolutely no warranty for GDB.  Type "show warranty" for details.
  8. This GDB was configured as "i586-mandrake-linux-gnu"...Using host libthread_db library "/lib/tls/libthread_db.so.1".
  9. (gdb) run
  10. Starting program: /home/exhortae/lex1/5/a.out
  11. Program received signal SIGSEGV, Segmentation fault.
  12. 0x4007c2c0 in feof () from /lib/tls/libc.so.6
  13. (gdb) bt
  14. #0  0x4007c2c0 in feof () from /lib/tls/libc.so.6
  15. #1  0x08049b32 in main ()
  16. (gdb)


 
le problème c'est que n'ayant jamais débugger, ni utiliser lex & yacc en même temps je comprends pas ce que le message d'erreur dans eof veut dire.
 

Reply

Marsh Posté le 21-12-2007 à 13:54:57    

Ca veut dire que le plantage a lieu dans la procédure main, au moment ou elle appelle feof() (ligne 42)
yyin n'est pas initialisé.
 
vw

Reply

Marsh Posté le 21-12-2007 à 14:39:37    

oui effectivement ça marche quand j'enlève la boucle, par contre je peux parser qu'une seule phrase.
 
finalement en remplaçant le main du .y par
 

Code :
  1. main ()
  2. {
  3.         yyin = stdin;
  4.         while (!feof (yyin))
  5.         {
  6.                 yyparse ();
  7.         }
  8. }


ça fonctionne  
 
par contre je sais pas si c'est valide.
 
en tout cas merci pour ton aide.


Message édité par exhortae le 21-12-2007 à 14:40:27
Reply

Marsh Posté le 21-12-2007 à 16:13:30    

Oui, ça m'a l'air pas mal comme ça.
 
vw

Reply

Marsh Posté le 21-12-2007 à 17:15:53    

oki,  
 
donc comme j'ai vu que yyin est *FILE, je me suis dit qu'au lieu de lui affecter stdin, j'allais lui affecter un fichier que j'ai moi même rempli (au lieu d'avoir à taper tout à la ligne de commande)
 
j'obtiens dont ça à la place du main
 

Code :
  1. main ()
  2. {
  3. yyin = fopen ("fichier.txt", "r+" );
  4. if (yyin != NULL)
  5. {
  6.  while (!feof (yyin))
  7.  {
  8.   yyparse ();
  9.  }
  10.  fclose (yyin);
  11. }
  12. else
  13. {
  14.  printf ("Impossible d'ouvrir le fichier definition\n" );
  15. }
  16. }


 
voilà le fichier text
 

Code :
  1. nom manu
  2. verb aime
  3. nom cerises
  4. conj quand
  5. nom elles
  6. verb sont
  7. nom fraiches
  8. verb dormir
  9. nom jean
  10. manu aime cerises quand elles sont fraiches.
  11. nom lit
  12. jean dormir lit.


 
et quand j'execute :
 

Code :
  1. [exhortae@localhost 5]$ ./a.out
  2. Phrase composee
  3. [exhortae@localhost 5]$


 
effectivement il ne prend en compte que la première phrase.
 
pourtant en éxécutant avec gdb j'ai pas d'erreur :
 

Code :
  1. Starting program: /home/exhortae/lex1/5/a.out
  2. Phrase composee
  3. Program exited normally.
  4. (gdb)


 
 
maintenant le programme sans utiliser de fichier (on tape à la ligne de commande) :
 
son main :
 

Code :
  1. extern FILE *yyin;
  2. main ()
  3. {
  4.         yyin = stdin;
  5.         if (yyin != NULL)
  6.         {
  7.                 while (!feof (yyin))
  8.                 {
  9.                         yyparse ();
  10.                 }
  11.         }
  12.         else
  13.         {
  14.                 printf ("Lecture impossible\n" );
  15.         }
  16. }


 
et là on parse bien toutes les phrases entrées.
 

Code :
  1. [exhortae@localhost 6]$ ./a.out
  2. nom manu
  3. verb aime
  4. nom cerises
  5. conj quand
  6. nom elles
  7. verb sont
  8. nom fraiches
  9. verb dormir
  10. nom jean
  11. manu aime cerises quand elles sont fraiches.
  12. Phrase composee
  13. nom lit
  14. jean dormir lit.
  15. Phrase simple


 
Comment faire pour parser tout le fichier :(


Message édité par exhortae le 21-12-2007 à 17:41:25
Reply

Marsh Posté le 21-12-2007 à 23:23:38    

si j'ai bien compris le code,  à chaque fois que j'ai un point suivi d'un retour à la ligne lex retourne la valeur 0 à yyparse qui sait qu'il doit parser une nouvelle ligne
 
donc en faisant

Code :
  1. main ()
  2. {
  3. yyin = fopen ("fichier.txt", "r+" );
  4. if (yyin != NULL)
  5. {
  6. while (yyparse () == 0);
  7.   fclose (yyin);
  8. }
  9. else
  10. {
  11. printf ("Impossible d'ouvrir le fichier definition\n" );
  12. }
  13. }


 
ça marche il parse toutes les lignes, par contre quand il arrive à la dernière ligne il la traite, puis affiche un syntax error, comme si il avait essayer de traiter la fin de fichier et n'avait pas trouvé sa règle dans la grammaire. Purrée je sèche là.

Reply

Marsh Posté le 23-12-2007 à 10:43:59    

Il faut que "lex" retourne un tocken FINDEFICHIER (tu l'appelles comme tu veux) indiquant la fin de fichier et dans "yacc" il faut que ta grammaire prennes en compte ce tocken.

Reply

Marsh Posté le 25-12-2007 à 08:50:38    

Merci.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed