1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Contrib. demo
4 // Author: Aleksandras Gluchovas
8 // Copyright: (c) Aleskandars Gluchovas
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
25 #if defined( wxUSE_TEMPLATE_STL )
36 /***** Implementation for class SJParser *****/
38 // statics used by inline'ed C helper-functions
39 static char* _gSrcStart
= 0;
40 static char* _gSrcEnd
= 0;
41 static wxChar
* _gLastSuppresedComment
= 0;
42 static int _gLineNo
= 0;
44 // FOR NOW:: comments queue is static
45 #define MAX_CQ_ENTRIES 128
46 static char* _gCommentsQueue
[MAX_CQ_ENTRIES
];
47 static int _gCQSize
= 0;
49 /***** keyword map related structures *****/
53 inline bool operator()( char* x
, char* y
) const
54 { return ( strcmp( x
,y
) < 0 );
58 //WXSTL_MAP(CharPtrT,CharPtrT, LESS_THEN_FUNCTOR(CharPtrT));
60 #if defined( wxUSE_TEMPLATE_STL )
62 typedef map
< char*, char*, less_c_str
> KeywordMapT
;
66 typedef char* CharPtrT
;
67 typedef WXSTL_MAP( CharPtrT
, CharPtrT
,less_c_str
) KeywordMapT
;
71 static KeywordMapT __gMultiLangMap
;
72 static int __gMapReady
= 0;
74 static char* __gKeyWords
[] =
110 static void check_keyword_map()
116 // "make sure" the address of the first member of non-polimorphic class
117 // coinsides with the address of the instance
119 char** keyword
= __gKeyWords
;
121 while ( (*keyword
) != 0 )
123 __gMultiLangMap
.insert(
124 KeywordMapT::value_type( *keyword
, *keyword
)
132 /***** helper functions *****/
134 static inline void skip_to_eol( char*& cur
)
136 while( *(cur
) != 10 && *cur
!= 13 && cur
< _gSrcEnd
) ++cur
;
139 static inline void skip_eol( char*& cur
)
150 static inline bool skip_to_next_comment_in_the_line( char*& cur
)
154 while( cur
< _gSrcEnd
&&
160 if ( cur
== _gSrcEnd
) return false;
164 if ( (*(cur
+1) == '*') ||
165 (*(cur
+1) == '/') ) return true;
178 inline static void store_line_no( int& toVar
)
183 inline static void restore_line_no( int storedLineNo
)
185 _gLineNo
= storedLineNo
;
188 inline static int get_line_no()
193 static void skip_to_prev_line( char*& cur
)
195 while( cur
>= _gSrcStart
&&
200 // NOTE:: '\n' is 13,10 for DOS
201 // '\n' is 10 for UNIX
203 // NOTE1: '\n' symbol is not used here,
204 // to provide possibility of loading
214 if ( *cur
== 13 ) --cur
;
216 while( cur
>= _gSrcStart
&&
221 ++cur
; // move to the first character in the line
224 static inline void skip_comments( char*& cur
)
226 ++cur
; // skip '/' token
228 if ( *cur
!= '/' && *cur
!= '*' ) return;
230 // first, store position of the comment into the queue
231 // (which further will be attached to the next context
234 if ( cur
-1 != _gLastSuppresedComment
)
236 if ( _gCQSize
== MAX_CQ_ENTRIES
)
238 size_t i
= MAX_CQ_ENTRIES
-1;
242 _gCommentsQueue
[i
-1] = _gCommentsQueue
[i
];
249 _gCommentsQueue
[_gCQSize
++] = cur
-1;
252 // if signle-line comment, skip it now
262 // check for multiline comment (handle nested multiline comments!)
270 // TBD:: check eof cond.
272 // detect and remove vertical columns of '*''s
274 while ( *cur
!= '/' && cur
< _gSrcEnd
)
280 if ( *(cur
+1) != '/' )
290 case 13 : line_len
= 0; break;
291 case 10 : { line_len
= 0; ++_gLineNo
; } break;
293 default : ++line_len
;
299 if ( cur
>= _gSrcEnd
) return;
303 if ( *(cur
-2) == '*' )
321 static inline void clear_commets_queue()
326 static inline void skip_quoted_string( char*& cur
)
328 ++cur
; // skip first quote '"'
330 // check if quote wasn't prefixed
331 if ( *(cur
-2) == '\\' )
336 while ( *cur
!= '"' && cur
< _gSrcEnd
)
338 if ( *cur
== 10 ) ++_gLineNo
;
342 if ( cur
>= _gSrcEnd
) return;
344 ++cur
; // skip the last quote
346 // check if it wasn't prefixed
348 if ( *(cur
-2) != '\\' )
354 // skips subsequent white space and comments
355 // (return false if the end of source code reached)
357 static inline bool get_next_token( char*& cur
)
359 for( ; cur
< _gSrcEnd
; ++cur
)
367 case 10 : { ++_gLineNo
;continue; }
369 case '/' : skip_comments( cur
);
379 if ( cur
>= _gSrcEnd
)
385 static inline void skip_preprocessor_dir( wxChar
*& cur
)
391 if ( *(cur
-1) != _T('\\') )
394 if ( cur
< _gSrcEnd
)
402 static void skip_token( char*& cur
)
406 skip_quoted_string( cur
);
420 // special case of "!=", "<=", ... 2 character composite tokens
434 ++cur
; // leading character is always skipped
436 for( ; cur
< _gSrcEnd
; ++cur
)
449 // FIXME:: QUICK-HACK:: to treat scope resolution
450 // tokens are a part of the string - e.g. SomeSpace::SubName would
453 case ':' : if ( *(cur
+1) == ':' )
472 static inline size_t get_token_len( char* tok
)
478 return size_t( tok
- start
);
481 // returns true, if given tokens are equel
483 static inline bool cmp_tokens( char* tok1
, char* tok2
)
485 // NOTE:: the case one token includes
486 // other in it's entirely is not handled
488 size_t len
= get_token_len( tok1
);
490 // assuming that tokens are non-zero length
494 if ( *(tok1
++) != *(tok2
++) )
504 static inline bool cmp_tokens_fast( char* tok1
, char* tok2
, size_t len
)
508 if ( *(tok1
++) != *(tok2
++) )
516 static inline void skip_tempalate_statement( char*& cur
)
520 // go one level deeper
521 while( *cur
!= '<' && cur
< _gSrcEnd
)
523 if (*cur
== 10 ) ++_gLineNo
;
527 // FIXME:: template should be checked statement for
528 // comments inside of it
537 ++cur
; // skip '<' or '>' token
542 while( *cur
!= '<' && *cur
!= '>' && cur
< _gSrcEnd
)
544 if (*cur
== 10 ) ++_gLineNo
;
551 static inline void skip_statement( char*& cur
)
553 for( ; cur
< _gSrcEnd
; ++cur
)
557 case ';' : ++cur
; // skip statement-terminator token
560 case '"' : skip_quoted_string(cur
);
564 case 10 : ++_gLineNo
;
567 case '/' : skip_comments( cur
);
574 // "reversed" versions of skip_token() and get_next_token()
576 static inline void skip_token_back( char*& cur
)
578 // FIXME:: now, when moving backwards, neither strings nor
579 // comment blocks are checked
581 --cur
; // skip to the trailing character
590 for( ; cur
< _gSrcEnd
; --cur
)
607 ++cur
; // get to the leading character of the token
610 static inline void skip_next_token_back( char*& cur
)
612 --cur
; // skip leading character of the current token
623 for( ; cur
< _gSrcEnd
; --cur
)
640 ++cur
; // position after the trailing charcter of the prev token
643 static wxString
get_token_str( char* cur
)
645 return wxString( cur
, get_token_len( cur
) );
648 // skips token or whole expression which may have
649 // nested expressions between '(' ')' brackets.
651 // Upon return, the cursor points to the terminating bracket ')',
653 // Return value is the size of the block
655 static size_t skip_block( char*& cur
)
657 size_t level
= 0; // nesting level
661 // NOTE:: assumed that block not necessarely starts
662 // with bracket rightaway
673 char* savedPos
= cur
;
675 store_line_no( tmpLnNo
);
677 get_next_token( cur
);
679 if ( cur
>= _gSrcEnd
) return 0;
691 restore_line_no( tmpLnNo
);
693 return size_t(cur
-start
);
702 // QUICK-HACK::to easily handle function prototypes ,
703 // it works, besause theoretically there should
704 // be no cast-expressions in non-implementation
705 // scope (e.g. "time( (long*)(ptr+1) )" should not
706 // appear in the declarations, thus it is most likelly
707 // for the ")(" fragment to be within a function
708 // prototype in the declarations scope
716 else return size_t(cur
-start
);
724 restore_line_no( tmpLnNo
);
726 return size_t(cur
-start
);
733 // returns 0, if end of source reached
734 static inline bool skip_imp_block( char*& cur
)
736 while( *cur
!= '{' && cur
< _gSrcEnd
)
739 if ( !get_next_token( cur
) ) return false;
742 while( *cur
!= '}' && cur
< _gSrcEnd
)
745 if ( !get_next_token( cur
) ) return false;
753 static bool is_class_token( char*& cur
)
755 // FIXME:: the below mess should be cleaned in it's entirely
758 if ( *(cur
+1) == 'n' )
760 return cmp_tokens_fast( cur
, "interface", 9 );
763 if ( *(cur
+1) == 'l' )
765 return cmp_tokens_fast( cur
, "class", 5 );
768 if ( *(cur
+1) == 't' )
770 return cmp_tokens_fast( cur
, "struct", 6 );
773 if ( *(cur
+1) == 'n' )
775 return cmp_tokens_fast( cur
, "union", 5 );
780 inline static bool is_forward_decl( char* cur
)
786 case ':' : return false;
787 case '{' : return false;
788 case '(' : return false;
790 case ';' : return true;
797 } while (cur
< _gSrcEnd
); // prevent running out of bounds
802 inline static bool is_function( char* cur
, bool& isAMacro
)
807 store_line_no( tmpLnNo
);
809 // NOTE:: comments and quoted strings are not checked here
811 // first,check for "single-line hanginging macros" like:
819 get_next_token( cur
);
824 restore_line_no( tmpLnNo
);
829 // it's not a macro, go to the begining of arg. list
833 // if bracket found, it's a function or a begining
837 restore_line_no( tmpLnNo
);
841 // end of statement found without any brackets in it
842 // - it cannot be a function
846 restore_line_no( tmpLnNo
);
852 } while( cur
< _gSrcEnd
);
855 restore_line_no( tmpLnNo
);
860 // upon return the cursor is positioned after the
861 // terminating curly brace
863 static inline void skip_scope_block( char*& cur
)
867 for( ; cur
< _gSrcEnd
; ++cur
)
871 case '/' : skip_comments( cur
);
874 case '"' : skip_quoted_string( cur
);
884 ++cur
; // skip final closing curly brace
888 case 10 : ++_gLineNo
; continue;
894 // moves tokens like '*' '**', '***', '&' from the name
897 static void arrange_indirection_tokens_between( wxString
& type
,
898 wxString
& identifier
)
900 // TBD:: FIXME:: return value of operators !
902 while ( identifier
[0u] == _T('*') ||
903 identifier
[0u] == _T('&')
906 type
+= identifier
[0u];
907 identifier
.erase(0,1);
909 if ( !identifier
.length() ) return;
914 // the only function where multi-lang keyword map is accessed
916 static bool is_keyword( char* cur
)
918 size_t len
= get_token_len( cur
);
920 // put a terminating zero after the given token
921 char tmp
= *(cur
+ len
);
924 KeywordMapT::iterator i
;
926 i
= __gMultiLangMap
.find( cur
);
928 // restore original character suppresed by terminating zero
931 return i
== __gMultiLangMap
.end() ? false : true;
934 static inline void get_string_between( wxChar
* start
, wxChar
* end
,
944 static wxChar
* set_comment_text( wxString
& text
, wxChar
* start
)
948 // to avoid poluting the queue with this comment
949 _gLastSuppresedComment
= start
;
951 skip_comments( end
);
953 if ( *(end
-1) == _T('/') )
958 // skip multiple leading '/''s or '*''s
959 while( *start
== _T('/') && start
< end
) ++start
;
960 while( *start
== _T('*') && start
< end
) ++start
;
962 get_string_between( start
, end
, &text
);
967 /***** Implementation for class CJSourceParser *****/
969 CJSourceParser::CJSourceParser( bool collectCommnets
, bool collectMacros
)
973 mCommentsOn( collectCommnets
),
974 mMacrosOn ( collectMacros
)
979 spFile
* CJSourceParser::Parse( char* start
, char* end
)
981 // set up state variables
982 mCurVis
= SP_VIS_PRIVATE
;
984 spFile
* pTopCtx
= new spFile();
996 _gSrcEnd
= mpEnd
; // let all the C-functions "smell" the end of file
1001 clear_commets_queue();
1003 // main parsing loop
1007 if ( !get_next_token( m_cur
) )
1008 // end of source reached
1011 if ( memcmp( m_cur
, "ScriptSection( const string&",
1012 strlen( "ScriptSection( const string&" )
1024 AddMacroNode( m_cur
);
1030 skip_token( m_cur
);
1036 skip_token( m_cur
);
1042 skip_token( m_cur
);
1048 skip_token( m_cur
);
1055 // 'const' is a part of the return type, not a keyword here
1056 if ( strncmp(m_cur
, "const", 5) != 0 && is_keyword( m_cur
) )
1058 // parses, token, if token identifies
1059 // the container context (e.g. class/namespace)
1060 // the corresponding context object is created
1061 // and set as current context
1063 ParseKeyword( m_cur
);
1067 if ( *m_cur
>= _T('0') && *m_cur
<= _T('9') )
1069 skip_token( m_cur
);
1073 if ( *m_cur
== _T('}') )
1075 if ( mCurCtxType
!= SP_CTX_CLASS
)
1077 // FOR NOW:: disable the below assertion
1079 // DBG:: unexpected closing-bracket found
1082 skip_token( m_cur
); // just skip it
1086 if ( mpCurCtx
->GetType() == SP_CTX_CLASS
)
1088 int curOfs
= ( (m_cur
+1) - _gSrcStart
);
1090 mpCurCtx
->mContextLength
= ( curOfs
- mpCurCtx
->mSrcOffset
);
1095 // terminate operation/class/namespace context
1096 // TBD:: check if it's really this type of context
1098 wxASSERT( mpCurCtx
);
1099 mpCurCtx
= mpCurCtx
->GetOutterContext();
1100 wxASSERT( mpCurCtx
);
1102 if ( mNestingLevel
== 0 )
1105 mCurCtxType
= SP_CTX_FILE
;
1107 // not-nested class delclaration finished,
1108 // rest template flag in any case
1112 skip_token( m_cur
);
1116 bool isAMacro
= false;
1118 if ( is_function( m_cur
, isAMacro
) )
1122 skip_token( m_cur
);
1126 char* savedPos
= m_cur
;
1129 store_line_no( tmpLnNo
);
1130 wxUnusedVar( tmpLnNo
);
1134 if ( !ParseNameAndRetVal( m_cur
, isAMacro
) )
1139 SkipFunction( m_cur
);
1144 if ( !ParseArguments( m_cur
) )
1146 // failure while parsing arguments,
1147 // remove enclosing operation context
1149 spContext
* pFailed
= mpCurCtx
;
1150 mpCurCtx
= mpCurCtx
->GetOutterContext();
1151 mpCurCtx
->RemoveChild( pFailed
);
1153 skip_to_eol( m_cur
);
1158 // otherwise, successfully close operation context:
1160 clear_commets_queue();
1162 SkipFunctionBody( m_cur
);
1164 mpCurCtx
= mpCurCtx
->GetOutterContext();
1167 wxASSERT( mpCurCtx
);
1171 else // otherwise it's declaration of a variable;
1173 // now, the cursor point to the end of statement (';' token)
1175 if ( mCurCtxType
!= SP_CTX_CLASS
)
1177 // non-class members are ignored
1179 skip_token( m_cur
); // skip the end of statement
1183 ParseMemberVar( m_cur
);
1189 void CJSourceParser::AttachComments( spContext
& ctx
, wxChar
* cur
)
1191 if ( !mCommentsOn
) return;
1193 MCommentListT
& lst
= ctx
.GetCommentList();
1195 wxChar
* prevComEnd
= 0;
1198 store_line_no( tmpLnNo
);
1200 // attach comments which were found before the given context
1202 for( int i
= 0; i
!= _gCQSize
; ++i
)
1204 spComment
* pComment
= new spComment();
1205 lst
.push_back( pComment
);
1207 // find the end of comment
1208 wxChar
* start
= _gCommentsQueue
[i
];
1210 pComment
->mIsMultiline
= ( *(start
+1) == _T('*') );
1212 // first comment in the queue and multiline
1213 // comments are always treated as a begining
1214 // of the new paragraph in the comment text
1218 pComment
->mStartsPar
= true;
1220 else if ( pComment
->mIsMultiline
)
1222 pComment
->mStartsPar
= true;
1226 // find out wheather there is a new-line
1227 // between to adjecent comments
1229 wxChar
* prevLine
= start
;
1230 skip_to_prev_line(prevLine
);
1232 if ( prevLine
>= prevComEnd
)
1233 pComment
->mStartsPar
= true;
1235 pComment
->mStartsPar
= false;
1238 prevComEnd
= set_comment_text( pComment
->m_Text
, start
);
1241 // attach comments which are at the end of the line
1242 // of the given context (if any)
1244 if ( skip_to_next_comment_in_the_line( cur
) )
1246 spComment
* pComment
= new spComment();
1247 lst
.push_back( pComment
);
1249 set_comment_text( pComment
->m_Text
, cur
);
1251 pComment
->mStartsPar
= 1;
1252 pComment
->mIsMultiline
= ( *(cur
+1) == _T('*') );
1254 // mark this comment, so that it would not
1255 // get in the comments list of the next context
1256 _gLastSuppresedComment
= cur
;
1259 restore_line_no( tmpLnNo
);
1261 clear_commets_queue();
1264 void CJSourceParser::AddMacroNode( wxChar
*& cur
)
1266 wxChar
* start
= cur
;
1268 int lineNo
= get_line_no();
1270 skip_preprocessor_dir( cur
);
1273 store_line_no( tmpLnNo
);
1275 if ( !mMacrosOn
) return;
1277 spPreprocessorLine
* pPL
= new spPreprocessorLine();
1278 pPL
->mSrcLineNo
= lineNo
;
1280 AttachComments( *pPL
, cur
);
1282 get_string_between( start
, cur
, &pPL
->m_Line
);
1284 ++start
; // skip '#'
1285 get_next_token( start
);
1287 pPL
->mDefType
= SP_PREP_DEF_OTHER
;
1289 // if we found a definition or redefinition,
1290 // determine the type exactly and assign
1291 // a name to the context
1293 if ( *start
== _T('d') )
1295 if ( cmp_tokens_fast( start
, _T("define"), 6 ) )
1297 char* tok
= start
+6;
1299 get_next_token( tok
);
1301 pPL
->m_Name
= get_token_str( tok
);
1304 get_next_token( tok
);
1308 pPL
->mDefType
= SP_PREP_DEF_DEFINE_SYMBOL
;
1310 pPL
->mDefType
= SP_PREP_DEF_REDEFINE_SYMBOL
;
1313 else if ( *start
== _T('i') )
1315 if ( cmp_tokens_fast( start
, _T("include"), 7 ) )
1317 pPL
->mDefType
= SP_PREP_DEF_INCLUDE_FILE
;
1319 else if ( *++start
== _T('f') )
1321 // either "#if" or "#ifdef"
1324 get_next_token( cur
);
1326 wxString condition
= get_token_str( cur
);
1328 // currently, everything except '0' is true
1329 if ( condition
== _T("0") ) {
1330 // skip until the following else or enif
1331 while ( cur
< _gSrcEnd
) {
1335 get_next_token( cur
);
1336 if ( *cur
++ == _T('#') && *cur
== _T('e') )
1341 // TODO parse the condition...
1344 else if ( cmp_tokens_fast( start
, _T("else"), 4 ) )
1346 // skip until "#endif"
1347 while ( cur
< _gSrcEnd
) {
1351 get_next_token( cur
);
1352 if ( *cur
++ == _T('#') && cmp_tokens_fast( cur
, "endif", 5 ) )
1357 mpCurCtx
->AddMember( pPL
);
1362 restore_line_no( tmpLnNo
);
1364 clear_commets_queue();
1367 void CJSourceParser::ParseKeyword( char*& cur
)
1369 // analyze token, which identifies the begining of a new context
1371 if ( CheckVisibilty( cur
) )
1377 if ( is_class_token( cur
) )
1379 if ( is_forward_decl( cur
) )
1381 // forward declarations are ignored;
1386 if ( mNestingLevel
== 0 )
1388 // change context form global class context
1389 mCurCtxType
= SP_CTX_CLASS
;
1394 // add information about new class (name, inheritance, etc)
1395 AddClassNode( cur
);
1397 // the default visiblity for class members is 'private'
1398 mCurVis
= SP_VIS_PRIVATE
;
1403 size_t len
= get_token_len( cur
);
1405 if ( cmp_tokens_fast( cur
, "typedef", len
) )
1408 get_next_token(cur
);
1410 if ( cmp_tokens_fast( cur
, "struct", len
) ||
1411 cmp_tokens_fast( cur
, "union", len
) ||
1412 cmp_tokens_fast( cur
, "class", len
)
1415 if ( mNestingLevel
== 0 )
1417 // change context form global class context
1418 mCurCtxType
= SP_CTX_CLASS
;
1423 // add information about new class (name, inheritance, etc)
1424 AddClassNode( cur
);
1426 // the default visiblity for class members is 'private'
1427 mCurVis
= SP_VIS_PRIVATE
;
1431 // FOR NOW:: typedef struct, etc are also ignored
1432 //skip_scope_block( cur );
1435 if ( cmp_tokens_fast( cur
, "enum", len
) )
1441 AddTypeDefNode( cur
);
1446 if ( cmp_tokens_fast( cur
, "enum", len
) )
1452 if ( cmp_tokens_fast( cur
, "extern", len
) )
1454 // extern's are ignored (both extern "C" and extern vars)
1455 while ( *cur
!= '{' &&
1459 get_next_token( cur
);
1464 if ( cmp_tokens_fast( cur
, "enum", len
) )
1466 // enumeration blocks are ignored
1468 skip_scope_block( cur
);
1470 get_next_token( cur
);
1471 skip_token( cur
); // skip ';' token;
1475 if ( cmp_tokens_fast( cur
, "package", len
) )
1477 // packages are ignored
1478 skip_statement( cur
);
1482 if ( cmp_tokens_fast( cur
, "import", len
) )
1484 // import statements are ignored
1485 skip_statement( cur
);
1489 if ( cmp_tokens_fast( cur
, "virtual", len
) )
1491 // probably the virtual method is in front of us;
1497 if ( cmp_tokens_fast( cur
, "template", len
) )
1500 skip_tempalate_statement( cur
);
1504 if ( cmp_tokens_fast( cur
, "friend", len
) )
1506 skip_statement( cur
);
1510 // ingnore "unsigificant" tokens (i.e. which do not
1511 // affect the current parsing context)
1516 bool CJSourceParser::ParseNameAndRetVal( char*& cur
, bool& isAMacro
)
1520 // FOR NOW:: all functions in the global
1521 // scope are ignored
1523 int lineNo
= get_line_no();
1527 bool isVirtual
= false;
1528 while( *cur
!= '(' )
1530 if ( get_token_str( cur
) == "virtual" )
1534 if ( !get_next_token( cur
) ) return false;
1537 char* bracketPos
= cur
;
1538 char* savedPos
= cur
+ 1;
1541 store_line_no( tmpLnNo
);
1543 // skip gap between function name and start of paramters list
1544 while ( *(cur
-1) == ' ' )
1547 // check if it's not a macro, and let plugin handle it, if so
1551 skip_token_back( cur
);
1555 if ( mpPlugin
->CanUnderstandContext( tmp
, _gSrcEnd
, mpCurCtx
) )
1559 mpPlugin
->ParseContext( _gSrcStart
, cur
, _gSrcEnd
, mpCurCtx
);
1567 spOperation
* pOp
= new spOperation();
1569 pOp
->mSrcLineNo
= lineNo
;
1570 pOp
->mSrcOffset
= int( start
- _gSrcStart
);
1571 pOp
->mHeaderLength
= int( bracketPos
- start
);
1572 if ( mpCurCtx
->GetContextType() == SP_CTX_CLASS
)
1573 pOp
->mScope
= mpCurCtx
->m_Name
;
1575 mpCurCtx
->AddMember( pOp
);
1576 pOp
->mVisibility
= mCurVis
;
1577 pOp
->mIsVirtual
= isVirtual
;
1579 // add comments about operation
1580 AttachComments( *pOp
, cur
);
1582 // go backwards to method name
1583 skip_token_back( cur
);
1585 pOp
->m_Name
= get_token_str( cur
);
1587 // checker whether it's not an operator
1588 char chFirst
= *pOp
->m_Name
.c_str();
1589 if ( !isalpha(chFirst
) && chFirst
!= '_' && chFirst
!= '~' ) {
1591 skip_next_token_back( cur
);
1592 skip_token_back( cur
);
1594 wxString lastToken
= get_token_str( cur
);
1595 if ( lastToken
== "operator" ) {
1596 lastToken
+= pOp
->m_Name
;
1597 pOp
->m_Name
= lastToken
;
1600 // ok, it wasn't an operator after all
1604 else if ( pOp
->m_Name
== "operator" ) {
1606 get_next_token( cur
);
1607 wxString oper
= get_token_str( cur
);
1609 pOp
->m_Name
+= oper
;
1612 // go backwards to method return type
1613 skip_next_token_back( cur
);
1617 wxString rettype
= wxString( start
, size_t( cur
-start
) );
1618 // FIXME just for now...
1619 wxString::size_type pos
= 0;
1620 wxString
toerase("WXDLLEXPORT ");
1621 while((pos
= rettype
.find(toerase
, pos
)) != wxString::npos
)
1622 rettype
.erase(pos
, toerase
.length());
1623 pOp
->m_RetType
= rettype
;
1626 arrange_indirection_tokens_between( pOp
->m_RetType
, pOp
->m_Name
);
1629 restore_line_no( tmpLnNo
);
1631 // now, enter operation context
1637 bool CJSourceParser::ParseArguments( char*& cur
)
1641 // now cursor position is right after the first opening bracket
1642 // of the function declaration
1644 char* blocks
[16]; // used exclusivelly for iterative "lean out"
1645 // of macros and misc. not-obviouse grammar
1646 // (dirty,, but we cannot do it very nice,
1647 // we're not preprocessor-free C/C++ code)
1652 size_t blocksSkipped
= 0;
1654 get_next_token( cur
);
1656 bool first_blk
= true;
1658 while( *cur
!= ')' && *cur
!= ',' )
1660 blocks
[blocksSkipped
] = cur
;
1667 blockSizes
[blocksSkipped
] = size_t(cur
-prev
);
1672 blockSizes
[blocksSkipped
] = skip_block( cur
);
1674 get_next_token( cur
);
1679 if ( blocksSkipped
== 1 )
1681 // check if the empty arg. list stressed with "void" inside
1682 if ( cmp_tokens_fast( blocks
[0] , "void", 4 ) )
1689 // FIXME:: TBD:: K&R-style function declarations!
1691 // if only one block enclosed, than it's probably
1692 // some macro, there should be at least two blocks,
1693 // one for argument type and another for it's identifier
1697 if ( blocksSkipped
== 0 )
1699 if ( *cur
== 10 ) ++_gLineNo
;
1702 break; // function without paramters
1705 // we should be in the operation context now
1706 spOperation
* pOp
= (spOperation
*)mpCurCtx
;
1708 spParameter
* pPar
= new spParameter();
1710 pOp
->AddMember( pPar
);
1711 // FOR NOW:: line number is not exact if argument list is mutiline
1712 pPar
->mSrcLineNo
= get_line_no();
1714 size_t nameBlock
= blocksSkipped
- 1;
1715 size_t typeBlock
= nameBlock
- 1;
1717 // check if default values present
1718 if ( *blocks
[typeBlock
] == '=' )
1720 // expressions like "int = 5" are ignored,
1721 // since name for paramters is required
1722 if ( blocksSkipped
== 3 )
1733 pPar
->m_InitVal
= wxString( blocks
[nameBlock
], blockSizes
[nameBlock
] );
1735 nameBlock
= nameBlock
- 2; // skip '=' token and default value block
1736 typeBlock
= nameBlock
- 1;
1739 // attach comments about the parameter
1740 AttachComments( *pPar
, blocks
[nameBlock
] );
1742 // retrieve argument name
1743 pPar
->m_Name
= wxString( blocks
[nameBlock
], blockSizes
[nameBlock
] );
1745 // retreive argument type
1747 size_t len
= blockSizes
[ typeBlock
];
1748 len
= size_t ( (blocks
[ typeBlock
] + len
) - blocks
[ 0 ] );
1750 pPar
->m_Type
= wxString( blocks
[0], len
);
1752 arrange_indirection_tokens_between( pPar
->m_Type
, pPar
->m_Name
);
1760 ++cur
; // skip comma
1761 get_next_token(cur
);
1765 // skip possible whitespace between ')' and following "const"
1766 while ( isspace(*cur
) )
1769 // check if it was really a function not a macro,
1770 // if so, than it should be terminated with semicolon ';'
1771 // or opening implemenetaton bracket '{'
1776 store_line_no( tmpLnNo
);
1782 if ( *tok
== '{' || *tok
== ';' )
1784 restore_line_no(tmpLnNo
);
1788 // check for unexpected tokens
1789 if ( *tok
== '=' || *tok
== '0' )
1792 if ( !get_next_token(tok
) ) return false;
1796 if ( *tok
== '}' ) return false;
1798 // if initialization list found
1801 restore_line_no(tmpLnNo
);
1805 if ( cmp_tokens_fast( tok
, "const", 5 ) )
1807 ((spOperation
*)mpCurCtx
)->mIsConstant
= true;
1810 if ( !get_next_token(tok
) ) return false;
1814 if ( CheckVisibilty( tok
) ) return false;
1816 // if next context found
1817 if ( is_keyword( tok
) ) return false;
1820 if ( !get_next_token(tok
) ) return false;
1827 void CJSourceParser::ParseMemberVar( char*& cur
)
1829 MMemberListT
& members
= mpCurCtx
->GetMembers();
1831 bool firstMember
= true;
1835 // jump to the end of statement
1836 // and start collecting same-type varibles
1837 // back-to-front towards the type identifier
1839 skip_statement( cur
);
1840 char* savedPos
= cur
;
1843 store_line_no( tmpLnNo
);
1845 --cur
; // rewind back to ';'
1849 spAttribute
* pAttr
= new spAttribute();
1850 // FOR NOW:: line not is not exact, if member declaration is multiline
1851 pAttr
->mSrcLineNo
= get_line_no();
1853 mpCurCtx
->AddMember( pAttr
);
1854 pAttr
->mVisibility
= mCurVis
;
1856 pAttr
->mIsConstant
= 0;
1863 skip_token_back( cur
);
1865 // attach comments about the attribute
1866 AttachComments( *pAttr
, cur
);
1868 pAttr
->m_Name
= get_token_str( cur
);
1870 // guessing that this going to be variable type
1871 skip_next_token_back( cur
);
1872 skip_token_back( cur
);
1874 pAttr
->m_Type
= get_token_str( cur
);
1876 // if comma, than variable list continues
1877 // otherwise the variable type reached - stop
1879 if ( *cur
== _T('=') )
1881 // yes, we've mistaken, it was not a identifier,
1882 // but it's default value
1883 pAttr
->m_InitVal
= pAttr
->m_Name
;
1885 // skip default value and '=' symbol
1886 skip_next_token_back( cur
);
1887 skip_token_back( cur
);
1889 pAttr
->m_Name
= get_token_str( cur
);
1891 skip_next_token_back( cur
);
1892 skip_token_back( cur
);
1897 type
= get_token_str( cur
);
1905 // set up types for all collected (same-type) attributes;
1906 while ( first
!= members
.size() - 1 )
1908 spAttribute
* pAttr
= members
[first
++]->CastToAttribute();
1912 if ( pAttr
->m_Type
.empty() )
1913 pAttr
->m_Type
= type
;
1914 pAttr
->mVisibility
= mCurVis
;
1916 if ( !pAttr
->m_Name
.empty() )
1917 arrange_indirection_tokens_between( pAttr
->m_Type
, pAttr
->m_Name
);
1921 restore_line_no( tmpLnNo
);
1923 clear_commets_queue();
1928 void CJSourceParser::SkipFunction( char*& cur
)
1930 while ( *cur
!= '(' && cur
< _gSrcEnd
)
1932 if (*cur
== 10 ) ++_gLineNo
;
1936 skip_next_token_back( cur
); // go back and skip function identifier
1937 skip_token_back( cur
); // go back and skip return type
1939 skip_block( cur
); // now, go ahead and skip whole declaration
1941 SkipFunctionBody( cur
);
1945 void CJSourceParser::SkipFunctionBody( char*& cur
)
1947 // FIXME:: check for comments and quoted stirngs here
1949 bool hasDefinition
= false;
1951 while( *cur
!= '{' && *cur
!= ';' )
1953 if (*cur
== 10 ) ++_gLineNo
;
1963 hasDefinition
= true;
1965 skip_scope_block( cur
); // skip the whole imp.
1968 if ( mpCurCtx
->GetType() == SP_CTX_OPERATION
)
1970 spOperation
& op
= *((spOperation
*)mpCurCtx
);
1972 int curOfs
= int ( cur
- _gSrcStart
);
1974 op
.mContextLength
= curOfs
- mpCurCtx
->mSrcOffset
;
1976 op
.mHasDefinition
= hasDefinition
;
1978 // separate scope resolution token from the name of operation
1980 for( size_t i
= 0; i
!= op
.m_Name
.length(); ++i
)
1982 if ( op
.m_Name
[i
] == ':' && op
.m_Name
[i
+1] == ':' )
1984 wxString
unscoped( op
.m_Name
, i
+2, op
.m_Name
.length() - ( i
+ 2 ) );
1986 op
.mScope
= wxString( op
.m_Name
, 0, i
);
1988 op
.m_Name
= unscoped
;
1996 bool CJSourceParser::CheckVisibilty( char*& cur
)
1998 size_t len
= get_token_len( cur
);
2000 if ( cmp_tokens_fast( cur
, "public:", len
) )
2002 mCurVis
= SP_VIS_PUBLIC
;
2006 if ( cmp_tokens_fast( cur
, "protected:", len
) )
2008 mCurVis
= SP_VIS_PROTECTED
;
2012 if ( cmp_tokens_fast( cur
, "private:", len
) )
2014 mCurVis
= SP_VIS_PRIVATE
;
2021 void CJSourceParser::AddClassNode( char*& cur
)
2023 char* ctxStart
= cur
;
2025 wxString classkeyword
= get_token_str( cur
);
2027 skip_token( cur
); // skip 'class' keyword
2028 if ( !get_next_token( cur
) ) return;
2034 get_next_token( cur
);
2037 // by default all class members are private
2038 mCurVis
= SP_VIS_PRIVATE
;
2040 spClass
* pClass
= new spClass();
2041 if ( classkeyword
== "class" )
2042 pClass
->mClassSubType
= SP_CLTYPE_CLASS
;
2043 else if ( classkeyword
== "struct" ) {
2044 pClass
->mClassSubType
= SP_CLTYPE_STRUCTURE
;
2046 mCurVis
= SP_VIS_PUBLIC
;
2048 else if ( classkeyword
== "union" ) {
2049 pClass
->mClassSubType
= SP_CLTYPE_UNION
;
2051 mCurVis
= SP_VIS_PUBLIC
;
2053 else if ( classkeyword
== "interface" )
2054 pClass
->mClassSubType
= SP_CLTYPE_INTERFACE
;
2056 pClass
->mClassSubType
= SP_CLTYPE_INVALID
;
2058 wxFAIL_MSG("unknown class keyword");
2061 mpCurCtx
->AddMember( pClass
);
2063 // attach comments about the class
2064 AttachComments( *pClass
, cur
);
2066 pClass
->mSrcLineNo
= get_line_no();
2068 pClass
->mSrcOffset
= int( ctxStart
- _gSrcStart
);
2070 char* nameTok
= cur
;
2071 pClass
->m_Name
= get_token_str( cur
);
2080 if ( !get_next_token( cur
) ) return;
2089 store_line_no( tmpLn
);
2091 skip_next_token_back( tok
);
2092 skip_token_back( tok
);
2094 restore_line_no( tmpLn
);
2096 // class name should precend ':' colon, thus
2097 // the one which was captured before was
2098 // proablty something else (like __dllexport MyClass : ... )
2100 if ( nameTok
!= tok
)
2102 pClass
->m_Name
= get_token_str( tok
);
2113 size_t len
= get_token_len( cur
);
2115 // skip neglectable C++ modifieres
2116 if ( cmp_tokens_fast( cur
, "public", len
) )
2119 if ( cmp_tokens_fast( cur
, "protected", len
) )
2122 if ( cmp_tokens_fast( cur
, "private", len
) )
2125 if ( cmp_tokens_fast( cur
, "virtual", len
) )
2128 // skip neglectable JAVA modifieres
2130 if ( cmp_tokens_fast( cur
, "extends", len
) )
2136 if ( cmp_tokens_fast( cur
, "implements", len
) )
2142 // all we need to know is superclass or interface
2146 store_line_no( tmpLn
);
2149 get_next_token(tok
);
2151 restore_line_no( tmpLn
);
2153 if ( *tok
!= ':' && *cur
!= ':' )
2155 pClass
->m_SuperClassNames
.push_back( wxString( cur
, len
) );
2162 store_line_no( tmpLn
);
2164 while ( pClass
->m_SuperClassNames
.size() )
2166 pClass
->m_SuperClassNames
.erase( &pClass
->m_SuperClassNames
[0] );
2170 // some non-obviouse token was following "class" keyword -
2171 // we've confused it with class name - thus now we're reverting this mistake
2173 skip_next_token_back( tok
);
2174 skip_token_back( tok
);
2176 pClass
->m_Name
= get_token_str( tok
);
2178 restore_line_no( tmpLn
);
2182 ++cur
; // skip opening curly brace
2184 pClass
->mHeaderLength
= ( cur
- ctxStart
);
2186 // now, enter the class context
2189 clear_commets_queue();
2192 void CJSourceParser::AddEnumNode( wxChar
*& cur
)
2194 // now the cursor is at "enum" keyword
2195 wxChar
* start
= cur
;
2197 spEnumeration
* pEnum
= new spEnumeration();
2198 mpCurCtx
->AddMember( pEnum
);
2200 pEnum
->mSrcLineNo
= get_line_no();
2203 AttachComments( *pEnum
, cur
);
2206 if ( !get_next_token( cur
) ) return;
2208 // check if enumeration has got it's identifier
2211 pEnum
->m_Name
= get_token_str( cur
);
2214 if ( !skip_imp_block( cur
) ) return;
2216 get_string_between( start
, cur
, &pEnum
->m_EnumContent
);
2218 if ( get_next_token(cur
) )
2220 // check if the identifier if after the {...} block
2223 pEnum
->m_Name
= get_token_str( cur
);
2226 clear_commets_queue();
2229 void CJSourceParser::AddTypeDefNode( wxChar
*& cur
)
2231 // now the cursor at the token next to "typedef" keyword
2233 if ( !get_next_token(cur
) ) return;
2235 wxChar
* start
= cur
;
2237 spTypeDef
* pTDef
= new spTypeDef();
2238 mpCurCtx
->AddMember( pTDef
);
2240 pTDef
->mSrcLineNo
= get_line_no();
2242 AttachComments( *pTDef
, cur
);
2244 skip_statement( cur
);
2247 store_line_no( tmpLnNo
);
2249 wxChar
* tok
= cur
-1;
2250 skip_next_token_back( tok
);
2252 wxChar
* nameEnd
= tok
;
2254 skip_token_back( tok
);
2256 wxChar
* nameStart
= tok
;
2258 skip_next_token_back( tok
);
2260 wxChar
* typeEnd
= tok
;
2262 // check if it's function prototype
2263 if ( *nameStart
== ')' )
2265 typeEnd
= nameStart
+1;
2267 // skip argument list
2268 while ( *nameStart
!= '(' ) --nameStart
;
2270 // skip to function type definition
2271 while ( *nameStart
!= ')' ) --nameStart
;
2273 skip_next_token_back( nameStart
);
2275 nameEnd
= nameStart
;
2277 skip_token_back( nameStart
);
2279 if ( *nameStart
== '*' ) ++nameStart
;
2282 get_string_between( start
, typeEnd
, &pTDef
->m_OriginalType
);
2284 get_string_between( nameStart
, nameEnd
, &pTDef
->m_Name
);
2286 clear_commets_queue();
2288 restore_line_no( tmpLnNo
);