#include #include #include #include #include #include #include "lexc.h" unsigned int _stklen=20000; #define CPP_VERSION 1 #define CPP_RELEASE 38 static void near usage(void) { static const char *tbf[]={ "cpp [options ...] fichier [fichier-résultat]", "Préprocesseur ANSI C", "\n", "-A : Numérotation des lignes du sources format ANSI", " Par défaut format # ligne source", "-C : Accepte commentaires imbriqués", "-D : Déclare une macro", " -Dmacro=val ou -Dmacro", " -Dmacro est équivalent à -Dmacro=1", "-E : Force un mot clé _export à la suite du mot clé class", " Patente a gosse pour assurer que toutes les fonctions", " membres sont _loadds.", "", "-Ff : Annule tout appel à la fonction f.", "", "-GN : Place toutes les chaines de caractères dans une", " table 'far'. La table sera nommé à partir du préfixe", " far_str_ et de N. Par défaut, N sera le nom du fichier", " source.", " Cette option solutionne la limite du segment de 64k", " sur les machines 16 bits.", " Si N finit avec un /, alors le nom du source y est", " ajouté. N est souvent le nom du sous-répertoire courant.", " Pour des raisons de simplicité, la table est globales.", " Elle doit donc avoir un nom unique.", "", "-I : Enregistre un path supplémentaire pour la", " recherche de fichier d'inclusion.", "-J : Insère silencieusement un fichier d'inclusion", " au début du source. Ce fichier d'inclusion", " sera préprocessé et conservé optionnellement.", " Il y a quatres variations possibles:", " -Jfichier.h", " -Jfichier.h,path", " -Jfichier.h,-path", " -Jfichier.h,--path", " Le premier cas inclue simplement le fichier", " Les trois autres interprètent le fichier et garde", " le résultat dans le répertoire path." " Le fichier sera relu simplement pour les sessions", " suivantes. Pour le troisième, une simple commande", " d'inclusion est insérée plutot qu'une copie du", " fichier interprété.", " Le quatrième a été ajouté pour supporter les", " fichiers d'inclusion précompilés de BC++.", " Dans ce cas, il ne faut pas de numérotation de lignes", " dans le fichier d'inclusion (BC GP fault). On peut", " en générer pour le reste du source toutefois.", "", "-K : Assure qu'un fichier d'inclusion n'est inclus qu'une", " fois. Cela optimise le traitement du préprocesseur.", "-K-n : Escamote le traitement -K pour le fichier n.", " Cela permet de multiple inclusion du fichier.", " Le path exact du fichier doit être spécifié.", " Si n est un répertoire, cela s'applique à tous", " les fichiers du répertoire.", "", "-L : Localise la déclaration d'une macro.", " -Lmacro", "-M : Affiche toutes les définitions de macros", " à la fin du traitement.", "-N : Ne cherche pas dans /usr/include", " Version UNIX seulement", "", "-O : Conversion des noms de fichiers d'inclusion", " x\\y\\z.h -> x/y/z.h", " Option utilse pour DJGCC", " Utilise pour DOS seulement", "", "-P : Ne génère pas la numérotation des lignes.", "-R : Pas de traduction des caractères français", " dans les chaines \"...\"", " Option sur Sunos seulement.", "-S : N'élimine pas le mot clé signed.", "-T : Trace les commandes #include.", " -Tfichier: produit les résultats dans fichier,", " -T sans argument produit à l'écran.", "-U : Pas de conversion à (unsigned char).", "-V : Insere #pragma interface au début de chaque", " fichier d'inclusion. Utile pour compiler avec GNU GCC.", NULL }; version_usagef (tbf,tbf,"CPP","CPP" # if defined(VERSION_SHARE) ,&version_share # elif defined(VERSION_PROD) ,&version_prod # elif defined(VERSION_DEV) ,&version_beta # elif defined(VERSION_ESSAI) ,&version_alpha # endif ,CPP_VERSION,CPP_RELEASE ,1991,0,0 ,NULL,NULL,NULL); } #if defined(CPU_SPARC) || defined(UNIX_LINUX) static char xlt[256]; /* Initialise le lookup pour traduction entre IBM PC et ISO */ static void cpp_initxlt(int ibm2iso) { int i; for (i=0; i<256; i++) xlt[i] = (char)i; if (ibm2iso){ /* Traduit IBMPC en ISO sur station SUN */ xlt[KEYIBM_EAIGU] = KEYISO_EAIGU; xlt[KEYIBM_AGRAVE] = KEYISO_AGRAVE; xlt[KEYIBM_EGRAVE] = KEYISO_EGRAVE; xlt[KEYIBM_UGRAVE] = KEYISO_UGRAVE; xlt[KEYIBM_ACONFLEX] = KEYISO_ACONFLEX; xlt[KEYIBM_ECONFLEX] = KEYISO_ECONFLEX; xlt[KEYIBM_ICONFLEX] = KEYISO_ICONFLEX; xlt[KEYIBM_OCONFLEX] = KEYISO_OCONFLEX; xlt[KEYIBM_UCONFLEX] = KEYISO_UCONFLEX; xlt[KEYIBM_CCDILLE] = KEYISO_CCDILLE; } } /* Génère une chaine "" ou '' en convertissant les code IBMPC en \0xxx Je ne suis pas certain de mon coup. Il se peut que le compilateur de SUN ne tolère pas les codes en dehors de l'ASCII. */ static void cpp_ibm2esc (FILE *fout, const char *_str, int DUM1) { const unsigned char *str = (unsigned char *)_str; char buf[10000]; char *ptbuf = buf; while (*str != '\0'){ if (*str >= 0x80){ char carac = xlt[*str++]; ptbuf += sprintf(ptbuf,"\\%o",carac); }else if (str[0] == '\\' && str[1] == 'a'){ *ptbuf++ = '\\'; *ptbuf++ = '7'; str += 2; }else{ *ptbuf++ = *str++; } } *ptbuf = '\0'; fputs (buf,fout); } #ifdef CPU_SPARC static char char2uns = 1; static char dosigned = 0; #else static char char2uns = 0; static char dosigned = 1; #endif #else #define cpp_initxlt(ibm2iso) static void cpp_ibm2esc(FILE *fout,const char *str, int DUM1) { fputs (str,fout); } static char char2uns = 0; static char dosigned = 1; #endif static char *far_str=NULL; static char *far_str_pt = NULL; static char *far_str_end = NULL; static char far_str_tbl[100]; /* Nom de la table de chaine */ /* Accumule une chaine dans un grand tableau et génère le nom de la variable à la place ainsi que le offset. Cette fonction est utilisé pour générer toutes les chaines littérales d'un source dans une grande table far. Les références à ces chaines sont remplacé par la table + un offset. */ static void far_str_accum (FILE *fout, const char *str, int declare) { if (declare) fprintf (fout,"(%s+%d)",far_str_tbl,far_str_pt-far_str); if (*str == '"') str++; far_str_pt = str_compile (str,far_str_pt); if (far_str_pt > far_str_end){ error_bexit ("Trop de chaine de caractères. Maximum 55k (option -G)\n" ,"Too many strings. Max 55k (-G option)\n"); } } static char old_lineinfo=1; /* Présente information sur ligne dans le source */ static void cpp_lineinfo( FILE *fout, int line, const char *file) { if (old_lineinfo){ fprintf (fout,"# %d \"%s\"\n",line,file); }else{ fprintf (fout,"#line %d \"%s\"\n",line,file); } } /* Il n'est pas possible de demander que les char soit unsigned par défaut. Le truc est d'insérer soit un cast devant les "", le '', et d'insérer le mot clé unsigned dans les déclarations de variables caractère. */ static void unsigned_insert(FILE *fout, const char *str) { if (char2uns){ fputs (str,fout); } } static TOKEN tok; static int curlin = -1; static int lineinfo = 0; static FILE *fout; static void near cpp_setline (void) { if (tok.noline != curlin){ /* Le token provient d'une ligne différente */ fputs ("\n",fout); if (lineinfo){ static const char *cur_file=NULL; const char *newcur_file = filesrc_curfile(); if (tok.noline != curlin+1 || cur_file != newcur_file){ cur_file = newcur_file; /* qui n'est pas la suivante: On informe */ /* le compilateur */ cpp_lineinfo (fout,filesrc_curline(),cur_file); } } curlin = tok.noline; } } static int class_export = 0; /* Préprocesseur sans reformattage avec info, correspondance avec source Fait la transformation des char ordinaire et unsigned char. Ca inclue les chaines littérales et les caractères. Concatène les séquences de chaines littérales: "allo" "comment" -> "allocomment" */ static int near cpp_do ( char **tbnulfct, /* Fonction dont il faut annuler les appels */ int nbnulfct, int do_far_str) /* Place les chaines littérals dans un tableau ? */ { int ret = 0; int laststring = 0; int last_extern = 0; /* Evite de modifier extern "C" */ int last_ismod = 0; int nulfct_on = 0; /* Annule un appelle de fonction */ /* et compte les parentheses imbriquées */ void (*output_str)(FILE *, const char *,int); int export_accum=0; /* On a vue a export on on attend pour generer */ /* un _export */ char export_laststr[100]; /* token a generer en retard */ export_laststr[0] = '\0'; curlin = -1; if (do_far_str){ fprintf (fout,"extern char far %s[];\n",far_str_tbl); far_str_pt = far_str = (char*) malloc_err (60000u,1); far_str_end = far_str + 55000u; /* Laisse securite */ output_str = far_str_accum; }else{ output_str = cpp_ibm2esc; } while (token_get(&tok) != -1){ if (nulfct_on > 0){ if (tok.type == TOK_CLSPAR){ nulfct_on--; }else if (tok.type == TOK_OPNPAR){ nulfct_on++; } }else{ extern int filesrc_level; char *tok_txt = token_txt(&tok); /* cfront supporte pas la concatenation ANSI C */ /* On fait le travail pour lui */ int new_last_ismod = 0; if (export_accum){ cpp_setline(); if (tok.type == TOK_OPNPAR){ fprintf (fout,"_export %s (",export_laststr); export_accum = 0; }else if (tok.type2.keyword == KEY_OPERATOR && tok.type == TOK_KEYWORD){ fprintf (fout,"%s _export %s ",export_laststr,tok_txt); export_accum = 0; }else if (tok.type2.keyword == KEY_CLASS && tok.type == TOK_KEYWORD){ fputs ("class _export ",fout); export_accum = 0; }else if (tok.type == TOK_PTV){ /* Ca permet de retomber sur nos pattes pour */ /* les export place un peu n'importe ou */ fprintf (fout,"%s ;",export_laststr); export_accum = 0; }else{ fprintf (fout,"%s ",export_laststr); strcpy (export_laststr,tok_txt); } }else if (tok.type == TOK_STRING){ int len = strlen(tok_txt); tok_txt[len-1] = '\0'; /* Elimine le " a la fin */ if (laststring){ /* Ce n'est pas la première string, on ne met pas le guillemet du début. */ (*output_str) (fout,tok_txt+1,0); }else{ cpp_setline (); if (!last_extern){ unsigned_insert(fout,"(unsigned char *) "); (*output_str) (fout,tok_txt,1); laststring = 1; }else{ /* On vient de voir extern "C" */ fprintf (fout,"%s\"",tok_txt); } } }else if (tok.type2.keyword == KEY_EXPORT && tok.type == TOK_KEYWORD){ /* En inversant le test, je suppose que c'est plus rapide */ export_laststr[0] = '\0'; export_accum = 1; }else{ /* On ajoute le " si dernier token etait une string */ if (laststring){ if (do_far_str){ *far_str_pt++ = '\0'; }else{ fputc ('"',fout); } } laststring = 0; last_extern = 0; cpp_setline(); if (tok.type == TOK_QUOTE){ unsigned_insert (fout,"(unsigned char) "); cpp_ibm2esc (fout,tok_txt,0); fputs (" ",fout); }else if (tok.type == TOK_PRAGMA){ fputs ("#pragma ",fout); fputs (tok_txt,fout); }else if (tok.type == TOK_KEYWORD){ if (tok.type2.keyword == KEY_UNSIGNED){ new_last_ismod = 1; }else if (tok.type2.keyword == KEY_SIGNED){ if (!dosigned){ tok_txt = ""; /* SUN20 est allergique au signed*/ } new_last_ismod = 1; }else if (tok.type2.keyword == KEY_CHAR){ if (!last_ismod) unsigned_insert (fout,"unsigned "); }else if (tok.type2.keyword == KEY_EXTERN){ last_extern = 1; }else if (class_export && tok.type2.keyword == KEY_CLASS){ fputs (tok_txt,fout); fputs (" ",fout); tok_txt = "_export"; } fputs (tok_txt,fout); fputs (" ",fout); }else if (tok.type == TOK_ID && nbnulfct > 0 && filesrc_level == 0){ char **pt = tbnulfct; int i; for (i=0; i 0){ char *pt = far_str; fprintf (fout,"char far %s[]={\n",far_str_tbl); for (i=0; i0){ fwrite (buf,1,nb,fout); } fclose (fin); free (buf); }else{ fprintf (fout,"#include \"%s\"\n",path); } } int main (int argc, char *argv0[]) { int ret = -1; ARGP_MULTI argp[26]; char **argv; basio_setlangue (argv0[0],"pcppf","pcppe"); argv = (char**)malloc_err (400*sizeof(char*),1); argc = anlparm_indirm (argc,argv0,argv,400,argp,"abcd*ef*gi*jk*lmnoprstuv"); if (argc < 2 ){ if (argc == 1) usage(); }else{ int err = 0; int noarg=1; int stdinclude=1; int prt_def = 0; int do_far_str = 0; FILE *ftrace = NULL; /* Log des includes */ lineinfo = 1; /* Produit info sur no de ligne dans */ /* le source */ token_init (); token_setchkkey (1); token_setpreproc(1); filesrc_settabmode(0); comment_setaccum(0); #ifdef CPU_SPARC token_setdef ("sun=1"); token_setdef ("unix=1"); #endif precond_pragmamode(1); { /* Analyse les options */ char *pt; int i; ARGP_MULTI *arg; cpp_initxlt(argp['r'-'a'].ptr==NULL); old_lineinfo = argp['a'-'a'].ptr == NULL; class_export = argp['e'-'a'].ptr != NULL; stdinclude = argp['n'-'a'].ptr == NULL; prt_def = argp['m'-'a'].ptr != NULL; comment_setmode (argp['c'-'a'].ptr != NULL); if (argp['o'-'a'].ptr != NULL) filesrc_set2unix(); /* Génération de #line, par défaut actif */ lineinfo = argp['p'-'a'].ptr == NULL; /* Génère le mot clé signed, C++ SUNOS 2.0 ne le bouffe pas */ dosigned = argp['s'-'a'].ptr != NULL; /* Conversion de char en unsigned char, par défaut actif */ char2uns = argp['u'-'a'].ptr == NULL; /* Insertion de #pragma interface au debut des fichier */ /* d'inclusion */ if (argp['v'-'a'].ptr != NULL){ filesrc_forceins ("#pragma interface"); } arg = &argp['k'-'a']; for (i=0; inbptr; i++){ char *pt = arg->ptrs[i]; if (pt[0] == '\0'){ filesrc_setdeja (1); }else if (pt[0] != '-'){ error_bprintf ("Option -k invalide: -k%s\n" ,"Invalid -k option: -k%s\n",pt); err = 1; }else{ filesrc_setxdeja (pt); } } /* Génération d'une table de string "far" */ do_far_str = argp['g'-'a'].ptr != NULL; if (do_far_str){ char suffix[MAXSIZ_PATH]; strcpy (suffix,argp['g'-'a'].ptr); int len = strlen(suffix); if (len == 0){ file_baseext (argv[noarg],suffix,NULL); }else if (suffix[len-1] == '/'){ suffix[len-1] = '_'; file_baseext (argv[noarg],suffix+len,NULL); } sprintf (far_str_tbl,"far_str_%s",suffix); } pt = argp['l'-'a'].ptr; if (pt != NULL){ if (pt[0] != '\0'){ preproc_setlocate (pt); }else{ err = 1; error_bprintf ("Option -L sans argument ???\n" ,"Option -L without argument ???\n"); } } pt = argp['t'-'a'].ptr; if (pt != NULL){ if (pt[0] == '\0'){ ftrace = stdout; }else{ ftrace = fopen_err (pt,"w",1); } filesrc_settrace (ftrace); } /* Traitement des defines */ arg = &argp['d'-'a']; for (i=0; inbptr; i++){ token_setdef (arg->ptrs[i]); } arg = &argp['i'-'a']; for (i=0; inbptr; i++){ filesrc_setpath (arg->ptrs[i]); } } #ifdef UNIX if (stdinclude) filesrc_setpath ("/usr/include"); #endif if (!err){ fout = stdout; if (argc == 3){ fout = fopen_err (argv[argc-1],"w",1); setvbuf (fout,NULL,_IOFBF,20*512); } if (argp['j'-'a'].ptr != NULL && !err){ char *pt = argp['j'-'a'].ptr; char *nxtpt = strchr (pt,','); /* Traitement du fichier de préinclusion */ if (nxtpt == NULL){ cpp_open (pt); ret = cpp_do (argp['f'-'a'].ptrs,argp['f'-'a'].nbptr ,do_far_str); token_close(); }else{ char path[MAXSIZ_PATH]; char path_def[MAXSIZ_PATH]; char path_dja[MAXSIZ_PATH]; *nxtpt++ = '\0'; int pre_copie = 1; if (*nxtpt == '-'){ nxtpt++; // On insère simplement un include dans le source // au début du fichier. pre_copie = 0; if (*nxtpt == '-'){ nxtpt++; lineinfo = 0; } } path_make (nxtpt,pt,path); file_chgext (path,path_def,"def"); file_chgext (path,path_dja,"dja"); if (file_exist (path) && file_exist(path_def)){ // Le fichier existe d'une session précédante. // On relie simplement les #define // cpp_precopie (path,pre_copie,fout); cpp_open (path_def); ret = cpp_do (NULL,0,0); token_close(); if (argp['k'-'a'].ptr != NULL){ filesrc_readdeja (path_dja); } }else{ // On doit produire le fichier dans path FILE *tmp_fout = fout; fout = fopen_err (path,"w",1); cpp_open (pt); ret = cpp_do (argp['f'-'a'].ptrs,argp['f'-'a'].nbptr ,do_far_str); filesrc_writedeja (path_dja); token_close(); fclose (fout); fout = tmp_fout; FILE *def_out = fopen_err (path_def,"w",1); bfprintf (stderr,"Préserve %s pour les sessions suivantes\n" ,"Preserving %s for next run\n",path_def); preproc_dumpmac (def_out); fclose (def_out); cpp_precopie (path,pre_copie,fout); } lineinfo = argp['p'-'a'].ptr == NULL; } } cpp_open (argv[noarg]); ret = cpp_do (argp['f'-'a'].ptrs,argp['f'-'a'].nbptr ,do_far_str); fprintf (fout,"\n"); if (fout != stdout){ fclose (fout); } ret |= lexcerr_getnb(); } token_close (); if (prt_def) preproc_dumpmac (stdout); if (ftrace != NULL && ftrace != stdout) fclose (ftrace); } return ret; }