pd_alg_first.cpp

Go to the documentation of this file.
00001 /** @file pd_alg_first.cpp  functions related to the first function*/
00002 
00003 
00004 /* Pushdown plugin for FAU Discrete Event Systems Library (libfaudes)
00005 
00006    Copyright (C) 2013  Stefan Jacobi, Sven Schneider, Anne-Kathrin Hess
00007 
00008 */
00009 
00010 #include "pd_alg_first.h"
00011 
00012 namespace faudes {
00013 
00014   
00015 /* *************************
00016  * PostCl
00017  * *************************/
00018 GrammarSymbolWordSet PostCl(const GrammarSymbolVector& word){
00019 
00020   GrammarSymbolWordSet rSet;
00021   GrammarSymbolVector postfix;
00022   GrammarSymbolVector::const_reverse_iterator vit;
00023   //iterate backwards over the word, thus building all postfixes
00024   for(vit = word.rbegin(); vit != word.rend(); vit++){
00025     
00026     postfix.insert(postfix.begin(),*vit);
00027     rSet.insert(postfix);
00028   }
00029   
00030   //lambda always belongs in the set
00031   GrammarSymbolVector lambda;
00032   Terminal* tlambda = new Terminal(PushdownGenerator::GlobalEventSymbolTablep()->Index(FAUDES_PD_LAMBDA));
00033   GrammarSymbolPtr ptr(tlambda);
00034   lambda.push_back(ptr);
00035   rSet.insert(lambda);
00036   
00037   return rSet;
00038 }
00039 
00040 /* *************************
00041  * Fds
00042  * *************************/
00043 GrammarSymbolWordSet Fds(const Grammar& gr){
00044   GrammarSymbolWordSet rSet, postfixSet;
00045   GrammarSymbolVector gsVector;
00046   std::set<GrammarProduction>::const_iterator gpit;
00047   
00048   //iterate over all grammar productions
00049   for(gpit = gr.GrammarProductionsBegin(); gpit != gr.GrammarProductionsEnd(); gpit++){
00050     
00051     gsVector.clear();
00052     
00053     //add lefthand side
00054     Nonterminal* nt = new Nonterminal(gpit->Lhs());
00055     NonterminalPtr ntPtr(nt);
00056     gsVector.push_back(ntPtr);
00057     rSet.insert(gsVector);
00058     
00059     //add postfixes of righthand side
00060     postfixSet = PostCl(gpit->Rhs());
00061     rSet.insert(postfixSet.begin(), postfixSet.end());
00062     
00063   }
00064   return rSet;
00065 }
00066 
00067 /* *************************
00068  * First1
00069  * *************************/
00070 GrammarSymbolWordMap First1(const Grammar& gr, const GrammarSymbolWordMap& f, bool* madeChanges){
00071   
00072   //take a copy rf of the old first function f for extending and returning
00073   GrammarSymbolWordMap rf = f;
00074   
00075   //helper variable to determine if changes were made from f to rf
00076   bool changed = false;
00077   *madeChanges = false;
00078   
00079   //get all postfixes and lefthand sides of the grammar
00080   GrammarSymbolWordSet words = Fds(gr);
00081   
00082   GrammarSymbolWordSet::const_iterator wordit;
00083   std::set<Terminal>::const_iterator insertWordit;
00084   
00085   std::set<GrammarProduction>::const_iterator gpit;
00086   //for every word w in Fds(gr)
00087   for(wordit = words.begin(); wordit != words.end(); wordit++){
00088     
00089     //get the first symbol of the word w = a.w'
00090     GrammarSymbolPtr firstSymbol = wordit->front();
00091     
00092     //if the first symbol is a terminal
00093     TerminalPtr terminalA = std::tr1::dynamic_pointer_cast<Terminal>(firstSymbol);
00094     if(terminalA != NULL){
00095       
00096       std::set<Terminal> rfw;
00097       //add the terminal to the first function rf
00098       //if w does not already exist in rf, create it
00099       if(rf.find(*wordit) == rf.end()){
00100         rf.insert(std::make_pair(*wordit, std::set<Terminal>()));
00101       }
00102       
00103       //add rf(w) = a to the first function rf
00104       changed = rf.find(*wordit)->second.insert(*terminalA).second;
00105       if(changed) *madeChanges = true;
00106     }
00107     
00108     //if the first symbol is a nonterminal
00109     NonterminalPtr nonterminalA = std::tr1::dynamic_pointer_cast<Nonterminal>(firstSymbol);
00110     if(nonterminalA != NULL){
00111       
00112       std::set<Terminal> directDependencies;
00113       
00114       //get the first symbols f(x) for every production (a-->x)
00115       for(gpit = gr.GrammarProductionsBegin(); gpit != gr.GrammarProductionsEnd(); gpit++){
00116         
00117         //check if the production has the nonterminal a on its lefthand side and if the
00118         //righthand side x exists in f
00119         if(gpit->Lhs() == *nonterminalA){
00120           if(f.find(gpit->Rhs()) != f.end()){
00121             
00122             //get f(x) and add it to directDependencies
00123             std::set<Terminal> fx = f.find(gpit->Rhs())->second;
00124             directDependencies.insert(fx.begin(),fx.end());
00125           }
00126         }
00127       }
00128       
00129       //construct the symbol a ...
00130       GrammarSymbolVector a;
00131       a.push_back(nonterminalA);
00132       //... and get the first symbols of a (f(a))
00133       std::set<Terminal> fa;
00134       if(f.find(a) != f.end()){
00135         fa = f.find(a)->second;
00136       }
00137       
00138       //get w' (the second part of the current word w = a.w'),
00139       GrammarSymbolVector wBack(wordit->begin() + 1, wordit->end());//can never go out of bounds because of outermost for loop
00140       
00141       //if w' is not empty, remove lambda from f(a) and the direct dependencies,
00142       //because eliminability of a does not imply eliminability of w'
00143       GrammarSymbolVector lambdaWord;
00144       Terminal tlambda(PushdownGenerator::GlobalEventSymbolTablep()->Index(FAUDES_PD_LAMBDA));
00145       
00146       //remove lambda and remember for later if lambda was in f(a)
00147       bool faContainsLambda = false;
00148       if(!wBack.empty()){  
00149         if(fa.erase(tlambda) == 1){
00150           faContainsLambda = true;
00151         }
00152         directDependencies.erase(tlambda);
00153       }
00154       
00155       //add new items to rf(w)
00156       std::set<Terminal> rfw;
00157       //if w does not already exist in rf, create it
00158       if(rf.find(*wordit) == rf.end()){
00159         rf.insert(std::make_pair(*wordit, std::set<Terminal>()));
00160       }
00161 
00162       //add f(a)
00163       for(insertWordit = fa.begin(); insertWordit != fa.end(); insertWordit++){
00164         changed = rf.find(*wordit)->second.insert(*insertWordit).second;
00165         if(changed) *madeChanges = true;
00166       }
00167       
00168       //add direct dependencies
00169       for(insertWordit = directDependencies.begin(); insertWordit != directDependencies.end(); insertWordit++){
00170         changed = rf.find(*wordit)->second.insert(*insertWordit).second;
00171         if(changed) *madeChanges = true;
00172       }
00173               
00174       //if a is eliminable, add f(w') to f(w)
00175       if(faContainsLambda){
00176         std::set<Terminal> fwBack;
00177         //get f(w')
00178         if(f.find(wBack) != f.end()){
00179           fwBack = f.find(wBack)->second;
00180         }
00181         
00182         //add f(w')
00183         for(insertWordit = fwBack.begin(); insertWordit != fwBack.end(); insertWordit++){
00184           changed = rf.find(*wordit)->second.insert(*insertWordit).second;
00185           if(changed) *madeChanges = true;
00186         }
00187       }
00188     }
00189   }
00190   return rf;  
00191 }
00192 
00193 /* *************************
00194  * FirstL
00195  * *************************/
00196 GrammarSymbolWordMap FirstL(const Grammar& gr, const GrammarSymbolWordMap& f){
00197   
00198   //calculate first function
00199   bool changed;
00200   GrammarSymbolWordMap fNew = First1(gr,f,&changed);
00201   
00202   //repeat until no changes are made
00203   if(changed){
00204     fNew = FirstL(gr,fNew);
00205   }
00206   
00207   return fNew;
00208 }
00209 
00210 /* *************************
00211  * FirstA
00212  * *************************/
00213 std::set<Terminal> FirstA(const Grammar& gr, const GrammarSymbolVector& word){
00214   
00215   //calculate first function
00216   GrammarSymbolWordMap f = FirstL(gr,f);
00217   
00218   GrammarSymbolWordMap::const_iterator fit = f.find(word);
00219   if(fit == f.end()){
00220     GrammarSymbolVector::const_iterator vit;
00221     std::stringstream errstr;
00222     errstr << "word " << std::endl;
00223     for(vit = word.begin(); vit != word.end(); vit++){
00224       errstr << (*vit)->Str();
00225     }
00226     errstr << " was not found in the first function";
00227     throw Exception("FirstA", errstr.str(), 1001);
00228   }
00229   
00230   return fit->second;
00231 }
00232 
00233 /* *************************
00234  * First
00235  * *************************/
00236 std::set<Terminal> First(const Grammar& gr, const GrammarSymbolVector& word){
00237   
00238   //"empty" words must still contain lambda!
00239   if(word.empty()){
00240     std::stringstream errstr;
00241     errstr << "word parameter was empty. try calling it with lambda instead of an empty vector.";
00242     throw Exception("First", errstr.str(), 1001);
00243   }
00244   
00245   //set of nonterminals to return
00246   std::set<Terminal> rSet;
00247   
00248   //if the first symbol of the word is a terminal (or lambda)
00249   TerminalPtr t = std::tr1::dynamic_pointer_cast<Terminal>(word.front());
00250   if(t != NULL) {
00251     
00252     //insert the terminal (can be lambda)
00253     rSet.insert(*t);
00254   }
00255   
00256   //if the first symbol of the word is a nonterminal
00257   NonterminalPtr nt = std::tr1::dynamic_pointer_cast<Nonterminal>(word.front());
00258   if(nt != NULL){
00259     
00260     //get first set of the nonterminal
00261     GrammarSymbolVector v;
00262     v.push_back(nt);
00263     rSet = FirstA(gr,v);
00264     
00265     //if the word contains more symbols and the set contains, it needs to erased
00266     //be removed from the set
00267     if(word.size() > 1){
00268       
00269       Terminal tlambda(PushdownGenerator::GlobalEventSymbolTablep()->Index(FAUDES_PD_LAMBDA));
00270       //the set contains lambda (the nonterminal is eliminable). the remaining word
00271       //needs to be examined
00272       if(rSet.erase(tlambda) == 1){
00273         
00274         //recursive call of first
00275         std::set<Terminal> recSet = First(gr, GrammarSymbolVector(word.begin() + 1, word.end()));
00276         rSet.insert(recSet.begin(), recSet.end());
00277       }
00278     }
00279   }
00280   return rSet;
00281 }
00282 
00283 /* *************************
00284  * FirstRed
00285  * *************************/
00286 std::set<Terminal> FirstRed(const Grammar& gr, const GrammarSymbolVector& word){
00287   
00288   //set to return
00289   std::set<Terminal> rSet;
00290   
00291   //if every symbol of the word is a symbol of the grammar, the word is consistent
00292   bool consistent = true;
00293   GrammarSymbolVector::const_iterator wordit;
00294   std::set<Terminal>::const_iterator tit;
00295   std::set<Nonterminal>::const_iterator ntit;
00296   
00297   //check every symbol of the word
00298   for(wordit = word.begin(); wordit != word.end(); wordit++){
00299     
00300     //if it's a terminal
00301     TerminalPtr t = std::tr1::dynamic_pointer_cast<Terminal>(*wordit);
00302     if(t != NULL) {
00303       //if it's not in the grammar's terminals
00304       if(gr.Terminals().find(*t) == gr.TerminalsEnd()){
00305         consistent = false;
00306         break;
00307       }
00308     }
00309     
00310     //if it's a nonterminal
00311     NonterminalPtr nt = std::tr1::dynamic_pointer_cast<Nonterminal>(*wordit);
00312     if(nt != NULL) {
00313       //if it's not in the grammar's nonterminals
00314       if(gr.Nonterminals().find(*nt) == gr.NonterminalsEnd()){
00315         consistent = false;
00316         break;
00317       }
00318     }
00319   }
00320   
00321   //call first only if it's consistent
00322   if(consistent){
00323     rSet = First(gr, word);
00324   }
00325   //else return empty set
00326   return rSet;
00327 }
00328 
00329 /* *************************
00330  * Filter1
00331  * *************************/
00332 NonterminalPtr Filter1(const std::set<Nonterminal>& symbolSet, const GrammarSymbolVector& w){
00333   
00334   GrammarSymbolVector::const_iterator wit;
00335   std::set<Nonterminal>::const_iterator ntit;
00336   //iterate over all symbols of the word
00337   for(wit = w.begin(); wit != w.end(); wit++){
00338     //test if current symbol is a nonterminal
00339     ConstNonterminalPtr nt = std::tr1::dynamic_pointer_cast<const Nonterminal>(*wit);
00340     if(nt != NULL){
00341           
00342       //look for the symbol in the nonterminal set
00343       ntit = symbolSet.find(*nt);
00344       
00345       //if the symbol was found, return it
00346       if(ntit != symbolSet.end()){
00347         Nonterminal* rNt = new Nonterminal(*nt);
00348         return NonterminalPtr(rNt);
00349       }
00350     }
00351   }
00352   //else return NULL
00353   return NonterminalPtr();
00354 }
00355 
00356 /* *************************
00357  * FirstAll
00358  * *************************/
00359 std::set<Terminal> FirstAll(const Grammar& gr, const GrammarSymbolVector& word){
00360   
00361   //set to return
00362   std::set<Terminal> rSet;
00363   
00364   //get nonterminals contained in the word
00365   std::set<Nonterminal> filterSet = Filter(gr.Nonterminals(), word);
00366   
00367   //if no nonterminals were found, call First
00368   if(filterSet.empty()){
00369     rSet = First(gr, word);
00370   }
00371   //if nonterminals were found
00372   else{
00373     
00374     //create temporary grammar with the first nonterminal as a start symbol
00375     Grammar tempGr = gr;
00376     NonterminalPtr firstNt = Filter1(gr.Nonterminals(), word);
00377     tempGr.SetStartSymbol(*firstNt);
00378     //remove nonproducte productions from this grammar
00379     Grammar optGr = Rnpp(tempGr);
00380     //if the grammar is not empty, call FirstRed
00381     if(!optGr.GrammarProductions().empty()){
00382       rSet = FirstRed(optGr, word);
00383     }
00384   }
00385   
00386   return rSet;
00387 }
00388 
00389 /* *************************
00390  * FirstLeq1
00391  * *************************/
00392 std::set<Terminal> FirstLeq1(const Grammar& gr, uint k, const GrammarSymbolVector& word){
00393   
00394   //set to return
00395   std::set<Terminal> rSet;
00396   
00397   //if k > 1, return empty set
00398   if(k > 1){
00399     return rSet;
00400   }
00401   
00402   //else determine first set
00403   rSet = FirstAll(gr, word);
00404   
00405   //if k == 0 and the first set is not empty, return lambda as first set
00406   if(k == 0 && !rSet.empty()){
00407     Terminal tlambda(PushdownGenerator::GlobalEventSymbolTablep()->Index(FAUDES_PD_LAMBDA));
00408     
00409     rSet.clear();
00410     rSet.insert(tlambda);
00411   }
00412     
00413   return rSet;
00414 }
00415 
00416 /* *****************
00417  * WriteMap
00418  * *****************/
00419 void WriteMap(GrammarSymbolWordMap f, bool changed){
00420   GrammarSymbolWordMap::const_iterator fit;
00421   std::set<Terminal>::const_iterator setit;
00422   GrammarSymbolVector::const_iterator wordit;
00423   std::stringstream mapstr;
00424   mapstr << "************************************************" << std::endl;
00425   mapstr << "changes made:";
00426   if(changed) mapstr << "yes" << std::endl;
00427   else mapstr << "no" << std::endl;
00428   mapstr << std::endl;
00429   for(fit = f.begin(); fit != f.end(); fit++){
00430     
00431     for(wordit = fit->first.begin(); wordit != fit->first.end(); wordit++){
00432       mapstr << (*wordit)->Str();
00433     }
00434     
00435     mapstr << ": ";
00436     mapstr << std::endl << "    ";
00437     for(setit = fit->second.begin(); setit != fit->second.end(); setit++){
00438       if(setit != fit->second.begin()){
00439         mapstr << ", ";
00440       }
00441         mapstr << (*wordit)->Str();
00442     }
00443     mapstr << std::endl;
00444   }
00445   
00446   std::cout << mapstr.str() << std::endl;
00447 }
00448   
00449 } // namespace faudes
00450 

libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen