/*************************************************************** * Parser accepting variables beginning with an upcase letter * * with possibility to save formulas to an output file. * * * * English version 6.0 - 08/20/2002 * * by J-P MOREAU, Paris. * * (www.jpmoreau.fr) * * ------------------------------------------------------------ * * Examples of valid expressions: * * A=10/4 * * B=25.478 * * C=-1 * * X=0.72 * * F=A*X^2+B*X+C * * F * * 25.75*2+1.784 * * 2*pi*R * * ------------------------------------------------------------ * * Example 1: F=A/B ) * * A=500 ) in any order * * B=2 ) * * F * * 250.00000000 * * ------------------------------------------------------------ * * Example 2: S=L*M * * V=S*H * * P=D*V * * L=100 * * M=50 * * H=5 * * D=1.6 * * P * * 40000.00000000 * * ------------------------------------------------------------ * * Example 3: exp(1) * * 2.71828183 * * sin(2) * * Résultat : 0.90929743 * * root(225) * * 15.00000000 * * ------------------------------------------------------------ * * Example 4: Mass = 2500 * * Surface=2*pi*Radius * * ------------------------------------------------------------ * * Example 5: F=A*X+B * * F * * Formula: A*X+B * * No formula or assignation for variable A * * No formula or assignation for variable X * * No formula or assignation for variable B * * 0.00000000 * * ------------------------------------------------------------ * * Version 5.0: possibility to read/save a session from/to a * '* text file and menu to choose an operation. * * ------------------------------------------------------------ * * Version 6.0: Function names can have several letters (cos, * * sin, atan, etc.). * ***************************************************************/ #include #include #include #include #include #include #define DELIMITER 1 #define VARIABLE 2 #define NUMBER 3 #define NB_VAR 40 // Maximum number of variables #define PI 4*atan(1) char *prog; // pointer to expression to evaluate char bak[100]; // store previous expression char token[40]; // current element (operator, variable or number char tok_type; // type of current element (1, 2 or 3) // pointer to a formula such as A...=... char *formule[NB_VAR]; // pointer to a name of variable char *vrbl[NB_VAR]; int flg[NB_VAR]; // 0=no 1=yes int indice; // number of the formula (0 to NB_VAR-1) int num=0; // number of next variable (0 to NB_VAR-1) int ok; // allows or not to display result double answer; // current result FILE *fp_in, *fp_out; // pointers to input/output files char nom_in[40], nom_out[40]; // names of input/output files char choice[2]; // choose an option in menu // table of error messages static char *ERR[]= { "Syntax error.", "Odd number of parentheses !", "No expression entered.", "Divide by zero !", "Argument of log negative or null !", "Argument of ln negative or null !", "Argument of root negative !", "INFINITY.", "Memory allocation error !" }; // headers offunctions used void calcule_exp(),level2(double *),level3(double *),level4(double *),level5(double *); void level6(double *),primitive(double *),get_token(),arith(char,double *,double *); void unary(char *,double *), serror(int), menu(); double find_var(char *); int get_formula(); int isdelim(char), is_in(char,char *); /************************************************ * Entry point in expression parser * * input : expression prog * * output: numerical value result * * --------------------------------------------- * * NOTA - It is a recursive descent parser. * * Ref.: "Advanced Turbo C by Herbert Schildt, * * Borland-Osborne/McGraw-Hill 1987". * ************************************************/ void calcule_exp(double *result) { get_token(); if(!*token) { serror(2); return; } level2(result); } // add or substract two terms void level2(double *result) { register char op; double hold; level3(result); while((op=*token)=='+' || op == '-') { get_token(); level3(&hold); arith(op,result,&hold); } } // multiply or divide two terms void level3(double *result) { register char op; double hold; level4(result); while((op=*token)=='*' || op == '/' || op == '%') { get_token(); level4(&hold); arith(op,result,&hold); } } // integer power or not void level4(double *result) { double hold; level5(result); if(*token=='^') { get_token(); level4(&hold); arith('^',result,&hold); } } /********************************************************* * Unary operator: +, - or function * * ------------------------------------------------------ * * Implemented functions are: * * acos for arc cosinus, asin for arc sinus, atan for * * arc tangent, cos for cosinus, exp for exponential, * * log pour decimal logarithm, ln pour neperian logarithm,* * the constant pi, root for square root, sin for sinus * * and tan for tangent. * *********************************************************/ void level5(double *result) { register char op[5]; strcpy(op,"");; if((tok_type==DELIMITER) && (is_in(*token,"+-acelprst"))) { strcpy(op,token); get_token(); } // no argument for the constant pi if (op[0]!='p') level6(result); if (strlen(op)>0) unary(op,result); } /****************************************** * Expression with parentheses * * --------------------------------------- * * Recursive treatment from outside to * * inside. * ******************************************/ void level6(double *result) { if((*token=='(') && (tok_type==DELIMITER)) { get_token(); level2(result); if(*token != ')') serror(1); // wrong number of parentheses ! get_token(); } else primitive(result); // evaluate final result } /************************************************** * Actual value of a number or a variable * * A variable is evaluated by its formula, if it * * exists, by calling find_var() that returns zero * * by default (be careful with divisions!). * * A number is evaluated by calling the standard * * C library function atof(). * **************************************************/ void primitive(double *result) { switch(tok_type) { case VARIABLE : *result=find_var(token); get_token(); return; case NUMBER : *result=atof(token); get_token(); return; default : serror(0); //syntax error message } } /**************************** * Arithmetical operations * * ------------------------ * * ^ : power operator * * % : modulo operator * ***************************/ void arith(char o, double *r, double *h) { register double t; switch(o) { case '-': *r=*r-*h; break; case '+': *r=*r+*h; break; case '*': *r=*r**h; break; case '/': if (*h!=0) *r=(*r)/(*h); else { serror(3); ok=0; } break; case '%': t=(*r)/(*h); *r=*r-(t*(*h)); break; case '^': *r=pow(*r,*h); } } /************************************** * Process a unary operation: * * - before a number or a function. * * Called by level5(). * **************************************/ void unary(char *o, double *r) { if(o[0]=='-') *r=-(*r); else if (strcmp(o,"acos")==0) *r=acos(*r); else if (strcmp(o,"asin")==0) *r=asin(*r); else if (strcmp(o,"atan")==0) *r=atan(*r); else if (strcmp(o,"cos")==0) *r=cos(*r); else if (strcmp(o,"exp")==0 || o[0]=='e') *r=exp(*r); else if (strcmp(o,"log")==0) if (*r>0) *r=log10(*r); else { serror(4); ok=0; } else if (strcmp(o,"ln")==0) if (*r>0) *r=log(*r); else { serror(5); ok=0; } else if (strcmp(o,"pi")==0) *r=4.0*atan(1.0); else if (strcmp(o,"root")==0 || o[0]=='r') if (*r>=0) *r=sqrt(*r); else { serror(6); ok=0; } else if (strcmp(o,"sin")==0) *r=sin(*r); else if (strcmp(o,"tan")==0) if (fabs(*r-PI/2)>1e-10) *r=tan(*r); else { serror(7); ok=0; } } /************************************************ * Finds the value of a variable by using its * * formula, if it exists, else returns zero. * * Called by primitive(). * ************************************************/ double find_var(char *s) { int i,n; char *q; double valeur; if (!isalpha(*s)) { serror(0); // the variable is not alphanumerical return 0; } // seek the variable number n=-1; for (i=1; i0) { n++; vrbl[n]= (char *) malloc(40); if (!vrbl[n]) { serror(8); exit(1); } strcpy(vrbl[n],var); formule[n]= (char *) malloc(40); if (!vrbl[n]) { serror(8); exit(1); } strcpy(formule[n],form); } } fclose(fp_in); printf(" Number of items read: %d\n",n); getchar(); return n; } /************************** * option save a session * **************************/ void save_session() { int i; //clrscr(); printf("\n *** SAVE A SESSION ***\n"); if (strlen(nom_out)==0) strcpy(nom_out,"calcul.asc"); if ((fp_out=fopen(nom_out,"w"))==NULL) { printf("\n Save: impossible to open file %s\n",nom_out); exit(1); } fprintf(fp_out," %d\n",num); for (i=1; i