Tulip  4.1.0
Better Visualization Through Research
 All Classes Files Functions Variables Enumerations Enumerator Properties Groups Pages
TLPParser.h
1 /*
2  *
3  * This file is part of Tulip (www.tulip-software.org)
4  *
5  * Authors: David Auber and the Tulip development Team
6  * from LaBRI, University of Bordeaux 1 and Inria Bordeaux - Sud Ouest
7  *
8  * Tulip is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation, either version 3
11  * of the License, or (at your option) any later version.
12  *
13  * Tulip is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU General Public License for more details.
17  *
18  */
19 ///@cond DOXYGEN_HIDDEN
20 
21 #ifndef DOXYGEN_NOTFOR_DEVEL
22 
23 #include <iostream>
24 #include <sstream>
25 #include <string>
26 #include <list>
27 
28 
29 namespace tlp {
30 
31 class PluginProgress;
32 
33 struct ParserError {
34  ParserError(int err=0,int lin=0,int cha=0):errorNumber(err),lineInFile(lin),charInLine(cha) {}
35  int errorNumber;
36  int lineInFile;
37  int charInLine;
38 };
39 
40 struct TLPValue {
41  std::string str;
42  long integer;
43  double real;
44  bool boolean;
45  std::pair<long, long> range;
46 };
47 
48 enum TLPToken { BOOLTOKEN,ENDOFSTREAM,STRINGTOKEN,INTTOKEN,DOUBLETOKEN,IDTOKEN,ERRORINFILE,OPENTOKEN,CLOSETOKEN,COMMENTTOKEN,RANGETOKEN};
49 //=====================================================================================
50 struct TLPTokenParser {
51  int curLine;
52  int curChar;
53  std::istream &is;
54  TLPTokenParser(std::istream &i):curLine(0),curChar(0),is(i) {}
55  TLPToken nextToken(TLPValue &val,int &curPos) {
56  val.str.erase();
57  bool endOfStream=false,strGet=false,slashMode=false,started=false,stop=false,strComment=false;
58  char ch;
59 
60  while ( (!stop) && (endOfStream=!(is.get(ch).fail()))) {
61  curPos++;
62  curChar++;
63 
64  if (strGet)
65  switch (ch) {
66  case 13 :
67  case '\n':
68  curChar=0;
69  curLine++;
70  val.str+=ch;
71  break;
72 
73  case '\t':
74  val.str+=" ";
75  break;
76 
77  case '\\':
78 
79  if (!slashMode) {
80  slashMode=true;
81  }
82  else {
83  val.str+=ch;
84  slashMode=false;
85  }
86 
87  break;
88 
89  case '"':
90 
91  if (!slashMode) {
92  return STRINGTOKEN;
93  }
94  else {
95  val.str+=ch;
96  slashMode=false;
97  }
98 
99  break;
100 
101  case 'n':
102 
103  if (slashMode) {
104  val.str+='\n';
105  slashMode=false;
106  break;
107  }
108 
109  default:
110 
111  if (!slashMode)
112  val.str+=ch;
113 
114  slashMode=false;
115  break;
116  }
117  else if (strComment)
118  switch (ch) {
119  case 13 :
120  case '\n':
121  curChar=0;
122  curLine++;
123  stop=true;
124  return COMMENTTOKEN;
125  break;
126 
127  default:
128  curChar++;
129  val.str+=ch;
130  break;
131  }
132  else
133  switch (ch) {
134  case ' ':
135  case '\t':
136 
137  if (started) stop=true;
138 
139  break;
140 
141  case 13 :
142  case '\n':
143  curChar=0;
144  curLine++;
145 
146  if (started) stop=true;
147 
148  break;
149 
150  case '(':
151 
152  if (!started) return OPENTOKEN;
153  else {
154  --curPos,--curChar;
155  is.unget();
156  stop=true;
157  }
158 
159  break;
160 
161  case ')':
162 
163  if (!started) return CLOSETOKEN;
164  else {
165  --curPos,--curChar;
166  is.unget();
167  stop=true;
168  }
169 
170  break;
171 
172  case '"':
173  strGet=true;
174 
175  if (started) {
176  --curPos,--curChar;
177  is.unget();
178  stop=true;
179  }
180  else started=true;
181 
182  break;
183 
184  case ';':
185  strComment=true;
186 
187  if (started) {
188  --curPos,--curChar;
189  is.unget();
190  stop=true;
191  }
192  else started=true;
193 
194  break;
195 
196  default :
197  val.str+=ch;
198  started=true;
199  break;
200  }
201  }
202 
203  if (!started && !endOfStream) return ENDOFSTREAM;
204 
205  char *endPtr=NULL;
206  const char *cstr = val.str.c_str();
207  errno = 0;
208  long resultl= strtol(cstr, &endPtr, 10);
209 
210  if (errno == ERANGE)
211  return ERRORINFILE;
212 
213  unsigned long strlength = val.str.length();
214 
215  if (endPtr==(cstr+ strlength)) {
216  val.integer=resultl;
217  return INTTOKEN;
218  }
219 
220  // check for a range
221  if (endPtr > cstr && (cstr + strlength) > (endPtr + 2)) {
222  val.range.first = resultl;
223 
224  if ((endPtr[0] == '.') && (endPtr[1] == '.')) {
225  char* beginPtr = endPtr + 2;
226  errno = 0;
227  resultl = strtol(beginPtr, &endPtr, 10);
228 
229  if (errno == ERANGE)
230  return ERRORINFILE;
231 
232  if (endPtr == (cstr + strlength)) {
233  if (resultl < val.range.first)
234  return ERRORINFILE;
235 
236  val.range.second = resultl;
237  return RANGETOKEN;
238  }
239  }
240  }
241 
242  endPtr=NULL;
243 
244  double resultd=strtod(cstr, &endPtr);
245 
246  if (errno == ERANGE)
247  return ERRORINFILE;
248 
249  if (endPtr==(cstr + strlength)) {
250  val.real=resultd;
251  return DOUBLETOKEN;
252  }
253 
254  if (strcasecmp(cstr, "true")==0) {
255  val.boolean=true;
256  return BOOLTOKEN;
257  }
258 
259  if (strcasecmp(cstr, "false")==0) {
260  val.boolean=false;
261  return BOOLTOKEN;
262  }
263 
264  if (started) return STRINGTOKEN;
265 
266  return ERRORINFILE;
267  }
268 };
269 //=====================================================================================
270 struct TLPBuilder {
271  virtual ~TLPBuilder() {}
272  virtual bool addBool(const bool)=0;
273  virtual bool addInt(const int)=0;
274  virtual bool addRange(int, int)=0;
275  virtual bool addDouble(const double)=0;
276  virtual bool addString(const std::string &)=0;
277  virtual bool addStruct(const std::string&,TLPBuilder*&)=0;
278  virtual bool close() =0;
279  virtual bool canRead() {
280  return false;
281  }
282  virtual bool read(std::istream&) {
283  return false;
284  }
285 };
286 
287 struct TLPTrue:public TLPBuilder {
288  bool addBool(const bool) {
289  return true;
290  }
291  bool addInt(const int) {
292  return true;
293  }
294  bool addRange(int, int) {
295  return true;
296  }
297  bool addDouble(const double) {
298  return true;
299  }
300  bool addString(const std::string &) {
301  return true;
302  }
303  bool addStruct(const std::string& /*structName*/, TLPBuilder*&newBuilder) {
304  newBuilder=new TLPTrue();
305  return true;
306  }
307  bool close() {
308  return true;
309  }
310 };
311 
312 struct TLPFalse:public TLPBuilder {
313  bool addBool(const bool) {
314  return false;
315  }
316  bool addInt(const int) {
317  return false;
318  }
319  bool addRange(int, int) {
320  return false;
321  }
322  bool addDouble(const double) {
323  return false;
324  }
325  bool addString(const std::string &) {
326  return false;
327  }
328  bool addStruct(const std::string& /*structName*/, TLPBuilder*&newBuilder) {
329  newBuilder=new TLPFalse();
330  return false;
331  }
332  bool close() {
333  return true;
334  }
335 };
336 //=====================================================================================
337 template <bool displayComment>
338 struct TLPParser {
339  std::list<TLPBuilder *> builderStack;
340  std::istream &inputStream;
341  TLPTokenParser *tokenParser;
342  PluginProgress *pluginProgress;
343  int fileSize,curPos;
344 
345  TLPParser(std::istream &inputStream,TLPBuilder *builder,PluginProgress *pluginProgress,int size): inputStream(inputStream),
346  pluginProgress(pluginProgress),
347  fileSize(size),
348  curPos(0) {
349  builderStack.push_front(builder);
350  }
351 
352  ~TLPParser() {
353  while (!builderStack.empty()) {
354  TLPBuilder *builder = builderStack.front();
355  builderStack.pop_front();
356 
357  if (builderStack.empty() || builder != builderStack.front())
358  delete builder;
359  }
360  }
361 
362  bool formatError() {
363  std::stringstream ess;
364  ess << "Error when parsing char " << tokenParser->curChar
365  << " at line " << tokenParser->curLine + 1;
366 
367  if (errno)
368  ess << std::endl << strerror(errno);
369 
370  pluginProgress->setError(ess.str());
371  return false;
372  }
373 
374  bool parse() {
375  TLPTokenParser tParser(inputStream);
376  tokenParser= &tParser;
377  TLPToken currentToken;
378  TLPValue currentValue;
379 
380  while ((currentToken=tokenParser->nextToken(currentValue,curPos))!=ENDOFSTREAM) {
381  if (curPos%2000==1) if (pluginProgress->progress(curPos,fileSize)!=TLP_CONTINUE)
382  return pluginProgress->state()!=TLP_CANCEL;
383 
384  switch (currentToken) {
385  case OPENTOKEN:
386  currentToken=tokenParser->nextToken(currentValue,curPos);
387 
388  if (currentToken!=STRINGTOKEN)
389  return formatError();//we can throw an exeption
390 
391  TLPBuilder *newBuilder;
392 
393  if (builderStack.front()->addStruct(currentValue.str, newBuilder)) {
394  builderStack.push_front(newBuilder);
395 
396  if (newBuilder->canRead())
397  if (!newBuilder->read(inputStream))
398  return formatError();
399  }
400  else
401  return formatError();
402 
403  break;
404 
405  case BOOLTOKEN:
406 
407  if (!builderStack.front()->addBool(currentValue.boolean))
408  return formatError();
409 
410  break;
411 
412  case INTTOKEN:
413 
414  if (!builderStack.front()->addInt(currentValue.integer))
415  return formatError();
416 
417  break;
418 
419  case RANGETOKEN:
420 
421  if (!builderStack.front()->addRange(currentValue.range.first,
422  currentValue.range.second))
423  return formatError();
424 
425  break;
426 
427  case DOUBLETOKEN:
428 
429  if (!builderStack.front()->addDouble(currentValue.real))
430  return formatError();
431 
432  break;
433 
434  case STRINGTOKEN:
435 
436  if (!builderStack.front()->addString(currentValue.str))
437  return formatError();
438 
439  break;
440 
441  case CLOSETOKEN:
442 
443  if (builderStack.front()->close()) {
444  TLPBuilder * builder = builderStack.front();
445  builderStack.pop_front();
446 
447  if (builder != builderStack.front())
448  delete builder;
449  }
450  else
451  return formatError();
452 
453  break;
454 
455  case ERRORINFILE:
456  return formatError();
457 
458  case ENDOFSTREAM:
459  return true;
460 
461  case COMMENTTOKEN:
462 
463  if (displayComment) qDebug() << "Comment line:" << tokenParser->curLine << "->" << currentValue.str;
464 
465  break;
466 
467  default:
468  break;
469  }
470  }
471 
472  return true;
473  }
474 };
475 
476 }
477 //=====================================================================================
478 
479 #endif // DOXYGEN_NOTFOR_DEVEL
480 ///@endcond