#include #include #include #include #include #include #include #include #include "lexc.h" #define OPT_PROFILE 0 extern int filesrc_noline; static void near preproc_error ( const char *line, const char *pos, const char *msgf, const char *msga) { char buff[100]; char bufa[100]; sprintf (buff,"D‚finition invalide : %s\n%%s\n%%*s\n",msgf); sprintf (bufa,"Invalid definition : %s\n%%s\n%%*s\n",msga); lexcerr_bprintf (buff,bufa ,line,(int)(pos-line),"^"); } /* #Sp‚cification: Pr‚processeur / macros / limites Nombre maximum de macros: 5000 */ #define MAXSYM_EXT 20 static struct{ /* Les tbsym sont alloues par section discontinues */ DEF_SYM *tbsym[MAXSYM_EXT]; /* Ca fait au maximum 5000 macros */ int nb; } tbx; /* Table de pointeur pour paramŠtre de macros Cette table est allou‚ en section au besoin */ #define MAX_TBPRM 1000 /* Alloue 1000 pointeur … la fois */ typedef struct _tbprm { int nbprm; struct _tbprm *next; char *tbprm[MAX_TBPRM]; } L_TBPRM; static L_TBPRM *ltbprm; /* Section courante */ static DEF_SYM *tbsym; static short nbsym; /* Nombre de symbole couramment dans tbsym */ /* Ne tient pas compte des tbx.tbsym[] d‚j… */ /* rempli */ #define MAXSYM 500 /* Nombre maximum de symbole dans tbsym */ static short global=0; /* Nombre de symboles d‚finis sur la ligne de commande */ static char *alphakey; /* Permet de savoir rapidement si un symbole existe */ static DEF_SYM **hashkey;/* Index hashing */ #if OPT_PROFILE int nblocate=0; /* Nombre d'appel preproc_locate */ int nbessai=0; /* Nombre d'iteration */ #define profile_inc(var) var++; static void profile_print(){ printf ("Preproc_locate %d %d %d %d\n",nblocate,nbessai,tbx.nb,nbsym); } static void profile_init(){ atexit(profile_print); } #else #define profile_inc(var) #define profile_init() #endif /* Insere un symbole dans la table de hashing */ static void near preproc_insertsym (DEF_SYM *ptsym) { char *nom = ptsym->nomdef; int hash = 0; alphakey[*nom] = 1; while (*nom != '\0') hash += *nom++; hash &= 0xff; ptsym->nextsym = hashkey[hash]; hashkey[hash] = ptsym; } /* Initialise ou r‚initialise la table de symbole des macros */ void preproc_init (void) { if (tbsym != NULL){ int i; int offset = global; for (i=0; inbprm; j++) free (ptsym->tbprm[j]); free (ptsym->nomdef); free (ptsym->repl); } offset = 0; } /* LibŠre les extensions de tbsyms */ for (i=1; inext != NULL){ L_TBPRM *next = ltbprm->next; free (ltbprm); ltbprm = next; } /* Replace l'allocateur dans ltbprm */ if (global > 0){ DEF_SYM *ptsym = tbsym + global -1; int nb = ptsym->nbprm; if (nb < 0) nb = 0; ltbprm->nbprm = (int)(ptsym->tbprm - ltbprm->tbprm) + nb; }else{ ltbprm->nbprm = 0; } }else{ tbsym = (DEF_SYM*) malloc_err ((unsigned)MAXSYM*sizeof(DEF_SYM),1); tbx.tbsym[0] = tbsym; tbx.nb = 1; hashkey = (DEF_SYM**) malloc_err(256*sizeof(DEF_SYM*),1); alphakey = (char *) malloc_err(256*sizeof(char),1); ltbprm = (L_TBPRM*) malloc_err (sizeof(L_TBPRM),1); ltbprm->next = NULL; ltbprm->nbprm = 0; profile_init(); } nbsym = global; { /* Reconstruit les index d'acces */ short i; DEF_SYM *ptsym = tbsym; for (i=0; i<256; i++) hashkey[i] = NULL; memset (alphakey,0,256); for (i=0; inomdef,ptsym->repl); if (strcmp(nomdef,ptsym->nomdef)==0){ ret = ptsym; break; }else{ ptsym = ptsym->nextsym; } } } if (talk){ if (ret != NULL){ printf ("ret = :%s: :%s:\n",ret->nomdef,ret->repl); }else{ printf ("ret = NULL\n"); } } return ret; } static char *preproc_declocate=NULL; /* Enregistre le nom de la macro dont on veut connaitre l'origine. On utilise cette fonction pour affich‚ l'endroit exacte o— une macro a ‚t‚ d‚clar‚. (quel source, inclue par quel autre, etc ...) */ void preproc_setlocate(const char *_locate) { if (preproc_declocate != NULL) free (preproc_declocate); preproc_declocate = strdup_err (_locate,1); } /* Enregistre une macro son remplacement */ /* #Sp‚cification: Pr‚processeur/macros/paramŠtres Une macro avec 0 paramŠtre s'utilise diff‚remment d'une macro sans paramŠtres. #define mac() ... et #define mac ... ne s'utilise pas de la mˆme fa‡on. */ void preproc_putdef ( const char *nomdef, /* nom de la macro */ const char *repl, /* Chaine de remplacement */ int lenrepl, char *tbprm[], /* ParamŠtres */ int nbprm, /* Nombre de paramŠtres */ /* -1 pour macro sans paramŠtre */ /* Diff‚rent de macro avec 0 paramŠtre */ int cmdline) /* provient de la ligne de commande ou pas */ { DEF_SYM *ptsym; token_initcomment(); /* Quand on voit un #define, on reset */ /* l'accumulation des commentaires */ /* Les fichier .m font deborder bufcom */ if (preproc_declocate != NULL && strcmp(nomdef,preproc_declocate)==0){ /* La macro qu'on enregistre interesse l'usager, On doit lui indiqu‚ o— la d‚claration s'est faite. */ bfprintf (stderr ,"Macro %s d‚clar‚e ici\n" ,"Macro %s defined here\n",preproc_declocate); filesrc_showpos (stderr); } if (tbsym == NULL){ preproc_init(); }else if (nbsym == MAXSYM){ if (tbx.nb == MAXSYM_EXT){ error_bexit ( "Limite du pr‚processeur: Trop de macros\n" "\tMaximum %d\n" ,"Preprocessor limit: Too many defines\n" "\tMaximum %d\n" ,MAXSYM_EXT*MAXSYM); }else{ /* V‚rifie si la table doit ˆtre grossie */ tbsym = (DEF_SYM*)malloc_err((unsigned)MAXSYM*sizeof(DEF_SYM),1); tbx.tbsym[tbx.nb++] = tbsym; nbsym = 0; } } if (cmdline){ /* Les macros de la ligne de commande doivent ˆtre les premiers De la liste. On r‚initialise la liste en eliminant tous les autres. Ce ne peut pas se produire durant l'interpr‚tation d'un source. */ preproc_init(); global++; } ptsym = tbsym+nbsym; ptsym->nomdef = strdup_err (nomdef,1); ptsym->repl = (char*)malloc_err(lenrepl+1,1); if (lenrepl > 0) memmove (ptsym->repl,repl,lenrepl); ptsym->repl[lenrepl] = '\0'; ptsym->lenrepl= lenrepl; ptsym->nbprm = (short)nbprm; ptsym->lastline = -1; if (nbprm > 0){ /* V‚rifie s'il y a de la place dans la table courante */ int nbtb = ltbprm->nbprm; if (nbtb + nbprm >= MAX_TBPRM){ /* Tous les pointeurs de ltbprm ne sont pas occup‚s */ L_TBPRM *newtb = (L_TBPRM*)malloc_err (sizeof(L_TBPRM),1); newtb->next = ltbprm; ltbprm = newtb; nbtb = 0; } ptsym->tbprm = <bprm->tbprm[nbtb]; ltbprm->nbprm = nbtb + nbprm; memmove (ptsym->tbprm,tbprm,nbprm*sizeof(char*)); }else{ /* Lors de r‚initialisation, on assume que tous les macros possŠde un pointeur valide, meme si nbprm = 0. */ ptsym->tbprm = <bprm->tbprm[ltbprm->nbprm]; } preproc_insertsym (ptsym); nbsym++; } /* Enregistrement de la d‚claration d'un define Retourne position de traitement dans la ligne suivante car peut sauter des commentaires Le texte de remplacement sera minimalement trait‚. S'il y a des commentaires imbriqu‚s dans le texte, il sera conserv‚. La fonction preproc_skipline permet de localiser la fin de la ligne avant le dernier commentaire (potentiellement ‚tendue sur plusieurs lignes). La fonction charge alors une nouvelle ligne dans line, c'est pourquoi il faut faire une copie temporaire dans repl. Les valeurs debpt et endpt serve uniquement … identifi‚ la partie valide de repl. */ char *preproc_recdefine( char *line, /* pointe au d‚but de la ligne #define */ /* line est aussi le buffer unique de ligne */ char *pt) { static char *repl=NULL; if (repl == NULL) repl=(char*)malloc_err(3000,1); if (token_idok(*pt)){ /* #Specification: preprocesseur/macro Longueur maximum d'un nom de macro: 99 caractŠres. */ char nomdef[100]; pt = token_copyid (pt,nomdef); if (*pt == '('){ /* macro avec paramŠtres */ /* #Specification: preprocesseur/limites Nombre maximum de paramŠtres pour un macro: 30 */ int nbprm=0; char *tbprm[30]; while (1) { char id[100]; pt++; /* saute ( ou , */ pt = str_skip (pt); if (token_idok(*pt)){ if (nbprm == 30){ preproc_error (line,pt ,"Trop de paramŠtre, maximum 30" ,"Too many parameters, max 30"); precond_skipline(&pt,line); break; }else{ pt = token_copyid (pt,id); tbprm[nbprm++] = strdup_err(id,1); pt = str_skip (pt); } } if (*pt != ','){ if (*pt == ')'){ char *debpt = pt = str_skip (pt+1); strcpy (repl,debpt); { char *endpt = precond_skipline (&pt,line); int len = (int)(endpt-debpt); repl[len] = '\0'; preproc_putdef (nomdef,repl,len,tbprm,nbprm,0); } }else{ preproc_error (line,pt,"ParenthŠse manquante" ,"Missing parenthesis"); precond_skipline(&pt,line); } break; } } }else if (isspace(*pt) || *pt == '\0'){ /* macro ordinaire */ char *debpt = pt = str_skip (pt); strcpy (repl,debpt); { char *endpt = precond_skipline (&pt,line); int len = (int)(endpt-debpt); repl[len] = '\0'; preproc_putdef (nomdef,repl,len,(char**)NULL,-1,0); } }else{ preproc_error (line,pt,"",""); precond_skipline(&pt,line); } }else{ preproc_error (line,pt,"Symbole invalide","Invalid symbol"); precond_skipline(&pt,line); } return (pt); } #if 0 static char sigerr; /* Signale les erreurs de unref */ /* Enregistre si on doit signaler des erreurs de undef ou pas */ void preproc_errundef (int outputerr) { sigerr = (char)outputerr; } #endif /* Elimine la d‚claration d'un define Retourne adresse de lecture dans la ligne */ char *preproc_undef( char *DUM1, /* pointe au d‚but de la ligne #undef */ char *ptl) { char txt[100]; ptl = token_copyid (ptl,txt); if (txt[0] != '\0'){ DEF_SYM *ptsym = preproc_locate (txt); if (ptsym != NULL){ ptsym->nomdef[0] = '\0'; #if 0 }else if (sigerr){ lexcerr_bprintf ("#undef : Symbole %s n'est pas d‚finie\n" ,"#undef : Undefined symbol %s\n",txt); #endif } } return (ptl); } /* Fait le remplacement d'un symbole si c'est un define Retourne 1 si le token a ‚t‚ remplac‚, 0 sinon Si le token ‚tait un define, la chaine de remplacement a ‚t‚ copi‚ dans le buffer de traitement (line) en reculant ptl. Cela simule un insertion V‚rifie l'utilisation r‚cursive d'un symbole */ int preproc_convert ( TOKEN *tok, /* token … convertir si requis */ char **ptl, /* position de lecture dans la ligne */ char *line, /* buffer de lecture */ const char *fullbuf) /* D‚but du buffer. ptl ne peut pas */ /* reculer plus loin */ /* Permet de d‚tect‚e les r‚cursions */ { int ret = 0; char *txt = token_txt (tok); char *repl; int lenrepl=0; if (strcmp(txt,"__LINE__")==0){ char buf[10]; lenrepl = sprintf (buf,"%d",filesrc_curline()); }else if (strcmp(txt,"__FILE__")==0){ char buf[MAXSIZ_PATH]; char fname[MAXSIZ_NAME]; path_splitlex (filesrc_curfile(),NULL,fname); lenrepl = sprintf (buf,"\"%s\"",fname); }else{ DEF_SYM *ptsym = preproc_locate (txt); if (ptsym != NULL){ if (ptsym->nbprm != -1){ /* Macro avec paramŠtre, il faut localiser les paramŠtres */ repl = preproc_expand (line,ptl,ptsym); if (repl != NULL) lenrepl = strlen(repl); }else{ lenrepl = ptsym->lenrepl; repl = ptsym->repl; } } } if (lenrepl != 0){ if ((int)(*ptl-fullbuf) < lenrepl){ lexcerr_bprintf ( "D‚bordement de l'expansion macro\n" "Probablement caus‚ par une d‚finition r‚cursive\n" "de macro\n" ,"Macro expansion overflow, probably caused\n" "by a recursive macro definition\n"); }else{ *ptl -= lenrepl; memmove (*ptl,repl,lenrepl); ret = 1; } } return ret; } /* Affiche la d‚claration de la toutes les macros d‚j… enregistr‚ */ void preproc_dumpmac (FILE *fout) { int i; for (i=0; inomdef); if (ptsym->nbprm >= 0){ int p; const char *ctrl = "%s"; fprintf (fout,"("); for (p=0; pnbprm; p++){ fprintf (fout,ctrl,ptsym->tbprm[p]); ctrl = ",%s"; } fprintf (fout,") "); } fprintf (fout,"\t%s\n",ptsym->repl); } } }