CMathExpression.cpp

Go to the documentation of this file.
00001 
00040 #include <cmath>
00041 #include <cstdlib>
00042 #include <iomanip>
00043 #include <sstream>
00044 #include <string>
00045 #include <vector>
00046 
00047 #include "popassert.h"
00048 #include "CVector3f.h"
00049 #include "compute.h"
00050 #include "CMathExpression.h"
00051 
00052 
00053 
00062 inline bool In(const char* Formula, int min, int max)
00063 {
00064   int Counter = 0;
00065   for (int i = min; i < max; ++i)
00066     {
00067       if (Formula[i] == '(')
00068         ++Counter;
00069       if (Formula[i] == ')')
00070         --Counter;
00071     }
00072   return (Counter != 0);
00073 }
00074 
00075 
00076 
00077 
00081 CValue* CMathExpression::BuildFormula(const char* Formula,
00082                                       int min,
00083                                       int max)
00084 {
00085   POP_ASSERT(Formula != NULL, "Using a NULL pointer.");
00086 
00087    if (min < max)
00088     {
00089       if (Formula[min] == ' ')
00090         return BuildFormula(Formula, min+1, max);
00091       if (Formula[max-1] == ' ')
00092         return BuildFormula(Formula, min, max-1);
00093     }
00094 
00095 
00096   int i, j;
00097 
00098   // Search for + or -
00099   for (i = max-1; i > min-1; --i)
00100     if ((Formula[i] == '+') || (Formula[i] == '-'))
00101       if ( !(In(Formula, min, i)) )
00102         if (Formula[i] == '+')
00103           return(CValue::GetNewAddition(BuildFormula(Formula, min, i), 
00104                                         BuildFormula(Formula, i+1, max)));
00105         else
00106           if (i == min)
00107             {
00108               return(CValue::GetNewOpposite(BuildFormula(Formula, i+1, max)));
00109             }
00110           else
00111             return(CValue::GetNewSubstraction(BuildFormula(Formula, min, i), 
00112                                               BuildFormula(Formula, i+1, max)));
00113 
00114   // Search for * or /
00115   for (i = max-1; i > min; --i)
00116     if ((Formula[i] == '*') || (Formula[i] == '/'))
00117       if ( !(In(Formula, min, i)) )
00118         if (Formula[i] == '*')
00119           return(CValue::GetNewProduct(BuildFormula(Formula, min, i), 
00120                                        BuildFormula(Formula, i+1, max)));
00121         else
00122           return(CValue::GetNewDivision(BuildFormula(Formula, min, i),
00123                                         BuildFormula(Formula, i+1, max)));
00124 
00125   // Search for sqrt, sin, cos, tan, exp or ^
00126   for (i = min; i < max; ++i)
00127     if ( (Formula[i] == 's') || (Formula[i] == 'c') ||
00128          (Formula[i] == 't') || (Formula[i] == 'e') ||
00129          (Formula[i] == 'l') || (Formula[i] == '^') )
00130       if ( !(In(Formula, min, i)) )
00131         switch (Formula[i])
00132           {
00133           case('s'):
00134             if ((Formula[i+1] == 'q') &&
00135                 (Formula[i+2] == 'r') &&
00136                 (Formula[i+3] == 't'))
00137               return(CValue::GetNewSqrt(BuildFormula(Formula, i+4, max)));
00138 
00139             if ((Formula[i+1] == 'i') &&
00140                 (Formula[i+2] == 'n'))
00141               return(CValue::GetNewSin(BuildFormula(Formula, i+3, max)));
00142 
00143             break;
00144 
00145           case('c'):
00146             if ((Formula[i+1] == 'o') &&
00147                 (Formula[i+2] == 's'))
00148               return(CValue::GetNewCos(BuildFormula(Formula, i+3, max)));
00149             break;
00150 
00151           case('t'):
00152             if ((Formula[i+1] == 'a') &&
00153                 (Formula[i+2] == 'n'))
00154               return(CValue::GetNewTan(BuildFormula(Formula, i+3, max)));
00155             break;
00156 
00157           case('e'):
00158             if ((Formula[i+1] == 'x') &&
00159                 (Formula[i+2] == 'p'))
00160               return(CValue::GetNewExp(BuildFormula(Formula, i+3, max)));
00161             break;
00162 
00163           case('l'):
00164             if (Formula[i+1] == 'n')
00165               return(CValue::GetNewLn(BuildFormula(Formula, i+2, max)));
00166             break;
00167 
00168           case('^') :
00169             return(CValue::GetNewPow(BuildFormula(Formula, min, i),
00170                                      BuildFormula(Formula, i+1, max)));
00171             break;
00172           }
00173 
00174   // Search for an opening parenthesis '('
00175   for (i = min; i < max; ++i)
00176     if (Formula[i] == '(')
00177       for (j = max; j > i; --j)
00178         if (Formula[j-1] == ')')
00179           return(BuildFormula(Formula, i+1, j));
00180 
00181   // Search for x, y or z
00182   for (i = min; i < max; ++i)
00183     if ((Formula[i] == 'x') || (Formula[i] == 'y') || (Formula[i] == 'z'))
00184       switch (Formula[i])
00185         {
00186         case('x'): return(new CVariable(CValue::TYPE_X)); break;
00187         case('y'): return(new CVariable(CValue::TYPE_Y)); break;
00188         case('z'): return(new CVariable(CValue::TYPE_Z)); break;
00189         }
00190 
00191   // Search for a number
00192   for (i = min; i < max; ++i)
00193     if ((Formula[i] <= '9') && (Formula[i] >= '0'))
00194       {
00195         j = i;
00196         while ( ( ( (Formula[j] <= '9') &&
00197                     (Formula[j] >= '0') ) ||
00198                   (Formula[j] == '.') )&&
00199                 (j < max))
00200           {
00201             ++j;
00202           }
00203         char* buffer = new char[j-i+1];
00204         int k;
00205         for (k = i; k < j; ++k)
00206           buffer[k-i] = Formula[k];
00207         buffer[k-i] = '\0';
00208         float Value = atof(buffer);
00209         delete []buffer;
00210         return(new CNumber(Value));
00211       }
00212 
00213   // Search for spaces
00214   if (min < max && Formula[min] == ' ')
00215     return(BuildFormula(Formula, min+1, max));
00216 
00217   // If nothing is found
00218   POP_ILLEGAL("Nothing has been found in formula construction.");
00219   return 0;
00220 }
00221 
00222 
00226 CMathExpression::CMathExpression(const char * Formula)
00227   : m_pFormula(0), m_pFunction(0)
00228 {
00229   if (Formula)
00230     {
00231       int i;
00232       std::string strFormula(Formula);
00233 
00234       for (i = 0; i < (int) strFormula.size(); ++i)
00235         {
00236           if (strFormula[i] == ' ' || strFormula[i] == '\t')
00237             {
00238               strFormula.erase(i, 1);
00239               --i;
00240             }
00241         }
00242 
00243       for (i = strFormula.size() - 1; i >= 0 && strFormula[i] != '='; --i);
00244       m_pFormula = 
00245         CValue::GetNewSubstraction(BuildFormula(strFormula.c_str(), 0, i),
00246                                    BuildFormula(strFormula.c_str(), i+1,
00247                                                 strFormula.size())
00248                                    );
00249       Compile();
00250     }
00251   else
00252     {
00253       m_pFormula = 0;
00254       m_pFunction = 0;
00255     }
00256 }
00257 
00258 
00263 bool CMathExpression::Validate(const std::string& strFormula,
00264                                int *value,
00265                                int min,
00266                                int max)
00267 {
00268   if (value)
00269     {
00270       value[0] = min;
00271       value[1] = max;
00272     }
00273 
00274   int i, j;
00275 
00276   if (min < 0 && max < 0)
00277     {
00278       for (i = 0; i < (int) strFormula.size() && strFormula[i] != '='; ++i);
00279       if (i == (int) strFormula.size())
00280         {
00281           return false;
00282         }
00283       else
00284         return (Validate(strFormula, value, 0, i) &&
00285                 Validate(strFormula, value, i+1, strFormula.size()));
00286     }
00287 
00288   // Take off spaces
00289   if (min < max)
00290     {
00291       if (strFormula[min] == ' ')
00292         return Validate(strFormula, value, min+1, max);
00293       if (strFormula[max-1] == ' ')
00294         return Validate(strFormula, value, min, max-1);
00295     }
00296 
00297   // Search for + or -
00298   for (i = max-1; i > min-1; --i)
00299     if ((strFormula[i] == '+') || (strFormula[i] == '-'))
00300       if ( !(In(strFormula.c_str(), min, i)) )
00301         if (strFormula[i] == '+')
00302           return (Validate(strFormula, value, min, i) &&
00303                   Validate(strFormula, value, i+1, max));
00304         else
00305           if (i == min)
00306             {
00307               return(Validate(strFormula, value, i+1, max));
00308             }
00309           else 
00310             return (Validate(strFormula, value, min, i) &&
00311                     Validate(strFormula, value, i+1, max));
00312 
00313   // Search for * or /
00314   for (i = max-1; i > min; --i)
00315     if ((strFormula[i] == '*') || (strFormula[i] == '/'))
00316       if ( !(In(strFormula.c_str(), min, i)) )
00317         if (strFormula[i] == '*')
00318           return (Validate(strFormula, value, min, i) &&
00319                   Validate(strFormula, value, i+1, max));
00320         else
00321           return (Validate(strFormula, value, min, i) &&
00322                   Validate(strFormula, value, i+1, max));
00323 
00324   // Search for sqrt, sin, cos, tan, exp or ^
00325   for (i = min; i < max; ++i)
00326     if ( (strFormula[i] == 's') || (strFormula[i] == 'c') ||
00327          (strFormula[i] == 't') || (strFormula[i] == 'e') ||
00328          (strFormula[i] == 'l') || (strFormula[i] == '^') )
00329       if ( !(In(strFormula.c_str(), min, i)) )
00330         switch (strFormula[i])
00331           {
00332           case('s'):
00333             if ((strFormula[i+1] == 'q') &&
00334                 (strFormula[i+2] == 'r') &&
00335                 (strFormula[i+3] == 't'))
00336               return(Validate(strFormula, value, i+4, max));
00337 
00338             if ((strFormula[i+1] == 'i') &&
00339                 (strFormula[i+2] == 'n'))
00340               return(Validate(strFormula, value, i+3, max));
00341 
00342             break;
00343 
00344           case('c'):
00345             if ((strFormula[i+1] == 'o') &&
00346                 (strFormula[i+2] == 's'))
00347               return(Validate(strFormula, value, i+3, max));
00348             break;
00349 
00350           case('t'):
00351             if ((strFormula[i+1] == 'a') &&
00352                 (strFormula[i+2] == 'n'))
00353               return(Validate(strFormula, value, i+3, max));
00354             break;
00355 
00356           case('e'):
00357             if ((strFormula[i+1] == 'x') &&
00358                 (strFormula[i+2] == 'p'))
00359               return(Validate(strFormula, value, i+3, max));
00360             break;
00361 
00362           case('l'):
00363             if (strFormula[i+1] == 'n')
00364               return(Validate(strFormula, value, i+2, max));
00365             break;
00366 
00367           case('^') :
00368             return (Validate(strFormula, value, min, i) &&
00369                     Validate(strFormula, value, i+1, max));
00370             break;
00371           }
00372 
00373   // Search for an opening parenthesis '('
00374   if (strFormula[min] == '(' && strFormula[max-1] == ')')
00375     return(Validate(strFormula, value, min+1, max-1));
00376 
00377   // Search for x, y or z
00378   if ((strFormula[min] == 'x') || (strFormula[min] == 'y') || (strFormula[min] == 'z'))
00379     return (min == max - 1);
00380 
00381   // Search for a number
00382   int dotfound = 0;
00383   int digitfound = 0;
00384   if ( ( (strFormula[min] <= '9') && (strFormula[min] >= '0') ) ||
00385        (strFormula[min] == '.') )
00386     {
00387       j = min;
00388       while ( ( ( (strFormula[j] <= '9') &&
00389                   (strFormula[j] >= '0') ) ||
00390                 (strFormula[j] == '.') )&&
00391               (j < max))
00392         {
00393           if (strFormula[j] == '.')
00394             ++dotfound;
00395           if (strFormula[j] <= '9' && strFormula[j] >= '0')
00396             ++digitfound;
00397           if (dotfound > 1)
00398             {
00399               return false;
00400             }
00401           ++j;
00402         }
00403 
00404       return (j == max && digitfound > 0);
00405     }
00406 
00407   return false;
00408 }
00409 
00410 
00415 void CMathExpression::Compile(std::vector<char>& v) const
00416 {
00417   v = std::vector<char>();
00418 
00419   // Function initialization
00420   v.push_back('\x55'); // pushl   %ebp
00421 
00422   v.push_back('\x89');
00423   v.push_back('\xe5'); // movl    %esp,%ebp
00424 
00425   v.push_back('\x8b');
00426   v.push_back('\x45');
00427   v.push_back('\x08'); // movl    0x8(%ebp),%eax
00428 
00429   v.push_back('\x9b');
00430   v.push_back('\xdb');
00431   v.push_back('\xe3'); // finit
00432 
00433 
00434   // Function compilation
00435   int i = 0;
00436   m_pFormula->Compile(v, i);
00437 
00438 
00439   // Function clean-up
00440   v.push_back('\x89');
00441   v.push_back('\xec'); // movl    %ebp,%esp
00442 
00443   v.push_back('\x5d'); // popl    %ebp
00444 
00445   v.push_back('\xc3'); // ret
00446 }
00447 
00448 

Generated on Fri Dec 5 03:20:33 2008 for Mathematical Ray-tracer by  doxygen 1.5.4