//g++ Ydf1.cc -Wall -o Ydf1 #include #include #include #include #define BUFSIZE 2048 #define LG_MAX_NAME 24 #define NB_MAX_VARIAB 10000 #define LG_MAX_BIGVAR 128 #define NB_MAX_EXPRESYM 10000 #define NB_MAX_DIFFVAR 10000 //#define NB_MAX_CPLX 1000 /*=============================================================================*/ struct st_diff { char vardiff[LG_MAX_NAME*2 + 1]; int deblockportee; }; /*=============================================================================*/ short trace=0; FILE *fpmodul, *fpginac; //char modul_file_name[LG_MAX_NAME+1]; int i, j=0, k; char buffer[BUFSIZE+1]; char delim[] =" \t(),\n"; //char *pstr1, *pstr3, *pstrw; //char *pstr2=NULL; short Phase=0; int NbIn, NbOut; int indicYS=0; int indic=0; char instruct[BUFSIZE+1]; short indicBLOCK=0; short indicCROUV=0; short indicTAB=0; char TabVar[NB_MAX_VARIAB][LG_MAX_BIGVAR+1]; int NbVar=0; short indicDECLAR=0; short indicAFFECT=0; short prodlevel=0; char Ysubstit[LG_MAX_NAME+1]; int iexp; char TabExpreSym[NB_MAX_EXPRESYM][LG_MAX_NAME + 1]; short TabFlagIn[NB_MAX_EXPRESYM]; int NbExpreSym = 0; //char affectsv[BUFSIZE+1]; struct st_diff TabDiff[NB_MAX_DIFFVAR]; int NbDiff = 0; int CurBlockLev = 0; //semaphore de decompte des accolades pour gerer le niveau d'imbrication des block char ModulName[LG_MAX_NAME+1]; //int lenModulName; char TabDejaDiff[NB_MAX_DIFFVAR][LG_MAX_NAME+1]; //!!! tableau en global a usage local : initialement, et int NbDejaDiff; // localement, mettre NbDejaDiff a ZERO ! short flagCPLX=0; int NbInCplx=0; //char TabCplx[NB_MAX_CPLX][LG_MAX_NAME + 1]; //int NbCplx=0; //principaux mots du langage C/C++ (liste non exhaustive ... ) #define NB_CWORD 109 char TabCword [NB_CWORD][LG_MAX_NAME] = { "abs", "acos", "asin", "atan", "atan2", "atoi", "atof", "atol", "break", "case", "char", "close", "complex", "const", "continue", "cos", "cosh", "default", "delete", "div", "do", "double", "enum", "else", "exp", "exit", "extern", "fabs", "float", "fclose" "feof", "fgetc", "fgets", "fopen", "for", "fprintf", "fputc", "fputs", "free", "getc", "getchar", "getenv", "gets", "goto", "if", "int", "isalnum", "isdigit", "islower", "isupper", "log", "log10", "long", "memchr", "memcmp", "memcpy", "memove", "new", "NULL", "open", "pow", "putenv", "puts", "rand", "read", "return", "scanf", "setenv", "sprintf", "short", "sin", "sinh", "sizeof", "sqrt", "srand", "sscanf", "static", "stdin", "stdout", "strcat", "strchr", "strcmp", "strcpy", "strlen", "strncat", "strncmp", "strncpy", "strpbrk", "strrchr", "strspn", "strstr", "strtok", "strtol", "struct", "switch", "tan", "tanh", "tolower", "toupper", "typedef", "union", "unsigned", "void", "volatile", "vfprintf", "vsprintf", "while", "write", "YREAL", }; /*=============================================================================*/ //*---------------------------------------------------------------------------*/ int c_word(char *word) { int wi; for (wi=0; wi="); if (pstr != NULL) return (str_affect(pstr+2)); pstr = strstr(str, "<="); if (pstr != NULL) return (str_affect(pstr+2)); pstr = strstr(str, "!="); if (pstr != NULL) return (str_affect(pstr+2)); //autres cas non traited plm : <<=, >>=, &=, ^=, |= //et enfin le cas d'une simple affectation pstr = strstr(str, "="); if (pstr != NULL) return pstr; return(NULL); } /*---------------------------------------------------------------------------*/ void str_lesschr(char *str, char car) { int lg, i,j; lg = strlen(str); i=j=0; for (i=0; i=pmax) return (NULL); p1 = str; //se positionner sur le 1er caratere non delimiteur while (p1[0]!='\0' && strchr(delim, p1[0])!=NULL) ++p1; //avancer tant qu'on ne retombe pas sur un caratere delimiteur p2=p1; while (p2[0]!='\0' && strchr(delim, p2[0])==NULL) ++p2; //on informe du delimiteur trouved avant de l'ecraser par '\0' *svdelim=p2[0]; p2[0]='\0'; return(p1); } /*---------------------------------------------------------------------------*/ void BackwardOut(char *instruct) { char *pstr1, *pstr2; char bufwrk[BUFSIZE+1]; if (trace) printf("\n/*BO:%s:*/\n", instruct); strcpy(bufwrk, instruct); pstr1 = bufwrk; fprintf(fpginac, " cout "); while (1) { pstr2 = strpbrk(pstr1, "\n\""); if (pstr2!=NULL) { if (pstr2[0]=='\n') { pstr2[0]='\0'; fprintf(fpginac," <<\"%s\" <=NB_MAX_VARIAB) { printf("Ydf1: too much variables in that modul (%s)\n", ModulName); exit(-9); } strcpy(TabVar[NbVar], strvar); ++NbVar; return(NbVar-1); } /*---------------------------------------------------------------------------*/ short is_yadvar(char *str) { char bufstr[7]; strncpy(bufstr, str, 6); //strcpy(bufstr, str); bufstr[6]='\0'; return (!strcmp(bufstr, "Yadvar")); } /*---------------------------------------------------------------------------*/ int exist_expresym(char *expresym) { int wi; for (wi=0; wi VAR = VAR {+,-,*,/} ( EXPR ) ; // ( avec pstr2 qui pointera sur le = et non plus le {+,-,*,/}= ) char bufwrk[BUFSIZE+1]; char *p3; //printf("befor|%s|%c|\n", instruct, pstr2[0]); memset(bufwrk, '\0', BUFSIZE+1); bufwrk[0]=pstr2[-1]; pstr2[-1] = '\0'; //on termine la variable affectee par un '\0' //il faut retrouver la variable affectee (ie se positionner dessus) p3 = pstr2-2; while ((p3[0]==' ' || p3[0]=='\t') && p3>instruct) --p3; //on remonte les espaces et \t while (p3[0]!=' ' && p3[0]!='\t' && p3>instruct) --p3; //on remonte les autres caractères if (p3|%s|%s|%s|<-\n", pstr1, pstr2, pstr3+1); //pour verif du decoupage strcpy(strtab, pstr2); str_lesschr(strtab, ' '); //printf ("->|%s|<-\n", strtab); //ajout de ce tableau comme variable dans un tableaux de variable idvar = add_var(strtab); sprintf (yadvari, "Yadvar%i", idvar); // //creation du symbol pour le tableau fprintf(fpginac," symbol %s(\"%s\");\n", yadvari, yadvari); //declaration de la variable intermediaire pour backward fprintf(fpginac," cout<<\"double %s = %s;\"<=NB_MAX_DIFFVAR) { printf(" Ydf1: Automatic derivativ stopped for modul %s\n", ModulName); printf(" because :=> too much derivative in that modul\n"); exit(-9); } strcpy(TabDiff[NbDiff].vardiff, DA_dx); TabDiff[NbDiff].deblockportee = CurBlockLev; ++NbDiff; fprintf(fpginac," cout<<\"double %s; \"<=NB_MAX_EXPRESYM) { printf(" Ydf1: Automatic derivativ stopped for modul %s\n", ModulName); printf(" because :=> too much token in that modul\n"); exit(-9); } /*nb: on est dans cette fct que si queaffect, CELA N'EST SANS DOUTE PLUS VRAI donc la variable n'a pas du faire l'objet // d'une declaration ce qui laisse penser qu'il s'agit d'une variable externe. // Si on est sur le token qui precede le '=', alors cela voudrait dire qu'on est en // train de de modifier cette variable externe, ce qui du coup modifie la fonction // elle meme, ce qui not fair et rend les testdf KO, --> WARNING if (!vuegal) { printf("WARNING: you may be are modifying a extenal variable (%s) ...\n", p1); printf(" this is not fair and may make failed the validation functions test\n"); } */ strcpy(TabExpreSym[NbExpreSym], p1); ++NbExpreSym; fprintf(fpginac," ex %s;\n", p1); fprintf(fpginac," symbol Ygs_%s(\"Ygs_%s\");\n", p1, p1); } pstr = pstr+strlen(pstr)+1; } } /*---------------------------------------------------------------------------*/ short dejadiff(char *var2diff) { //char TabDejaDiff[NB_MAX_DIFFVAR][LG_MAX_NAME+1]; //!!! tableau en global a usage local : initialement, et // localement, mettre NbDejaDiff a ZERO ! int wi; for (wi=0; wi=NB_MAX_DIFFVAR) { printf(" Ydf1: Automatic derivativ stopped for modul %s\n", ModulName); printf(" because :=> too much derivative in that modul\n"); exit(-9); } strcpy(TabDiff[NbDiff].vardiff, dA_DV); TabDiff[NbDiff].deblockportee = CurBlockLev; ++NbDiff; fprintf(fpginac," ex %s;\n", dA_DV); fprintf(fpginac," cout<<\"double %s; \"<=NB_MAX_DIFFVAR) { printf(" Ydf1: Automatic derivativ stopped for modul %s\n", ModulName); printf(" because :=> too much derivative in that modul\n"); exit(-9); } strcpy(TabDejaDiff[NbDejaDiff], dA_DV); ++NbDejaDiff; fprintf(fpginac," %s = %s.diff(Ygs_%s, 1);\n", dA_DV, A, p1); fprintf(fpginac," cout<<\"%s = \" <=NB_MAX_DIFFVAR) { printf(" Ydf1: Automatic derivativ stopped for modul %s\n", ModulName); printf(" because :=> too much derivative in that modul\n"); exit(-9); } strcpy(TabDiff[NbDiff].vardiff, DA_dx); TabDiff[NbDiff].deblockportee = CurBlockLev; ++NbDiff; fprintf(fpginac," cout<<\"double %s; \"<=NB_MAX_DIFFVAR) { printf(" Ydf1: Automatic derivativ stopped for modul %s\n", ModulName); printf(" because :=> too much derivative in that modul\n"); exit(-9); } strcpy(TabDejaDiff[NbDejaDiff], dA_DV); ++NbDejaDiff; if (!strcmp(p1, TabExpreSym[wi])) { //fprintf(fpginac," cout<<\"Yd%s_D%s + \";", A, p1); fprintf(fpginac," cout<<\"%s + \";", dA_DV); } else if (id_input(p1)==-1) //(!is_input(p1)) { //fprintf(fpginac," cout<<\"Yd%s_D%s*YD%s_d%s + \";", A, p1, p1, TabExpreSym[wi]); if (id_diff(DV_dx)>=0) //on s'assure que DV_dx existe bien ... fprintf(fpginac," cout<<\"%s*%s + \";", dA_DV, DV_dx); } } } pstr = pstr+strlen(pstr)+1; } fprintf(fpginac," cout <<\"0;\"< beta ( betr , beti ) ;" // ^ //exemple2: "} else { complex < double > beta ( betr , beti ), alpha ( ar , ai ), gamma;" // ^ pstr2[-1]='\0'; //nb: le token est en principe preceded d'au moins un ' ' ou '\t' //on produit le debut if (instruct=0 && idin2>=0) { TabFlagIn[idin1] = TabFlagIn[idin2] = -1; //on neutralise ces entrees car c'est le complexe ++NbInCplx; //associed qui devient la variable d'entree //idin1 = idin2 = -1; //flagvarcplx=0; } else //sinon, il s'agit d'une variable intermediaire, on produit DAdx pour backward { BackProduce_DAdx(varcplx); } //re-init et passage a l'eventuelle variable suivante flagvarcplx=0; idin1 = idin2 = -1; pstr = pstr+strlen(pstr)+1; //pour avancer sur la chaine de carateres continue; } if (str_qalphanum(p1)) if (!c_word(p1) && !is_yadvar(p1)) { if (!flagvarcplx) { //on est sur le 1er token apres "double", donc c'est sense etre le //nom de la variable complexe beta /*xxxxxxxxx if (!exist_expresym(p1)) { if (NbExpreSym>=NB_MAX_EXPRESYM) { printf(" Ydf1: Automatic derivativ stopped for modul %s\n", ModulName); printf(" because :=> too much token in that modul\n"); exit(-9); } strcpy(TabExpreSym[NbExpreSym], p1); ++NbExpreSym; fprintf(fpginac," ex %s;\n", p1); fprintf(fpginac," symbol Ygs_%s(\"Ygs_%s\");\n", p1, p1); } */ Sto_GinProduce_ExpreSym(p1); /*xxxxxxxxx // if (!exist_cplx(p1)) { if (NbCplx>=NB_MAX_CPLX) { printf(" Ydf1: Automatic derivativ stopped for modul %s\n", ModulName); printf(" because :=> too much complex token in that modul\n"); exit(-9); } strcpy(TabCplx[NbCplx], p1); ++NbCplx; } */ strcpy(varcplx, p1); //="beta" flagvarcplx=1; } else { //on est sur une des variables d'entree (betr ou beti) qui forme le complexe //if (is_input(p1)) ++flagisinput; if (idin1==-1) idin1=id_input(p1); else idin2=id_input(p1); } } pstr = pstr+strlen(pstr)+1; } //on reconduit la suite (declaration proprement dite) tel quel pour backward BackwardOut(pstr2); } /*---------------------------------------------------------------------------*/ /*=============================================================================*/ void queaffect(char *instruct, char *pstr2) { char *pstr3; char affectsv[BUFSIZE+1]; if (trace) printf("\n/*indicAFFECT:|%s|%s|*/\n", instruct, pstr2); //des tokens d'affectation ('=', '+=', '-=', '*=', '/=') //on ete detected ... et pstr2 pointe dessus printf ("|%s|\n|%s|\n", instruct, pstr2); //exemple: "} else { double ZFROZEN2 = x1 ;" //si on a VAR {+,-,*,/}= EXPR; on va transformer en VAR = VAR {+,-,*,/} ( EXPR ); if (pstr2[0]=='+' || pstr2[0]=='-' || pstr2[0]=='*' || pstr2[0]=='/') { //printf("avant:|%s|%p|%c|\n", instruct, pstr2, pstr2[0]); transfo_affect(instruct, pstr2); //(! modifie la chaine passed mais pstr2 doit pointer sur '=') //printf("apres:|%s|%p|%c|\n", instruct, pstr2, pstr2[0]); } //si les variables sont externes au module (une variable globale par exemple) //il faut quand meme la declarer pour ginac Sto_GinProduce_ExpreSym(instruct); //ensuite, on va decouper l'instruction en 3 morceaux : Debut (instruct) Variable(pstr3) Suite(pstr2) --pstr2; while ((pstr2[0]==' ' || pstr2[0]=='\t') && pstr2>instruct) --pstr2; //on remonte les espaces et \t pstr3=pstr2; //pstr3 va servire a pointer sur le debut de la variable affectee while (pstr3[0]!=' ' && pstr3[0]!='\t' && pstr3>instruct) --pstr3; //on remonte les autres caractères if (pstr3>=instruct) //si on est pas au debut de instruct { pstr3[0]='\0'; //on met un '\0' avant la variable affected ++pstr3; } ++pstr2; pstr2[0]='\0'; //on met un '\0' apres la variable ++pstr2; //pour ne pas perdre la partie affectation de la suite de 'instruction //on devrait etre dans la situation suivante: ex: " if ( C1 ) " "A" " = pow ( x , 2 ) , B ; " // ^instruct ^pstr3 ^pstr2 //au passage, on interdit l'affectation des variables d'input ...! if (id_input(pstr3)!=-1) //(is_input(pstr3)) { printf (" Ydf1: Automatic derivative failed for modul %s\n", ModulName); printf (" because :=> input values must not be changed !\n"); exit (-9); } //positionnenemt d'un flag pour savoir s'il s'agit d'un YSi indicYS = id_YSi(pstr3); //puis on produit pour backward if (instruct0) //if (indicBLOCK && !indicCROUV) { fprintf(fpginac," cout << \"{\"<=9 !?) if (indicYS<=0 || (indicYS>0 && prodlevel>=9)) { BackwardOut(pstr3); //la variable fprintf(fpginac," cout <<\" \";\n"); //(un espace separateur?) BackwardOut(affectsv); //puis la suite (partie affectation prealablement sauvegarded) } //eventuellement, il faut terminer par une accolade fermante ('}') if ((indicBLOCK-indicCROUV)>0) //if (indicBLOCK && !indicCROUV) { fprintf(fpginac," cout <0) //if (indicBLOCK && !indicCROUV) { fprintf(fpginac," cout << \"{\"<0) { fprintf(fpginac," cout < 6) { printf (" Ydf1: Syntaxe error: Ydf1 modul_file_name module_name nbin nbout [prodlevel]}\n"); exit(-9); } strcpy(modul_file_name, argv[1]); if ((fpmodul = fopen(modul_file_name, "r")) <= 0) { printf (" Ydf1: In file (%s) not found \n", argv[1]); exit(-9); } if (argc==6) { prodlevel=atoi(argv[5]); } NbIn = atoi(argv[3]); NbOut = atoi(argv[4]); /*-----*/ if ((fpginac = fopen("Y37wrk.cc", "w")) <= 0) { printf (" Ydf1: Pb when opening out file (Y37wrk.cc)\n"); exit(-9); } /*-----*/ //on recupere le nom du module (pour apres) strcpy(ModulName, argv[2]); //en enlevant lenmodulname = strlen(ModulName); //eventuellement .h if (ModulName[lenmodulname-1]=='h' && ModulName[lenmodulname-2]=='.') ModulName[lenmodulname-2]='\0'; /* entête */ fprintf (fpginac, "#include \n"); fprintf (fpginac, "#include \n"); fprintf (fpginac, "using namespace std;\n"); fprintf (fpginac, "using namespace GiNaC;\n"); fprintf (fpginac, "int main()\n"); fprintf (fpginac, "{\n"); memset(instruct, '\0', BUFSIZE+1); //instruct[0]='\0'; /* boucle de lecture du module */ while ( (fgets(buffer, BUFSIZE+1, fpmodul)) != NULL) { //printf("lu|%s|\n", buffer); pstr1 = strtok(buffer, delim); while (pstr1!=NULL) { //printf("pstr1=|%s|\n", pstr1); if (!strcmp(pstr1, "{")) ++CurBlockLev; if (!strcmp(pstr1, "}")) decrem_diff_blocklev(); //--CurBlockLev; //printf("CurBlockLev=%i\n", CurBlockLev); //---------------------------------------------------------- //traitement ligne forward //---------------------------------------------------------- if (Phase==0 && !strcmp(pstr1, "forward")) { Phase=1; } else if (Phase==1) { if (!strcmp(pstr1, "{")) //if (pstr1[0]=='{') { if (nbinfound != NbIn) { printf (" Ydf1: Automatic derivative failed for modul %s\n", ModulName); printf (" because :=> Desagree on input: found %i expected %i\n", nbinfound, NbIn); exit (-9); } fprintf(fpginac, " cout << \"void %s::backward (", ModulName); for (k=0; k0) { printf (" Ydf1: Automatic derivative failed for modul %s\n", ModulName); printf (" because :=> YSi must not appears neither on declaration or on right side of an affectation !\n"); exit (-9); } } //fin de constitution de la chaine; il faut traiter if (!strcmp(pstr1, ";")) { if (indicDECLAR && !indicAFFECT) //=> SI QUE DECLAR { if (flagCPLX) //ex: " if ( C1 ) complex < double > A ( rA , iA ) ; " quedeclar_cplx(instruct, pstr2); // ^ else //cas 'normal' quedeclar(instruct, pstr2); //ex: " if ( C1 ) double A ; " // ^instruct ^pstr2 } else if (indicDECLAR) //=> SI DECLAR ET AFFECT { declaretaffect(instruct, pstr2); //ex: "if ( C1 ) double A = pow ( x , 2 ) , B ; " } // ^instruct ^pstr2 else if (indicAFFECT) //=> SI QUE AFFECT { queaffect(instruct, pstr2); //ex: " if ( C1 ) A = pow ( x , 2 ) , B ; " } // ^instruct ^pstr2 else { // ???!!!! reconduit-on ou pas tel quel !!!??? if (prodlevel==1 || prodlevel>2) { //on reproduite tel quel, QUE pour BACKWARD et donc RIEN pour GINAC. //il doit s'agir de ce genre d'instruction dont on ne sait que faire //pour la derivation comme *printf*, *str*, *get*, *scan*, io, ... //j'ai un pb avec les " exemple : strcpy ( toto , "toto" ) ; ... //ca devrait etre regled //printf(" cout << \"%s\";\n", instruct); BackwardOut(instruct); //par contre c'est ok pour par exemple: strcpy(toto,titi); } } //re-init pour instruction suivante indicBLOCK=indicCROUV=indicTAB=indicAFFECT=indicDECLAR=indicYS=0; //re-init des indicateurs pstr2=NULL; memset(instruct, '\0', BUFSIZE+1); //reinit de instruct }//fin de if ';' }//fin du if Phase 2 //passer au token suivant pstr1 = strtok(NULL, delim); } } BackwardOut(instruct); //pour reconduire la fin du code pour backward qui peut (et //devrait) consister des carateres de terminaison de block ('}') //fprintf(fpginac, " } \n\n", pstr2); // fin pour ginac fprintf(fpginac, " } \n\n"); // fin pour ginac exit(0); }