![]() |
Tulip
4.6.0
Better Visualization Through Research
|
00001 /* 00002 * 00003 * This file is part of Tulip (www.tulip-software.org) 00004 * 00005 * Authors: David Auber and the Tulip development Team 00006 * from LaBRI, University of Bordeaux 00007 * 00008 * Tulip is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU Lesser General Public License 00010 * as published by the Free Software Foundation, either version 3 00011 * of the License, or (at your option) any later version. 00012 * 00013 * Tulip is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00016 * See the GNU General Public License for more details. 00017 * 00018 */ 00019 ///@cond DOXYGEN_HIDDEN 00020 00021 #ifndef DOXYGEN_NOTFOR_DEVEL 00022 00023 #include <sstream> 00024 #include <string> 00025 #include <list> 00026 00027 00028 namespace tlp { 00029 00030 class PluginProgress; 00031 00032 struct ParserError { 00033 ParserError(int err=0,int lin=0,int cha=0):errorNumber(err),lineInFile(lin),charInLine(cha) {} 00034 int errorNumber; 00035 int lineInFile; 00036 int charInLine; 00037 }; 00038 00039 struct TLPValue { 00040 std::string str; 00041 long integer; 00042 double real; 00043 bool boolean; 00044 std::pair<long, long> range; 00045 }; 00046 00047 enum TLPToken { BOOLTOKEN,ENDOFSTREAM,STRINGTOKEN,INTTOKEN,DOUBLETOKEN,IDTOKEN,ERRORINFILE,OPENTOKEN,CLOSETOKEN,COMMENTTOKEN,RANGETOKEN}; 00048 //===================================================================================== 00049 struct TLPTokenParser { 00050 int curLine; 00051 int curChar; 00052 std::istream &is; 00053 TLPTokenParser(std::istream &i):curLine(0),curChar(0),is(i) {} 00054 TLPToken nextToken(TLPValue &val,int &curPos) { 00055 val.str.erase(); 00056 bool endOfStream=false,strGet=false,slashMode=false,started=false,stop=false,strComment=false; 00057 char ch; 00058 00059 while ( (!stop) && (endOfStream=!(is.get(ch).fail()))) { 00060 curPos++; 00061 curChar++; 00062 00063 if (strGet) 00064 switch (ch) { 00065 case 13 : 00066 case '\n': 00067 curChar=0; 00068 curLine++; 00069 val.str+=ch; 00070 break; 00071 00072 case '\t': 00073 val.str+=" "; 00074 break; 00075 00076 case '\\': 00077 00078 if (!slashMode) { 00079 slashMode=true; 00080 } 00081 else { 00082 val.str+=ch; 00083 slashMode=false; 00084 } 00085 00086 break; 00087 00088 case '"': 00089 00090 if (!slashMode) { 00091 return STRINGTOKEN; 00092 } 00093 else { 00094 val.str+=ch; 00095 slashMode=false; 00096 } 00097 00098 break; 00099 00100 case 'n': 00101 00102 if (slashMode) { 00103 val.str+='\n'; 00104 slashMode=false; 00105 break; 00106 } 00107 00108 default: 00109 00110 if (!slashMode) 00111 val.str+=ch; 00112 00113 slashMode=false; 00114 break; 00115 } 00116 else if (strComment) 00117 switch (ch) { 00118 case 13 : 00119 case '\n': 00120 curChar=0; 00121 curLine++; 00122 stop=true; 00123 return COMMENTTOKEN; 00124 break; 00125 00126 default: 00127 curChar++; 00128 val.str+=ch; 00129 break; 00130 } 00131 else 00132 switch (ch) { 00133 case ' ': 00134 case '\t': 00135 00136 if (started) stop=true; 00137 00138 break; 00139 00140 case 13 : 00141 case '\n': 00142 curChar=0; 00143 curLine++; 00144 00145 if (started) stop=true; 00146 00147 break; 00148 00149 case '(': 00150 00151 if (!started) return OPENTOKEN; 00152 else { 00153 --curPos,--curChar; 00154 is.unget(); 00155 stop=true; 00156 } 00157 00158 break; 00159 00160 case ')': 00161 00162 if (!started) return CLOSETOKEN; 00163 else { 00164 --curPos,--curChar; 00165 is.unget(); 00166 stop=true; 00167 } 00168 00169 break; 00170 00171 case '"': 00172 strGet=true; 00173 00174 if (started) { 00175 --curPos,--curChar; 00176 is.unget(); 00177 stop=true; 00178 } 00179 else started=true; 00180 00181 break; 00182 00183 case ';': 00184 strComment=true; 00185 00186 if (started) { 00187 --curPos,--curChar; 00188 is.unget(); 00189 stop=true; 00190 } 00191 else started=true; 00192 00193 break; 00194 00195 default : 00196 val.str+=ch; 00197 started=true; 00198 break; 00199 } 00200 } 00201 00202 if (!started && !endOfStream) return ENDOFSTREAM; 00203 00204 char *endPtr=NULL; 00205 const char *cstr = val.str.c_str(); 00206 errno = 0; 00207 long resultl= strtol(cstr, &endPtr, 10); 00208 00209 if (errno == ERANGE) 00210 return ERRORINFILE; 00211 00212 unsigned long strlength = val.str.length(); 00213 00214 if (endPtr==(cstr+ strlength)) { 00215 val.integer=resultl; 00216 return INTTOKEN; 00217 } 00218 00219 // check for a range 00220 if (endPtr > cstr && (cstr + strlength) > (endPtr + 2)) { 00221 val.range.first = resultl; 00222 00223 if ((endPtr[0] == '.') && (endPtr[1] == '.')) { 00224 char* beginPtr = endPtr + 2; 00225 errno = 0; 00226 resultl = strtol(beginPtr, &endPtr, 10); 00227 00228 if (errno == ERANGE) 00229 return ERRORINFILE; 00230 00231 if (endPtr == (cstr + strlength)) { 00232 if (resultl < val.range.first) 00233 return ERRORINFILE; 00234 00235 val.range.second = resultl; 00236 return RANGETOKEN; 00237 } 00238 } 00239 } 00240 00241 endPtr=NULL; 00242 00243 double resultd=strtod(cstr, &endPtr); 00244 00245 if (errno == ERANGE) 00246 return ERRORINFILE; 00247 00248 if (endPtr==(cstr + strlength)) { 00249 val.real=resultd; 00250 return DOUBLETOKEN; 00251 } 00252 00253 if (strcasecmp(cstr, "true")==0) { 00254 val.boolean=true; 00255 return BOOLTOKEN; 00256 } 00257 00258 if (strcasecmp(cstr, "false")==0) { 00259 val.boolean=false; 00260 return BOOLTOKEN; 00261 } 00262 00263 if (started) return STRINGTOKEN; 00264 00265 return ERRORINFILE; 00266 } 00267 }; 00268 //===================================================================================== 00269 struct TLPBuilder { 00270 virtual ~TLPBuilder() {} 00271 virtual bool addBool(const bool)=0; 00272 virtual bool addInt(const int)=0; 00273 virtual bool addRange(int, int)=0; 00274 virtual bool addDouble(const double)=0; 00275 virtual bool addString(const std::string &)=0; 00276 virtual bool addStruct(const std::string&,TLPBuilder*&)=0; 00277 virtual bool close() =0; 00278 virtual bool canRead() { 00279 return false; 00280 } 00281 virtual bool read(std::istream&) { 00282 return false; 00283 } 00284 }; 00285 00286 struct TLPTrue:public TLPBuilder { 00287 bool addBool(const bool) { 00288 return true; 00289 } 00290 bool addInt(const int) { 00291 return true; 00292 } 00293 bool addRange(int, int) { 00294 return true; 00295 } 00296 bool addDouble(const double) { 00297 return true; 00298 } 00299 bool addString(const std::string &) { 00300 return true; 00301 } 00302 bool addStruct(const std::string& /*structName*/, TLPBuilder*&newBuilder) { 00303 newBuilder=new TLPTrue(); 00304 return true; 00305 } 00306 bool close() { 00307 return true; 00308 } 00309 }; 00310 00311 struct TLPFalse:public TLPBuilder { 00312 bool addBool(const bool) { 00313 return false; 00314 } 00315 bool addInt(const int) { 00316 return false; 00317 } 00318 bool addRange(int, int) { 00319 return false; 00320 } 00321 bool addDouble(const double) { 00322 return false; 00323 } 00324 bool addString(const std::string &) { 00325 return false; 00326 } 00327 bool addStruct(const std::string& /*structName*/, TLPBuilder*&newBuilder) { 00328 newBuilder=new TLPFalse(); 00329 return false; 00330 } 00331 bool close() { 00332 return true; 00333 } 00334 }; 00335 //===================================================================================== 00336 template <bool displayComment> 00337 struct TLPParser { 00338 std::list<TLPBuilder *> builderStack; 00339 std::istream &inputStream; 00340 TLPTokenParser *tokenParser; 00341 PluginProgress *pluginProgress; 00342 int fileSize,curPos; 00343 00344 TLPParser(std::istream &inputStream,TLPBuilder *builder,PluginProgress *pluginProgress,int size): inputStream(inputStream), 00345 pluginProgress(pluginProgress), 00346 fileSize(size), 00347 curPos(0) { 00348 builderStack.push_front(builder); 00349 } 00350 00351 ~TLPParser() { 00352 while (!builderStack.empty()) { 00353 TLPBuilder *builder = builderStack.front(); 00354 builderStack.pop_front(); 00355 00356 if (builderStack.empty() || builder != builderStack.front()) 00357 delete builder; 00358 } 00359 } 00360 00361 bool formatError() { 00362 std::stringstream ess; 00363 ess << "Error when parsing char " << tokenParser->curChar 00364 << " at line " << tokenParser->curLine + 1; 00365 00366 if (errno) 00367 ess << std::endl << strerror(errno); 00368 00369 pluginProgress->setError(ess.str()); 00370 return false; 00371 } 00372 00373 bool parse() { 00374 TLPTokenParser tParser(inputStream); 00375 tokenParser= &tParser; 00376 TLPToken currentToken; 00377 TLPValue currentValue; 00378 00379 while ((currentToken=tokenParser->nextToken(currentValue,curPos))!=ENDOFSTREAM) { 00380 if (curPos%2000==1) if (pluginProgress->progress(curPos,fileSize)!=TLP_CONTINUE) 00381 return pluginProgress->state()!=TLP_CANCEL; 00382 00383 switch (currentToken) { 00384 case OPENTOKEN: 00385 currentToken=tokenParser->nextToken(currentValue,curPos); 00386 00387 if (currentToken!=STRINGTOKEN) 00388 return formatError();//we can throw an exeption 00389 00390 TLPBuilder *newBuilder; 00391 00392 if (builderStack.front()->addStruct(currentValue.str, newBuilder)) { 00393 builderStack.push_front(newBuilder); 00394 00395 if (newBuilder->canRead()) 00396 if (!newBuilder->read(inputStream)) 00397 return formatError(); 00398 } 00399 else 00400 return formatError(); 00401 00402 break; 00403 00404 case BOOLTOKEN: 00405 00406 if (!builderStack.front()->addBool(currentValue.boolean)) 00407 return formatError(); 00408 00409 break; 00410 00411 case INTTOKEN: 00412 00413 if (!builderStack.front()->addInt(currentValue.integer)) 00414 return formatError(); 00415 00416 break; 00417 00418 case RANGETOKEN: 00419 00420 if (!builderStack.front()->addRange(currentValue.range.first, 00421 currentValue.range.second)) 00422 return formatError(); 00423 00424 break; 00425 00426 case DOUBLETOKEN: 00427 00428 if (!builderStack.front()->addDouble(currentValue.real)) 00429 return formatError(); 00430 00431 break; 00432 00433 case STRINGTOKEN: 00434 00435 if (!builderStack.front()->addString(currentValue.str)) 00436 return formatError(); 00437 00438 break; 00439 00440 case CLOSETOKEN: 00441 00442 if (builderStack.front()->close()) { 00443 TLPBuilder * builder = builderStack.front(); 00444 builderStack.pop_front(); 00445 00446 if (builder != builderStack.front()) 00447 delete builder; 00448 } 00449 else 00450 return formatError(); 00451 00452 break; 00453 00454 case ERRORINFILE: 00455 return formatError(); 00456 00457 case ENDOFSTREAM: 00458 return true; 00459 00460 case COMMENTTOKEN: 00461 00462 if (displayComment) tlp::debug() << "Comment line:" << tokenParser->curLine << "->" << currentValue.str; 00463 00464 break; 00465 00466 default: 00467 break; 00468 } 00469 } 00470 00471 if (pluginProgress) 00472 pluginProgress->progress(fileSize,fileSize); 00473 00474 return true; 00475 } 00476 }; 00477 00478 } 00479 //===================================================================================== 00480 00481 #endif // DOXYGEN_NOTFOR_DEVEL 00482 ///@endcond