Difficulté à comprendre un code

Difficulté à comprendre un code - C - Programmation

Marsh Posté le 23-12-2012 à 18:40:19    

Salut,

 

Dans le chapitre sur les déclarations complexes du K&R, on a cet exemple de programme qui génère la description verbale d'une déclaration :
(il n'est pas présenté exactement comme ça dans le bouquin, j'ai complété/ré-agencé pour essayer de mieux piger)

 
Code :
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <ctype.h>
  4. #define MAXLEX 100
  5. enum {NOM, PARENS, CROCHETS};
  6. void dcl(void);
  7. void dclabs(void);
  8. int lirelex(void);
  9. int lirecar(void);
  10. void remettrecar(int);
  11. int typelex;
  12. char lex[MAXLEX];
  13. char nom[MAXLEX];
  14. char type[MAXLEX];
  15. char sortie[MAXLEX];
  16. char tamp[MAXLEX];
  17. int ptamp = 0;
  18. main()
  19. {
  20.     while(lirelex() != EOF)
  21.     {
  22.         strcpy(type, lex);
  23.         sortie[0] = '\0';
  24.         dcl();
  25.         if(typelex != '\n')
  26.             printf("erreur de syntaxe\n" );
  27.         printf("%s : %s %s\n", nom, sortie, type);
  28.     }
  29.     return 0;
  30. }
  31. int lirecar(void)
  32. {
  33.     return (ptamp > 0) ? tamp[--ptamp] : getchar();
  34. }
  35. void remettrecar(int c)
  36. {
  37.     if(ptamp >= MAXLEX)
  38.         printf("remettrecar : trop de caractères\n" );
  39.     else
  40.         tamp[ptamp++] = c;
  41. }
  42. int lirelex(void)
  43. {
  44.     int c;
  45.     char *p = lex;
  46.     while((c = lirecar()) == ' ' || c == '\t')
  47.         ;
  48.     if(c == '(')
  49.     {
  50.         if((c = lirecar()) == ')')
  51.         {
  52.             strcpy(lex, "()" );
  53.             return typelex = PARENS;
  54.         }
  55.         else
  56.         {
  57.             remettrecar(c);
  58.             return typelex = '(';
  59.         }
  60.     }
  61.     else if (c == '[')
  62.     {
  63.         for(*p++ = c; (*p++ = lirecar()) != ']'; )
  64.             ;
  65.         *p = '\0';
  66.         return typelex = CROCHETS;
  67.     }
  68.     else if(isalpha(c))
  69.     {
  70.         for(*p++ = c; isalnum(c = lirecar()); )
  71.             *p++ = c;
  72.         *p = '\0';
  73.         remettrecar(c);
  74.         return typelex = NOM;
  75.     }
  76.     else
  77.         return typelex = c;
  78. }
  79. void dcl(void)
  80. {
  81.     int ne;
  82.     for(ne = 0; lirelex() == '*'; )
  83.         ne++;
  84.     dclabs();
  85.     while (ne-- > 0)
  86.         strcat(sortie, " pointeur sur" );
  87. }
  88. void dclabs(void)
  89. {
  90.     int type;
  91.     if(typelex == '(')
  92.     {
  93.         dcl();
  94.         if(typelex != ')')
  95.             printf("erreur : ) manquante\n" );
  96.     }
  97.     else if (typelex == NOM)
  98.         strcpy(nom, lex);
  99.     else
  100.         printf("erreur : on attend un nom ou (dcl)\n" );
  101.     while((type = lirelex()) == PARENS || type == CROCHETS)
  102.         if(type == PARENS)
  103.             strcat(sortie, " fonction retournant" );
  104.         else
  105.         {
  106.             strcat(sortie, " tableau" );
  107.             strcat(sortie, lex);
  108.             strcat(sortie, " de" );
  109.         }
  110. }
 

Exemple : int (*test()) () --> le programme affiche test : fonction retournant pointeur sur fonction retournant int

 

Bon, déjà, la grammaire de ce genre de déclarations, c'est pas facile à appréhender je trouve.
Et concernant le programme, j'arrive pas à analyser l'ensemble du truc. Trop de fonctions qui s'appellent les unes les autres, je ne saisis pas le déroulement.
J'ai essayé de trouver une méthode de schématisation visuelle, sans succès, il me faudrait un grand tableau veleda peut-être, pour arriver à une représentation claire  :D
Essayé de mettre du commentaire partout aussi, mais c'est encore plus fouillis au final.

 

Rien que la méthode avec lirecar() et remettrecar(c), je trouve pas ça naturel, d'emblée ça me met le cerveau en vrac  [:bigorneau magique:5]

 

Donc deux requêtes :
- existe-t-il un moyen efficace de "visualiser" clairement le fonctionnement d'un code non (ou mal) commenté ? Une méthode standard de représentation graphique, avec des boîtes et des flèches je sais pas..
- et bien sûr, si quelqu'un se sent de m'aider à comprendre le code   :jap:  (plusieurs jours que je me prends la tête dessus   [:dobeliou2] )


Message édité par simius_computus le 23-12-2012 à 18:41:32

---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
Reply

Marsh Posté le 23-12-2012 à 18:40:19   

Reply

Marsh Posté le 24-12-2012 à 11:27:38    

Avec un logigramme, bon courage pour la suite.

Reply

Marsh Posté le 24-12-2012 à 13:34:05    

Noter que ce code ne marche pas si les paramètres des fonctions figurent dans la déclaration.
Par exemple, si on a une fonction
int *myf(char *s) {... }
la déclaration puis l'assignation qui suivent sont correctes
int *((*test)(char *));
test = &myf;
mais le code ne sait pas analyser la déclaration int *((*test)(char *))
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 25-12-2012 à 01:53:31    

Oui, ça fait justement partie des exos proposés par le bouquin : compléter le code.
Mais je peux pas les faire tant que j'ai pas pigé bien le truc de A à Z !
 
Bon là c'est trêve de Nowel  :o  
 
Jovalise, un logigramme, okay je vais googler  :D


---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
Reply

Marsh Posté le 25-12-2012 à 02:22:46    

Ben en fait faut juste que tu t’intéresse a dclabs qui est quasi recursive, au détail près que la récursion passe a travers dcl:  
dclabs fait:
...
if(typelex == '(')
    {
        dcl();
        if(typelex != ')')
            printf("erreur : ) manquante\n" );
    }
...
et  
dcl fait un appel à dclabs:
...
    dclabs();
...
C'est le seul truc un peu complexe du code.
 
On pourrait réécrire dclabs() sans avoir besoin de dcl, la récursion serait plus apparente:

Code :
  1. void dclabs(void)
  2. {
  3.     int type;
  4.     if(typelex == '(')
  5.     {
  6.         int ne;
  7.         for(ne = 0; lirelex() == '*'; )
  8.             ne++;
  9.         dclabs();
  10.         while (ne-- > 0)
  11.             strcat(sortie, " pointeur sur" );
  12.         if(typelex != ')')
  13.             printf("erreur : ) manquante\n" );
  14.     }
  15.     else if (typelex == NOM)
  16.         strcpy(nom, lex);
  17.     else
  18.         printf("erreur : on attend un nom ou (dcl)\n" );
  19.     while((type = lirelex()) == PARENS || type == CROCHETS)
  20.         if(type == PARENS)
  21.             strcat(sortie, " fonction retournant" );
  22.         else
  23.         {
  24.             strcat(sortie, " tableau" );
  25.             strcat(sortie, lex);
  26.             strcat(sortie, " de" );
  27.         }
  28. }


A+,


Message édité par gilou le 25-12-2012 à 02:28:40

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 25-12-2012 à 17:50:40    

Ah oui ça simplifie déjà les choses, merci. Après j'ai du mal à tracer le tandem lirecar() et remettrecar().
Quand j'aurai assimilé je posterai les solutions que je trouve aux exos du livre.


Message édité par simius_computus le 25-12-2012 à 17:51:18

---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
Reply

Marsh Posté le 25-12-2012 à 21:09:38    

Lirecar c'est tout con, ça lit un caractère de stdin, sauf si tu as stocké des caractères a lire dans un buffer ad-hoc (ptamp) avec remettrecar auquel cas, ça lit dans ce buffer.
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 25-12-2012 à 21:28:56    

Je comprends ce que ça fait, mais naturellement j'aurais mis la saisie dans un tableau, en virant les espaces etc.. Mais ça je suppose que c'est la méthode "bête"  :D


---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
Reply

Marsh Posté le 25-12-2012 à 21:50:09    

Ça serait plus simple, et au lieu de faire remettrecar, il suffirait de reculer le pointeur.  
Ce programme est pas du tout un modèle de qualité. Le seul avantage a faire comme ils font c'est de pas être limité par la taille de l'entrée (ce que ferait un tableau dans lequel on copie), mais vu comment ils se limitent en sortie avec sortie[MAXLEX] euh...
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 25-12-2012 à 23:05:26    

C'est ce que je me disais aussi !
 
Bonne soirée,


---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
Reply

Sujets relatifs:

Leave a Replay

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