pd_dotparser.h
Go to the documentation of this file.
1 /** @file pd_dotparser.h parser functions for DOT language */
2 
3 /* Pushdown plugin for FAU Discrete Event Systems Library (libfaudes)
4 
5  Copyright (C) 2014 Ramon Barakat, Stefan Jacobi, Sven Schneider, Anne-Kathrin Hess
6 
7 
8  (DOT language see: http://www.graphviz.org/content/dot-language )
9 
10  The following is an abstract grammar defining the DOT language for Pushdowngenerator.
11  Terminals are shown in quotes.
12  Literal characters are given in single quotes.
13  Parentheses ( and ) indicate grouping when needed.
14  Square brackets [ and ] enclose optional items.
15  Vertical bars | separate alternatives
16 
17 
18  graph : [ "strict" ] ("graph" | "digraph") [ ID ] '{' stmt_list '}'
19  stmt_list : state_stmts ';' init_stmt ';' sb_stmt [ ';' event_stmts] [ ';' trans_stmts ]
20  state_stmts : ID [marked_stmt] [ ';' state_stmt ]
21  marked_stmt : '[' "double" ']'
22  init_stmt : '->' ID
23  sb_stmt : ID '[' "attr" '=' "stackbottom" ']'
24  event_stmts : ID '[' "attr" '=' attr_stmts ']' [ ';' event_stmts]
25  attr_stmts : ('c' | 'C') [('o' | 'O')] [('f' | 'F')][('a' | 'A')]
26  trans_stmts : ID '->' ID '[' "label" '=' ID ',' '[' stack_sym ']' '[' stack_sym ']' ]
27  stack_sym : [ID [ ',' ID] ]
28 
29  */
30 
31 #ifndef FAUDES_PD_DOTPARSER_H
32 #define FAUDES_PD_DOTPARSER_H
33 
34 
35 #include "pd_pdgenerator.h"
36 
37 namespace faudes {
38 
39 // split string by separator
40 std::vector<std::string> split(const std::string& rStr, const std::string& rSep,
41  const std::string& rFilename, const int lineNr);
42 
43 /**
44  * Get string literal between quotations ("ide") to &resText and return the position after the second quotation (").
45  *
46  * @param rPos
47  * position where to search from
48  *
49  * @param rInput
50  * input string
51  *
52  * @param rRestString
53  * return the string after the second quotation
54  *
55  * @param rFilename
56  * name of current file
57  *
58  * @param lineNr
59  * current line number
60  *
61  * @return std::string::size_type
62  * position after the second quotation
63  */
64 std::string::size_type getIde(std::string::size_type& rPos,
65  const std::string& rInput, std::string& rRestString,
66  const std::string& rFilename, const int lineNr);
67 
68 
69 /**
70  * check if given string is a replacement for lambda
71  * Replacements are empty string (""),
72  * underline ("_") ,
73  * html lambda code ("&lambda;")
74  * or "lambda"
75  *
76  * @param str
77  * string to check
78  *
79  * @return
80  * true, if given string is a replacement for lambda
81  */
82 bool IsLambdaReplacement(const std::string& str);
83 
84 
85 /**
86  * Parse a System (TcGenerator) from given dot-file.
87  * For this, a temporary file will be created which annotates empty pop and push
88  * operations to each transition and a default stack bottom.
89  * The temporary file will be parsed by TpdGenerator::DotRead().
90  *
91  * @param filename
92  * file to parse
93  *
94  * @return
95  * system from given file
96  */
97 System SystemFromDot(const std::string& filename);
98 
99 
100 #ifndef TEMP
101 #define TEMP template <class GlobalAttr, class StateAttr, class EventAttr, class TransAttr>
102 #endif
103 
104 #ifndef THIS
105 #define THIS TpdGenerator<GlobalAttr, StateAttr, EventAttr, TransAttr>
106 #endif
107 
108 
109 //insert all stack symbols from given vector to generator
110 TEMP void ParserInsStackSymbols(std::vector<std::string>& rVec,const std::string& rFileName,const int lineNr,THIS& rPd) {
111  if(rVec.empty()){
112  //add lambda to generator
113  rPd.InsLambdaStackSymbol();
114 
115  //add lambda to vector cause empty vector not allowed in pop or push
116  rVec.push_back(FAUDES_PD_LAMBDA);
117  }else{
118  for (std::vector<std::string>::const_iterator itstr = rVec.begin(); itstr != rVec.end(); ++itstr) {
119  std::string name = *itstr;
120  //check if lambda
121  if(IsLambdaReplacement(name)){
122  if(rVec.size() == 1){
123  name = FAUDES_PD_LAMBDA;
124  //add lambda to generator
125  rPd.InsLambdaStackSymbol();
126 
127  //add lambda to vector
128  rVec.clear();
129  rVec.push_back(FAUDES_PD_LAMBDA);
130  }
131  #ifdef FAUDES_CHECKED
132  else{
133  std::stringstream errstr;
134  errstr << rFileName << " L:"<< lineNr<< " pop/push lambda vector can't contain more than exactly one symbol(=lambda) ";
135  throw Exception("pd_dotparser::ParserInsStackSymbols", errstr.str(), 200);
136  }
137  #endif
138 
139  }else{
140  //add stack symbol to generator
141  if(!rPd.ExistsStackSymbol(name))
142  rPd.InsStackSymbol(name);
143  }
144  }
145  }
146 }
147 
148 
149 
150 //parse transition (like "x1" -> "x2" [label = ev,[pop],[push] )
151 TEMP bool ParseTransition(const std::string input,const std::string& rFilename,const int linenr,THIS& rPd) {
152 
153  std::string srcState, eventName, trgState, label;
154  std::vector<std::string> vPop, vPush;
155  std::string::size_type end_position,pos= 0;
156 
157  //get src state
158  pos = getIde(pos,input,srcState,rFilename,linenr);
159  //get trg state
160  pos = getIde(++pos,input,trgState,rFilename,linenr);
161 
162  //find lable of the transition
163  pos = input.find("label",pos);
164 
165  #ifdef FAUDES_CHECKED
166  // check if src state exists
167  if(!rPd.ExistsState(srcState)) {
168  std::stringstream errstr;
169  errstr << rFilename << " L:"<< linenr<< " state not exists : " << srcState << " !";
170  throw Exception("pd_dotparser::ParseTransition", errstr.str(), 200);
171  }
172  // check if trg state exists
173  if(!rPd.ExistsState(trgState)) {
174  std::stringstream errstr;
175  errstr << rFilename << " L:"<< linenr<< " state not exists : " << trgState << " !";
176  throw Exception("pd_dotparser::ParseTransition", errstr.str(), 200);
177  }
178 
179  //will probably never happen
180  if(pos == std::string::npos) {
181  std::stringstream errstr;
182  errstr << rFilename << " L:"<< linenr<< " missing label for transition : " << srcState << "->" << trgState << " !";
183  throw Exception("pd_dotparser::ParseTransition", errstr.str(), 200);
184  }
185  #endif
186 
187  //get ID
188  pos = getIde(pos,input,label,rFilename,linenr);
189 
190  //parse event
191  end_position = std::min(label.find(','),label.find('['));
192 
193  if(end_position != std::string::npos )
194  {
195  //get event name
196  eventName = label.substr(0,end_position);
197 
198  //check if event is lambda
199  if(IsLambdaReplacement(eventName))
200  eventName = FAUDES_PD_LAMBDA;
201 
202  //add event to generator
203  if(! rPd.ExistsEvent(eventName))
204  rPd.InsEvent(eventName);
205 
206  //get pop/push symbols
207  pos = label.find("[");
208  if (pos != std::string::npos)
209  {
210  //get pop symbols
211  end_position = label.find("]",++pos);
212 
213  //check syntax
214  #ifdef FAUDES_CHECKED
215  std::string::size_type tmp = label.find('[',pos);
216  if(tmp < end_position){
217  std::stringstream errstr;
218  errstr << rFilename << " L:"<< linenr<< " Expected ']' find '[' .";
219  throw Exception("pd_dotparser::ParseTransition", errstr.str(), 200);
220  }
221  #endif
222 
223  // get popped symbols
224  if (end_position != std::string::npos)
225  {
226  std::string found_text = label.substr(pos, end_position-pos);
227  vPop = split(found_text,",",rFilename,linenr);
228 
229  //add stack symbols to generator
230  ParserInsStackSymbols(vPop,rFilename,linenr,rPd);
231 
232  }else{
233  #ifdef FAUDES_CHECKED
234  std::stringstream errstr;
235  errstr << rFilename << " L:"<< linenr << " Missing ']'." ;
236  throw Exception("pd_dotparser::ParseTransition", errstr.str(), 200);
237  #endif
238  }
239 
240  //get push symbols
241  pos = label.find('[',++pos);
242  if (pos != std::string::npos)
243  {
244  end_position = label.find("]",++pos);
245  if (end_position != std::string::npos)
246  {
247  std::string found_text = label.substr(pos, end_position-pos);
248  vPush.push_back(FAUDES_PD_LAMBDA);
249  vPush = split(found_text,",",rFilename,linenr);
250 
251  //add stack symbols to generator
252  ParserInsStackSymbols(vPush,rFilename,linenr,rPd);
253 
254  //add transition to generator
255  return rPd.SetTransition(srcState,eventName,trgState,vPop,vPush);
256  }else{
257  #ifdef FAUDES_CHECKED
258  std::stringstream errstr;
259  errstr << rFilename << " L:"<< linenr << " Missing ']'." ;
260  throw Exception("pd_dotparser::ParseTransition", errstr.str(), 200);
261  #endif
262  }
263  }else{
264  #ifdef FAUDES_CHECKED
265  std::stringstream errstr;
266  errstr << rFilename << " L:"<< linenr << " Missing '[' for pushed symbols." ;
267  throw Exception("pd_dotparser::ParseTransition", errstr.str(), 200);
268  #endif
269  }
270  }else{
271  #ifdef FAUDES_CHECKED
272  std::stringstream errstr;
273  errstr << rFilename << " L:"<< linenr << " Missing '[' for pop and pushed symbols." ;
274  throw Exception("pd_dotparser::ParseTransition", errstr.str(), 200);
275  #endif
276  }
277  }
278 
279  return false;
280 }
281 
282 //parse events with given attributes
283 //The default attribute is non-controllable, non-forcible, observable and high-level.
284 //(see http://www.rt.techfak.fau.de/FGdes/faudes/reference/corefaudes_alphabet.html#EventSet)
285 TEMP void ParseEvent(std::string input,const std::string& rFileName,const int lineNr,THIS& rPd) {
286  std::string::size_type pos= 0;
287  std::string eventName, attr;
288 
289  //get event name
290  getIde(pos,input,eventName,rFileName,lineNr);
291 
292  //get attributes
293  pos = input.find("attr",pos);
294  getIde(pos,input,attr,rFileName,lineNr);
295 
296  #ifdef FAUDES_CHECKED
297  if(rPd.ExistsEvent(eventName)) {
298  std::stringstream errstr;
299  errstr << rFileName << " L:"<< lineNr<< " event : " << eventName << " already exists !";
300  throw Exception("pd_dotparser::ParseEvent", errstr.str(), 200);
301  }
302  #endif
303 
304  //add event to generator
305  Idx event = rPd.InsEvent(eventName);
306 
307  //set attributes
308  //(see http://www.rt.techfak.fau.de/FGdes/faudes/reference/corefaudes_alphabet.html#EventSet)
309  for(unsigned i = 0; i < attr.size(); i++) {
310  // controllability
311  if(attr[i] == 'C') rPd.SetControllable(event);
312  if(attr[i] == 'c') rPd.ClrControllable(event);
313  // observability
314  if(attr[i] == 'O') rPd.SetObservable(event);
315  if(attr[i] == 'o') rPd.ClrObservable(event);
316  // forcibility
317  if(attr[i] == 'F') rPd.SetForcible(event);
318  if(attr[i] == 'f') rPd.ClrForcible(event);
319  // high-level alphabet membership
320  if(attr[i] == 'A') rPd.SetHighlevel(event);
321  if(attr[i] == 'a') rPd.SetLowlevel(event);
322  }
323 }
324 
325 //parse states
326 TEMP void ParseState(const std::string input,const std::string& rFileName,const int lineNr,THIS& rPd) {
327  std::string::size_type pos= 0;
328  std::string state;
329 
330  //get state name
331  getIde(pos,input,state,rFileName,lineNr);
332 
333  //add state to generator
334  if(!rPd.ExistsState(state))
335  rPd.InsState(state);
336 
337  //set initial state, if so
338  if(input.find("->")!= std::string::npos) {
339  rPd.SetInitState(state);
340  }
341 
342  //set marked state, if so
343  pos = input.find("shape=double",++pos);
344  if(pos != std::string::npos)
345  rPd.SetMarkedState(state);
346 }
347 
348 //parse stack bottom
349 TEMP void ParseStackBottom(const std::string input,const std::string& rFilename,const int linenr,THIS& rPd) {
350  std::string::size_type pos= 0;
351  std::string bottom;
352 
353  //get stack bottom name
354  getIde(pos,input,bottom,rFilename,linenr);
355 
356  //add and set stack bottom
357  rPd.InsStackSymbol(bottom);
358  rPd.SetStackBottom(bottom);
359 }
360 
361 // parsing and create a generator from given dot file
362 TEMP void CreatPdFromDot(const std::string& fileName,THIS& pd) {
363  // get filestream
364  //std::fstream file (fileName);
365  std::ifstream file (fileName.c_str(), std::ios::in | std::ios::binary);
366 
367 
368  if (file.is_open())
369  {
370  //remember linenr. for error handling
371  int lineNr = 0;
372 
373  // parsing line by line
374  std::string line;
375  while ( getline(file,line) )
376  {
377  ++lineNr;
378  std::string sub = line;
379 
380  // remove spaces
381  sub.erase(std::remove_if(sub.begin(), sub.end(), ::isspace), sub.end());
382 
383  // remove comments
384  sub = sub.substr(0,sub.find_first_of("//"));
385 
386  if(sub.empty())
387  continue;
388 
389  if(sub.find("shape=none") != std::string::npos ||
390  sub.find("shape=point") != std::string::npos )
391  continue;
392 
393  // if M=(Q, Sigma, Gamma, init state , stack bottom, Qm, delta) is included in file
394  // skip lines
395  if(sub.find("label=<")!= std::string::npos ||
396  sub.find("<br")!= std::string::npos)
397  continue;
398 
399  if(sub.find("digraph")!= std::string::npos)
400  sub = sub.substr(sub.find("{"));
401 
402  //parse event or stack bottom
403  if(sub.find("attr=\"")!= std::string::npos) {
404  //get attributes
405  std::string attr = sub.substr(sub.find("attr=\""));
406  //make lower case for comparing
407  std::for_each(attr.begin(), attr.end(), tolower);
408  // check if attribute is stack bottom
409  if(attr.find("stackbottom")!= std::string::npos)
410  ParseStackBottom(sub,fileName,lineNr,pd);
411  else
412  ParseEvent(sub,fileName,lineNr,pd);
413  } else {
414  // parse transition
415  if(sub.find("->")!= std::string::npos &&
416  sub.find("label")!= std::string::npos) {
417  ParseTransition(sub,fileName,lineNr,pd);
418  } else {
419  if(sub.find('"') != std::string::npos)
420  ParseState(sub,fileName,lineNr,pd);
421  }
422  }
423  }
424  //close file
425  file.close();
426 
427  //warn if initial state or stack bottom don't exists
428  #ifdef FAUDES_CHECKED
429  if(pd.InitStates().Empty()){
430  std::stringstream errstr;
431  errstr << "Missing initial State : " << fileName;
432  FD_WARN("pd_dotparser::CreatePdFromDot : " + errstr.str());
433  //throw Exception("pd_dotparser::CreatePdFromDot", errstr.str(), 200);
434  }
435 
436  if(!pd.ExistsStackSymbol(pd.StackBottom())){
437  std::stringstream errstr;
438  errstr << "Missing stack bottom : " << fileName;
439  FD_WARN("pd_dotparser::CreatePdFromDot : " + errstr.str());
440  //throw Exception("pd_dotparser::CreatePdFromDot", errstr.str(), 200);
441  }
442  #endif
443  }
444  else
445  {
446  #ifdef FAUDES_CHECKED
447  std::stringstream errstr;
448  errstr << "Unable to open file : " << fileName;
449  throw Exception("pd_dotparser::CreatePdFromDot", errstr.str(), 1);
450  #endif
451  }
452 }
453 
454 #undef THIS
455 #undef TEMP
456 }
457  //namespace
458 
459 #endif

libFAUDES 2.26g --- 2015.08.17 --- c++ api documentaion by doxygen