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 wxChar
* _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( wxChar
*& cur
)
395 if ( *(cur
-1) != _T('\\') )
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 wxString
get_token_str( char* cur
)
649 return wxString( 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( wxString
& type
,
902 wxString
& identifier
)
904 // TBD:: FIXME:: return value of operators !
906 while ( identifier
[0u] == _T('*') ||
907 identifier
[0u] == _T('&')
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( wxChar
* start
, wxChar
* end
,
948 static wxChar
* set_comment_text( wxString
& text
, wxChar
* start
)
952 // to avoid poluting the queue with this comment
953 _gLastSuppresedComment
= start
;
955 skip_comments( end
);
957 if ( *(end
-1) == _T('/') )
962 // skip multiple leading '/''s or '*''s
963 while( *start
== _T('/') && start
< end
) ++start
;
964 while( *start
== _T('*') && 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( m_cur
) )
1012 // end of source reached
1015 if ( memcmp( m_cur
, "ScriptSection( const string&",
1016 strlen( "ScriptSection( const string&" )
1028 AddMacroNode( m_cur
);
1034 skip_token( m_cur
);
1040 skip_token( m_cur
);
1046 skip_token( m_cur
);
1052 skip_token( m_cur
);
1059 // 'const' is a part of the return type, not a keyword here
1060 if ( strncmp(m_cur
, "const", 5) != 0 && is_keyword( m_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( m_cur
);
1071 if ( *m_cur
>= _T('0') && *m_cur
<= _T('9') )
1073 skip_token( m_cur
);
1077 if ( *m_cur
== _T('}') )
1079 if ( mCurCtxType
!= SP_CTX_CLASS
)
1081 // FOR NOW:: disable the below assertion
1083 // DBG:: unexpected closing-bracket found
1086 skip_token( m_cur
); // just skip it
1090 if ( mpCurCtx
->GetType() == SP_CTX_CLASS
)
1092 int curOfs
= ( (m_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
1116 skip_token( m_cur
);
1120 bool isAMacro
= false;
1122 if ( is_function( m_cur
, isAMacro
) )
1126 skip_token( m_cur
);
1130 char* savedPos
= m_cur
;
1133 store_line_no( tmpLnNo
);
1134 wxUnusedVar( tmpLnNo
);
1138 if ( !ParseNameAndRetVal( m_cur
, isAMacro
) )
1143 SkipFunction( m_cur
);
1148 if ( !ParseArguments( m_cur
) )
1150 // failure while parsing arguments,
1151 // remove enclosing operation context
1153 spContext
* pFailed
= mpCurCtx
;
1154 mpCurCtx
= mpCurCtx
->GetOutterContext();
1155 mpCurCtx
->RemoveChild( pFailed
);
1157 skip_to_eol( m_cur
);
1162 // otherwise, successfully close operation context:
1164 clear_commets_queue();
1166 SkipFunctionBody( m_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( m_cur
); // skip the end of statement
1187 ParseMemberVar( m_cur
);
1193 void CJSourceParser::AttachComments( spContext
& ctx
, wxChar
* cur
)
1195 if ( !mCommentsOn
) return;
1197 MCommentListT
& lst
= ctx
.GetCommentList();
1199 wxChar
* 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 wxChar
* start
= _gCommentsQueue
[i
];
1214 pComment
->mIsMultiline
= ( *(start
+1) == _T('*') );
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 else if ( pComment
->mIsMultiline
)
1226 pComment
->mStartsPar
= true;
1230 // find out wheather there is a new-line
1231 // between to adjecent comments
1233 wxChar
* prevLine
= start
;
1234 skip_to_prev_line(prevLine
);
1236 if ( prevLine
>= prevComEnd
)
1237 pComment
->mStartsPar
= true;
1239 pComment
->mStartsPar
= false;
1242 prevComEnd
= set_comment_text( pComment
->m_Text
, start
);
1245 // attach comments which are at the end of the line
1246 // of the given context (if any)
1248 if ( skip_to_next_comment_in_the_line( cur
) )
1250 spComment
* pComment
= new spComment();
1251 lst
.push_back( pComment
);
1253 set_comment_text( pComment
->m_Text
, cur
);
1255 pComment
->mStartsPar
= 1;
1256 pComment
->mIsMultiline
= ( *(cur
+1) == _T('*') );
1258 // mark this comment, so that it would not
1259 // get in the comments list of the next context
1260 _gLastSuppresedComment
= cur
;
1263 restore_line_no( tmpLnNo
);
1265 clear_commets_queue();
1268 void CJSourceParser::AddMacroNode( wxChar
*& cur
)
1270 wxChar
* start
= cur
;
1272 int lineNo
= get_line_no();
1274 skip_preprocessor_dir( cur
);
1277 store_line_no( tmpLnNo
);
1279 if ( !mMacrosOn
) return;
1281 spPreprocessorLine
* pPL
= new spPreprocessorLine();
1282 pPL
->mSrcLineNo
= lineNo
;
1284 AttachComments( *pPL
, cur
);
1286 get_string_between( start
, cur
, &pPL
->m_Line
);
1288 ++start
; // skip '#'
1289 get_next_token( start
);
1291 pPL
->mDefType
= SP_PREP_DEF_OTHER
;
1293 // if we found a definition or redefinition,
1294 // determine the type exactly and assign
1295 // a name to the context
1297 if ( *start
== _T('d') )
1299 if ( cmp_tokens_fast( start
, _T("define"), 6 ) )
1301 char* tok
= start
+6;
1303 get_next_token( tok
);
1305 pPL
->m_Name
= get_token_str( tok
);
1308 get_next_token( tok
);
1312 pPL
->mDefType
= SP_PREP_DEF_DEFINE_SYMBOL
;
1314 pPL
->mDefType
= SP_PREP_DEF_REDEFINE_SYMBOL
;
1317 else if ( *start
== _T('i') )
1319 if ( cmp_tokens_fast( start
, _T("include"), 7 ) )
1321 pPL
->mDefType
= SP_PREP_DEF_INCLUDE_FILE
;
1323 else if ( *++start
== _T('f') )
1325 // either "#if" or "#ifdef"
1328 get_next_token( cur
);
1330 wxString condition
= get_token_str( cur
);
1332 // currently, everything except '0' is true
1333 if ( condition
== _T("0") ) {
1334 // skip until the following else or enif
1335 while ( cur
< _gSrcEnd
) {
1339 get_next_token( cur
);
1340 if ( *cur
++ == _T('#') && *cur
== _T('e') )
1345 // TODO parse the condition...
1348 else if ( cmp_tokens_fast( start
, _T("else"), 4 ) )
1350 // skip until "#endif"
1351 while ( cur
< _gSrcEnd
) {
1355 get_next_token( cur
);
1356 if ( *cur
++ == _T('#') && cmp_tokens_fast( cur
, "endif", 5 ) )
1361 mpCurCtx
->AddMember( pPL
);
1366 restore_line_no( tmpLnNo
);
1368 clear_commets_queue();
1371 void CJSourceParser::ParseKeyword( char*& cur
)
1373 // analyze token, which identifies the begining of a new context
1375 if ( CheckVisibilty( cur
) )
1381 if ( is_class_token( cur
) )
1383 if ( is_forward_decl( cur
) )
1385 // forward declarations are ignored;
1390 if ( mNestingLevel
== 0 )
1392 // change context form global class context
1393 mCurCtxType
= SP_CTX_CLASS
;
1398 // add information about new class (name, inheritance, etc)
1399 AddClassNode( cur
);
1401 // the default visiblity for class members is 'private'
1402 mCurVis
= SP_VIS_PRIVATE
;
1407 size_t len
= get_token_len( cur
);
1409 if ( cmp_tokens_fast( cur
, "typedef", len
) )
1412 get_next_token(cur
);
1414 if ( cmp_tokens_fast( cur
, "struct", len
) ||
1415 cmp_tokens_fast( cur
, "union", len
) ||
1416 cmp_tokens_fast( cur
, "class", len
)
1419 if ( mNestingLevel
== 0 )
1421 // change context form global class context
1422 mCurCtxType
= SP_CTX_CLASS
;
1427 // add information about new class (name, inheritance, etc)
1428 AddClassNode( cur
);
1430 // the default visiblity for class members is 'private'
1431 mCurVis
= SP_VIS_PRIVATE
;
1435 // FOR NOW:: typedef struct, etc are also ignored
1436 //skip_scope_block( cur );
1439 if ( cmp_tokens_fast( cur
, "enum", len
) )
1445 AddTypeDefNode( cur
);
1450 if ( cmp_tokens_fast( cur
, "enum", len
) )
1456 if ( cmp_tokens_fast( cur
, "extern", len
) )
1458 // extern's are ignored (both extern "C" and extern vars)
1459 while ( *cur
!= '{' &&
1463 get_next_token( cur
);
1468 if ( cmp_tokens_fast( cur
, "enum", len
) )
1470 // enumeration blocks are ignored
1472 skip_scope_block( cur
);
1474 get_next_token( cur
);
1475 skip_token( cur
); // skip ';' token;
1479 if ( cmp_tokens_fast( cur
, "package", len
) )
1481 // packages are ignored
1482 skip_statement( cur
);
1486 if ( cmp_tokens_fast( cur
, "import", len
) )
1488 // import statements are ignored
1489 skip_statement( cur
);
1493 if ( cmp_tokens_fast( cur
, "virtual", len
) )
1495 // probably the virtual method is in front of us;
1501 if ( cmp_tokens_fast( cur
, "template", len
) )
1504 skip_tempalate_statement( cur
);
1508 if ( cmp_tokens_fast( cur
, "friend", len
) )
1510 skip_statement( cur
);
1514 // ingnore "unsigificant" tokens (i.e. which do not
1515 // affect the current parsing context)
1520 bool CJSourceParser::ParseNameAndRetVal( char*& cur
, bool& isAMacro
)
1524 // FOR NOW:: all functions in the global
1525 // scope are ignored
1527 int lineNo
= get_line_no();
1531 bool isVirtual
= false;
1532 while( *cur
!= '(' )
1534 if ( get_token_str( cur
) == "virtual" )
1538 if ( !get_next_token( cur
) ) return false;
1541 char* bracketPos
= cur
;
1542 char* savedPos
= cur
+ 1;
1545 store_line_no( tmpLnNo
);
1547 // skip gap between function name and start of paramters list
1548 while ( *(cur
-1) == ' ' )
1551 // check if it's not a macro, and let plugin handle it, if so
1555 skip_token_back( cur
);
1559 if ( mpPlugin
->CanUnderstandContext( tmp
, _gSrcEnd
, mpCurCtx
) )
1563 mpPlugin
->ParseContext( _gSrcStart
, cur
, _gSrcEnd
, mpCurCtx
);
1571 spOperation
* pOp
= new spOperation();
1573 pOp
->mSrcLineNo
= lineNo
;
1574 pOp
->mSrcOffset
= int( start
- _gSrcStart
);
1575 pOp
->mHeaderLength
= int( bracketPos
- start
);
1576 if ( mpCurCtx
->GetContextType() == SP_CTX_CLASS
)
1577 pOp
->mScope
= mpCurCtx
->m_Name
;
1579 mpCurCtx
->AddMember( pOp
);
1580 pOp
->mVisibility
= mCurVis
;
1581 pOp
->mIsVirtual
= isVirtual
;
1583 // add comments about operation
1584 AttachComments( *pOp
, cur
);
1586 // go backwards to method name
1587 skip_token_back( cur
);
1589 pOp
->m_Name
= get_token_str( cur
);
1591 // checker whether it's not an operator
1592 char chFirst
= *pOp
->m_Name
.c_str();
1593 if ( !isalpha(chFirst
) && chFirst
!= '_' && chFirst
!= '~' ) {
1595 skip_next_token_back( cur
);
1596 skip_token_back( cur
);
1598 wxString lastToken
= get_token_str( cur
);
1599 if ( lastToken
== "operator" ) {
1600 lastToken
+= pOp
->m_Name
;
1601 pOp
->m_Name
= lastToken
;
1604 // ok, it wasn't an operator after all
1608 else if ( pOp
->m_Name
== "operator" ) {
1610 get_next_token( cur
);
1611 wxString oper
= get_token_str( cur
);
1613 pOp
->m_Name
+= oper
;
1616 // go backwards to method return type
1617 skip_next_token_back( cur
);
1621 wxString rettype
= wxString( start
, size_t( cur
-start
) );
1622 // FIXME just for now...
1623 wxString::size_type pos
= 0;
1624 wxString
toerase("WXDLLEXPORT ");
1625 while((pos
= rettype
.find(toerase
, pos
)) != wxString::npos
)
1626 rettype
.erase(pos
, toerase
.length());
1627 pOp
->m_RetType
= rettype
;
1630 arrange_indirection_tokens_between( pOp
->m_RetType
, pOp
->m_Name
);
1633 restore_line_no( tmpLnNo
);
1635 // now, enter operation context
1641 bool CJSourceParser::ParseArguments( char*& cur
)
1645 // now cursor position is right after the first opening bracket
1646 // of the function declaration
1648 char* blocks
[16]; // used exclusivelly for iterative "lean out"
1649 // of macros and misc. not-obviouse grammar
1650 // (dirty,, but we cannot do it very nice,
1651 // we're not preprocessor-free C/C++ code)
1656 size_t blocksSkipped
= 0;
1658 get_next_token( cur
);
1660 bool first_blk
= true;
1662 while( *cur
!= ')' && *cur
!= ',' )
1664 blocks
[blocksSkipped
] = cur
;
1671 blockSizes
[blocksSkipped
] = size_t(cur
-prev
);
1676 blockSizes
[blocksSkipped
] = skip_block( cur
);
1678 get_next_token( cur
);
1683 if ( blocksSkipped
== 1 )
1685 // check if the empty arg. list stressed with "void" inside
1686 if ( cmp_tokens_fast( blocks
[0] , "void", 4 ) )
1693 // FIXME:: TBD:: K&R-style function declarations!
1695 // if only one block enclosed, than it's probably
1696 // some macro, there should be at least two blocks,
1697 // one for argument type and another for it's identifier
1701 if ( blocksSkipped
== 0 )
1703 if ( *cur
== 10 ) ++_gLineNo
;
1706 break; // function without paramters
1709 // we should be in the operation context now
1710 spOperation
* pOp
= (spOperation
*)mpCurCtx
;
1712 spParameter
* pPar
= new spParameter();
1714 pOp
->AddMember( pPar
);
1715 // FOR NOW:: line number is not exact if argument list is mutiline
1716 pPar
->mSrcLineNo
= get_line_no();
1718 size_t nameBlock
= blocksSkipped
- 1;
1719 size_t typeBlock
= nameBlock
- 1;
1721 // check if default values present
1722 if ( *blocks
[typeBlock
] == '=' )
1724 // expressions like "int = 5" are ignored,
1725 // since name for paramters is required
1726 if ( blocksSkipped
== 3 )
1737 pPar
->m_InitVal
= wxString( blocks
[nameBlock
], blockSizes
[nameBlock
] );
1739 nameBlock
= nameBlock
- 2; // skip '=' token and default value block
1740 typeBlock
= nameBlock
- 1;
1743 // attach comments about the parameter
1744 AttachComments( *pPar
, blocks
[nameBlock
] );
1746 // retrieve argument name
1747 pPar
->m_Name
= wxString( blocks
[nameBlock
], blockSizes
[nameBlock
] );
1749 // retreive argument type
1751 size_t len
= blockSizes
[ typeBlock
];
1752 len
= size_t ( (blocks
[ typeBlock
] + len
) - blocks
[ 0 ] );
1754 pPar
->m_Type
= wxString( blocks
[0], len
);
1756 arrange_indirection_tokens_between( pPar
->m_Type
, pPar
->m_Name
);
1764 ++cur
; // skip comma
1765 get_next_token(cur
);
1769 // skip possible whitespace between ')' and following "const"
1770 while ( isspace(*cur
) )
1773 // check if it was really a function not a macro,
1774 // if so, than it should be terminated with semicolon ';'
1775 // or opening implemenetaton bracket '{'
1780 store_line_no( tmpLnNo
);
1786 if ( *tok
== '{' || *tok
== ';' )
1788 restore_line_no(tmpLnNo
);
1792 // check for unexpected tokens
1793 if ( *tok
== '=' || *tok
== '0' )
1796 if ( !get_next_token(tok
) ) return false;
1800 if ( *tok
== '}' ) return false;
1802 // if initialization list found
1805 restore_line_no(tmpLnNo
);
1809 if ( cmp_tokens_fast( tok
, "const", 5 ) )
1811 ((spOperation
*)mpCurCtx
)->mIsConstant
= true;
1814 if ( !get_next_token(tok
) ) return false;
1818 if ( CheckVisibilty( tok
) ) return false;
1820 // if next context found
1821 if ( is_keyword( tok
) ) return false;
1824 if ( !get_next_token(tok
) ) return false;
1831 void CJSourceParser::ParseMemberVar( char*& cur
)
1833 MMemberListT
& members
= mpCurCtx
->GetMembers();
1835 bool firstMember
= true;
1839 // jump to the end of statement
1840 // and start collecting same-type varibles
1841 // back-to-front towards the type identifier
1843 skip_statement( cur
);
1844 char* savedPos
= cur
;
1847 store_line_no( tmpLnNo
);
1849 --cur
; // rewind back to ';'
1853 spAttribute
* pAttr
= new spAttribute();
1854 // FOR NOW:: line not is not exact, if member declaration is multiline
1855 pAttr
->mSrcLineNo
= get_line_no();
1857 mpCurCtx
->AddMember( pAttr
);
1858 pAttr
->mVisibility
= mCurVis
;
1860 pAttr
->mIsConstant
= 0;
1867 skip_token_back( cur
);
1869 // attach comments about the attribute
1870 AttachComments( *pAttr
, cur
);
1872 pAttr
->m_Name
= get_token_str( cur
);
1874 // guessing that this going to be variable type
1875 skip_next_token_back( cur
);
1876 skip_token_back( cur
);
1878 pAttr
->m_Type
= get_token_str( cur
);
1880 // if comma, than variable list continues
1881 // otherwise the variable type reached - stop
1883 if ( *cur
== _T('=') )
1885 // yes, we've mistaken, it was not a identifier,
1886 // but it's default value
1887 pAttr
->m_InitVal
= pAttr
->m_Name
;
1889 // skip default value and '=' symbol
1890 skip_next_token_back( cur
);
1891 skip_token_back( cur
);
1893 pAttr
->m_Name
= get_token_str( cur
);
1895 skip_next_token_back( cur
);
1896 skip_token_back( cur
);
1901 type
= get_token_str( cur
);
1909 // set up types for all collected (same-type) attributes;
1910 while ( first
!= members
.size() - 1 )
1912 spAttribute
* pAttr
= members
[first
++]->CastToAttribute();
1916 if ( pAttr
->m_Type
.empty() )
1917 pAttr
->m_Type
= type
;
1918 pAttr
->mVisibility
= mCurVis
;
1920 if ( !pAttr
->m_Name
.empty() )
1921 arrange_indirection_tokens_between( pAttr
->m_Type
, pAttr
->m_Name
);
1925 restore_line_no( tmpLnNo
);
1927 clear_commets_queue();
1932 void CJSourceParser::SkipFunction( char*& cur
)
1934 while ( *cur
!= '(' && cur
< _gSrcEnd
)
1936 if (*cur
== 10 ) ++_gLineNo
;
1940 skip_next_token_back( cur
); // go back and skip function identifier
1941 skip_token_back( cur
); // go back and skip return type
1943 skip_block( cur
); // now, go ahead and skip whole declaration
1945 SkipFunctionBody( cur
);
1949 void CJSourceParser::SkipFunctionBody( char*& cur
)
1951 // FIXME:: check for comments and quoted stirngs here
1953 bool hasDefinition
= false;
1955 while( *cur
!= '{' && *cur
!= ';' )
1957 if (*cur
== 10 ) ++_gLineNo
;
1967 hasDefinition
= true;
1969 skip_scope_block( cur
); // skip the whole imp.
1972 if ( mpCurCtx
->GetType() == SP_CTX_OPERATION
)
1974 spOperation
& op
= *((spOperation
*)mpCurCtx
);
1976 int curOfs
= int ( cur
- _gSrcStart
);
1978 op
.mContextLength
= curOfs
- mpCurCtx
->mSrcOffset
;
1980 op
.mHasDefinition
= hasDefinition
;
1982 // separate scope resolution token from the name of operation
1984 for( size_t i
= 0; i
!= op
.m_Name
.length(); ++i
)
1986 if ( op
.m_Name
[i
] == ':' && op
.m_Name
[i
+1] == ':' )
1988 wxString
unscoped( op
.m_Name
, i
+2, op
.m_Name
.length() - ( i
+ 2 ) );
1990 op
.mScope
= wxString( op
.m_Name
, 0, i
);
1992 op
.m_Name
= unscoped
;
2000 bool CJSourceParser::CheckVisibilty( char*& cur
)
2002 size_t len
= get_token_len( cur
);
2004 if ( cmp_tokens_fast( cur
, "public:", len
) )
2006 mCurVis
= SP_VIS_PUBLIC
;
2010 if ( cmp_tokens_fast( cur
, "protected:", len
) )
2012 mCurVis
= SP_VIS_PROTECTED
;
2016 if ( cmp_tokens_fast( cur
, "private:", len
) )
2018 mCurVis
= SP_VIS_PRIVATE
;
2025 void CJSourceParser::AddClassNode( char*& cur
)
2027 char* ctxStart
= cur
;
2029 wxString classkeyword
= get_token_str( cur
);
2031 skip_token( cur
); // skip 'class' keyword
2032 if ( !get_next_token( cur
) ) return;
2038 get_next_token( cur
);
2041 // by default all class members are private
2042 mCurVis
= SP_VIS_PRIVATE
;
2044 spClass
* pClass
= new spClass();
2045 if ( classkeyword
== "class" )
2046 pClass
->mClassSubType
= SP_CLTYPE_CLASS
;
2047 else if ( classkeyword
== "struct" ) {
2048 pClass
->mClassSubType
= SP_CLTYPE_STRUCTURE
;
2050 mCurVis
= SP_VIS_PUBLIC
;
2052 else if ( classkeyword
== "union" ) {
2053 pClass
->mClassSubType
= SP_CLTYPE_UNION
;
2055 mCurVis
= SP_VIS_PUBLIC
;
2057 else if ( classkeyword
== "interface" )
2058 pClass
->mClassSubType
= SP_CLTYPE_INTERFACE
;
2060 pClass
->mClassSubType
= SP_CLTYPE_INVALID
;
2062 wxFAIL_MSG("unknown class keyword");
2065 mpCurCtx
->AddMember( pClass
);
2067 // attach comments about the class
2068 AttachComments( *pClass
, cur
);
2070 pClass
->mSrcLineNo
= get_line_no();
2072 pClass
->mSrcOffset
= int( ctxStart
- _gSrcStart
);
2074 char* nameTok
= cur
;
2075 pClass
->m_Name
= get_token_str( cur
);
2084 if ( !get_next_token( cur
) ) return;
2093 store_line_no( tmpLn
);
2095 skip_next_token_back( tok
);
2096 skip_token_back( tok
);
2098 restore_line_no( tmpLn
);
2100 // class name should precend ':' colon, thus
2101 // the one which was captured before was
2102 // proablty something else (like __dllexport MyClass : ... )
2104 if ( nameTok
!= tok
)
2106 pClass
->m_Name
= get_token_str( tok
);
2117 size_t len
= get_token_len( cur
);
2119 // skip neglectable C++ modifieres
2120 if ( cmp_tokens_fast( cur
, "public", len
) )
2123 if ( cmp_tokens_fast( cur
, "protected", len
) )
2126 if ( cmp_tokens_fast( cur
, "private", len
) )
2129 if ( cmp_tokens_fast( cur
, "virtual", len
) )
2132 // skip neglectable JAVA modifieres
2134 if ( cmp_tokens_fast( cur
, "extends", len
) )
2140 if ( cmp_tokens_fast( cur
, "implements", len
) )
2146 // all we need to know is superclass or interface
2150 store_line_no( tmpLn
);
2153 get_next_token(tok
);
2155 restore_line_no( tmpLn
);
2157 if ( *tok
!= ':' && *cur
!= ':' )
2159 pClass
->m_SuperClassNames
.push_back( wxString( cur
, len
) );
2166 store_line_no( tmpLn
);
2168 while ( pClass
->m_SuperClassNames
.size() )
2170 pClass
->m_SuperClassNames
.erase( &pClass
->m_SuperClassNames
[0] );
2174 // some non-obviouse token was following "class" keyword -
2175 // we've confused it with class name - thus now we're reverting this mistake
2177 skip_next_token_back( tok
);
2178 skip_token_back( tok
);
2180 pClass
->m_Name
= get_token_str( tok
);
2182 restore_line_no( tmpLn
);
2186 ++cur
; // skip opening curly brace
2188 pClass
->mHeaderLength
= ( cur
- ctxStart
);
2190 // now, enter the class context
2193 clear_commets_queue();
2196 void CJSourceParser::AddEnumNode( wxChar
*& cur
)
2198 // now the cursor is at "enum" keyword
2199 wxChar
* start
= cur
;
2201 spEnumeration
* pEnum
= new spEnumeration();
2202 mpCurCtx
->AddMember( pEnum
);
2204 pEnum
->mSrcLineNo
= get_line_no();
2207 AttachComments( *pEnum
, cur
);
2210 if ( !get_next_token( cur
) ) return;
2212 // check if enumeration has got it's identifier
2215 pEnum
->m_Name
= get_token_str( cur
);
2218 if ( !skip_imp_block( cur
) ) return;
2220 get_string_between( start
, cur
, &pEnum
->m_EnumContent
);
2222 if ( get_next_token(cur
) )
2224 // check if the identifier if after the {...} block
2227 pEnum
->m_Name
= get_token_str( cur
);
2230 clear_commets_queue();
2233 void CJSourceParser::AddTypeDefNode( wxChar
*& cur
)
2235 // now the cursor at the token next to "typedef" keyword
2237 if ( !get_next_token(cur
) ) return;
2239 wxChar
* start
= cur
;
2241 spTypeDef
* pTDef
= new spTypeDef();
2242 mpCurCtx
->AddMember( pTDef
);
2244 pTDef
->mSrcLineNo
= get_line_no();
2246 AttachComments( *pTDef
, cur
);
2248 skip_statement( cur
);
2251 store_line_no( tmpLnNo
);
2253 wxChar
* tok
= cur
-1;
2254 skip_next_token_back( tok
);
2256 wxChar
* nameEnd
= tok
;
2258 skip_token_back( tok
);
2260 wxChar
* nameStart
= tok
;
2262 skip_next_token_back( tok
);
2264 wxChar
* typeEnd
= tok
;
2266 // check if it's function prototype
2267 if ( *nameStart
== ')' )
2269 typeEnd
= nameStart
+1;
2271 // skip argument list
2272 while ( *nameStart
!= '(' ) --nameStart
;
2274 // skip to function type definition
2275 while ( *nameStart
!= ')' ) --nameStart
;
2277 skip_next_token_back( nameStart
);
2279 nameEnd
= nameStart
;
2281 skip_token_back( nameStart
);
2283 if ( *nameStart
== '*' ) ++nameStart
;
2286 get_string_between( start
, typeEnd
, &pTDef
->m_OriginalType
);
2288 get_string_between( nameStart
, nameEnd
, &pTDef
->m_Name
);
2290 clear_commets_queue();
2292 restore_line_no( tmpLnNo
);