1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Contrib. demo 
   4 // Author:      Aleksandras Gluchovas 
   8 // Copyright:   (c) Aleskandars Gluchovas 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13 #pragma implementation "acell.h" 
  17 // For compilers that support precompilation, includes "wx/wx.h". 
  18 #include "wx/wxprec.h" 
  30 #if defined( wxUSE_TEMPLATE_STL ) 
  41 /***** Implementation for class SJParser *****/ 
  43 // statics used by inline'ed C helper-functions 
  44 static char* _gSrcStart 
= 0; 
  45 static char* _gSrcEnd   
= 0; 
  46 static char* _gLastSuppresedComment 
= 0; 
  47 static int   _gLineNo      
= 0; 
  49 // FOR NOW:: comments queue is static 
  50 #define MAX_CQ_ENTRIES 128 
  51 static char* _gCommentsQueue
[MAX_CQ_ENTRIES
]; 
  52 static int    _gCQSize 
= 0; 
  54 /***** keyword map related structures *****/ 
  58     inline bool operator()( char* x
, char* y
) const  
  59         {       return ( strcmp( x
,y 
) < 0 ); 
  63 //WXSTL_MAP(CharPtrT,CharPtrT, LESS_THEN_FUNCTOR(CharPtrT)); 
  65 #if defined( wxUSE_TEMPLATE_STL ) 
  67         typedef map
< char*, char*, less_c_str 
> KeywordMapT
; 
  71         typedef char* CharPtrT
; 
  72         typedef WXSTL_MAP( CharPtrT
, CharPtrT 
,less_c_str
) KeywordMapT
; 
  76 static KeywordMapT __gMultiLangMap
; 
  77 static int         __gMapReady 
= 0; 
  79 static char* __gKeyWords
[] = 
 115 static void check_keyword_map() 
 121                 // "make sure" the address of the first member of non-polimorphic class 
 122                 // coinsides with the address of the instance 
 124                 char** keyword 
= __gKeyWords
; 
 126                 while ( (*keyword
) != 0 ) 
 128                         __gMultiLangMap
.insert(  
 129                                 KeywordMapT::value_type( *keyword
, *keyword 
)  
 137 /***** helper functions *****/ 
 139 static inline void skip_to_eol( char*& cur 
) 
 141         while( *(cur
) != 10 && *cur 
!= 13 && cur 
< _gSrcEnd
) ++cur
; 
 144 static inline void skip_eol( char*& cur 
) 
 155 static inline bool skip_to_next_comment_in_the_line( char*& cur 
) 
 159                 while( cur 
< _gSrcEnd  
&& 
 165                 if ( cur 
== _gSrcEnd 
) return FALSE
; 
 169                         if ( (*(cur
+1) == '*') || 
 170                                  (*(cur
+1) == '/') ) return TRUE
; 
 183 inline static void store_line_no( int& toVar 
) 
 188 inline static void restore_line_no( int storedLineNo 
) 
 190         _gLineNo 
= storedLineNo
; 
 193 inline static int get_line_no() 
 198 static void skip_to_prev_line( char*& cur 
) 
 200         while( cur 
>= _gSrcStart  
&& 
 205         // NOTE:: '\n' is 13,10 for DOS 
 206         //        '\n' is 10 for UNIX 
 208         // NOTE1: '\n' symbol is not used here, 
 209         //        to provide possibility of loading 
 219         if ( *cur 
== 13 ) --cur
; 
 221         while( cur 
>= _gSrcStart  
&& 
 226         ++cur
; // move to the first character in the line 
 229 static inline void skip_comments( char*& cur 
) 
 231         ++cur
; // skip '/' token 
 233         if ( *cur 
!= '/' && *cur 
!= '*' ) return; 
 235         // first, store position of the comment into the queue 
 236         // (which further will be attached to the next context 
 239         if ( cur
-1 != _gLastSuppresedComment 
) 
 241                 if ( _gCQSize 
== MAX_CQ_ENTRIES 
) 
 243                         size_t i 
= MAX_CQ_ENTRIES
-1; 
 247                                 _gCommentsQueue
[i
-1] = _gCommentsQueue
[i
]; 
 254                 _gCommentsQueue
[_gCQSize
++] = cur
-1; 
 257         // if signle-line comment, skip it now 
 267         // check for multiline comment (handle nested multiline comments!) 
 275                 // TBD:: check eof cond. 
 277                 // detect and remove vertical columns of '*''s 
 279                 while ( *cur 
!= '/' && cur 
< _gSrcEnd 
) 
 285                                                 if ( *(cur
+1) != '/' ) 
 295                                 case 13 : line_len 
= 0; break; 
 296                                 case 10 : { line_len 
= 0; ++_gLineNo
; } break; 
 298                                 default : ++line_len
; 
 304                 if ( cur 
>= _gSrcEnd  
) return; 
 308                 if ( *(cur
-2) == '*' ) 
 326 static inline void clear_commets_queue() 
 331 static inline void skip_quoted_string( char*& cur 
) 
 333         ++cur
; // skip first quote '"' 
 335         // check if quote wasn't prefixed 
 336         if ( *(cur
-2) == '\\' ) 
 341                 while ( *cur 
!= '"' && cur 
< _gSrcEnd 
) 
 343                         if ( *cur 
== 10 ) ++_gLineNo
; 
 347                 if ( cur 
>= _gSrcEnd 
) return; 
 349                 ++cur
; // skip the last quote 
 351                 // check if it wasn't prefixed 
 353                 if ( *(cur
-2) != '\\' ) 
 359 // skips subsequent white space and comments 
 360 // (return false if the end of source code reached) 
 362 static inline bool get_next_token( char*& cur 
) 
 364         for( ; cur 
< _gSrcEnd
; ++cur 
) 
 372                         case 10  : { ++_gLineNo
;continue; } 
 374                         case '/' : skip_comments( cur 
); 
 384         if ( cur 
>= _gSrcEnd 
) 
 391 static inline void skip_preprocessor_dir( char*& cur 
) 
 397                 if ( *(cur
-1) != '\\' )  
 400                 if ( cur 
< _gSrcEnd 
) 
 408 static void skip_token( char*& cur 
) 
 412                 skip_quoted_string( cur 
); 
 429         ++cur
; // leading character is always skipped 
 431         for( ; cur 
< _gSrcEnd 
; ++cur 
) 
 444                         // FIXME:: QUICK-HACK:: to treat scope resolution 
 445                         //         tokens are a part of the string - e.g. SomeSpace::SubName would 
 448                         case ':' : if ( *(cur
+1) == ':' )  
 467 static inline size_t get_token_len( char* tok 
) 
 473         return size_t( tok 
- start 
); 
 476 // returns true, if given tokens are equel 
 478 static inline bool cmp_tokens( char* tok1
, char* tok2 
) 
 480         // NOTE:: the case one token includes  
 481         //        other in it's entirely is not handled 
 483         size_t len 
= get_token_len( tok1 
); 
 485         // assuming that tokens are non-zero length 
 489                 if ( *(tok1
++) != *(tok2
++) ) 
 499 static inline bool cmp_tokens_fast( char* tok1
, char* tok2
, size_t len 
) 
 503                 if ( *(tok1
++) != *(tok2
++) ) 
 511 static inline void skip_tempalate_statement( char*& cur 
) 
 515         // go one level deeper 
 516         while( *cur 
!= '<' && cur 
< _gSrcEnd 
) 
 518                 if (*cur 
== 10 ) ++_gLineNo
; 
 522         // FIXME:: template should be checked statement for  
 523         //         comments inside of it 
 532                 ++cur
; // skip '<' or '>' token 
 537                 while( *cur 
!= '<' && *cur 
!= '>' && cur 
< _gSrcEnd 
) 
 539                         if (*cur 
== 10 ) ++_gLineNo
; 
 546 static inline void skip_statement( char*& cur 
) 
 548         for( ; cur 
< _gSrcEnd
; ++cur 
) 
 552                         case  ';' : ++cur
; // skip statement-terminator token 
 555                         case  '"' : skip_quoted_string(cur
); 
 559                         case  10  : ++_gLineNo
; 
 562                         case  '/' : skip_comments( cur 
); 
 569 // "reversed" versions of skip_token() and get_next_token() 
 571 static inline void skip_token_back( char*& cur 
) 
 573         // FIXME:: now, when moving backwards, neither strings nor 
 574         //         comment blocks are checked 
 576         --cur
; // skip to the trailing character 
 585         for( ; cur 
< _gSrcEnd 
; --cur 
) 
 602         ++cur
; // get to the leading character of the token 
 605 static inline void skip_next_token_back( char*& cur 
) 
 607         --cur
; // skip leading character of the current token 
 618         for( ; cur 
< _gSrcEnd
; --cur 
) 
 635         ++cur
; // position after the trailing charcter of the prev token 
 638 static string 
get_token_str( char* cur 
) 
 640         return string( cur
, get_token_len( cur 
) ); 
 643 // skips token or whole expression which may have 
 644 // nested  expressions between '(' ')' brackets. 
 646 // Upon return, the cursor points to the terminating bracket ')', 
 648 // Return value is the size of the block 
 650 static size_t skip_block( char*& cur 
) 
 652         size_t level 
= 0; // nesting level 
 656         // NOTE:: assumed that block not necessarely starts  
 657         //        with bracket rightaway  
 668                 char* savedPos 
= cur
; 
 670                 store_line_no( tmpLnNo 
); 
 672                 get_next_token( cur 
); 
 674                 if ( cur 
>= _gSrcEnd 
) return 0; 
 686                                 restore_line_no( tmpLnNo 
); 
 688                                 return size_t(cur
-start
); 
 697                                 // QUICK-HACK::to easily handle function prototypes , 
 698                                 // it works, besause theoretically there should 
 699                                 // be no cast-expressions in non-implementation  
 700                                 // scope (e.g. "time( (long*)(ptr+1) )" should not 
 701                                 // appear in the declarations, thus it is most likelly  
 702                                 // for the ")(" fragment to be within a function  
 703                                 // prototype in the declarations scope 
 711                                 else return size_t(cur
-start
); 
 719                                 restore_line_no( tmpLnNo 
); 
 721                                 return size_t(cur
-start
); 
 728 // returns 0, if end of source reached 
 729 static inline bool skip_imp_block( char*& cur 
) 
 731         while( *cur 
!= '{' && cur 
< _gSrcEnd 
)  
 734                 if ( !get_next_token( cur 
) ) return FALSE
; 
 737         while( *cur 
!= '}' && cur 
< _gSrcEnd 
)  
 740                 if ( !get_next_token( cur 
) ) return FALSE
; 
 748 static bool is_class_token( char*& cur 
) 
 750         // FIXME:: the below mess should be cleaned in it's entirely 
 753                 if ( *(cur
+1) == 'n' ) 
 755                         return cmp_tokens_fast( cur
, "interface", 9 ); 
 758                 if ( *(cur
+1) == 'l' ) 
 760                         return cmp_tokens_fast( cur
, "class", 5 ); 
 763                 if ( *(cur
+1) == 't' ) 
 765                         return cmp_tokens_fast( cur
, "struct", 6 ); 
 768                 if ( *(cur
+1) == 'n' ) 
 770                         return cmp_tokens_fast( cur
, "union", 5 ); 
 775 inline static bool is_forward_decl( char* cur 
) 
 781                         case ':' : return FALSE
; 
 782                         case '{' : return FALSE
; 
 783                         case '(' : return FALSE
; 
 785                         case ';' : return TRUE
;  
 792         } while (cur 
< _gSrcEnd
); // prevent running out of bounds 
 797 inline static bool is_function( char* cur
, bool& isAMacro 
) 
 802         store_line_no( tmpLnNo 
); 
 804         // NOTE:: comments and quoted strings are not checked here 
 806         // first,check for "single-line hanginging macros" like: 
 814         get_next_token( cur 
); 
 819                 restore_line_no( tmpLnNo 
); 
 824         // it's not a macro, go to the begining of arg. list 
 828                 // if bracket found, it's a function or a begining 
 832                         restore_line_no( tmpLnNo 
); 
 836                 // end of statement found without any brackets in it 
 837                 // - it cannot be a function  
 841                         restore_line_no( tmpLnNo 
); 
 847         } while( cur 
< _gSrcEnd
); 
 850         restore_line_no( tmpLnNo 
); 
 855 // upon return the cursor is positioned after the 
 856 // terminating curly brace  
 858 static inline void skip_scope_block( char*& cur 
) 
 862         for( ; cur 
< _gSrcEnd 
; ++cur 
) 
 866                         case '/' : skip_comments( cur 
); 
 869                         case '"' : skip_quoted_string( cur 
); 
 879                                                    ++cur
; // skip final closing curly brace 
 883                         case 10 : ++_gLineNo
; continue; 
 889 // moves tokens like '*' '**', '***', '&' from the name 
 892 static void arrange_indirection_tokens_between( string
& type
, 
 895         // TBD:: FIXME:: return value of operators ! 
 897         while ( identifier
[0] == '*' || 
 901                 type 
+= identifier
[0]; 
 902                 identifier
.erase(0,1); 
 904                 if ( !identifier
.length() ) return; 
 909 // the only function where multi-lang keyword map is accessed 
 911 static bool is_keyword( char* cur 
) 
 913         size_t len 
= get_token_len( cur 
); 
 915         // put a terminating zero after the given token  
 916         char tmp 
= *(cur 
+ len
); 
 919         KeywordMapT::iterator i
;  
 921         i 
= __gMultiLangMap
.find( cur 
); 
 923         // restore original character suppresed by terminating zero 
 926     return i 
== __gMultiLangMap
.end() ? false : true; 
 929 static inline void get_string_between( char* start
, char* end
,  
 939 static char* set_comment_text( string
& text
, char* start 
) 
 943         // to avoid poluting the queue with this comment 
 944         _gLastSuppresedComment 
= start
; 
 946         skip_comments( end 
); 
 948         if ( *(end
-1) == '/' )  
 953         // skip multiple leading '/''s or '*''s  
 954         while( *start 
== '/' && start 
< end 
) ++start
; 
 955         while( *start 
== '*' && start 
< end 
) ++start
; 
 957         get_string_between( start
, end
, &text 
); 
 962 /***** Implementation for class CJSourceParser *****/ 
 964 CJSourceParser::CJSourceParser( bool collectCommnets
, bool collectMacros 
) 
 968           mCommentsOn( collectCommnets 
), 
 969           mMacrosOn  ( collectMacros 
) 
 974 spFile
* CJSourceParser::Parse( char* start
, char* end 
) 
 976         // set up state variables 
 977         mCurVis       
= SP_VIS_PRIVATE
; 
 979         spFile
* pTopCtx 
= new spFile(); 
 991         _gSrcEnd   
= mpEnd
; // let all the C-functions "smell" the end of file 
 996         clear_commets_queue(); 
1002                 if ( !get_next_token( cur 
) )  
1003                         // end of source reached 
1006                 if ( memcmp( cur
, "ScriptSection( const string&",  
1007                                  strlen( "ScriptSection( const string&" )  
1019                                         AddMacroNode( cur 
);             
1050         // 'const' is a part of the return type, not a keyword here 
1051                 if ( strncmp(cur
, "const", 5) != 0 && is_keyword( cur 
) ) 
1053                         // parses, token, if token identifies 
1054                         // the container context (e.g. class/namespace) 
1055                         // the corresponding context object is created 
1056                         // and set as current context 
1058                         ParseKeyword( cur 
); 
1062                 if ( *cur 
>= '0' && *cur 
<= '9' )  
1070                         if ( mCurCtxType 
!= SP_CTX_CLASS 
) 
1072                                 // FOR NOW:: disable the below assertion  
1074                                 // DBG:: unexpected closing-bracket found 
1077                                 skip_token( cur 
); // just skip it 
1081                         if ( mpCurCtx
->GetType() == SP_CTX_CLASS 
) 
1083                                 int curOfs 
= ( (cur
+1) - _gSrcStart 
); 
1085                                 mpCurCtx
->mContextLength 
= ( curOfs 
- mpCurCtx
->mSrcOffset 
); 
1090                         // terminate operation/class/namespace context  
1091                         // TBD:: check if it's really this type of context 
1093                         wxASSERT( mpCurCtx 
); 
1094                         mpCurCtx 
= mpCurCtx
->GetOutterContext(); 
1095                         wxASSERT( mpCurCtx 
); 
1097                         if ( mNestingLevel 
== 0 ) 
1100                                 mCurCtxType 
= SP_CTX_FILE
; 
1102                                 // not-nested class delclaration finished, 
1103                                 // rest template flag in any case 
1113                 if ( is_function( cur
, isAMacro 
) ) 
1121                         char* savedPos 
= cur
; 
1124                         store_line_no( tmpLnNo 
); 
1128                         if ( !ParseNameAndRetVal( cur
, isAMacro 
) ) 
1133                                         SkipFunction( cur 
); 
1138                         if ( !ParseArguments( cur 
) ) 
1140                                 // failure while parsing arguments, 
1141                                 // remove enclosing operation context 
1143                                 spContext
* pFailed 
= mpCurCtx
; 
1144                                 mpCurCtx 
= mpCurCtx
->GetOutterContext(); 
1145                                 mpCurCtx
->RemoveChild( pFailed 
); 
1152                                 // otherwise, successfully close operation context: 
1154                                 clear_commets_queue(); 
1156                                 SkipFunctionBody( cur 
); 
1158                                 mpCurCtx 
= mpCurCtx
->GetOutterContext(); 
1161                                 wxASSERT( mpCurCtx 
); 
1165                 else // otherwise it's declaration of a variable; 
1167                         // now, the cursor point to the end of statement (';' token) 
1169                         if ( mCurCtxType 
!= SP_CTX_CLASS 
) 
1171                                 // non-class members are ignored 
1173                                 skip_token( cur 
); // skip the end of statement 
1177                         ParseMemberVar( cur 
); 
1183 void CJSourceParser::AttachComments( spContext
& ctx
, char* cur 
) 
1185         if ( !mCommentsOn 
) return; 
1187         MCommentListT
& lst 
= ctx
.GetCommentList(); 
1189         char* prevComEnd 
= 0; 
1192         store_line_no( tmpLnNo 
); 
1194         // attach comments which were found before the given context 
1196         for( int i 
= 0; i 
!= _gCQSize
; ++i 
) 
1198                 spComment
* pComment 
= new spComment(); 
1199                 lst
.push_back( pComment 
); 
1201                 // find the end of comment 
1202                 char* start 
= _gCommentsQueue
[i
]; 
1204                 pComment
->mIsMultiline 
= ( *(start
+1) == '*' ); 
1206                 // first comment in the queue and multiline  
1207                 // comments are always treated as a begining  
1208                 // of the new paragraph in the comment text 
1212                         pComment
->mStartsPar 
= TRUE
; 
1214                 if ( pComment
->mIsMultiline 
) 
1216                         pComment
->mStartsPar 
= TRUE
; 
1219                         // find out wheather there is a new-line 
1220                         // between to adjecent comments 
1223                         char* prevLine 
= start
; 
1224                         skip_to_prev_line(prevLine
); 
1226                         if ( prevLine 
>= prevComEnd 
) 
1228                                 pComment
->mStartsPar 
= TRUE
; 
1230                                 pComment
->mStartsPar 
= FALSE
; 
1233                 prevComEnd 
= set_comment_text( pComment
->mText
, start 
); 
1237         // attach comments which are at the end of the line 
1238         // of the given context (if any) 
1240         if ( skip_to_next_comment_in_the_line( cur 
) ) 
1242                 spComment
* pComment 
= new spComment(); 
1243                 lst
.push_back( pComment 
); 
1245                 set_comment_text( pComment
->mText
, cur 
); 
1247                 pComment
->mStartsPar 
= 1; 
1248                 pComment
->mIsMultiline 
= ( *(cur
+1) == '*' ); 
1250                 // mark this comment, so that it would not 
1251                 // get in the comments list of the next context 
1252                 _gLastSuppresedComment 
= cur
; 
1255         restore_line_no( tmpLnNo 
); 
1257         clear_commets_queue(); 
1260 void CJSourceParser::AddMacroNode( char*& cur 
) 
1264         int lineNo 
= get_line_no(); 
1266         skip_preprocessor_dir( cur 
); 
1269         store_line_no( tmpLnNo 
); 
1271         if ( !mMacrosOn 
) return; 
1273         spPreprocessorLine
* pPL 
= new spPreprocessorLine(); 
1274         pPL
->mSrcLineNo 
= lineNo
; 
1276         AttachComments( *pPL
, cur 
); 
1278         get_string_between( start
, cur
, &pPL
->mLine 
); 
1280         ++start
; // skip '#' 
1281         get_next_token( start 
); 
1283         pPL
->mDefType 
= SP_PREP_DEF_OTHER
; 
1285         // if we found a definition or redefinition, 
1286         // determine the type exactly and assign 
1287         // a name to the context 
1289         if ( *start 
== 'd' ) 
1291                 if ( cmp_tokens_fast( start
, "define", 6 ) ) 
1293                         char* tok 
= start
+6; 
1295                         get_next_token( tok 
); 
1297                         pPL
->mName 
= get_token_str( tok 
); 
1300                         get_next_token( tok
); 
1304                                 pPL
->mDefType 
= SP_PREP_DEF_DEFINE_SYMBOL
; 
1306                                 pPL
->mDefType 
= SP_PREP_DEF_REDEFINE_SYMBOL
; 
1310         if ( *start 
== 'i' ) 
1312                 if ( cmp_tokens_fast( start
, "include", 7 ) ) 
1314                         pPL
->mDefType 
= SP_PREP_DEF_INCLUDE_FILE
; 
1317         mpCurCtx
->AddMember( pPL 
); 
1319         restore_line_no( tmpLnNo 
); 
1321         clear_commets_queue(); 
1324 void CJSourceParser::ParseKeyword( char*& cur 
) 
1326         // analyze token, which identifies the begining of a new context 
1328         if ( CheckVisibilty( cur 
) ) 
1334         if ( is_class_token( cur 
) ) 
1336                 if ( is_forward_decl( cur 
) ) 
1338                         // forward declarations are ignored; 
1343                 if ( mNestingLevel 
== 0 ) 
1345                         // change context form global class context 
1346                         mCurCtxType 
= SP_CTX_CLASS
; 
1351                 // add information about new class (name, inheritance, etc) 
1352                 AddClassNode( cur 
); 
1354                 // the default visiblity for class members is 'private' 
1355                 mCurVis 
= SP_VIS_PRIVATE
; 
1360         size_t len 
= get_token_len( cur 
); 
1362         if ( cmp_tokens_fast( cur
, "typedef", len  
) ) 
1365                 get_next_token(cur
); 
1367                 if ( cmp_tokens_fast( cur
, "struct", len 
) || 
1368                          cmp_tokens_fast( cur
, "union",  len 
) || 
1369                          cmp_tokens_fast( cur
, "class",  len 
) 
1372                         if ( mNestingLevel 
== 0 ) 
1374                                 // change context form global class context 
1375                                 mCurCtxType 
= SP_CTX_CLASS
; 
1380                         // add information about new class (name, inheritance, etc) 
1381                         AddClassNode( cur 
); 
1383                         // the default visiblity for class members is 'private' 
1384                         mCurVis 
= SP_VIS_PRIVATE
; 
1388                         // FOR NOW:: typedef struct, etc are also ignored  
1389                         //skip_scope_block( cur ); 
1392                 if ( cmp_tokens_fast( cur
, "enum", len  
) ) 
1398                 AddTypeDefNode( cur 
); 
1403         if ( cmp_tokens_fast( cur
, "enum", len 
) ) 
1409         if ( cmp_tokens_fast( cur
, "extern", len 
) ) 
1411                 // extern's are ignored (both extern "C" and extern vars) 
1412                 while ( *cur 
!= '{' && 
1416                         get_next_token( cur 
); 
1421         if ( cmp_tokens_fast( cur
, "enum", len 
) ) 
1423                 // enumeration blocks are ignored 
1425                 skip_scope_block( cur 
); 
1427                 get_next_token( cur 
); 
1428                 skip_token( cur 
); // skip ';' token; 
1432         if ( cmp_tokens_fast( cur
, "package", len  
) ) 
1434                 // packages are ignored 
1435                 skip_statement( cur 
); 
1439         if ( cmp_tokens_fast( cur
, "import", len  
) ) 
1441                 // import statements are ignored 
1442                 skip_statement( cur 
); 
1446         if ( cmp_tokens_fast( cur
, "virtual", len  
) ) 
1448                 // probably the virtual method is in front of us; 
1454         if ( cmp_tokens_fast( cur
, "template", len  
) ) 
1457                 skip_tempalate_statement( cur 
); 
1461         if ( cmp_tokens_fast( cur
, "friend", len  
) ) 
1463                 skip_statement( cur 
); 
1467         // ingnore "unsigificant" tokens (i.e. which do not 
1468         // affect the current parsing context) 
1473 bool CJSourceParser::ParseNameAndRetVal( char*& cur
, bool& isAMacro 
) 
1477         // FOR NOW:: all functions in the global 
1478         //           scope are ignored 
1480         int lineNo 
= get_line_no(); 
1484     bool isVirtual 
= false; 
1485         while( *cur 
!= '(' ) 
1487         if ( get_token_str( cur 
) == "virtual" ) 
1491                 if ( !get_next_token( cur 
) ) return FALSE
; 
1494         char* bracketPos 
= cur
; 
1495         char* savedPos   
= cur 
+ 1; 
1498         store_line_no( tmpLnNo 
); 
1500         // skip gap between function name and start of paramters list 
1501         while ( *(cur
-1) == ' ' ) 
1504         // check if it's not a macro, and let plugin handle it, if so 
1508                 skip_token_back( cur 
); 
1512                 if ( mpPlugin
->CanUnderstandContext( tmp
, _gSrcEnd
, mpCurCtx 
) ) 
1516                         mpPlugin
->ParseContext( _gSrcStart
, cur
, _gSrcEnd
, mpCurCtx 
); 
1524         spOperation
* pOp 
= new spOperation(); 
1526         pOp
->mSrcLineNo    
= lineNo
; 
1527         pOp
->mSrcOffset    
= int( start 
- _gSrcStart 
); 
1528         pOp
->mHeaderLength 
= int( bracketPos 
- start 
); 
1530         mpCurCtx
->AddMember( pOp 
); 
1531         pOp
->mVisibility 
= mCurVis
; 
1532     pOp
->mIsVirtual 
= isVirtual
; 
1534         // add comments about operation 
1535         AttachComments( *pOp
, cur 
); 
1537         // go backwards to method name 
1538         skip_token_back( cur 
); 
1540         pOp
->mName 
= get_token_str( cur 
); 
1542         // go backwards to method return type 
1543         skip_next_token_back( cur 
); 
1547                 pOp
->mRetType 
= string( start
, size_t( cur
-start 
) ); 
1549         arrange_indirection_tokens_between( pOp
->mRetType
, pOp
->mName 
); 
1552         restore_line_no( tmpLnNo 
); 
1554         // now, enter operation context 
1560 bool CJSourceParser::ParseArguments( char*& cur 
) 
1564         // now cursor position is right after the first opening bracket 
1565         // of the function declaration 
1567         char* blocks    
[16]; // used exclusivelly for iterative "lean out" 
1568                                                   // of macros and misc. not-obviouse grammar 
1569                                                   // (dirty,, but we cannot do it very nice, 
1570                                                   //  we're not preprocessor-free C/C++ code) 
1575                 size_t blocksSkipped 
= 0; 
1577                 get_next_token( cur 
); 
1581                 while( *cur 
!= ')' && *cur 
!= ',' ) 
1583                         blocks
[blocksSkipped
] = cur
; 
1590                                 blockSizes
[blocksSkipped
] = size_t(cur
-prev
); 
1595                                 blockSizes
[blocksSkipped
] = skip_block( cur 
); 
1597                         get_next_token( cur 
); 
1602                 if ( blocksSkipped 
== 1 )  
1604                         // check if the empty arg. list stressed with "void" inside 
1605                         if ( cmp_tokens_fast( blocks
[0] , "void", 4 ) ) 
1608                         // FIXME:: TBD:: K&R-style function declarations! 
1610                         // if only one block enclosed, than it's probably 
1611                         // some macro, there should be at least two blocks, 
1612                         // one for argument type and another for it's identifier 
1616                 if ( blocksSkipped 
== 0 ) 
1618                         if ( *cur 
== 10 ) ++_gLineNo
; 
1621                         break; // function without paramters 
1624                 // we should be in the operation context now 
1625                 spOperation
* pOp 
= (spOperation
*)mpCurCtx
; 
1627                 spParameter
* pPar 
= new spParameter(); 
1629                 pOp
->AddMember( pPar 
); 
1630                 // FOR NOW:: line number is not exact if argument list is mutiline 
1631                 pPar
->mSrcLineNo 
= get_line_no(); 
1633                 size_t nameBlock 
= blocksSkipped 
- 1; 
1634                 size_t typeBlock 
= nameBlock 
- 1; 
1636                 // check if default values present 
1637                 if ( *blocks
[typeBlock
] == '=' ) 
1639                         // expressions like "int = 5" are ignored, 
1640                         // since name for paramters is required 
1641                         if ( blocksSkipped 
== 3 ) 
1652                         pPar
->mInitVal 
= string( blocks
[nameBlock
], blockSizes
[nameBlock
] ); 
1654                         nameBlock 
= nameBlock 
- 2; // skip '=' token and default value block 
1655                         typeBlock 
= nameBlock 
- 1; 
1658                 // attach comments about the parameter 
1659                 AttachComments( *pPar
, blocks
[nameBlock
] ); 
1661                 // retrieve argument name 
1662                 pPar
->mName 
= string( blocks
[nameBlock
], blockSizes
[nameBlock
] ); 
1664                 // retreive argument type 
1666                 size_t len 
= blockSizes
[ typeBlock 
]; 
1667                 len 
= size_t ( (blocks
[ typeBlock 
] + len
) - blocks
[ 0 ] ); 
1669                 pPar
->mType 
= string( blocks
[0], len 
); 
1671                 arrange_indirection_tokens_between( pPar
->mType
, pOp
->mName 
); 
1679                 ++cur
; // skip comma 
1680                 get_next_token(cur
); 
1684     // skip possible whitespace between ')' and following "const" 
1685     while ( isspace(*cur
) ) 
1688         // check if it was really a function not a macro, 
1689         // if so, than it should be terminated with semicolon ';' 
1690         // or opening implemenetaton bracket '{' 
1695         store_line_no( tmpLnNo 
); 
1699                 if ( *tok 
== '{' || *tok 
== ';' )  
1701                         restore_line_no(tmpLnNo
); 
1705                 // check for unexpected tokens 
1706                 if ( *tok 
== '=' || *tok 
== '0' )  
1709                         if ( !get_next_token(tok
) ) return FALSE
; 
1713                 if ( *tok 
== '}' ) return FALSE
; 
1715                 // if initialization list found 
1718                         restore_line_no(tmpLnNo
); 
1722                 if ( cmp_tokens_fast( tok
, "const", 5 ) ) 
1724             ((spOperation
*)mpCurCtx
)->mIsConstant 
= true; 
1727                         if ( !get_next_token(tok
) ) return FALSE
; 
1731                 if ( CheckVisibilty( tok 
) ) return FALSE
; 
1733                 // if next context found 
1734                 if ( is_keyword( tok 
) ) return FALSE
; 
1737                 if ( !get_next_token(tok
) ) return FALSE
; 
1744 void CJSourceParser::ParseMemberVar( char*& cur 
) 
1746         MMemberListT
& members 
= mpCurCtx
->GetMembers(); 
1748         bool firstMember 
= 1; 
1754         // jump to the end of statement 
1755         // and start collecting same-type varibles 
1756         // back-to-front towards the type identifier 
1758         skip_statement( cur 
); 
1759         char* savedPos 
= cur
; 
1762         store_line_no( tmpLnNo 
); 
1764     --cur
; // rewind back to ';' 
1768                 spAttribute
* pAttr 
= new spAttribute(); 
1769                 // FOR NOW:: line not is not exact, if member declaration is multiline 
1770                 pAttr
->mSrcLineNo 
= get_line_no(); 
1772                 mpCurCtx
->AddMember( pAttr 
); 
1773                 pAttr
->mVisibility 
= mCurVis
; 
1775                 pAttr
->mIsConstant 
= 0; 
1780                         first 
= members
.size() - 1;; 
1783                 skip_token_back( cur 
); 
1785                 // attach comments about the attribute 
1786                 AttachComments( *pAttr
, cur 
); 
1788                 pAttr
->mName 
= get_token_str( cur 
); 
1790                 // guessing that this going to be variable type 
1791                 skip_next_token_back( cur 
); 
1792                 skip_token_back( cur 
); 
1794                 pAttr
->mType 
= get_token_str( cur 
); 
1796                 // if comma, than variable list continues 
1797                 // otherwise the variable type reached - stop 
1801                         // yes, we've mistaken, it was not a identifier, 
1802                         // but it's default value 
1806                         // skip default value and '=' symbol 
1807                         skip_next_token_back( cur 
); 
1808                         skip_token_back( cur 
); 
1810                         pAttr
->mName 
= get_token_str( cur 
); 
1812                         skip_next_token_back( cur 
); 
1813                         skip_token_back( cur 
); 
1818                         type 
= get_token_str( cur 
); 
1824         // set up types for all collected (same-type) attributes; 
1825         while ( first 
!= members
.size() - 1 ) 
1827                 spAttribute
* pAttr 
= (spAttribute
*)members
[first
]; 
1829                 pAttr
->mType       
= type
; 
1830                 pAttr
->mVisibility 
= mCurVis
; 
1832                 arrange_indirection_tokens_between( pAttr
->mType
, pAttr
->mName 
); 
1838         restore_line_no( tmpLnNo 
); 
1840         clear_commets_queue(); 
1845 void CJSourceParser::SkipFunction( char*& cur 
) 
1847         while ( *cur 
!= '(' && cur 
< _gSrcEnd 
)  
1849                 if (*cur 
== 10 ) ++_gLineNo
; 
1853         skip_next_token_back( cur 
); // go back and skip function identifier 
1854         skip_token_back( cur 
);      // go back and skip return type 
1856         skip_block( cur 
);           // now, go ahead and skip whole declaration 
1858         SkipFunctionBody( cur 
); 
1862 void CJSourceParser::SkipFunctionBody( char*& cur 
) 
1864         // FIXME:: check for comments and quoted stirngs here 
1866         bool hasDefinition 
= FALSE
; 
1868         while( *cur 
!= '{' && *cur 
!= ';' ) 
1870                 if (*cur 
== 10 ) ++_gLineNo
; 
1880                 hasDefinition 
= TRUE
; 
1882                 skip_scope_block( cur 
); // skip the whole imp. 
1885         if ( mpCurCtx
->GetType() == SP_CTX_OPERATION 
) 
1887                 spOperation
& op 
= *((spOperation
*)mpCurCtx
); 
1889                 int curOfs 
= int ( cur 
- _gSrcStart 
); 
1891                 op
.mContextLength 
= curOfs 
- mpCurCtx
->mSrcOffset
; 
1893                 op
.mHasDefinition 
= hasDefinition
; 
1895                 // separate scope resolution token from the name of operation 
1897                 for( size_t i 
= 0; i 
!= op
.mName
.length(); ++i 
) 
1899                         if ( op
.mName
[i
] == ':' && op
.mName
[i
+1] == ':' ) 
1901                                 string 
unscoped( op
.mName
, i
+2, op
.mName
.length() - ( i 
+ 2 ) ); 
1903                                 op
.mScope 
= string( op
.mName
, 0, i 
); 
1905                                 op
.mName 
= unscoped
; 
1913 bool CJSourceParser::CheckVisibilty( char*& cur 
) 
1915         size_t len 
= get_token_len( cur 
); 
1917         if ( cmp_tokens_fast( cur
, "public:", len 
) ) 
1919                 mCurVis 
= SP_VIS_PUBLIC
; 
1923         if ( cmp_tokens_fast( cur
, "protected:", len 
) ) 
1925                 mCurVis 
= SP_VIS_PROTECTED
; 
1929         if ( cmp_tokens_fast( cur
, "private:", len 
) ) 
1931                 mCurVis 
= SP_VIS_PRIVATE
; 
1938 void CJSourceParser::AddClassNode( char*& cur 
) 
1940         char* ctxStart 
= cur
; 
1942         skip_token( cur 
); // skip 'class' keyword 
1943         if ( !get_next_token( cur 
) ) return; 
1949                 get_next_token( cur 
); 
1952         spClass
* pClass 
= new spClass(); 
1955         mpCurCtx
->AddMember( pClass 
); 
1957         // by default all class members are private 
1958         mCurVis       
= SP_VIS_PRIVATE
; 
1960         // attach comments about the class 
1961         AttachComments( *pClass
, cur 
); 
1963         pClass
->mSrcLineNo 
= get_line_no(); 
1965         pClass
->mSrcOffset 
= int( ctxStart 
- _gSrcStart 
); 
1967         char* nameTok 
= cur
; 
1968         pClass
->mName 
= get_token_str( cur 
); 
1977                 if ( !get_next_token( cur 
) ) return; 
1986                         store_line_no( tmpLn 
); 
1988                         skip_next_token_back( tok 
); 
1989                         skip_token_back( tok 
); 
1991                         restore_line_no( tmpLn 
); 
1993                         // class name should precend ':' colon, thus 
1994                         // the one which was captured before was 
1995                         // proablty something else (like __dllexport MyClass : ... ) 
1997                         if ( nameTok 
!= tok 
) 
1999                                 pClass
->mName 
= get_token_str( tok 
); 
2010                 size_t len 
= get_token_len( cur 
); 
2012                 // skip neglectable C++ modifieres 
2013                 if ( cmp_tokens_fast( cur
, "public", len 
) ) 
2016                 if ( cmp_tokens_fast( cur
, "protected", len 
) ) 
2019                 if ( cmp_tokens_fast( cur
, "private", len 
) ) 
2022                 if ( cmp_tokens_fast( cur
, "virtual", len 
) ) 
2025                 // skip neglectable JAVA modifieres 
2027                 if ( cmp_tokens_fast( cur
, "extends", len 
) ) 
2033                 if ( cmp_tokens_fast( cur
, "implements", len 
) ) 
2039                 // all we need to know is superclass or interface 
2043                 store_line_no( tmpLn 
); 
2046                 get_next_token(tok
); 
2048                 restore_line_no( tmpLn 
); 
2050                 if ( *tok 
!= ':' && *cur 
!= ':' ) 
2052                         pClass
->mSuperClassNames
.push_back( string( cur
, len 
) ); 
2059                 store_line_no( tmpLn 
); 
2061                 while ( pClass
->mSuperClassNames
.size() ) 
2063                         pClass
->mSuperClassNames
.erase( &pClass
->mSuperClassNames
[0] ); 
2067                 // some non-obviouse token was following "class" keyword - 
2068                 // we've confused it with class name - thus now we're reverting this mistake 
2070                 skip_next_token_back( tok 
); 
2071                 skip_token_back( tok 
); 
2073                 pClass
->mName 
= get_token_str( tok 
); 
2075                 restore_line_no( tmpLn 
); 
2079         ++cur
; // skip opening curly brace 
2081         pClass
->mHeaderLength 
= ( cur 
- ctxStart 
); 
2083         // now, enter the class context 
2086         clear_commets_queue(); 
2089 void CJSourceParser::AddEnumNode( char*& cur 
) 
2091         // now the cursor is at "enum" keyword 
2094         spEnumeration
* pEnum 
= new spEnumeration(); 
2095         mpCurCtx
->AddMember( pEnum 
); 
2097         pEnum
->mSrcLineNo 
= get_line_no(); 
2100         AttachComments( *pEnum
, cur 
); 
2103         if ( !get_next_token( cur 
) ) return; 
2105         // check if enumeration has got it's identifier 
2108                 pEnum
->mName 
= get_token_str( cur 
); 
2111         if ( !skip_imp_block( cur 
) ) return; 
2113         get_string_between( start
, cur
, &pEnum
->mEnumContent 
); 
2115         if ( get_next_token(cur
) ) 
2117                 // check if the identifier if after the {...} block 
2120                         pEnum
->mName 
= get_token_str( cur 
); 
2123         clear_commets_queue(); 
2126 void CJSourceParser::AddTypeDefNode( char*& cur 
) 
2128         // now the cursor at the token next to "typedef" keyword 
2130         if ( !get_next_token(cur
) ) return; 
2134         spTypeDef
* pTDef 
= new spTypeDef(); 
2135         mpCurCtx
->AddMember( pTDef 
); 
2137         pTDef
->mSrcLineNo 
= get_line_no(); 
2139         AttachComments( *pTDef
, cur 
); 
2141         skip_statement( cur 
); 
2144         store_line_no( tmpLnNo 
); 
2147         skip_next_token_back( tok 
); 
2149         char* nameEnd 
= tok
; 
2151         skip_token_back( tok 
); 
2153         char* nameStart 
= tok
; 
2155         skip_next_token_back( tok 
); 
2157         char* typeEnd 
= tok
; 
2159         // check if it's function prototype 
2160         if ( *nameStart 
== ')' ) 
2162                 typeEnd 
= nameStart
+1; 
2164                 // skip argument list 
2165                 while ( *nameStart 
!= '(' ) --nameStart
; 
2167                 // skip to function type definition 
2168                 while ( *nameStart 
!= ')' ) --nameStart
; 
2170                 skip_next_token_back( nameStart 
); 
2172                 nameEnd 
= nameStart
; 
2174                 skip_token_back( nameStart 
); 
2176                 if ( *nameStart 
== '*' ) ++nameStart
; 
2179         get_string_between( start
, typeEnd
, &pTDef
->mOriginalType 
); 
2181         get_string_between( nameStart
, nameEnd
, &pTDef
->mName 
); 
2183         clear_commets_queue(); 
2185         restore_line_no( tmpLnNo 
);