Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

expressionparser.h

Go to the documentation of this file.
00001 
00007 #ifndef ___EXPRESSIONPARSER_H___
00008 #define ___EXPRESSIONPARSER_H___
00009 
00010 #include "../src/exprparser.h"
00011 #include "../src/pointerlookup.h"
00012 
00013 #ifdef ANSI_COMPATIBLE
00014 /* Optional: provides definition of snprintf on systems lacking them */
00015 #include "../src/ind_types.h"
00016 #endif
00017 
00018 
00020 template <class MapT=PointerLookup<Typeless> >
00021 class ExpressionParser : public ExprParser<> {
00022 public:
00023   typedef MapT MapType;
00024   
00025   ExpressionParser(MapType& p,const char* expr)
00026     : ExprParser<>(expr), params(p) {  };
00027 
00028   virtual ~ExpressionParser() { }
00029 
00030   template <class DT> DT* lookup_pointer(DT*& x);
00031 
00032 private:
00033 
00034   virtual const char*   getstringval();
00035   virtual const Typeless& getval();
00036   
00037   MapType& params;
00038 };
00039 
00040 
00041 
00045 template <class MapT>
00046 template <class DT>
00047 DT* ExpressionParser<MapT>::lookup_pointer(DT*& x)
00048 {
00049   Typeless*     p  = params.getptr(remaining);
00050   Polymorph<DT>* pp = dynamic_cast<Polymorph<DT>*>(p);
00051   return x = (pp ? pp->valueptr() : 0);
00052 }
00053 
00054 
00055 
00065 template <class MapT>
00066 const Typeless& ExpressionParser<MapT>::getval()
00067 {
00068   const char* str      = remaining;
00069   int identlen         = String::C_identifier_length(str,':');
00070   size_t checklen      = identlen;
00071 
00072   if (!identlen)  /* Must be a numeric literal, then */
00073     return ExprParser<>::getval();
00074 
00075   /* Look up parameter value */
00076   const Typeless* p=0;
00077   p = params.getptr(string(str,checklen));
00078   remaining=str+identlen;
00079   if (p) return *p;
00080   else { /* Nothing found */
00081     static Polymorph<int> dummy(Uninitialized);
00082     return dummy;
00083   }
00084 }
00085 
00086 
00087 
00101 template <class MapT>
00102 const char *ExpressionParser<MapT>::getstringval()
00103 {
00104   const size_t bufsize=16384; // Arbitrary limit
00105   static char buf[bufsize];
00106   const char* maxbufptr=buf+bufsize;
00107 
00108   char* bufptr=buf;
00109   int identlen;
00110 
00111   const char* str = remaining;
00112   while (remaining && *remaining && bufptr<maxbufptr) {
00113     /* Copy any bare characters without substitution */
00114     while (*remaining && *remaining != '$' && bufptr<maxbufptr)
00115       *(bufptr++) = *(remaining)++;
00116     
00117     /* Substitute strings starting with a dollar sign ($) */
00118     if (*remaining == '$') { /* Swallow first $ */
00119       (remaining)++;
00120       if (*remaining == '$') /* Copy literal $, if present */
00121         *(bufptr++) = *(remaining)++;
00122       else {
00123         int bracefound=false;
00124         string formatflags="";
00125         if (*remaining == '{') {
00126           bracefound=true;
00127           (remaining)++;
00128         }
00129 
00130         /* Support conditional text, where e.g. ${?param,text} will print text if param
00131            is non-zero and not the empty string */
00132         bool conditional=false;
00133         if (*remaining=='?') {
00134           (remaining)++;
00135           conditional=true;
00136         }
00137 
00138         /* Anything non-alphabetic other than : must be a printing format specification */
00139         if (!isalpha(*remaining) && (*remaining)!=':') {
00140           const char *start=remaining;
00141           while (*remaining && !isalpha(*remaining))
00142             (remaining)++;
00143           formatflags=string(start,remaining);
00144         }
00145 
00146         /* Figure out what part of the remaining string is the identifier */
00147         identlen = String::C_identifier_length(remaining,':');
00148       
00149         /* Look up parameter value */
00150         const Typeless* p = params.getptr(string(remaining,identlen));
00151         remaining +=identlen;
00152         const string representation=p->stringrep(String::StreamFormat(formatflags));
00153         
00154         /* Insert either the string representation of the parameter, or replacement text (if conditional) */
00155         if (p) {
00156           if (!conditional)
00157             bufptr += SNPRINTF(bufptr,maxbufptr-bufptr,"%s",representation.c_str());
00158           else {
00159             if (*remaining==',' && bracefound) {
00160               (remaining)++;
00161               /* Grab text between ',' and '}' */
00162               const char *start=remaining;
00163               while (*remaining && !(*remaining=='}'))
00164                 (remaining)++;
00165               const string replacetext=string(start,remaining);
00166 
00167               /* Insert replacement text if parameter expanded to something non-empty */
00168               if (p->isnumeric()? p->numericvalue()!=0 : representation!="")
00169                 bufptr += SNPRINTF(bufptr,maxbufptr-bufptr,"%s",replacetext.c_str());
00170             }
00171             /* Insert parameter value if it expanded to something non-empty */
00172             else if (p->isnumeric()? p->numericvalue()!=0 : representation!="")
00173               bufptr += SNPRINTF(bufptr,maxbufptr-bufptr,"%s",representation.c_str());
00174           }
00175         }
00176         
00177         if (bracefound) {
00178           if (*remaining == '}')
00179             (remaining)++;
00180           else
00181             message(Msg::Warning,"Missing right brace in "+string(str));
00182         }
00183       }
00184     }
00185   }
00186   *bufptr='\0';
00187     
00188   return buf;
00189 }
00190 
00191 
00192 
00193 /*******************************************************************************/
00198 template <class MapT=PointerLookup<Typeless>, class ParserT=ExpressionParser<MapT> >
00199 class ParamStringParser : public StringParser {
00200 public:
00201   typedef ParserT ParserType;
00202   typedef MapT    MapType;
00203 
00204   ParamStringParser(MapType& m) : params(m) {  };
00205   
00206   virtual ~ParamStringParser() {  }
00207   virtual StringParser* clone() const {  return new ParamStringParser(*this);  };
00208 
00209   virtual double&   parse(const string& s, double&   x) const {  return x = parserfactory(s.c_str()).cmdf();  }
00210   virtual int&      parse(const string& s, int&      x) const {  return x = parserfactory(s.c_str()).cmdi();  }
00211   virtual Tristate& parse(const string& s, Tristate& x) const {  return x = Tristate(parserfactory(s.c_str()).cmdi());  }
00212   virtual string&   parse(const string& s, string&   x) const {  return x = parserfactory(s.c_str()).cmds();  }
00213   
00214   virtual double*&   parse(const string& s, double*&   x) const {  return x = parse_pointer(s,x); }
00215   virtual int*&      parse(const string& s, int*&      x) const {  return x = parse_pointer(s,x); }
00216   virtual Tristate*& parse(const string& s, Tristate*& x) const {  return x = parse_pointer(s,x); }
00217   virtual string*&   parse(const string& s, string*&   x) const {  return x = parse_pointer(s,x); }
00218 
00219   /* Unchanged templated routines from the base class have to be
00220      duplicated explicitly here due to limitations in C++'s overload
00221      resolution rules and in the using directive. */
00222   virtual string   parse(const string& s) const 
00223     {  return StringParser::parse(s);  }
00224 
00225   /* Compared to the base class, adds support for single and double quotes,
00226      so that word breaking will group quoted items together and suppress
00227      the quotes. */
00228   virtual arglist&  parse(const string& s, arglist&  x) const {
00229     x.resize(0);
00230     const char* remaining = s.c_str();
00231     while (*remaining) 
00232       x.push_back(parse_token(remaining));
00233     return x;
00234   }
00235   
00236   virtual void error(const string& s) const {
00237     Msg::LevelHandler<>* mh = Msg::LevelHandler<>::default_instance();
00238     if (mh) (*mh)(Msg::Error,s);
00239   }
00240 
00241 private:
00242   MapType& params;
00243 
00244   string      parse_token(  const char*& remaining) const;
00245   const char* consume_quote(const char*& remaining) const;
00246   
00252   ParserType parserfactory(const char* expr) const
00253     {  return ParserType(params,expr);  }
00254   
00271 //template <class T>  
00272 #define PARSE_POINTER_DEF(T)\
00273   T*&  parse_pointer(const string& s, T*&  x) const {   \
00274     if (!ispointer(s))                                  \
00275       parse(s,*x);                                      \
00276     else {                                              \
00277       T* ptr;                                           \
00278       parserfactory(s.c_str()+1).lookup_pointer(ptr);   \
00279       if (ptr) x=ptr;                                   \
00280       else error("StringParser: Could not get a "       \
00281                  "pointer of required type from "+s);   \
00282     }                                                   \
00283     return x;                                           \
00284   }
00285   
00286   PARSE_POINTER_DEF(double);
00287   PARSE_POINTER_DEF(int);
00288   PARSE_POINTER_DEF(Tristate);
00289   PARSE_POINTER_DEF(string);
00290   
00291   
00292   virtual bool ispointer(const string& s) const {
00293     std::istrstream ist(s.c_str(),s.length());
00294     unsigned char w;
00295     ist >> w;
00296     return (w == '&');
00297   }
00298 };
00299 
00300 
00302 template <class MapT, class ParserT>
00303 const char* ParamStringParser<MapT,ParserT>::consume_quote(const char*& remaining) const  {
00304   const char* quotepos=remaining;
00305   while (*(++(remaining)) && (*remaining!=*quotepos));
00306   const char* end=remaining;
00307   if (!*remaining) {
00308     string q;
00309     q=*quotepos;
00310     error("Unmatched " + q);
00311   }
00312   else (remaining)++;
00313   return end;
00314 }
00315 
00317 template <class MapT, class ParserT>
00318 string ParamStringParser<MapT,ParserT>::parse_token(const char*& remaining) const {
00319   while (isspace(*remaining)) (remaining)++;
00320   const char* start=remaining;
00321   const char* end=remaining;
00322   
00323   switch (*remaining) {
00324   case '\0': break;
00325   case  '#': while (*(++(remaining))); start=end=(remaining); break;
00326   case '\"': start++; end=consume_quote(remaining); break;
00327   case '\'': start++; end=consume_quote(remaining); break;
00328   default:
00329     while (*(++(remaining))  && !isspace(*remaining) &&
00330              (*remaining!='"') && (*remaining!='\''));
00331     if (*remaining=='"' || *remaining=='\'') consume_quote(remaining);
00332     end=remaining;
00333     break;
00334   }
00335   
00336   /* Swallow trailing garbage until we're sure there's something interesting left,
00337      and return a new string. */
00338   while (isspace(*remaining)) (remaining)++;
00339   return string(start,end);
00340 }
00341 
00342 
00343 #endif /* ___EXPRESSIONPARSER_H___ */

Generated on Mon Jan 20 02:35:44 2003 for RF-LISSOM by doxygen1.3-rc2