1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Contrib. demo 
   4 // Author:      Aleksandras Gluchovas 
   8 // Copyright:   (c) Aleskandars Gluchovas 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13 #  pragma implementation "acell.h" 
  16 // For compilers that support precompilation, includes "wx/wx.h". 
  17 #include "wx/wxprec.h" 
  29 #if defined( wxUSE_TEMPLATE_STL ) 
  40 /***** Implementation for class SJParser *****/ 
  42 // statics used by inline'ed C helper-functions 
  43 static char* _gSrcStart 
= 0; 
  44 static char* _gSrcEnd   
= 0; 
  45 static char* _gLastSuppresedComment 
= 0; 
  46 static int   _gLineNo      
= 0; 
  48 // FOR NOW:: comments queue is static 
  49 #define MAX_CQ_ENTRIES 128 
  50 static char* _gCommentsQueue
[MAX_CQ_ENTRIES
]; 
  51 static int    _gCQSize 
= 0; 
  53 /***** keyword map related structures *****/ 
  57     inline bool operator()( char* x
, char* y
) const 
  58     {     return ( strcmp( x
,y 
) < 0 ); 
  62 //WXSTL_MAP(CharPtrT,CharPtrT, LESS_THEN_FUNCTOR(CharPtrT)); 
  64 #if defined( wxUSE_TEMPLATE_STL ) 
  66     typedef map
< char*, char*, less_c_str 
> KeywordMapT
; 
  70     typedef char* CharPtrT
; 
  71     typedef WXSTL_MAP( CharPtrT
, CharPtrT 
,less_c_str
) KeywordMapT
; 
  75 static KeywordMapT __gMultiLangMap
; 
  76 static int         __gMapReady 
= 0; 
  78 static char* __gKeyWords
[] = 
 114 static void check_keyword_map() 
 120         // "make sure" the address of the first member of non-polimorphic class 
 121         // coinsides with the address of the instance 
 123         char** keyword 
= __gKeyWords
; 
 125         while ( (*keyword
) != 0 ) 
 127             __gMultiLangMap
.insert( 
 128                 KeywordMapT::value_type( *keyword
, *keyword 
) 
 136 /***** helper functions *****/ 
 138 static inline void skip_to_eol( char*& cur 
) 
 140     while( *(cur
) != 10 && *cur 
!= 13 && cur 
< _gSrcEnd
) ++cur
; 
 143 static inline void skip_eol( char*& cur 
) 
 154 static inline bool skip_to_next_comment_in_the_line( char*& cur 
) 
 158         while( cur 
< _gSrcEnd  
&& 
 164         if ( cur 
== _gSrcEnd 
) return false; 
 168             if ( (*(cur
+1) == '*') || 
 169                  (*(cur
+1) == '/') ) return true; 
 182 inline static void store_line_no( int& toVar 
) 
 187 inline static void restore_line_no( int storedLineNo 
) 
 189     _gLineNo 
= storedLineNo
; 
 192 inline static int get_line_no() 
 197 static void skip_to_prev_line( char*& cur 
) 
 199     while( cur 
>= _gSrcStart  
&& 
 204     // NOTE:: '\n' is 13,10 for DOS 
 205     //        '\n' is 10 for UNIX 
 207     // NOTE1: '\n' symbol is not used here, 
 208     //        to provide possibility of loading 
 218     if ( *cur 
== 13 ) --cur
; 
 220     while( cur 
>= _gSrcStart  
&& 
 225     ++cur
; // move to the first character in the line 
 228 static inline void skip_comments( char*& cur 
) 
 230     ++cur
; // skip '/' token 
 232     if ( *cur 
!= '/' && *cur 
!= '*' ) return; 
 234     // first, store position of the comment into the queue 
 235     // (which further will be attached to the next context 
 238     if ( cur
-1 != _gLastSuppresedComment 
) 
 240         if ( _gCQSize 
== MAX_CQ_ENTRIES 
) 
 242             size_t i 
= MAX_CQ_ENTRIES
-1; 
 246                 _gCommentsQueue
[i
-1] = _gCommentsQueue
[i
]; 
 253         _gCommentsQueue
[_gCQSize
++] = cur
-1; 
 256     // if signle-line comment, skip it now 
 266     // check for multiline comment (handle nested multiline comments!) 
 274         // TBD:: check eof cond. 
 276         // detect and remove vertical columns of '*''s 
 278         while ( *cur 
!= '/' && cur 
< _gSrcEnd 
) 
 284                         if ( *(cur
+1) != '/' ) 
 294                 case 13 : line_len 
= 0; break; 
 295                 case 10 : { line_len 
= 0; ++_gLineNo
; } break; 
 297                 default : ++line_len
; 
 303         if ( cur 
>= _gSrcEnd  
) return; 
 307         if ( *(cur
-2) == '*' ) 
 325 static inline void clear_commets_queue() 
 330 static inline void skip_quoted_string( char*& cur 
) 
 332     ++cur
; // skip first quote '"' 
 334     // check if quote wasn't prefixed 
 335     if ( *(cur
-2) == '\\' ) 
 340         while ( *cur 
!= '"' && cur 
< _gSrcEnd 
) 
 342             if ( *cur 
== 10 ) ++_gLineNo
; 
 346         if ( cur 
>= _gSrcEnd 
) return; 
 348         ++cur
; // skip the last quote 
 350         // check if it wasn't prefixed 
 352         if ( *(cur
-2) != '\\' ) 
 358 // skips subsequent white space and comments 
 359 // (return false if the end of source code reached) 
 361 static inline bool get_next_token( char*& cur 
) 
 363     for( ; cur 
< _gSrcEnd
; ++cur 
) 
 371             case 10  : { ++_gLineNo
;continue; } 
 373             case '/' : skip_comments( cur 
); 
 383     if ( cur 
>= _gSrcEnd 
) 
 389 static inline void skip_preprocessor_dir( char*& cur 
) 
 395         if ( *(cur
-1) != '\\' ) 
 398         if ( cur 
< _gSrcEnd 
) 
 406 static void skip_token( char*& cur 
) 
 410         skip_quoted_string( cur 
); 
 424     // special case of "!=", "<=", ... 2 character composite tokens 
 438     ++cur
; // leading character is always skipped 
 440     for( ; cur 
< _gSrcEnd 
; ++cur 
) 
 453             // FIXME:: QUICK-HACK:: to treat scope resolution 
 454             //         tokens are a part of the string - e.g. SomeSpace::SubName would 
 457             case ':' : if ( *(cur
+1) == ':' ) 
 476 static inline size_t get_token_len( char* tok 
) 
 482     return size_t( tok 
- start 
); 
 485 // returns true, if given tokens are equel 
 487 static inline bool cmp_tokens( char* tok1
, char* tok2 
) 
 489     // NOTE:: the case one token includes 
 490     //        other in it's entirely is not handled 
 492     size_t len 
= get_token_len( tok1 
); 
 494     // assuming that tokens are non-zero length 
 498         if ( *(tok1
++) != *(tok2
++) ) 
 508 static inline bool cmp_tokens_fast( char* tok1
, char* tok2
, size_t len 
) 
 512         if ( *(tok1
++) != *(tok2
++) ) 
 520 static inline void skip_tempalate_statement( char*& cur 
) 
 524     // go one level deeper 
 525     while( *cur 
!= '<' && cur 
< _gSrcEnd 
) 
 527         if (*cur 
== 10 ) ++_gLineNo
; 
 531     // FIXME:: template should be checked statement for 
 532     //         comments inside of it 
 541         ++cur
; // skip '<' or '>' token 
 546         while( *cur 
!= '<' && *cur 
!= '>' && cur 
< _gSrcEnd 
) 
 548             if (*cur 
== 10 ) ++_gLineNo
; 
 555 static inline void skip_statement( char*& cur 
) 
 557     for( ; cur 
< _gSrcEnd
; ++cur 
) 
 561             case  ';' : ++cur
; // skip statement-terminator token 
 564             case  '"' : skip_quoted_string(cur
); 
 568             case  10  : ++_gLineNo
; 
 571             case  '/' : skip_comments( cur 
); 
 578 // "reversed" versions of skip_token() and get_next_token() 
 580 static inline void skip_token_back( char*& cur 
) 
 582     // FIXME:: now, when moving backwards, neither strings nor 
 583     //         comment blocks are checked 
 585     --cur
; // skip to the trailing character 
 594     for( ; cur 
< _gSrcEnd 
; --cur 
) 
 611     ++cur
; // get to the leading character of the token 
 614 static inline void skip_next_token_back( char*& cur 
) 
 616     --cur
; // skip leading character of the current token 
 627     for( ; cur 
< _gSrcEnd
; --cur 
) 
 644     ++cur
; // position after the trailing charcter of the prev token 
 647 static string 
get_token_str( char* cur 
) 
 649     return string( cur
, get_token_len( cur 
) ); 
 652 // skips token or whole expression which may have 
 653 // nested  expressions between '(' ')' brackets. 
 655 // Upon return, the cursor points to the terminating bracket ')', 
 657 // Return value is the size of the block 
 659 static size_t skip_block( char*& cur 
) 
 661     size_t level 
= 0; // nesting level 
 665     // NOTE:: assumed that block not necessarely starts 
 666     //        with bracket rightaway 
 677         char* savedPos 
= cur
; 
 679         store_line_no( tmpLnNo 
); 
 681         get_next_token( cur 
); 
 683         if ( cur 
>= _gSrcEnd 
) return 0; 
 695                 restore_line_no( tmpLnNo 
); 
 697                 return size_t(cur
-start
); 
 706                 // QUICK-HACK::to easily handle function prototypes , 
 707                 // it works, besause theoretically there should 
 708                 // be no cast-expressions in non-implementation 
 709                 // scope (e.g. "time( (long*)(ptr+1) )" should not 
 710                 // appear in the declarations, thus it is most likelly 
 711                 // for the ")(" fragment to be within a function 
 712                 // prototype in the declarations scope 
 720                 else return size_t(cur
-start
); 
 728                 restore_line_no( tmpLnNo 
); 
 730                 return size_t(cur
-start
); 
 737 // returns 0, if end of source reached 
 738 static inline bool skip_imp_block( char*& cur 
) 
 740     while( *cur 
!= '{' && cur 
< _gSrcEnd 
) 
 743         if ( !get_next_token( cur 
) ) return false; 
 746     while( *cur 
!= '}' && cur 
< _gSrcEnd 
) 
 749         if ( !get_next_token( cur 
) ) return false; 
 757 static bool is_class_token( char*& cur 
) 
 759     // FIXME:: the below mess should be cleaned in it's entirely 
 762         if ( *(cur
+1) == 'n' ) 
 764             return cmp_tokens_fast( cur
, "interface", 9 ); 
 767         if ( *(cur
+1) == 'l' ) 
 769             return cmp_tokens_fast( cur
, "class", 5 ); 
 772         if ( *(cur
+1) == 't' ) 
 774             return cmp_tokens_fast( cur
, "struct", 6 ); 
 777         if ( *(cur
+1) == 'n' ) 
 779             return cmp_tokens_fast( cur
, "union", 5 ); 
 784 inline static bool is_forward_decl( char* cur 
) 
 790             case ':' : return false; 
 791             case '{' : return false; 
 792             case '(' : return false; 
 794             case ';' : return true; 
 801     } while (cur 
< _gSrcEnd
); // prevent running out of bounds 
 806 inline static bool is_function( char* cur
, bool& isAMacro 
) 
 811     store_line_no( tmpLnNo 
); 
 813     // NOTE:: comments and quoted strings are not checked here 
 815     // first,check for "single-line hanginging macros" like: 
 823     get_next_token( cur 
); 
 828         restore_line_no( tmpLnNo 
); 
 833     // it's not a macro, go to the begining of arg. list 
 837         // if bracket found, it's a function or a begining 
 841             restore_line_no( tmpLnNo 
); 
 845         // end of statement found without any brackets in it 
 846         // - it cannot be a function 
 850             restore_line_no( tmpLnNo 
); 
 856     } while( cur 
< _gSrcEnd
); 
 859     restore_line_no( tmpLnNo 
); 
 864 // upon return the cursor is positioned after the 
 865 // terminating curly brace 
 867 static inline void skip_scope_block( char*& cur 
) 
 871     for( ; cur 
< _gSrcEnd 
; ++cur 
) 
 875             case '/' : skip_comments( cur 
); 
 878             case '"' : skip_quoted_string( cur 
); 
 888                            ++cur
; // skip final closing curly brace 
 892             case 10 : ++_gLineNo
; continue; 
 898 // moves tokens like '*' '**', '***', '&' from the name 
 901 static void arrange_indirection_tokens_between( string
& type
, 
 904     // TBD:: FIXME:: return value of operators ! 
 906     while ( identifier
[0u] == '*' || 
 907             identifier
[0u] == '&' 
 910         type 
+= identifier
[0u]; 
 911         identifier
.erase(0,1); 
 913         if ( !identifier
.length() ) return; 
 918 // the only function where multi-lang keyword map is accessed 
 920 static bool is_keyword( char* cur 
) 
 922     size_t len 
= get_token_len( cur 
); 
 924     // put a terminating zero after the given token 
 925     char tmp 
= *(cur 
+ len
); 
 928     KeywordMapT::iterator i
; 
 930     i 
= __gMultiLangMap
.find( cur 
); 
 932     // restore original character suppresed by terminating zero 
 935     return i 
== __gMultiLangMap
.end() ? false : true; 
 938 static inline void get_string_between( char* start
, char* end
, 
 948 static char* set_comment_text( string
& text
, char* start 
) 
 952     // to avoid poluting the queue with this comment 
 953     _gLastSuppresedComment 
= start
; 
 955     skip_comments( end 
); 
 957     if ( *(end
-1) == '/' ) 
 962     // skip multiple leading '/''s or '*''s 
 963     while( *start 
== '/' && start 
< end 
) ++start
; 
 964     while( *start 
== '*' && start 
< end 
) ++start
; 
 966     get_string_between( start
, end
, &text 
); 
 971 /***** Implementation for class CJSourceParser *****/ 
 973 CJSourceParser::CJSourceParser( bool collectCommnets
, bool collectMacros 
) 
 977       mCommentsOn( collectCommnets 
), 
 978       mMacrosOn  ( collectMacros 
) 
 983 spFile
* CJSourceParser::Parse( char* start
, char* end 
) 
 985     // set up state variables 
 986     mCurVis       
= SP_VIS_PRIVATE
; 
 988     spFile
* pTopCtx 
= new spFile(); 
1000     _gSrcEnd   
= mpEnd
; // let all the C-functions "smell" the end of file 
1005     clear_commets_queue(); 
1007     // main parsing loop 
1011         if ( !get_next_token( cur 
) ) 
1012             // end of source reached 
1015         if ( memcmp( cur
, "ScriptSection( const string&", 
1016                      strlen( "ScriptSection( const string&" ) 
1028                     AddMacroNode( cur 
); 
1059         // 'const' is a part of the return type, not a keyword here 
1060         if ( strncmp(cur
, "const", 5) != 0 && is_keyword( cur 
) ) 
1062             // parses, token, if token identifies 
1063             // the container context (e.g. class/namespace) 
1064             // the corresponding context object is created 
1065             // and set as current context 
1067             ParseKeyword( cur 
); 
1071         if ( *cur 
>= '0' && *cur 
<= '9' ) 
1079             if ( mCurCtxType 
!= SP_CTX_CLASS 
) 
1081                 // FOR NOW:: disable the below assertion 
1083                 // DBG:: unexpected closing-bracket found 
1086                 skip_token( cur 
); // just skip it 
1090             if ( mpCurCtx
->GetType() == SP_CTX_CLASS 
) 
1092                 int curOfs 
= ( (cur
+1) - _gSrcStart 
); 
1094                 mpCurCtx
->mContextLength 
= ( curOfs 
- mpCurCtx
->mSrcOffset 
); 
1099             // terminate operation/class/namespace context 
1100             // TBD:: check if it's really this type of context 
1102             wxASSERT( mpCurCtx 
); 
1103             mpCurCtx 
= mpCurCtx
->GetOutterContext(); 
1104             wxASSERT( mpCurCtx 
); 
1106             if ( mNestingLevel 
== 0 ) 
1109                 mCurCtxType 
= SP_CTX_FILE
; 
1111                 // not-nested class delclaration finished, 
1112                 // rest template flag in any case 
1120         bool isAMacro 
= false; 
1122         if ( is_function( cur
, isAMacro 
) ) 
1130             char* savedPos 
= cur
; 
1133             store_line_no( tmpLnNo 
); 
1134             wxUnusedVar( tmpLnNo 
); 
1138             if ( !ParseNameAndRetVal( cur
, isAMacro 
) ) 
1143                     SkipFunction( cur 
); 
1148             if ( !ParseArguments( cur 
) ) 
1150                 // failure while parsing arguments, 
1151                 // remove enclosing operation context 
1153                 spContext
* pFailed 
= mpCurCtx
; 
1154                 mpCurCtx 
= mpCurCtx
->GetOutterContext(); 
1155                 mpCurCtx
->RemoveChild( pFailed 
); 
1162                 // otherwise, successfully close operation context: 
1164                 clear_commets_queue(); 
1166                 SkipFunctionBody( cur 
); 
1168                 mpCurCtx 
= mpCurCtx
->GetOutterContext(); 
1171                 wxASSERT( mpCurCtx 
); 
1175         else // otherwise it's declaration of a variable; 
1177             // now, the cursor point to the end of statement (';' token) 
1179             if ( mCurCtxType 
!= SP_CTX_CLASS 
) 
1181                 // non-class members are ignored 
1183                 skip_token( cur 
); // skip the end of statement 
1187             ParseMemberVar( cur 
); 
1193 void CJSourceParser::AttachComments( spContext
& ctx
, char* cur 
) 
1195     if ( !mCommentsOn 
) return; 
1197     MCommentListT
& lst 
= ctx
.GetCommentList(); 
1199     char* prevComEnd 
= 0; 
1202     store_line_no( tmpLnNo 
); 
1204     // attach comments which were found before the given context 
1206     for( int i 
= 0; i 
!= _gCQSize
; ++i 
) 
1208         spComment
* pComment 
= new spComment(); 
1209         lst
.push_back( pComment 
); 
1211         // find the end of comment 
1212         char* start 
= _gCommentsQueue
[i
]; 
1214         pComment
->mIsMultiline 
= ( *(start
+1) == '*' ); 
1216         // first comment in the queue and multiline 
1217         // comments are always treated as a begining 
1218         // of the new paragraph in the comment text 
1222             pComment
->mStartsPar 
= true; 
1224         if ( pComment
->mIsMultiline 
) 
1226             pComment
->mStartsPar 
= true; 
1229             // find out wheather there is a new-line 
1230             // between to adjecent comments 
1233             char* prevLine 
= start
; 
1234             skip_to_prev_line(prevLine
); 
1236             if ( prevLine 
>= prevComEnd 
) 
1238                 pComment
->mStartsPar 
= true; 
1240                 pComment
->mStartsPar 
= false; 
1243         prevComEnd 
= set_comment_text( pComment
->mText
, start 
); 
1247     // attach comments which are at the end of the line 
1248     // of the given context (if any) 
1250     if ( skip_to_next_comment_in_the_line( cur 
) ) 
1252         spComment
* pComment 
= new spComment(); 
1253         lst
.push_back( pComment 
); 
1255         set_comment_text( pComment
->mText
, cur 
); 
1257         pComment
->mStartsPar 
= 1; 
1258         pComment
->mIsMultiline 
= ( *(cur
+1) == '*' ); 
1260         // mark this comment, so that it would not 
1261         // get in the comments list of the next context 
1262         _gLastSuppresedComment 
= cur
; 
1265     restore_line_no( tmpLnNo 
); 
1267     clear_commets_queue(); 
1270 void CJSourceParser::AddMacroNode( char*& cur 
) 
1274     int lineNo 
= get_line_no(); 
1276     skip_preprocessor_dir( cur 
); 
1279     store_line_no( tmpLnNo 
); 
1281     if ( !mMacrosOn 
) return; 
1283     spPreprocessorLine
* pPL 
= new spPreprocessorLine(); 
1284     pPL
->mSrcLineNo 
= lineNo
; 
1286     AttachComments( *pPL
, cur 
); 
1288     get_string_between( start
, cur
, &pPL
->mLine 
); 
1290     ++start
; // skip '#' 
1291     get_next_token( start 
); 
1293     pPL
->mDefType 
= SP_PREP_DEF_OTHER
; 
1295     // if we found a definition or redefinition, 
1296     // determine the type exactly and assign 
1297     // a name to the context 
1299     if ( *start 
== 'd' ) 
1301         if ( cmp_tokens_fast( start
, "define", 6 ) ) 
1303             char* tok 
= start
+6; 
1305             get_next_token( tok 
); 
1307             pPL
->m_Name 
= get_token_str( tok 
); 
1310             get_next_token( tok
); 
1314                 pPL
->mDefType 
= SP_PREP_DEF_DEFINE_SYMBOL
; 
1316                 pPL
->mDefType 
= SP_PREP_DEF_REDEFINE_SYMBOL
; 
1319     else if ( *start 
== 'i' ) 
1321         if ( cmp_tokens_fast( start
, "include", 7 ) ) 
1323             pPL
->mDefType 
= SP_PREP_DEF_INCLUDE_FILE
; 
1325         else if ( *++start 
== 'f' ) 
1327             // either "#if" or "#ifdef" 
1330             get_next_token( cur 
); 
1332             string condition 
= get_token_str( cur 
); 
1334             // currently, everything except '0' is true 
1335             if ( condition 
== "0" ) { 
1336                 // skip until the following else or enif 
1337                 while ( cur 
< _gSrcEnd 
) { 
1341                     get_next_token( cur 
); 
1342                     if ( *cur
++ == '#' && *cur 
== 'e' ) 
1347             // TODO parse the condition... 
1350     else if ( cmp_tokens_fast( start
, "else", 4 ) ) 
1352         // skip until "#endif" 
1353         while ( cur 
< _gSrcEnd 
) { 
1357             get_next_token( cur 
); 
1358             if ( *cur
++ == '#' && cmp_tokens_fast( cur
, "endif", 5 ) ) 
1363     mpCurCtx
->AddMember( pPL 
); 
1368     restore_line_no( tmpLnNo 
); 
1370     clear_commets_queue(); 
1373 void CJSourceParser::ParseKeyword( char*& cur 
) 
1375     // analyze token, which identifies the begining of a new context 
1377     if ( CheckVisibilty( cur 
) ) 
1383     if ( is_class_token( cur 
) ) 
1385         if ( is_forward_decl( cur 
) ) 
1387             // forward declarations are ignored; 
1392         if ( mNestingLevel 
== 0 ) 
1394             // change context form global class context 
1395             mCurCtxType 
= SP_CTX_CLASS
; 
1400         // add information about new class (name, inheritance, etc) 
1401         AddClassNode( cur 
); 
1403         // the default visiblity for class members is 'private' 
1404         mCurVis 
= SP_VIS_PRIVATE
; 
1409     size_t len 
= get_token_len( cur 
); 
1411     if ( cmp_tokens_fast( cur
, "typedef", len  
) ) 
1414         get_next_token(cur
); 
1416         if ( cmp_tokens_fast( cur
, "struct", len 
) || 
1417              cmp_tokens_fast( cur
, "union",  len 
) || 
1418              cmp_tokens_fast( cur
, "class",  len 
) 
1421             if ( mNestingLevel 
== 0 ) 
1423                 // change context form global class context 
1424                 mCurCtxType 
= SP_CTX_CLASS
; 
1429             // add information about new class (name, inheritance, etc) 
1430             AddClassNode( cur 
); 
1432             // the default visiblity for class members is 'private' 
1433             mCurVis 
= SP_VIS_PRIVATE
; 
1437             // FOR NOW:: typedef struct, etc are also ignored 
1438             //skip_scope_block( cur ); 
1441         if ( cmp_tokens_fast( cur
, "enum", len  
) ) 
1447         AddTypeDefNode( cur 
); 
1452     if ( cmp_tokens_fast( cur
, "enum", len 
) ) 
1458     if ( cmp_tokens_fast( cur
, "extern", len 
) ) 
1460         // extern's are ignored (both extern "C" and extern vars) 
1461         while ( *cur 
!= '{' && 
1465             get_next_token( cur 
); 
1470     if ( cmp_tokens_fast( cur
, "enum", len 
) ) 
1472         // enumeration blocks are ignored 
1474         skip_scope_block( cur 
); 
1476         get_next_token( cur 
); 
1477         skip_token( cur 
); // skip ';' token; 
1481     if ( cmp_tokens_fast( cur
, "package", len  
) ) 
1483         // packages are ignored 
1484         skip_statement( cur 
); 
1488     if ( cmp_tokens_fast( cur
, "import", len  
) ) 
1490         // import statements are ignored 
1491         skip_statement( cur 
); 
1495     if ( cmp_tokens_fast( cur
, "virtual", len  
) ) 
1497         // probably the virtual method is in front of us; 
1503     if ( cmp_tokens_fast( cur
, "template", len  
) ) 
1506         skip_tempalate_statement( cur 
); 
1510     if ( cmp_tokens_fast( cur
, "friend", len  
) ) 
1512         skip_statement( cur 
); 
1516     // ingnore "unsigificant" tokens (i.e. which do not 
1517     // affect the current parsing context) 
1522 bool CJSourceParser::ParseNameAndRetVal( char*& cur
, bool& isAMacro 
) 
1526     // FOR NOW:: all functions in the global 
1527     //           scope are ignored 
1529     int lineNo 
= get_line_no(); 
1533     bool isVirtual 
= false; 
1534     while( *cur 
!= '(' ) 
1536         if ( get_token_str( cur 
) == "virtual" ) 
1540         if ( !get_next_token( cur 
) ) return false; 
1543     char* bracketPos 
= cur
; 
1544     char* savedPos   
= cur 
+ 1; 
1547     store_line_no( tmpLnNo 
); 
1549     // skip gap between function name and start of paramters list 
1550     while ( *(cur
-1) == ' ' ) 
1553     // check if it's not a macro, and let plugin handle it, if so 
1557         skip_token_back( cur 
); 
1561         if ( mpPlugin
->CanUnderstandContext( tmp
, _gSrcEnd
, mpCurCtx 
) ) 
1565             mpPlugin
->ParseContext( _gSrcStart
, cur
, _gSrcEnd
, mpCurCtx 
); 
1573     spOperation
* pOp 
= new spOperation(); 
1575     pOp
->mSrcLineNo    
= lineNo
; 
1576     pOp
->mSrcOffset    
= int( start 
- _gSrcStart 
); 
1577     pOp
->mHeaderLength 
= int( bracketPos 
- start 
); 
1578     if ( mpCurCtx
->GetContextType() == SP_CTX_CLASS 
) 
1579         pOp
->mScope 
= mpCurCtx
->m_Name
; 
1581     mpCurCtx
->AddMember( pOp 
); 
1582     pOp
->mVisibility 
= mCurVis
; 
1583     pOp
->mIsVirtual 
= isVirtual
; 
1585     // add comments about operation 
1586     AttachComments( *pOp
, cur 
); 
1588     // go backwards to method name 
1589     skip_token_back( cur 
); 
1591     pOp
->m_Name 
= get_token_str( cur 
); 
1593     // checker whether it's not an operator 
1594     char chFirst 
= *pOp
->m_Name
.c_str(); 
1595     if ( !isalpha(chFirst
) && chFirst 
!= '_' && chFirst 
!= '~' ) { 
1597         skip_next_token_back( cur 
); 
1598         skip_token_back( cur 
); 
1600         string lastToken 
= get_token_str( cur 
); 
1601         if ( lastToken 
== "operator" ) { 
1602             lastToken 
+= pOp
->m_Name
; 
1603             pOp
->m_Name 
= lastToken
; 
1606             // ok, it wasn't an operator after all 
1610     else if ( pOp
->m_Name 
== "operator" ) { 
1612         get_next_token( cur 
); 
1613         string oper 
= get_token_str( cur 
); 
1615         pOp
->m_Name 
+= oper
; 
1618     // go backwards to method return type 
1619     skip_next_token_back( cur 
); 
1623         string rettype 
= string( start
, size_t( cur
-start 
) ); 
1624         // FIXME just for now... 
1625         string::size_type pos 
= 0; 
1626         string 
toerase("WXDLLEXPORT "); 
1627         while((pos 
= rettype
.find(toerase
, pos
)) != string::npos
) 
1628             rettype
.erase(pos
, toerase
.length()); 
1629         pOp
->mRetType 
= rettype
; 
1632     arrange_indirection_tokens_between( pOp
->mRetType
, pOp
->m_Name 
); 
1635     restore_line_no( tmpLnNo 
); 
1637     // now, enter operation context 
1643 bool CJSourceParser::ParseArguments( char*& cur 
) 
1647     // now cursor position is right after the first opening bracket 
1648     // of the function declaration 
1650     char* blocks    
[16]; // used exclusivelly for iterative "lean out" 
1651                           // of macros and misc. not-obviouse grammar 
1652                           // (dirty,, but we cannot do it very nice, 
1653                           //  we're not preprocessor-free C/C++ code) 
1658         size_t blocksSkipped 
= 0; 
1660         get_next_token( cur 
); 
1662         bool first_blk 
= true; 
1664         while( *cur 
!= ')' && *cur 
!= ',' ) 
1666             blocks
[blocksSkipped
] = cur
; 
1673                 blockSizes
[blocksSkipped
] = size_t(cur
-prev
); 
1678                 blockSizes
[blocksSkipped
] = skip_block( cur 
); 
1680             get_next_token( cur 
); 
1685         if ( blocksSkipped 
== 1 ) 
1687             // check if the empty arg. list stressed with "void" inside 
1688             if ( cmp_tokens_fast( blocks
[0] , "void", 4 ) ) 
1695             // FIXME:: TBD:: K&R-style function declarations! 
1697             // if only one block enclosed, than it's probably 
1698             // some macro, there should be at least two blocks, 
1699             // one for argument type and another for it's identifier 
1703         if ( blocksSkipped 
== 0 ) 
1705             if ( *cur 
== 10 ) ++_gLineNo
; 
1708             break; // function without paramters 
1711         // we should be in the operation context now 
1712         spOperation
* pOp 
= (spOperation
*)mpCurCtx
; 
1714         spParameter
* pPar 
= new spParameter(); 
1716         pOp
->AddMember( pPar 
); 
1717         // FOR NOW:: line number is not exact if argument list is mutiline 
1718         pPar
->mSrcLineNo 
= get_line_no(); 
1720         size_t nameBlock 
= blocksSkipped 
- 1; 
1721         size_t typeBlock 
= nameBlock 
- 1; 
1723         // check if default values present 
1724         if ( *blocks
[typeBlock
] == '=' ) 
1726             // expressions like "int = 5" are ignored, 
1727             // since name for paramters is required 
1728             if ( blocksSkipped 
== 3 ) 
1739             pPar
->mInitVal 
= string( blocks
[nameBlock
], blockSizes
[nameBlock
] ); 
1741             nameBlock 
= nameBlock 
- 2; // skip '=' token and default value block 
1742             typeBlock 
= nameBlock 
- 1; 
1745         // attach comments about the parameter 
1746         AttachComments( *pPar
, blocks
[nameBlock
] ); 
1748         // retrieve argument name 
1749         pPar
->m_Name 
= string( blocks
[nameBlock
], blockSizes
[nameBlock
] ); 
1751         // retreive argument type 
1753         size_t len 
= blockSizes
[ typeBlock 
]; 
1754         len 
= size_t ( (blocks
[ typeBlock 
] + len
) - blocks
[ 0 ] ); 
1756         pPar
->mType 
= string( blocks
[0], len 
); 
1758         arrange_indirection_tokens_between( pPar
->mType
, pPar
->m_Name 
); 
1766         ++cur
; // skip comma 
1767         get_next_token(cur
); 
1771     // skip possible whitespace between ')' and following "const" 
1772     while ( isspace(*cur
) ) 
1775     // check if it was really a function not a macro, 
1776     // if so, than it should be terminated with semicolon ';' 
1777     // or opening implemenetaton bracket '{' 
1782     store_line_no( tmpLnNo 
); 
1788         if ( *tok 
== '{' || *tok 
== ';' ) 
1790             restore_line_no(tmpLnNo
); 
1794         // check for unexpected tokens 
1795         if ( *tok 
== '=' || *tok 
== '0' ) 
1798             if ( !get_next_token(tok
) ) return false; 
1802         if ( *tok 
== '}' ) return false; 
1804         // if initialization list found 
1807             restore_line_no(tmpLnNo
); 
1811         if ( cmp_tokens_fast( tok
, "const", 5 ) ) 
1813             ((spOperation
*)mpCurCtx
)->mIsConstant 
= true; 
1816             if ( !get_next_token(tok
) ) return false; 
1820         if ( CheckVisibilty( tok 
) ) return false; 
1822         // if next context found 
1823         if ( is_keyword( tok 
) ) return false; 
1826         if ( !get_next_token(tok
) ) return false; 
1833 void CJSourceParser::ParseMemberVar( char*& cur 
) 
1835     MMemberListT
& members 
= mpCurCtx
->GetMembers(); 
1837     bool firstMember 
= true; 
1841     // jump to the end of statement 
1842     // and start collecting same-type varibles 
1843     // back-to-front towards the type identifier 
1845     skip_statement( cur 
); 
1846     char* savedPos 
= cur
; 
1849     store_line_no( tmpLnNo 
); 
1851     --cur
; // rewind back to ';' 
1855         spAttribute
* pAttr 
= new spAttribute(); 
1856         // FOR NOW:: line not is not exact, if member declaration is multiline 
1857         pAttr
->mSrcLineNo 
= get_line_no(); 
1859         mpCurCtx
->AddMember( pAttr 
); 
1860         pAttr
->mVisibility 
= mCurVis
; 
1862         pAttr
->mIsConstant 
= 0; 
1869         skip_token_back( cur 
); 
1871         // attach comments about the attribute 
1872         AttachComments( *pAttr
, cur 
); 
1874         pAttr
->m_Name 
= get_token_str( cur 
); 
1876         // guessing that this going to be variable type 
1877         skip_next_token_back( cur 
); 
1878         skip_token_back( cur 
); 
1880         pAttr
->mType 
= get_token_str( cur 
); 
1882         // if comma, than variable list continues 
1883         // otherwise the variable type reached - stop 
1887             // yes, we've mistaken, it was not a identifier, 
1888             // but it's default value 
1892             // skip default value and '=' symbol 
1893             skip_next_token_back( cur 
); 
1894             skip_token_back( cur 
); 
1896             pAttr
->m_Name 
= get_token_str( cur 
); 
1898             skip_next_token_back( cur 
); 
1899             skip_token_back( cur 
); 
1904             type 
= get_token_str( cur 
); 
1912     // set up types for all collected (same-type) attributes; 
1913     while ( first 
!= members
.size() - 1 ) 
1915         spAttribute
* pAttr 
= members
[first
++]->CastToAttribute(); 
1919         if ( pAttr
->mType
.empty() ) 
1920             pAttr
->mType 
= type
; 
1921         pAttr
->mVisibility 
= mCurVis
; 
1923         if ( !pAttr
->m_Name
.empty() ) 
1924             arrange_indirection_tokens_between( pAttr
->mType
, pAttr
->m_Name 
); 
1928     restore_line_no( tmpLnNo 
); 
1930     clear_commets_queue(); 
1935 void CJSourceParser::SkipFunction( char*& cur 
) 
1937     while ( *cur 
!= '(' && cur 
< _gSrcEnd 
) 
1939         if (*cur 
== 10 ) ++_gLineNo
; 
1943     skip_next_token_back( cur 
); // go back and skip function identifier 
1944     skip_token_back( cur 
);      // go back and skip return type 
1946     skip_block( cur 
);           // now, go ahead and skip whole declaration 
1948     SkipFunctionBody( cur 
); 
1952 void CJSourceParser::SkipFunctionBody( char*& cur 
) 
1954     // FIXME:: check for comments and quoted stirngs here 
1956     bool hasDefinition 
= false; 
1958     while( *cur 
!= '{' && *cur 
!= ';' ) 
1960         if (*cur 
== 10 ) ++_gLineNo
; 
1970         hasDefinition 
= true; 
1972         skip_scope_block( cur 
); // skip the whole imp. 
1975     if ( mpCurCtx
->GetType() == SP_CTX_OPERATION 
) 
1977         spOperation
& op 
= *((spOperation
*)mpCurCtx
); 
1979         int curOfs 
= int ( cur 
- _gSrcStart 
); 
1981         op
.mContextLength 
= curOfs 
- mpCurCtx
->mSrcOffset
; 
1983         op
.mHasDefinition 
= hasDefinition
; 
1985         // separate scope resolution token from the name of operation 
1987         for( size_t i 
= 0; i 
!= op
.m_Name
.length(); ++i 
) 
1989             if ( op
.m_Name
[i
] == ':' && op
.m_Name
[i
+1] == ':' ) 
1991                 string 
unscoped( op
.m_Name
, i
+2, op
.m_Name
.length() - ( i 
+ 2 ) ); 
1993                 op
.mScope 
= string( op
.m_Name
, 0, i 
); 
1995                 op
.m_Name 
= unscoped
; 
2003 bool CJSourceParser::CheckVisibilty( char*& cur 
) 
2005     size_t len 
= get_token_len( cur 
); 
2007     if ( cmp_tokens_fast( cur
, "public:", len 
) ) 
2009         mCurVis 
= SP_VIS_PUBLIC
; 
2013     if ( cmp_tokens_fast( cur
, "protected:", len 
) ) 
2015         mCurVis 
= SP_VIS_PROTECTED
; 
2019     if ( cmp_tokens_fast( cur
, "private:", len 
) ) 
2021         mCurVis 
= SP_VIS_PRIVATE
; 
2028 void CJSourceParser::AddClassNode( char*& cur 
) 
2030     char* ctxStart 
= cur
; 
2032     string classkeyword 
= get_token_str( cur 
); 
2034     skip_token( cur 
); // skip 'class' keyword 
2035     if ( !get_next_token( cur 
) ) return; 
2041         get_next_token( cur 
); 
2044     // by default all class members are private 
2045     mCurVis 
= SP_VIS_PRIVATE
; 
2047     spClass
* pClass 
= new spClass(); 
2048     if ( classkeyword 
== "class" ) 
2049         pClass
->mClassSubType 
= SP_CLTYPE_CLASS
; 
2050     else if ( classkeyword 
== "struct" ) { 
2051         pClass
->mClassSubType 
= SP_CLTYPE_STRUCTURE
; 
2053         mCurVis 
= SP_VIS_PUBLIC
; 
2055     else if ( classkeyword 
== "union" ) { 
2056         pClass
->mClassSubType 
= SP_CLTYPE_UNION
; 
2058         mCurVis 
= SP_VIS_PUBLIC
; 
2060     else if ( classkeyword 
== "interface" ) 
2061         pClass
->mClassSubType 
= SP_CLTYPE_INTERFACE
; 
2063         pClass
->mClassSubType 
= SP_CLTYPE_INVALID
; 
2065         wxFAIL_MSG("unknown class keyword"); 
2068     mpCurCtx
->AddMember( pClass 
); 
2070     // attach comments about the class 
2071     AttachComments( *pClass
, cur 
); 
2073     pClass
->mSrcLineNo 
= get_line_no(); 
2075     pClass
->mSrcOffset 
= int( ctxStart 
- _gSrcStart 
); 
2077     char* nameTok 
= cur
; 
2078     pClass
->m_Name 
= get_token_str( cur 
); 
2087         if ( !get_next_token( cur 
) ) return; 
2096             store_line_no( tmpLn 
); 
2098             skip_next_token_back( tok 
); 
2099             skip_token_back( tok 
); 
2101             restore_line_no( tmpLn 
); 
2103             // class name should precend ':' colon, thus 
2104             // the one which was captured before was 
2105             // proablty something else (like __dllexport MyClass : ... ) 
2107             if ( nameTok 
!= tok 
) 
2109                 pClass
->m_Name 
= get_token_str( tok 
); 
2120         size_t len 
= get_token_len( cur 
); 
2122         // skip neglectable C++ modifieres 
2123         if ( cmp_tokens_fast( cur
, "public", len 
) ) 
2126         if ( cmp_tokens_fast( cur
, "protected", len 
) ) 
2129         if ( cmp_tokens_fast( cur
, "private", len 
) ) 
2132         if ( cmp_tokens_fast( cur
, "virtual", len 
) ) 
2135         // skip neglectable JAVA modifieres 
2137         if ( cmp_tokens_fast( cur
, "extends", len 
) ) 
2143         if ( cmp_tokens_fast( cur
, "implements", len 
) ) 
2149         // all we need to know is superclass or interface 
2153         store_line_no( tmpLn 
); 
2156         get_next_token(tok
); 
2158         restore_line_no( tmpLn 
); 
2160         if ( *tok 
!= ':' && *cur 
!= ':' ) 
2162             pClass
->mSuperClassNames
.push_back( string( cur
, len 
) ); 
2169         store_line_no( tmpLn 
); 
2171         while ( pClass
->mSuperClassNames
.size() ) 
2173             pClass
->mSuperClassNames
.erase( &pClass
->mSuperClassNames
[0] ); 
2177         // some non-obviouse token was following "class" keyword - 
2178         // we've confused it with class name - thus now we're reverting this mistake 
2180         skip_next_token_back( tok 
); 
2181         skip_token_back( tok 
); 
2183         pClass
->m_Name 
= get_token_str( tok 
); 
2185         restore_line_no( tmpLn 
); 
2189     ++cur
; // skip opening curly brace 
2191     pClass
->mHeaderLength 
= ( cur 
- ctxStart 
); 
2193     // now, enter the class context 
2196     clear_commets_queue(); 
2199 void CJSourceParser::AddEnumNode( char*& cur 
) 
2201     // now the cursor is at "enum" keyword 
2204     spEnumeration
* pEnum 
= new spEnumeration(); 
2205     mpCurCtx
->AddMember( pEnum 
); 
2207     pEnum
->mSrcLineNo 
= get_line_no(); 
2210     AttachComments( *pEnum
, cur 
); 
2213     if ( !get_next_token( cur 
) ) return; 
2215     // check if enumeration has got it's identifier 
2218         pEnum
->m_Name 
= get_token_str( cur 
); 
2221     if ( !skip_imp_block( cur 
) ) return; 
2223     get_string_between( start
, cur
, &pEnum
->mEnumContent 
); 
2225     if ( get_next_token(cur
) ) 
2227         // check if the identifier if after the {...} block 
2230             pEnum
->m_Name 
= get_token_str( cur 
); 
2233     clear_commets_queue(); 
2236 void CJSourceParser::AddTypeDefNode( char*& cur 
) 
2238     // now the cursor at the token next to "typedef" keyword 
2240     if ( !get_next_token(cur
) ) return; 
2244     spTypeDef
* pTDef 
= new spTypeDef(); 
2245     mpCurCtx
->AddMember( pTDef 
); 
2247     pTDef
->mSrcLineNo 
= get_line_no(); 
2249     AttachComments( *pTDef
, cur 
); 
2251     skip_statement( cur 
); 
2254     store_line_no( tmpLnNo 
); 
2257     skip_next_token_back( tok 
); 
2259     char* nameEnd 
= tok
; 
2261     skip_token_back( tok 
); 
2263     char* nameStart 
= tok
; 
2265     skip_next_token_back( tok 
); 
2267     char* typeEnd 
= tok
; 
2269     // check if it's function prototype 
2270     if ( *nameStart 
== ')' ) 
2272         typeEnd 
= nameStart
+1; 
2274         // skip argument list 
2275         while ( *nameStart 
!= '(' ) --nameStart
; 
2277         // skip to function type definition 
2278         while ( *nameStart 
!= ')' ) --nameStart
; 
2280         skip_next_token_back( nameStart 
); 
2282         nameEnd 
= nameStart
; 
2284         skip_token_back( nameStart 
); 
2286         if ( *nameStart 
== '*' ) ++nameStart
; 
2289     get_string_between( start
, typeEnd
, &pTDef
->mOriginalType 
); 
2291     get_string_between( nameStart
, nameEnd
, &pTDef
->m_Name 
); 
2293     clear_commets_queue(); 
2295     restore_line_no( tmpLnNo 
);