Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics
[Home] [Tutorials] [All Classes] [Grouped Classes]

X:/dropbox/visualizationlibrary/src/vlCore/VLXParserVLT.hpp

Go to the documentation of this file.
00001 /**************************************************************************************/
00002 /*                                                                                    */
00003 /*  Visualization Library                                                             */
00004 /*  http://www.visualizationlibrary.org                                               */
00005 /*                                                                                    */
00006 /*  Copyright (c) 2005-2010, Michele Bosi                                             */
00007 /*  All rights reserved.                                                              */
00008 /*                                                                                    */
00009 /*  Redistribution and use in source and binary forms, with or without modification,  */
00010 /*  are permitted provided that the following conditions are met:                     */
00011 /*                                                                                    */
00012 /*  - Redistributions of source code must retain the above copyright notice, this     */
00013 /*  list of conditions and the following disclaimer.                                  */
00014 /*                                                                                    */
00015 /*  - Redistributions in binary form must reproduce the above copyright notice, this  */
00016 /*  list of conditions and the following disclaimer in the documentation and/or       */
00017 /*  other materials provided with the distribution.                                   */
00018 /*                                                                                    */
00019 /*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
00020 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
00021 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
00022 /*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
00023 /*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
00024 /*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
00025 /*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
00026 /*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
00027 /*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
00028 /*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
00029 /*                                                                                    */
00030 /**************************************************************************************/
00031 
00032 #ifndef VLXParserVLT_INCLUDE_ONCE
00033 #define VLXParserVLT_INCLUDE_ONCE
00034 
00035 #include <vlCore/VLXParser.hpp>
00036 #include <vlCore/VLTTokenizer.hpp>
00037 #include <cstdlib>
00038 
00039 #ifdef _MSC_VER
00040   #define atoll _atoi64
00041 #endif
00042 
00043 namespace vl
00044 {
00046   class VLXParserVLT: public VLXParser
00047   {
00048     VL_INSTRUMENT_CLASS(vl::VLXParserVLT, VLXParser)
00049 
00050   public:
00051     VLXParserVLT()
00052     {
00053       mTokenizer = new VLTTokenizer;
00054       mVersion = 0;
00055     }
00056 
00057     bool getToken(VLTToken& token) { return mTokenizer->getToken(token); }
00058 
00059     bool parseHeader()
00060     {
00061       mVersion = 0;
00062       mEncoding.clear();
00063 
00064       // VLX
00065       if (!getToken(mToken) || mToken.mType != VLTToken::Identifier || mToken.mString != "VLX")
00066       {
00067         Log::error("'VLX' header not found!\n");
00068         return false;
00069       }
00070 
00071       // version
00072       if (!getToken(mToken) || mToken.mType != VLTToken::Identifier || mToken.mString != "version")
00073         return false;
00074 
00075       if (!getToken(mToken) || mToken.mType != VLTToken::Equals)
00076         return false;
00077 
00078       if (!getToken(mToken) || mToken.mType != VLTToken::Integer || mToken.mString != "100")
00079         return false;
00080       else
00081         mVersion = (unsigned short)atoi( mToken.mString.c_str() );
00082 
00083       // encoding
00084       if (!getToken(mToken) || mToken.mType != VLTToken::Identifier || mToken.mString != "encoding")
00085         return false;
00086 
00087       if (!getToken(mToken) || mToken.mType != VLTToken::Equals)
00088         return false;
00089 
00090       if (!getToken(mToken) || mToken.mType != VLTToken::Identifier || mToken.mString != "ascii")
00091         return false;
00092       else
00093         mEncoding = mToken.mString;
00094 
00095       return true;
00096     }
00097 
00098     bool parse()
00099     {
00100       class CloseFileClass
00101       {
00102       public:
00103         CloseFileClass(VirtualFile* f): mFile(f) {}
00104         ~CloseFileClass()
00105         {
00106           if (mFile)
00107             mFile->close();
00108         }
00109       private:
00110         ref<VirtualFile> mFile;
00111       } CloseFile(tokenizer()->inputFile());
00112 
00113       // clear metadata
00114       mMetadata.clear();
00115 
00116       // read version and encoding
00117       if (!parseHeader())
00118       {
00119         Log::error( Say("Line %n : error parsing VLT header at '%s'.\n") << tokenizer()->lineNumber() << mToken.mString );
00120         return false;
00121       }
00122 
00123       if (mVersion != 100)
00124       {
00125         Log::error("VLX version not supported.\n");
00126         return false;
00127       }
00128 
00129       if (mEncoding != "ascii")
00130       {
00131         Log::error("Encoding not supported.\n");
00132         return false;
00133       }
00134 
00135       while(getToken(mToken) && mToken.mType != VLTToken::TOKEN_EOF)
00136       {
00137         if(mToken.mType == VLTToken::TagHeader)
00138         {
00139           mLastTag = mToken.mString;
00140 
00141           if(getToken(mToken) && mToken.mType == VLTToken::LeftCurlyBracket)
00142           {
00143             ref<VLXStructure> st = new VLXStructure;
00144             st->setLineNumber( tokenizer()->lineNumber() );
00145 
00146             if (!parseStructure(st.get()))
00147             {
00148               if (mToken.mString.length())
00149                 Log::error( Say("Line %n : parse error at '%s'.\n") << mTokenizer->lineNumber() << mToken.mString.c_str() );
00150               else
00151                 Log::error( Say("Line %n : parse error.\n") << mTokenizer->lineNumber() );
00152               return false;
00153             }
00154 
00155             mStructures.push_back(st);
00156           }
00157           else
00158           {
00159             Log::error( Say("Line %n : parse error at '%s'.\n") << mTokenizer->lineNumber() << mToken.mString.c_str() );
00160             return false;
00161           }
00162         }
00163         else
00164         {
00165           Log::error( Say("Line %n : parse error at '%s'.\n") << mTokenizer->lineNumber() << mToken.mString.c_str() );
00166           return false;
00167         }
00168       }
00169 
00170       parseMetadata();
00171 
00172       VL_CHECK(mToken.mType == VLTToken::TOKEN_EOF)
00173       return mToken.mType == VLTToken::TOKEN_EOF;
00174     }
00175 
00176     bool parseStructure(VLXStructure* object)
00177     {
00178       // consume last tag if there was one
00179       if (!mLastTag.empty())
00180       {
00181         object->setTag(mLastTag.c_str());
00182         mLastTag.clear();
00183       }
00184 
00185       while(getToken(mToken))
00186       {
00187         if (mToken.mType == VLTToken::RightCurlyBracket)
00188         {
00189           return true;
00190         }
00191         else
00192         if (mToken.mType == VLTToken::Identifier)
00193         {
00194           // ID field requires a proper #identifier
00195           if (mToken.mString.length() == 2)
00196           {
00197             if (mToken.mString == "ID")
00198             {
00199               // Check if ID has already been set
00200               if (!object->uid().empty() && object->uid() != "#NULL")
00201               {
00202                 Log::error("ID already set.\n");
00203                 return false;
00204               }
00205 
00206               // Equals
00207               if (!getToken(mToken) || mToken.mType != VLTToken::Equals)
00208                 return false;
00209 
00210               // #identifier
00211               if (getToken(mToken) && mToken.mType == VLTToken::ID)
00212               {
00213                 object->setID(mToken.mString.c_str());
00214                 continue;
00215               }
00216               else
00217                 return false;
00218             }
00219             else
00220             // ID is a reserved keyword: all the other case combinations are illegal
00221             if (mToken.mString == "Id" || mToken.mString == "iD" || mToken.mString == "id")
00222               return false;
00223           }
00224 
00225           // non-ID key-values
00226           object->value().push_back( VLXStructure::Value() );
00227           VLXStructure::Value& name_value = object->value().back();
00228 
00229           // Key
00230           name_value.setKey( mToken.mString.c_str() );
00231 
00232           // Equals
00233           if (!getToken(mToken) || mToken.mType != VLTToken::Equals)
00234             return false;
00235 
00236           // Member value
00237           if (getToken(mToken))
00238           {
00239             name_value.value().setLineNumber( tokenizer()->lineNumber() );
00240 
00241             // A new <Tag>
00242             if (mToken.mType == VLTToken::TagHeader)
00243             {
00244               if (mLastTag.empty())
00245               {
00246                 mLastTag = mToken.mString;
00247                 if (!getToken(mToken))
00248                   return false;
00249               }
00250               else
00251                 return false;
00252             }
00253 
00254             // A new { Structure }
00255             if (mToken.mType == VLTToken::LeftCurlyBracket)
00256             {
00257               ref<VLXStructure> object = new VLXStructure;
00258               object->setLineNumber( tokenizer()->lineNumber() );
00259               name_value.value().setStructure(object.get());
00260               if (!parseStructure( object.get() ) )
00261                 return false;
00262             }
00263             else
00264             // An [ list ]
00265             if (mToken.mType == VLTToken::LeftSquareBracket)
00266             {
00267               ref<VLXList> list = new VLXList;
00268               list->setLineNumber( tokenizer()->lineNumber() );
00269               name_value.value().setList(list.get());
00270               if ( !parseList( list.get() ) )
00271                 return false;
00272             }
00273             else
00274             // An ( array )
00275             if (mToken.mType == VLTToken::LeftRoundBracket)
00276             {
00277               ref<VLXArray> arr;
00278               if ( parseArray( arr ) )
00279                 name_value.value().setArray(arr.get());
00280               else
00281                 return false;
00282             }
00283             else
00284             // A {< rawtext block >}
00285             if (mToken.mType == VLTToken::LeftFancyBracket)
00286             {
00287               if(!getToken(mToken) || mToken.mType != VLTToken::RawtextBlock)
00288                 return false;
00289               name_value.value().setRawtextBlock( new VLXRawtextBlock(mLastTag.c_str()) );
00290               name_value.value().getRawtextBlock()->setValue( mToken.mString.c_str() );
00291               // consume the tag
00292               mLastTag.clear();
00293               if(!getToken(mToken) || mToken.mType != VLTToken::RightFancyBracket)
00294                 return false;
00295             }
00296             else
00297             // A "string"
00298             if (mToken.mType == VLTToken::String)
00299             {
00300               if (!mLastTag.empty())
00301                 return false;
00302               name_value.value().setString(mToken.mString.c_str());
00303             }
00304             else
00305             // An Identifier
00306             if (mToken.mType == VLTToken::Identifier)
00307             {
00308               if (!mLastTag.empty())
00309                 return false;
00310               name_value.value().setIdentifier(mToken.mString.c_str());
00311             }
00312             else
00313             // An #id
00314             if (mToken.mType == VLTToken::ID)
00315             {
00316               if (!mLastTag.empty())
00317                 return false;
00318               name_value.value().setID(mToken.mString.c_str());
00319             }
00320             else
00321             // A boolean true/false
00322             if (mToken.mType == VLTToken::Boolean)
00323             {
00324               if (!mLastTag.empty())
00325                 return false;
00326               name_value.value().setBool(mToken.mString == "true");
00327             }
00328             else
00329             // An integer
00330             if (mToken.mType == VLTToken::Integer)
00331             {
00332               if (!mLastTag.empty())
00333                 return false;
00334               name_value.value().setInteger( atoll(mToken.mString.c_str()) );
00335             }
00336             else
00337             // A float
00338             if (mToken.mType == VLTToken::real)
00339             {
00340               if (!mLastTag.empty())
00341                 return false;
00342               name_value.value().setReal( atof(mToken.mString.c_str()) );
00343             }
00344             else
00345               return false;
00346           }
00347         }
00348         else
00349           return false;
00350       }
00351       return false;
00352     }
00353 
00354     bool parseList(VLXList* list)
00355     {
00356       // consume last tag if there was one
00357       if (!mLastTag.empty())
00358       {
00359         list->setTag(mLastTag.c_str());
00360         mLastTag.clear();
00361       }
00362 
00363       while(getToken(mToken))
00364       {
00365         if (mToken.mType == VLTToken::RightSquareBracket)
00366           return true;
00367         else
00368         {
00369           VLXValue value;
00370           value.setLineNumber( tokenizer()->lineNumber() );
00371           switch( mToken.mType )
00372           {
00373             // <tag>
00374             case VLTToken::TagHeader:
00375               {
00376                 if (mLastTag.empty())
00377                   mLastTag = mToken.mString;
00378                 else
00379                   return false;
00380                 break;
00381               }
00382 
00383             // object
00384             case VLTToken::LeftCurlyBracket:
00385               {
00386                 ref<VLXStructure> object = new VLXStructure;
00387                 object->setLineNumber( tokenizer()->lineNumber() );
00388                 if ( parseStructure( object.get() ) )
00389                 {
00390                   value.setStructure(object.get());
00391                   list->value().push_back( value );
00392                 }
00393                 else
00394                   return false;
00395                 break;
00396               }
00397 
00398             // list
00399             case VLTToken::LeftSquareBracket:
00400               {
00401                 ref<VLXList> sub_list = new VLXList;
00402                 sub_list->setLineNumber( tokenizer()->lineNumber() );
00403                 if ( parseList( sub_list.get() ) )
00404                 {
00405                   value.setList( sub_list.get() );
00406                   list->value().push_back( value );
00407                 }
00408                 else
00409                   return false;
00410                 break;
00411               }
00412 
00413             // array
00414             case VLTToken::LeftRoundBracket:
00415               {
00416                 ref<VLXArray> arr;
00417                 if (parseArray(arr))
00418                 {
00419                   value.setArray(arr.get());
00420                   list->value().push_back(value);
00421                 }
00422                 else
00423                   return false;
00424                 break;
00425               }
00426 
00427             // string
00428             case VLTToken::String:
00429               if (!mLastTag.empty())
00430                 return false;
00431               value.setString( mToken.mString.c_str() ); list->value().push_back( value );
00432               break;
00433 
00434             // identifier
00435             case VLTToken::Identifier:
00436               if (!mLastTag.empty())
00437                 return false;
00438               value.setIdentifier( mToken.mString.c_str() ); list->value().push_back( value );
00439               break;
00440 
00441             // A {< rawtext block >}
00442             case VLTToken::LeftFancyBracket:
00443             {
00444               if(!getToken(mToken) || mToken.mType != VLTToken::RawtextBlock)
00445                 return false;
00446               
00447               value.setRawtextBlock( new VLXRawtextBlock(mLastTag.c_str()) );
00448               value.getRawtextBlock()->setValue( mToken.mString.c_str() );
00449               list->value().push_back( value );
00450               // consume the tag
00451               mLastTag.clear();
00452 
00453               if(!getToken(mToken) || mToken.mType != VLTToken::RightFancyBracket)
00454                 return false;
00455               break;
00456             }
00457 
00458             // ID
00459             case VLTToken::ID:
00460               if (!mLastTag.empty())
00461                 return false;
00462               value.setID( mToken.mString.c_str() ); list->value().push_back( value );
00463               break;
00464 
00465             // boolean
00466             case VLTToken::Boolean:
00467               if (!mLastTag.empty())
00468                 return false;
00469               value.setBool( mToken.mString == "true" ); list->value().push_back( value );
00470               break;
00471 
00472             // int
00473             case VLTToken::Integer:
00474               if (!mLastTag.empty())
00475                 return false;
00476               value.setInteger( atoll(mToken.mString.c_str()) ); list->value().push_back( value );
00477               break;
00478 
00479             // float
00480             case VLTToken::real:
00481               if (!mLastTag.empty())
00482                 return false;
00483               value.setReal( atof(mToken.mString.c_str()) ); list->value().push_back( value );
00484               break;
00485 
00486           default:
00487             return false;
00488           }
00489         }
00490       }
00491       return false;
00492     }
00493 
00494     bool parseArray(ref<VLXArray>& arr)
00495     {
00496       // consume last tag if there was one
00497       struct struct_consume_tag
00498       {
00499         struct_consume_tag(ref<VLXArray>* p1, std::string* p2): p_arr(p1), p_tag(p2) {}
00500 
00501        ~struct_consume_tag()
00502         {
00503           if ((*p_arr).get() && !p_tag->empty())
00504           {
00505             (*p_arr)->setTag(p_tag->c_str());
00506             p_tag->clear();
00507           }
00508         }
00509 
00510         ref<VLXArray>* p_arr;
00511         std::string* p_tag;
00512       } consume_tag(&arr, &mLastTag);
00513 
00514       if(getToken(mToken))
00515       {
00516         // (1) from the fist token we decide what kind of array it is going to be
00517         // (2) empty arrays default to empty VLXArrayInteger
00518 
00519         if (mToken.mType == VLTToken::RightRoundBracket)
00520         {
00521           arr = new VLXArrayInteger;
00522           return true;
00523         }
00524         /*
00525         else
00526         if (mToken.mType == VLTToken::String)
00527         {
00528           ref<VLXArrayString> arr_string;
00529           arr = arr_string = new VLXArrayString;
00530           do 
00531             arr_string->mValue.push_back(mToken.mString);
00532           while(getToken(mToken) && mToken.mType == VLTToken::String);
00533           return mToken.mType == VLTToken::RightRoundBracket;
00534         }
00535         else
00536         if (mToken.mType == VLTToken::Identifier)
00537         {
00538           ref<VLXArrayIdentifier> arr_identifier;
00539           arr = arr_identifier = new VLXArrayIdentifier;
00540           do 
00541             arr_identifier->mValue.push_back(mToken.mString);
00542           while(getToken(mToken) && mToken.mType == VLTToken::Identifier);
00543           return mToken.mType == VLTToken::RightRoundBracket;
00544         }
00545         else
00546         if (mToken.mType == VLTToken::ID)
00547         {
00548           ref<VLXArrayID> arr_uid;
00549           arr = arr_uid = new VLXArrayID;
00550           do
00551             arr_uid->mValue.push_back(mToken.mString.c_str());
00552           while(getToken(mToken) && mToken.mType == VLTToken::ID);
00553           return mToken.mType == VLTToken::RightRoundBracket;
00554         }
00555         */
00556         else
00557         if (mToken.mType == VLTToken::Integer)
00558         {
00559           ref<VLXArrayInteger> arr_integer;
00560           arr = arr_integer = new VLXArrayInteger;
00561           do
00562           {
00563             switch(mToken.mType)
00564             {
00565             case VLTToken::Integer: arr_integer->value().push_back( atoll( mToken.mString.c_str() ) ); break;
00566             case VLTToken::RightRoundBracket: return true;
00567             default:
00568               return false;
00569             }
00570           }
00571           while(getToken(mToken));
00572           return false;
00573         }
00574         else
00575         if (mToken.mType == VLTToken::real)
00576         {
00577           ref<VLXArrayReal> arr_floating;
00578           arr = arr_floating = new VLXArrayReal;
00579           arr_floating->value().reserve(1024);
00580           // mic fixme: 
00581           // READING ARRAYS OF NUMBERS IS THE MAIN HOT SPOT FOR THE VLT PARSER
00582           // - we could speed things up by quickly tokenizing and aotf-ing all the numbers here
00583           // - we could also use a quicker atof() that works for numbers of the type +1234.1234 using the tokenizer to determine the sub-type
00584           // - ideally we should mix the following: 
00585           //   - read big chunks of bytes instead of one by one like now
00586           //   - merge the quick atof with the tokenizer in one single operation, fall back to standard atof() when complex numbers are detected
00587           //   - proceed until we find ")"
00588           //   - we could disallow comments in Arrays to speedup the parsing
00589           do
00590           {
00591             switch(mToken.mType)
00592             {
00593             case VLTToken::Integer:
00594             case VLTToken::real: arr_floating->value().push_back( atof( mToken.mString.c_str() ) ); break;
00595             case VLTToken::RightRoundBracket: return true;
00596             default:
00597               return false;
00598             }
00599           }
00600           while(getToken(mToken));
00601           return false;
00602         }
00603         else
00604           return false;
00605       }
00606 
00607       return false;
00608     }
00609 
00610     // for debug only
00611     void listTokens()
00612     {
00613       while(getToken(mToken) && mToken.mType != VLTToken::TOKEN_EOF)
00614       {
00615         switch(mToken.mType)
00616         {
00617           case VLTToken::LeftRoundBracket:   printf("LeftSquareBracket (\n"); break;
00618           case VLTToken::RightRoundBracket:  printf("RightSquareBracket )\n"); break;
00619           case VLTToken::LeftSquareBracket:  printf("LeftSquareBracket [\n"); break;
00620           case VLTToken::RightSquareBracket: printf("RightSquareBracket ]\n"); break;
00621           case VLTToken::LeftCurlyBracket:   printf("LeftCurlyBracket {\n"); break;
00622           case VLTToken::RightCurlyBracket:  printf("RightCurlyBracket } \n"); break;
00623           case VLTToken::LeftFancyBracket:   printf("LeftFancyBracket >}\n"); break;
00624           case VLTToken::RightFancyBracket:  printf("RightFancyBracket {< \n"); break;
00625           case VLTToken::Equals:             printf("Equals =\n"); break;
00626           case VLTToken::String:             printf("String = %s\n", mToken.mString.c_str()); break;
00627           case VLTToken::ID:                printf("ID = %s\n", mToken.mString.c_str()); break;
00628           case VLTToken::Identifier:         printf("Identifier = %s\n", mToken.mString.c_str()); break;
00629           case VLTToken::RawtextBlock:       printf("RawtextBlock = %s\n", mToken.mString.c_str()); break;
00630           case VLTToken::real:               printf("real = %s\n", mToken.mString.c_str()); break;
00631           case VLTToken::Integer:            printf("Integer = %s\n", mToken.mString.c_str()); break;
00632           case VLTToken::TagHeader:          printf("TagHeader = %s\n", mToken.mString.c_str()); break;
00633           default:
00634             break;
00635         }
00636       }
00637       if (mToken.mType != VLTToken::TOKEN_EOF)
00638       {
00639         printf("Line %d: syntax error : '%s'.\n", mTokenizer->lineNumber(), mToken.mString.c_str());
00640       }
00641     }
00642 
00643     VLTTokenizer* tokenizer() { return mTokenizer.get(); }
00644 
00645     const VLTTokenizer* tokenizer() const { return mTokenizer.get(); }
00646 
00647   private:
00648     std::string mLastTag;
00649     ref<VLTTokenizer> mTokenizer;
00650     VLTToken mToken;
00651   };
00652 }
00653 
00654 #ifdef _MSC_VER
00655   #undef atoll
00656 #endif
00657 
00658 #endif

Visualization Library 2011.09.1160 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 2 2013 13:40:33.
Permission is granted to use this page to write and publish articles regarding Visualization Library.