| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

In This Package:

CreateRules.cc

Go to the documentation of this file.
00001 
00002 //
00003 // RuleParser
00004 // Code that uses the Boost SPIRIT parser to deconstruct
00005 // a string into a selection that can be run quickly.
00006 //  
00008 #include <boost/spirit/core.hpp>
00009 #include <boost/spirit/symbols/symbols.hpp>
00010 #include <boost/spirit/utility.hpp>
00011 #include <boost/spirit/dynamic.hpp>
00012 
00013 #include <iostream>
00014 #include <string>
00015 #include <stack>
00016 #include <typeinfo>
00017 #include <algorithm>
00018 #include <cctype>
00019 
00020 #include "RuleParser/ParameterDescription.h"
00021 #include "RuleParser/Rules.h"
00022 #include "RuleParser/RuleFactory.h"
00023 #include "RuleParser/CreateRules.h"
00024 #include "units.h"
00025 
00027 using namespace std;
00028 using namespace boost::spirit;
00029 using namespace RuleParser;
00030 
00031 
00032 
00033 
00034 // Storage for semantic actions.
00035 struct ParserStore
00036 {
00037   // Temporary data storage
00038   stack<std::string>          mStackOperators;
00039   stack<double>               mStackDouble;
00040   stack<double>               mStackUnit;
00041   stack<string>               mStackString;
00042   stack<ParameterDescription> mStackParam; 
00043   stack<Rule*>                mStackRules;    
00044 
00045   stack<string>               mTempStack;
00046 
00047   void popval(double& r) { r = mStackDouble.top(); mStackDouble.pop();};
00048   void popval(string& r) { r = mStackString.top(); mStackString.pop();};
00049 
00050   void clear() { 
00051     while(! mStackOperators.empty()) mStackOperators.pop();
00052     while(! mStackDouble   .empty()) mStackDouble   .pop();
00053     while(! mStackString   .empty()) mStackString   .pop();
00054     while(! mStackParam    .empty()) mStackParam    .pop();
00055     while(! mStackRules    .empty()) mStackRules    .pop();
00056   };
00057 };
00058 
00059 
00061 //
00062 //  Semantic actions
00063 //
00065 
00066 struct debugprint{
00067   debugprint(std::string n) : name(n) {};
00068   std::string name;
00069   void operator()(char const* a, char const* b) const{
00070     string s(a,b);
00071     //cout << "      debugprint name=" << name << " matched " << s << std::endl;
00072   }
00073   void operator()(char const* a) const{
00074     //cout << "      debugprint name=" << name << " matched char " << a << std::endl;
00075   }
00076   void operator()(const double &a) const{
00077     //cout << "      debugprint name=" << name << " matched double " << a << std::endl;
00078   }
00079 };
00080 
00081 struct mySemantic {
00082   mySemantic(ParserStore& rp) : m_store(rp) {};
00083   ParserStore& m_store;
00084 };
00085 
00086 struct my_do_double : public mySemantic
00087 {
00088   my_do_double(ParserStore& rp) : mySemantic(rp) {};
00089   void operator()(const double &d) const{
00090     m_store.mStackDouble.push(d);
00091   }
00092 };
00093 
00094 struct my_do_string : public mySemantic
00095 {
00096   my_do_string(ParserStore& rp) : mySemantic(rp) {};
00097   void operator()(char const* a, char const* b) const{
00098     string s(a,b);
00099     m_store.mStackString.push(s);
00100   }
00101 };
00102 
00103 struct my_do_unit : public mySemantic
00104 {
00105   my_do_unit(ParserStore& rp) : mySemantic(rp) {};
00106   void operator()(const double &d) const{
00107     m_store.mStackUnit.push(d);
00108   }
00109 };
00110 
00111 struct my_do_double_with_unit : public mySemantic
00112 {
00113   my_do_double_with_unit(ParserStore& rp) : mySemantic(rp) {};
00114   void operator()(char const*, char const*) const {
00115     assert(m_store.mStackUnit.size()>0);
00116     assert(m_store.mStackDouble.size()>0);
00117     double d = m_store.mStackUnit.top() * m_store.mStackDouble.top();
00118     m_store.mStackDouble.pop();
00119     m_store.mStackUnit.pop();
00120     m_store.mStackDouble.push(d);
00121   }
00122 };
00123 
00124 struct my_do_param : public mySemantic
00125 {
00126   my_do_param(ParserStore& rp) : mySemantic(rp) {};
00127     // void operator()(char const* a, char const* b) const{
00128     //   string s(a,b);
00129     //   m_store.mStackParamName.push(s);
00130     //   cout << "Stacking " << s << std::endl;
00131     // }
00132   void operator()(const ParameterDescription& d) const {
00133     //cout << "Stacking parameter " << d.name() << " " << d.id() << " " << d.type() << std::endl;
00134     m_store.mStackParam.push(d);
00135   }
00136 };
00137 
00138 struct my_do_operator : public mySemantic
00139 {
00140   my_do_operator(ParserStore& rp) : mySemantic(rp) {};
00141   void operator()(char const* a, char const* b) const{
00142     std::string s(a,b);
00143     //cout << "Stacking operator " << s << std::endl;
00144     m_store.mStackOperators.push(s);
00145   }      
00146     // void operator()(char const a) const{
00147     //   std::string s(1,a);
00148     //   cout << "Stacking operator " << s << std::endl;
00149     //   m_store.mStackOperators.push(s);
00150     // }      
00151 };
00152 
00153 
00154 template<typename T>
00155 struct my_do_simple_comparison : public mySemantic
00156 {
00157   my_do_simple_comparison(ParserStore& rp,bool param_on_left) : mySemantic(rp), m_param_on_left(param_on_left){};
00158   bool m_param_on_left;
00159 
00160   void operator()(char const* a, char const* b) const{
00161     
00162     //cout<<"cmp string a: "<<a<<endl;
00163     //cout<<"cmp string b: "<<b<<endl;
00164     
00165     string s(a,b);
00166     T val;
00167     m_store.popval(val);
00168 
00169     ParameterDescription par = m_store.mStackParam.top();
00170     m_store.mStackParam.pop();
00171 
00172     string op = m_store.mStackOperators.top();
00173     m_store.mStackOperators.pop();
00174 
00175       // check handedness.. flip if not 'standard handedness'
00176     if(m_param_on_left != true) {
00177       if(op == "<" ) op = ">";
00178       if(op == "<=") op = ">=";
00179       if(op == ">" ) op = "<";
00180       if(op == ">=") op = "<=";
00181     }
00182 
00183     Rule* outRule = 0;
00184     if(op=="<" ) outRule = new LT_Rule<T>(s,par.id(),val);
00185     if(op=="<=") outRule = new LE_Rule<T>(s,par.id(),val);
00186     if(op==">" ) outRule = new GT_Rule<T>(s,par.id(),val);
00187     if(op==">=") outRule = new GE_Rule<T>(s,par.id(),val);
00188     if(op=="==" || op=="=") outRule = new EQ_Rule<T>(s,par.id(),val);
00189     if(op=="!=") outRule = new NEQ_Rule<T>(s,par.id(),val);
00190 
00191     assert(outRule);
00192     m_store.mStackRules.push(outRule);
00193     //cout << "STACK rule " << typeid(*outRule).name() << "  \"" << outRule->name() << "\"" << endl;
00194   }
00195 };
00196 
00197 
00198 template <typename T>
00199 struct my_do_custom : public mySemantic
00200 {
00201   my_do_custom(ParserStore& rp,
00202                const ParameterDescription& par,
00203                int which_operator,
00204                bool param_on_left) 
00205           : mySemantic(rp)
00206           , m_par(par)
00207           , m_which_operator(which_operator)
00208           , m_param_on_left(param_on_left){};
00209 
00210   const ParameterDescription& m_par;
00211   int  m_which_operator;
00212   bool m_param_on_left;
00213 
00214   void operator()(char const* , char const* ) const{
00215       // This is a custom rule provided by the user. Call on his/her RuleFactor to make it.
00216     T val;
00217     m_store.popval(val);
00218 
00219     assert(m_par.factory());
00220     Rule* rule = m_par.factory()->createRule(m_par, m_which_operator, val, m_param_on_left);
00221 
00222     assert(rule);
00223     m_store.mStackRules.push(rule);
00224     //cout << "STACK custom rule " << typeid(*rule).name() << "  \"" << rule->name() << "\"" << endl;         
00225   }
00226 };
00227 
00228 struct my_do_and : public mySemantic
00229 {
00230   my_do_and(ParserStore& rp) : mySemantic(rp) {};
00231   void operator()(char const* a, char const* b) const{
00232 
00233     //cout<<"string a: "<<a<<endl;
00234     //cout<<"string b: "<<b<<endl;
00235 
00236     string s(a,b);
00237 
00238     assert(m_store.mStackRules.size()>=2);
00239     Rule* rule2 = m_store.mStackRules.top();
00240     m_store.mStackRules.pop();
00241 
00242     Rule* rule1 = m_store.mStackRules.top();
00243     m_store.mStackRules.pop();
00244 
00245     string name=rule1->name();
00246     name.append(" ");
00247     name.append(s);
00248 
00249     Rule* outRule = new AndRule(name,rule1,rule2);
00250     //cout << "STACK and-rule composed of " << rule1->name() << " and " << rule2->name() << std::endl;
00251 
00252     m_store.mStackRules.push(outRule);
00253   }    
00254 };
00255 
00256 struct my_do_or : public mySemantic
00257 {
00258   my_do_or(ParserStore& rp) : mySemantic(rp) {};
00259   void operator()(char const* a, char const* b) const{
00260 
00261     //cout<<"string a: "<<a<<endl;
00262     //cout<<"string b: "<<b<<endl;
00263 
00264     string s(a,b);
00265 
00266     assert(m_store.mStackRules.size()>=2);
00267     Rule*  rule2 = m_store.mStackRules.top();
00268     m_store.mStackRules.pop();
00269 
00270     Rule*  rule1 = m_store.mStackRules.top();
00271     m_store.mStackRules.pop();
00272 
00273     string name=rule1->name();
00274     name.append(" ");
00275     name.append(s);
00276 
00277     Rule* outRule = new OrRule(name,rule1,rule2);
00278     //cout << "STACK or-rule composed of " << rule1->name() << " and " << rule2->name() << std::endl;
00279 
00280     m_store.mStackRules.push(outRule);
00281   }    
00282 };
00283 
00284 struct my_do_not : public mySemantic
00285 {
00286   my_do_not(ParserStore& rp) : mySemantic(rp) {};
00287   void operator()(char const* a, char const* b) const{
00288     assert(m_store.mStackRules.size()>=1);
00289     Rule* rule1 = m_store.mStackRules.top();
00290     m_store.mStackRules.pop();
00291 
00292     Rule* outRule = new NotRule(string(a,b),rule1);
00293     //cout << "STACK not-rule composed of " << rule1->name() << std::endl;
00294 
00295     m_store.mStackRules.push(outRule);
00296   }    
00297 };
00298 
00299 struct my_do_any : public mySemantic
00300 {
00301   my_do_any(ParserStore& rp) : mySemantic(rp) {};
00302   void operator()(char const* , char const* ) const{
00303     //cout << "STACK any-rule " << std::endl;
00304 
00305     m_store.mStackRules.push(new AnyRule);
00306   }    
00307 };
00308 
00309 struct my_do_none : public mySemantic
00310 {
00311   my_do_none(ParserStore& rp) : mySemantic(rp) {};
00312   void operator()(char const* , char const* ) const{
00313     // cout << "STACK none-rule " << std::endl;
00314 
00315     m_store.mStackRules.push(new NoneRule);
00316   }    
00317 };
00318 
00319 
00320 
00322 //
00323 //  Description of our grammar
00324 //
00326 
00327 struct ruleparser : public grammar<ruleparser>
00328 {  
00329   ruleparser(ParserStore& s, ParameterList pars) 
00330     : m_store(s)
00331     , m_pars(pars) {};
00332   ParserStore &m_store;
00333   ParameterList m_pars;
00334 
00335   template <typename ScannerT>
00336   struct definition
00337   {
00338     definition(const ruleparser& self)
00339     {   
00340       // Load units.
00341       static unitlist sUnitlist;
00342       const unitlist::UnitList_t& ulist = sUnitlist();
00343       unitlist::UnitList_t::const_iterator it = ulist.begin();
00344       for( ; it != ulist.end(); ++it ){
00345         unit_symbols.add(it->first.begin(),it->first.end(),it->second);
00346       }
00347       
00348       
00349       value_real
00350         = (real_p[my_do_double(self.m_store)] >> unit_symbols[my_do_unit(self.m_store)][debugprint("unit")])
00351           [my_do_double_with_unit(self.m_store)][debugprint("realvalue-with-unit")]
00352         | (real_p[my_do_double(self.m_store)])[debugprint("realvalue")]
00353         ;
00354 
00355           // Strings must be single-quoted, contain only a-z,A-Z,0-9,/,_
00356       value_string
00357         = ch_p('\'') >> (*(alnum_p | ch_p('/') | ch_p('-')| ch_p('_')))[my_do_string(self.m_store)][debugprint("stringvalue")] >> ch_p('\'')
00358         ;
00359 
00360       custom_comparison = nothing_p;
00361 
00362       for(unsigned int i=0; i<self.m_pars.size(); i++) {
00363         const ParameterDescription& par = self.m_pars[i];
00364         // change to a lowercase name so it will match with a as_lower_d directive
00365         // use the temporary stack to store an actual string location, so it is still there
00366         // when the parser runs.
00367         std::string temp = par.name();
00368         for(std::string::iterator c = temp.begin(); c!= temp.end(); ++c)  *c = tolower(*c);
00369         self.m_store.mTempStack.push(temp);
00370         std::string& parname = self.m_store.mTempStack.top();
00371         //cout << "Setting rules for parameter " << par.name() << "\t" << parname << endl;
00372         
00373         if( par.factory() ) {
00374         // It's a custom type. Set up custom rules for it.
00375         // Add one line for every operator allowed.
00376         for(unsigned int iop=0; iop < par.operators().size(); ++iop){
00377             std::string temp = par.operators()[iop];
00378             // change to a lowercase name so it will match with a as_lower_d directive
00379             for(std::string::iterator c = temp.begin(); c!= temp.end(); ++c)  *c = tolower(*c);
00380             self.m_store.mTempStack.push(temp);
00381             std::string& op = self.m_store.mTempStack.top();
00382 
00383             // Custom floating point parameter.
00384             if(par.type() == typeid(double).name()){
00385               custom_comparison 
00386                 = (  as_lower_d[parname.c_str()]
00387                   >> as_lower_d[op.c_str()]
00388                   >> value_real
00389                   ) [my_do_custom<double>(self.m_store,par,iop,true)] // Lefthand operation
00390               
00391                 | (  value_real
00392                   >> as_lower_d[op.c_str()]
00393                   >> as_lower_d[parname.c_str()] 
00394                   ) [my_do_custom<double>(self.m_store,par,iop,false)] // righthand operation
00395               
00396                 | custom_comparison.copy() // Append.
00397                 ;
00398             }
00399             
00400             // Custom string-or-who-knows
00401             else {
00402               custom_comparison 
00403                 = (  as_lower_d[parname.c_str()]
00404                   >> as_lower_d[op.c_str()]
00405                   >> value_string
00406                   ) [my_do_custom<string>(self.m_store,par,iop,true)] // Lefthand operation
00407               
00408                 | (  value_string
00409                   >> as_lower_d[op.c_str()]
00410                   >> as_lower_d[parname.c_str()] 
00411                   ) [my_do_custom<string>(self.m_store,par,iop,false)] // righthand operation
00412               
00413                 | custom_comparison.copy() // Append.
00414                 ;
00415             }
00416             
00417             
00418           }
00419 
00420         } else {
00421           // Not a custom type.
00422           
00423           if(par.type() == typeid(double).name())
00424             parlist_real.add(parname.begin(), parname.end(), par);
00425           else// If you dont' understand the type, treat it as a string.
00426             parlist_string.add(parname.begin(), parname.end(), par);
00427         }
00428       };
00429 
00430       // Match a name of parameter, after converting to lowercase.
00431       par_real   = as_lower_d[parlist_real[my_do_param(self.m_store)]];
00432       par_string = as_lower_d[parlist_string[my_do_param(self.m_store)]];
00433 
00434       // Valid numerical operators (int and double types)
00435       // N.B. Longer strings should go first, to ensure lazy matching doesn't screw you.
00436       operators_num 
00437         = str_p("<=" )
00438         | str_p(">=")
00439         | str_p("<" )
00440         | str_p(">")
00441         | str_p("==")
00442         | str_p("=" )
00443         | str_p("!=")
00444         ;
00445       
00446       // Valid string operators
00447       operators_string
00448         = str_p("==" )
00449         | str_p("=")
00450         | str_p("!=")
00451         ;
00452 
00453       basic_lefthand_comparison // e.g. pdgcode<2
00454         = (par_real   >> operators_num   [my_do_operator(self.m_store)] >> value_real  )[my_do_simple_comparison<double>(self.m_store,true)]
00455         | (par_string >> operators_string[my_do_operator(self.m_store)] >> value_string)[my_do_simple_comparison<string>(self.m_store,true)]
00456         ;
00457 
00458       basic_righthand_comparison // e.g. 2>pdgcode
00459         = (
00460           (value_real   >> operators_num   [my_do_operator(self.m_store)] >> par_real  )[my_do_simple_comparison<double>(self.m_store,false)]
00461         | (value_string >> operators_string[my_do_operator(self.m_store)] >> par_string)[my_do_simple_comparison<string>(self.m_store,false)]
00462         );
00463 
00464       // A comparison is a basic lhs comparison, a basic rhs comparison, or a custom comparison.
00465       comparison 
00466         = basic_lefthand_comparison[debugprint("lefthand-comparison")]
00467         | basic_righthand_comparison[debugprint("righthand-comparison")]
00468         | custom_comparison[debugprint("custom-comparison")]
00469         ;
00470         
00471       // An expression is a term, optionally followed by AND term, or OR term
00472       expression 
00473         = (term >>
00474              !( ((as_lower_d["and"]|str_p("&&")) >> term)[my_do_and(self.m_store)][debugprint("do-and")] 
00475               | ((as_lower_d["or"] |str_p("||")) >> term)[my_do_or(self.m_store)][debugprint("do-or")]
00476               )
00477            )[debugprint("expression")]
00478         ;
00479 
00480       // A term is 'any', 'none', comparison, (expression), or not term
00481       term
00482         =  (as_lower_d["any"] | as_lower_d["all"] )[my_do_any(self.m_store)]
00483         |  ( as_lower_d["none"]| as_lower_d["nothing"])[my_do_none(self.m_store)]
00484         |  comparison[debugprint("comparison-as-term")]
00485         |  ('(' >> expression >> ')')[debugprint("expression-as-term")]
00486         |  ((as_lower_d["not"]|str_p("!")) >> term)[my_do_not(self.m_store)][debugprint("do-not")][debugprint("not-as-term")]
00487         ;
00488 
00489 
00490       // Final result can be padded with whitespace.
00491       my_grammar
00492         = expression >> end_p
00493         ;
00494     }
00495 
00496     symbols<ParameterDescription> parlist_real;
00497     symbols<ParameterDescription> parlist_int;
00498     symbols<ParameterDescription> parlist_string;
00499     symbols<double> unit_symbols;
00500     stored_rule<ScannerT> custom_comparison;
00501     rule<ScannerT> operators_num;
00502     rule<ScannerT> operators_string;
00503     rule<ScannerT> par_real, par_int, par_string;
00504     rule<ScannerT> value_real, value_int, value_string;
00505     rule<ScannerT> basic_lefthand_comparison, basic_righthand_comparison;
00506     rule<ScannerT> comparison, term, selection, expression;    
00507     rule<ScannerT> my_grammar;
00508     const rule<ScannerT>&
00509       start() const { return my_grammar; }
00510   };
00511 };
00512 
00513 
00514 
00515 
00517 //
00518 //  Main function
00519 //
00521 
00522 bool  RuleParser::CreateRules(
00523                              const std::string&    inString,
00524                              const ParameterList&  inParameters,
00525                              Rule*                 &outRule                   
00526                              )
00527 {
00532   
00533   ParserStore store;  //mustn't delete until ruleparser is dead.
00534   ruleparser rp(store,inParameters);    //  Our parser
00535 
00536   // Default.
00537   outRule = 0; // Failure.
00538 
00539   if(inString.empty()) {
00540     // In the case of no selection, default to selecting nothing.
00541     outRule = new NoneRule;
00542   }
00543   
00544   store.clear();
00545   
00546   // Fix for a bug in Spirit.. this is the recommended workaround.
00547   parse_info<> info = parse(inString.c_str(), rp, space_p);
00548 
00549   if (info.full)
00550   {
00551     outRule = store.mStackRules.top();
00552     return true;
00553   }
00554   cerr << "-------------------------\n";
00555   cerr << "Parsing failed\n";
00556   cerr << "stopped at: \"" << info.stop << "\"\n";
00557   cerr << "-------------------------\n";
00558   return false;
00559 }
00560 
| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

Generated on Mon Apr 11 20:09:14 2011 for RuleParser by doxygen 1.4.7