pd_alg_first.cpp
Go to the documentation of this file.
1 /** @file pd_alg_first.cpp functions related to the first function*/
2 
3 
4 /* Pushdown plugin for FAU Discrete Event Systems Library (libfaudes)
5 
6  Copyright (C) 2013 Stefan Jacobi, Sven Schneider, Anne-Kathrin Hess
7 
8 */
9 
10 #include "pd_alg_first.h"
11 
12 namespace faudes {
13 
14 
15 /* *************************
16  * PostCl
17  * *************************/
19 
21  GrammarSymbolVector postfix;
22  GrammarSymbolVector::const_reverse_iterator vit;
23  //iterate backwards over the word, thus building all postfixes
24  for(vit = word.rbegin(); vit != word.rend(); vit++){
25 
26  postfix.insert(postfix.begin(),*vit);
27  rSet.insert(postfix);
28  }
29 
30  //lambda always belongs in the set
31  GrammarSymbolVector lambda;
33  GrammarSymbolPtr ptr(tlambda);
34  lambda.push_back(ptr);
35  rSet.insert(lambda);
36 
37  return rSet;
38 }
39 
40 /* *************************
41  * Fds
42  * *************************/
44  GrammarSymbolWordSet rSet, postfixSet;
45  GrammarSymbolVector gsVector;
46  std::set<GrammarProduction>::const_iterator gpit;
47 
48  //iterate over all grammar productions
49  for(gpit = gr.GrammarProductionsBegin(); gpit != gr.GrammarProductionsEnd(); gpit++){
50 
51  gsVector.clear();
52 
53  //add lefthand side
54  Nonterminal* nt = new Nonterminal(gpit->Lhs());
55  NonterminalPtr ntPtr(nt);
56  gsVector.push_back(ntPtr);
57  rSet.insert(gsVector);
58 
59  //add postfixes of righthand side
60  postfixSet = PostCl(gpit->Rhs());
61  rSet.insert(postfixSet.begin(), postfixSet.end());
62 
63  }
64  return rSet;
65 }
66 
67 /* *************************
68  * First1
69  * *************************/
70 GrammarSymbolWordMap First1(const Grammar& gr, const GrammarSymbolWordMap& f, bool* madeChanges){
71 
72  //take a copy rf of the old first function f for extending and returning
73  GrammarSymbolWordMap rf = f;
74 
75  //helper variable to determine if changes were made from f to rf
76  bool changed = false;
77  *madeChanges = false;
78 
79  //get all postfixes and lefthand sides of the grammar
80  GrammarSymbolWordSet words = Fds(gr);
81 
82  GrammarSymbolWordSet::const_iterator wordit;
83  std::set<Terminal>::const_iterator insertWordit;
84 
85  std::set<GrammarProduction>::const_iterator gpit;
86  //for every word w in Fds(gr)
87  for(wordit = words.begin(); wordit != words.end(); wordit++){
88 
89  //get the first symbol of the word w = a.w'
90  GrammarSymbolPtr firstSymbol = wordit->front();
91 
92  //if the first symbol is a terminal
93  TerminalPtr terminalA = std::tr1::dynamic_pointer_cast<Terminal>(firstSymbol);
94  if(terminalA != NULL){
95 
96  std::set<Terminal> rfw;
97  //add the terminal to the first function rf
98  //if w does not already exist in rf, create it
99  if(rf.find(*wordit) == rf.end()){
100  rf.insert(std::make_pair(*wordit, std::set<Terminal>()));
101  }
102 
103  //add rf(w) = a to the first function rf
104  changed = rf.find(*wordit)->second.insert(*terminalA).second;
105  if(changed) *madeChanges = true;
106  }
107 
108  //if the first symbol is a nonterminal
109  NonterminalPtr nonterminalA = std::tr1::dynamic_pointer_cast<Nonterminal>(firstSymbol);
110  if(nonterminalA != NULL){
111 
112  std::set<Terminal> directDependencies;
113 
114  //get the first symbols f(x) for every production (a-->x)
115  for(gpit = gr.GrammarProductionsBegin(); gpit != gr.GrammarProductionsEnd(); gpit++){
116 
117  //check if the production has the nonterminal a on its lefthand side and if the
118  //righthand side x exists in f
119  if(gpit->Lhs() == *nonterminalA){
120  if(f.find(gpit->Rhs()) != f.end()){
121 
122  //get f(x) and add it to directDependencies
123  std::set<Terminal> fx = f.find(gpit->Rhs())->second;
124  directDependencies.insert(fx.begin(),fx.end());
125  }
126  }
127  }
128 
129  //construct the symbol a ...
131  a.push_back(nonterminalA);
132  //... and get the first symbols of a (f(a))
133  std::set<Terminal> fa;
134  if(f.find(a) != f.end()){
135  fa = f.find(a)->second;
136  }
137 
138  //get w' (the second part of the current word w = a.w'),
139  GrammarSymbolVector wBack(wordit->begin() + 1, wordit->end());//can never go out of bounds because of outermost for loop
140 
141  //if w' is not empty, remove lambda from f(a) and the direct dependencies,
142  //because eliminability of a does not imply eliminability of w'
143  GrammarSymbolVector lambdaWord;
145 
146  //remove lambda and remember for later if lambda was in f(a)
147  bool faContainsLambda = false;
148  if(!wBack.empty()){
149  if(fa.erase(tlambda) == 1){
150  faContainsLambda = true;
151  }
152  directDependencies.erase(tlambda);
153  }
154 
155  //add new items to rf(w)
156  std::set<Terminal> rfw;
157  //if w does not already exist in rf, create it
158  if(rf.find(*wordit) == rf.end()){
159  rf.insert(std::make_pair(*wordit, std::set<Terminal>()));
160  }
161 
162  //add f(a)
163  for(insertWordit = fa.begin(); insertWordit != fa.end(); insertWordit++){
164  changed = rf.find(*wordit)->second.insert(*insertWordit).second;
165  if(changed) *madeChanges = true;
166  }
167 
168  //add direct dependencies
169  for(insertWordit = directDependencies.begin(); insertWordit != directDependencies.end(); insertWordit++){
170  changed = rf.find(*wordit)->second.insert(*insertWordit).second;
171  if(changed) *madeChanges = true;
172  }
173 
174  //if a is eliminable, add f(w') to f(w)
175  if(faContainsLambda){
176  std::set<Terminal> fwBack;
177  //get f(w')
178  if(f.find(wBack) != f.end()){
179  fwBack = f.find(wBack)->second;
180  }
181 
182  //add f(w')
183  for(insertWordit = fwBack.begin(); insertWordit != fwBack.end(); insertWordit++){
184  changed = rf.find(*wordit)->second.insert(*insertWordit).second;
185  if(changed) *madeChanges = true;
186  }
187  }
188  }
189  }
190  return rf;
191 }
192 
193 /* *************************
194  * FirstL
195  * *************************/
197 
198  //calculate first function
199  bool changed;
200  GrammarSymbolWordMap fNew = First1(gr,f,&changed);
201 
202  //repeat until no changes are made
203  if(changed){
204  fNew = FirstL(gr,fNew);
205  }
206 
207  return fNew;
208 }
209 
210 /* *************************
211  * FirstA
212  * *************************/
213 std::set<Terminal> FirstA(const Grammar& gr, const GrammarSymbolVector& word){
214 
215  //calculate first function
216  GrammarSymbolWordMap f = FirstL(gr,f);
217 
218  GrammarSymbolWordMap::const_iterator fit = f.find(word);
219  if(fit == f.end()){
220  GrammarSymbolVector::const_iterator vit;
221  std::stringstream errstr;
222  errstr << "word " << std::endl;
223  for(vit = word.begin(); vit != word.end(); vit++){
224  errstr << (*vit)->Str();
225  }
226  errstr << " was not found in the first function";
227  throw Exception("FirstA", errstr.str(), 1001);
228  }
229 
230  return fit->second;
231 }
232 
233 /* *************************
234  * First
235  * *************************/
236 std::set<Terminal> First(const Grammar& gr, const GrammarSymbolVector& word){
237 
238  //"empty" words must still contain lambda!
239  if(word.empty()){
240  std::stringstream errstr;
241  errstr << "word parameter was empty. try calling it with lambda instead of an empty vector.";
242  throw Exception("First", errstr.str(), 1001);
243  }
244 
245  //set of nonterminals to return
246  std::set<Terminal> rSet;
247 
248  //if the first symbol of the word is a terminal (or lambda)
249  TerminalPtr t = std::tr1::dynamic_pointer_cast<Terminal>(word.front());
250  if(t != NULL) {
251 
252  //insert the terminal (can be lambda)
253  rSet.insert(*t);
254  }
255 
256  //if the first symbol of the word is a nonterminal
257  NonterminalPtr nt = std::tr1::dynamic_pointer_cast<Nonterminal>(word.front());
258  if(nt != NULL){
259 
260  //get first set of the nonterminal
262  v.push_back(nt);
263  rSet = FirstA(gr,v);
264 
265  //if the word contains more symbols and the set contains, it needs to erased
266  //be removed from the set
267  if(word.size() > 1){
268 
270  //the set contains lambda (the nonterminal is eliminable). the remaining word
271  //needs to be examined
272  if(rSet.erase(tlambda) == 1){
273 
274  //recursive call of first
275  std::set<Terminal> recSet = First(gr, GrammarSymbolVector(word.begin() + 1, word.end()));
276  rSet.insert(recSet.begin(), recSet.end());
277  }
278  }
279  }
280  return rSet;
281 }
282 
283 /* *************************
284  * FirstRed
285  * *************************/
286 std::set<Terminal> FirstRed(const Grammar& gr, const GrammarSymbolVector& word){
287 
288  //set to return
289  std::set<Terminal> rSet;
290 
291  //if every symbol of the word is a symbol of the grammar, the word is consistent
292  bool consistent = true;
293  GrammarSymbolVector::const_iterator wordit;
294  std::set<Terminal>::const_iterator tit;
295  std::set<Nonterminal>::const_iterator ntit;
296 
297  //check every symbol of the word
298  for(wordit = word.begin(); wordit != word.end(); wordit++){
299 
300  //if it's a terminal
301  TerminalPtr t = std::tr1::dynamic_pointer_cast<Terminal>(*wordit);
302  if(t != NULL) {
303  //if it's not in the grammar's terminals
304  if(gr.Terminals().find(*t) == gr.TerminalsEnd()){
305  consistent = false;
306  break;
307  }
308  }
309 
310  //if it's a nonterminal
311  NonterminalPtr nt = std::tr1::dynamic_pointer_cast<Nonterminal>(*wordit);
312  if(nt != NULL) {
313  //if it's not in the grammar's nonterminals
314  if(gr.Nonterminals().find(*nt) == gr.NonterminalsEnd()){
315  consistent = false;
316  break;
317  }
318  }
319  }
320 
321  //call first only if it's consistent
322  if(consistent){
323  rSet = First(gr, word);
324  }
325  //else return empty set
326  return rSet;
327 }
328 
329 /* *************************
330  * Filter1
331  * *************************/
332 NonterminalPtr Filter1(const std::set<Nonterminal>& symbolSet, const GrammarSymbolVector& w){
333 
334  GrammarSymbolVector::const_iterator wit;
335  std::set<Nonterminal>::const_iterator ntit;
336  //iterate over all symbols of the word
337  for(wit = w.begin(); wit != w.end(); wit++){
338  //test if current symbol is a nonterminal
339  ConstNonterminalPtr nt = std::tr1::dynamic_pointer_cast<const Nonterminal>(*wit);
340  if(nt != NULL){
341 
342  //look for the symbol in the nonterminal set
343  ntit = symbolSet.find(*nt);
344 
345  //if the symbol was found, return it
346  if(ntit != symbolSet.end()){
347  Nonterminal* rNt = new Nonterminal(*nt);
348  return NonterminalPtr(rNt);
349  }
350  }
351  }
352  //else return NULL
353  return NonterminalPtr();
354 }
355 
356 /* *************************
357  * FirstAll
358  * *************************/
359 std::set<Terminal> FirstAll(const Grammar& gr, const GrammarSymbolVector& word){
360 
361  //set to return
362  std::set<Terminal> rSet;
363 
364  //get nonterminals contained in the word
365  std::set<Nonterminal> filterSet = Filter(gr.Nonterminals(), word);
366 
367  //if no nonterminals were found, call First
368  if(filterSet.empty()){
369  rSet = First(gr, word);
370  }
371  //if nonterminals were found
372  else{
373 
374  //create temporary grammar with the first nonterminal as a start symbol
375  Grammar tempGr = gr;
376  NonterminalPtr firstNt = Filter1(gr.Nonterminals(), word);
377  tempGr.SetStartSymbol(*firstNt);
378  //remove nonproducte productions from this grammar
379  Grammar optGr = Rnpp(tempGr);
380  //if the grammar is not empty, call FirstRed
381  if(!optGr.GrammarProductions().empty()){
382  rSet = FirstRed(optGr, word);
383  }
384  }
385 
386  return rSet;
387 }
388 
389 /* *************************
390  * FirstLeq1
391  * *************************/
392 std::set<Terminal> FirstLeq1(const Grammar& gr, uint k, const GrammarSymbolVector& word){
393 
394  //set to return
395  std::set<Terminal> rSet;
396 
397  //if k > 1, return empty set
398  if(k > 1){
399  return rSet;
400  }
401 
402  //else determine first set
403  rSet = FirstAll(gr, word);
404 
405  //if k == 0 and the first set is not empty, return lambda as first set
406  if(k == 0 && !rSet.empty()){
408 
409  rSet.clear();
410  rSet.insert(tlambda);
411  }
412 
413  return rSet;
414 }
415 
416 /* *****************
417  * WriteMap
418  * *****************/
419 void WriteMap(GrammarSymbolWordMap f, bool changed){
420  GrammarSymbolWordMap::const_iterator fit;
421  std::set<Terminal>::const_iterator setit;
422  GrammarSymbolVector::const_iterator wordit;
423  std::stringstream mapstr;
424  mapstr << "************************************************" << std::endl;
425  mapstr << "changes made:";
426  if(changed) mapstr << "yes" << std::endl;
427  else mapstr << "no" << std::endl;
428  mapstr << std::endl;
429  for(fit = f.begin(); fit != f.end(); fit++){
430 
431  for(wordit = fit->first.begin(); wordit != fit->first.end(); wordit++){
432  mapstr << (*wordit)->Str();
433  }
434 
435  mapstr << ": ";
436  mapstr << std::endl << " ";
437  for(setit = fit->second.begin(); setit != fit->second.end(); setit++){
438  if(setit != fit->second.begin()){
439  mapstr << ", ";
440  }
441  mapstr << (*wordit)->Str();
442  }
443  mapstr << std::endl;
444  }
445 
446  std::cout << mapstr.str() << std::endl;
447 }
448 
449 } // namespace faudes
450 

libFAUDES 2.24g --- 2014.09.15 --- c++ api documentaion by doxygen