]> git.saurik.com Git - wxWidgets.git/blob - utils/HelpGen/src/cjparser.cpp
glibc's vswprintf doesn't nul terminate on truncation.
[wxWidgets.git] / utils / HelpGen / src / cjparser.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: No names yet.
3 // Purpose: Contrib. demo
4 // Author: Aleksandras Gluchovas
5 // Modified by:
6 // Created: 22/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Aleskandars Gluchovas
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #ifndef WX_PRECOMP
20 #include "wx/wx.h"
21 #endif
22
23 #include "cjparser.h"
24
25 #if defined( wxUSE_TEMPLATE_STL )
26
27 #include <map>
28
29 #else
30
31 #include "wxstlac.h"
32
33 #endif
34
35
36 /***** Implementation for class SJParser *****/
37
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;
43
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;
48
49 /***** keyword map related structures *****/
50
51 struct less_c_str
52 {
53 inline bool operator()( char* x, char* y) const
54 { return ( strcmp( x,y ) < 0 );
55 }
56 };
57
58 //WXSTL_MAP(CharPtrT,CharPtrT, LESS_THEN_FUNCTOR(CharPtrT));
59
60 #if defined( wxUSE_TEMPLATE_STL )
61
62 typedef map< char*, char*, less_c_str > KeywordMapT;
63
64 #else
65
66 typedef char* CharPtrT;
67 typedef WXSTL_MAP( CharPtrT, CharPtrT ,less_c_str) KeywordMapT;
68
69 #endif
70
71 static KeywordMapT __gMultiLangMap;
72 static int __gMapReady = 0;
73
74 static char* __gKeyWords[] =
75 {
76 "public",
77 "protected",
78 "private",
79
80 "class",
81 "struct",
82 "union",
83 "enum",
84 "interface",
85
86 "package",
87 "import",
88
89 "typedef",
90 "template",
91 "friend",
92 "const",
93 "volatile",
94 "mutable",
95 "virtual",
96 "inline",
97 "static",
98 "register",
99
100 "final",
101 "abstract",
102 "native",
103
104 "__stdcall",
105 "extern",
106
107 0
108 };
109
110 static void check_keyword_map()
111 {
112 if ( !__gMapReady )
113 {
114 __gMapReady = 1;
115
116 // "make sure" the address of the first member of non-polimorphic class
117 // coinsides with the address of the instance
118
119 char** keyword = __gKeyWords;
120
121 while ( (*keyword) != 0 )
122 {
123 __gMultiLangMap.insert(
124 KeywordMapT::value_type( *keyword, *keyword )
125 );
126
127 ++keyword;
128 }
129 }
130 }
131
132 /***** helper functions *****/
133
134 static inline void skip_to_eol( char*& cur )
135 {
136 while( *(cur) != 10 && *cur != 13 && cur < _gSrcEnd) ++cur;
137 }
138
139 static inline void skip_eol( char*& cur )
140 {
141 if ( *cur == 13 )
142
143 cur += 2;
144 else
145 cur += 1;
146
147 ++_gLineNo;
148 }
149
150 static inline bool skip_to_next_comment_in_the_line( char*& cur )
151 {
152 do
153 {
154 while( cur < _gSrcEnd &&
155 *cur != 10 &&
156 *cur != 13 &&
157 *cur != '/'
158 ) ++cur;
159
160 if ( cur == _gSrcEnd ) return false;
161
162 if ( *cur == '/' )
163 {
164 if ( (*(cur+1) == '*') ||
165 (*(cur+1) == '/') ) return true;
166 else
167 {
168 ++cur;
169 continue;
170 }
171 }
172
173 return false;
174
175 } while(1);
176 }
177
178 inline static void store_line_no( int& toVar )
179 {
180 toVar = _gLineNo;
181 }
182
183 inline static void restore_line_no( int storedLineNo )
184 {
185 _gLineNo = storedLineNo;
186 }
187
188 inline static int get_line_no()
189 {
190 return _gLineNo;
191 }
192
193 static void skip_to_prev_line( char*& cur )
194 {
195 while( cur >= _gSrcStart &&
196 *cur != 10 &&
197 *cur != 13
198 ) --cur;
199
200 // NOTE:: '\n' is 13,10 for DOS
201 // '\n' is 10 for UNIX
202
203 // NOTE1: '\n' symbol is not used here,
204 // to provide possibility of loading
205 // file as binary
206
207 --cur;
208 if ( *cur == 10 )
209 {
210 ++cur;
211 return;
212 }
213
214 if ( *cur == 13 ) --cur;
215
216 while( cur >= _gSrcStart &&
217 *cur != 10 &&
218 *cur != 13
219 ) --cur;
220
221 ++cur; // move to the first character in the line
222 }
223
224 static inline void skip_comments( char*& cur )
225 {
226 ++cur; // skip '/' token
227
228 if ( *cur != '/' && *cur != '*' ) return;
229
230 // first, store position of the comment into the queue
231 // (which further will be attached to the next context
232 // found)
233
234 if ( cur-1 != _gLastSuppresedComment )
235 {
236 if ( _gCQSize == MAX_CQ_ENTRIES )
237 {
238 size_t i = MAX_CQ_ENTRIES-1;
239
240 while( i != 0 )
241 {
242 _gCommentsQueue[i-1] = _gCommentsQueue[i];
243 --i;
244 }
245
246 --_gCQSize ;
247 }
248
249 _gCommentsQueue[_gCQSize++] = cur-1;
250 }
251
252 // if signle-line comment, skip it now
253 if ( *cur == '/' )
254 {
255 skip_to_eol( cur );
256 skip_eol( cur );
257 return;
258 }
259
260 size_t level = 1;
261
262 // check for multiline comment (handle nested multiline comments!)
263
264 int line_len = 0;
265
266 ++cur;
267 ++cur;
268 do
269 {
270 // TBD:: check eof cond.
271
272 // detect and remove vertical columns of '*''s
273
274 while ( *cur != '/' && cur < _gSrcEnd )
275 {
276 switch (*cur)
277 {
278 case '*' :
279 {
280 if ( *(cur+1) != '/' )
281 {
282 if ( line_len == 1 )
283
284 *cur = ' ';
285 }
286
287 break;
288 }
289
290 case 13 : line_len = 0; break;
291 case 10 : { line_len = 0; ++_gLineNo; } break;
292
293 default : ++line_len;
294 }
295
296 ++cur;
297 }
298
299 if ( cur >= _gSrcEnd ) return;
300
301 ++cur;
302
303 if ( *(cur-2) == '*' )
304 {
305 --level;
306 if ( level == 0 )
307 break;
308 }
309 else
310 if ( *cur == '*' )
311 {
312 ++cur;
313 ++cur;
314
315 ++level;
316 }
317
318 } while(1);
319 }
320
321 static inline void clear_commets_queue()
322 {
323 _gCQSize = 0;
324 }
325
326 static inline void skip_quoted_string( char*& cur )
327 {
328 ++cur; // skip first quote '"'
329
330 // check if quote wasn't prefixed
331 if ( *(cur-2) == '\\' )
332 return;
333
334 do
335 {
336 while ( *cur != '"' && cur < _gSrcEnd )
337 {
338 if ( *cur == 10 ) ++_gLineNo;
339 ++cur;
340 }
341
342 if ( cur >= _gSrcEnd ) return;
343
344 ++cur; // skip the last quote
345
346 // check if it wasn't prefixed
347
348 if ( *(cur-2) != '\\' )
349 break;
350
351 } while (1);
352 }
353
354 // skips subsequent white space and comments
355 // (return false if the end of source code reached)
356
357 static inline bool get_next_token( char*& cur )
358 {
359 for( ; cur < _gSrcEnd; ++cur )
360 {
361 switch( *(cur) )
362 {
363 case ' ' : continue;
364 case '\t': continue;
365 case 13 : continue;
366
367 case 10 : { ++_gLineNo;continue; }
368
369 case '/' : skip_comments( cur );
370 --cur;
371 continue;
372
373 default : break;
374 };
375
376 break;
377 }
378
379 if ( cur >= _gSrcEnd )
380 return false;
381 else
382 return true;
383 }
384
385 static inline void skip_preprocessor_dir( wxChar*& cur )
386 {
387 do
388 {
389 skip_to_eol(cur);
390
391 if ( *(cur-1) != _T('\\') )
392 break;
393
394 if ( cur < _gSrcEnd )
395 skip_eol( cur );
396 else
397 break;
398
399 } while(1);
400 }
401
402 static void skip_token( char*& cur )
403 {
404 if ( *cur == '"' )
405 {
406 skip_quoted_string( cur );
407 return;
408 }
409
410 if ( *cur == ',' ||
411 *cur == ';' ||
412 *cur == ')' ||
413 *cur == '('
414 )
415 {
416 ++cur;
417 return;
418 }
419
420 // special case of "!=", "<=", ... 2 character composite tokens
421 if ( *cur == '<' ||
422 *cur == '>' ||
423 *cur == '=' ||
424 *cur == '!'
425 )
426 {
427 cur++;
428 if ( *cur == '=' )
429 cur++;
430
431 return;
432 }
433
434 ++cur; // leading character is always skipped
435
436 for( ; cur < _gSrcEnd ; ++cur )
437 {
438 switch ( *cur )
439 {
440 case ' ' : break;
441 case '\t': break;
442 case 13 : break;
443 case 10 : break;
444 case ',' : break;
445 case ';' : break;
446 case '<' : break;
447 case '>' : break;
448
449 // FIXME:: QUICK-HACK:: to treat scope resolution
450 // tokens are a part of the string - e.g. SomeSpace::SubName would
451 // become one token
452
453 case ':' : if ( *(cur+1) == ':' )
454 {
455 ++cur;
456 continue;
457 }
458
459 break;
460 case '=' : break;
461 case '(' : break;
462 case ')' : break;
463 case '{' : break;
464 case '}' : break;
465
466 default : continue;
467 };
468 break;
469 }
470 }
471
472 static inline size_t get_token_len( char* tok )
473 {
474 char* start = tok;
475
476 skip_token( tok );
477
478 return size_t( tok - start );
479 }
480
481 // returns true, if given tokens are equel
482
483 static inline bool cmp_tokens( char* tok1, char* tok2 )
484 {
485 // NOTE:: the case one token includes
486 // other in it's entirely is not handled
487
488 size_t len = get_token_len( tok1 );
489
490 // assuming that tokens are non-zero length
491
492 do
493 {
494 if ( *(tok1++) != *(tok2++) )
495 return false;
496
497 --len;
498
499 } while ( --len );
500
501 return true;
502 }
503
504 static inline bool cmp_tokens_fast( char* tok1, char* tok2, size_t len )
505 {
506 do
507 {
508 if ( *(tok1++) != *(tok2++) )
509 return false;
510
511 } while ( --len );
512
513 return true;
514 }
515
516 static inline void skip_tempalate_statement( char*& cur )
517 {
518 size_t level = 0;
519
520 // go one level deeper
521 while( *cur != '<' && cur < _gSrcEnd )
522 {
523 if (*cur == 10 ) ++_gLineNo;
524 ++cur;
525 }
526
527 // FIXME:: template should be checked statement for
528 // comments inside of it
529
530 do
531 {
532 if ( *cur == '<' )
533 ++level;
534 else
535 --level;
536
537 ++cur; // skip '<' or '>' token
538
539 if ( level == 0 )
540 return;
541
542 while( *cur != '<' && *cur != '>' && cur < _gSrcEnd )
543 {
544 if (*cur == 10 ) ++_gLineNo;
545 ++cur;
546 }
547
548 } while (1);
549 }
550
551 static inline void skip_statement( char*& cur )
552 {
553 for( ; cur < _gSrcEnd; ++cur )
554
555 switch (*cur)
556 {
557 case ';' : ++cur; // skip statement-terminator token
558 return;
559
560 case '"' : skip_quoted_string(cur);
561 --cur;
562 continue;
563
564 case 10 : ++_gLineNo;
565
566 continue;
567 case '/' : skip_comments( cur );
568 --cur;
569 continue;
570 default : continue;
571 }
572 }
573
574 // "reversed" versions of skip_token() and get_next_token()
575
576 static inline void skip_token_back( char*& cur )
577 {
578 // FIXME:: now, when moving backwards, neither strings nor
579 // comment blocks are checked
580
581 --cur; // skip to the trailing character
582
583 if ( *cur == ',' ||
584 *cur == ')' ||
585 *cur == '('
586 )
587 return;
588
589
590 for( ; cur < _gSrcEnd ; --cur )
591 {
592 switch ( *cur )
593 {
594 case ' ' : break;
595 case '\t': break;
596 case 13 : break;
597 case 10 : break;
598 case ',' : break;
599 case '(' : break;
600
601 default : continue;
602 };
603
604 break;
605 }
606
607 ++cur; // get to the leading character of the token
608 }
609
610 static inline void skip_next_token_back( char*& cur )
611 {
612 --cur; // skip leading character of the current token
613
614 if ( *cur == ',' ||
615 *cur == ')' ||
616 *cur == '('
617 )
618 {
619 ++cur;
620 return;
621 }
622
623 for( ; cur < _gSrcEnd; --cur )
624 {
625 switch ( *cur )
626 {
627 case ' ' : continue;
628 case '\t': continue;
629 case 13 : continue;
630 case 10 : continue;
631 case ',' : continue;
632 case '(' : continue;
633
634 default : break;
635 };
636
637 break;
638 }
639
640 ++cur; // position after the trailing charcter of the prev token
641 }
642
643 static wxString get_token_str( char* cur )
644 {
645 return wxString( cur, get_token_len( cur ) );
646 }
647
648 // skips token or whole expression which may have
649 // nested expressions between '(' ')' brackets.
650 //
651 // Upon return, the cursor points to the terminating bracket ')',
652 //
653 // Return value is the size of the block
654
655 static size_t skip_block( char*& cur )
656 {
657 size_t level = 0; // nesting level
658
659 char* start = cur;
660
661 // NOTE:: assumed that block not necessarely starts
662 // with bracket rightaway
663
664 if ( *cur == '(' )
665 {
666 ++level;
667 }
668
669 do
670 {
671 skip_token( cur );
672
673 char* savedPos = cur;
674 int tmpLnNo;
675 store_line_no( tmpLnNo );
676
677 get_next_token( cur );
678
679 if ( cur >= _gSrcEnd ) return 0;
680
681 if ( *cur == '(' )
682 {
683 ++level;
684 }
685 else
686 if ( *cur == ')' )
687 {
688 if ( level == 0 )
689 {
690 cur = savedPos;
691 restore_line_no( tmpLnNo );
692
693 return size_t(cur-start);
694 }
695
696 --level;
697
698 if ( level == 0 )
699 {
700 ++cur;
701
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
709
710 if ( *cur == '(' )
711 {
712 ++level;
713 continue;
714 }
715
716 else return size_t(cur-start);
717 }
718 }
719 else
720 {
721 if ( level == 0 )
722 {
723 cur = savedPos;
724 restore_line_no( tmpLnNo );
725
726 return size_t(cur-start);
727 }
728 }
729
730 } while(1);
731 }
732
733 // returns 0, if end of source reached
734 static inline bool skip_imp_block( char*& cur )
735 {
736 while( *cur != '{' && cur < _gSrcEnd )
737 {
738 skip_token( cur );
739 if ( !get_next_token( cur ) ) return false;
740 }
741
742 while( *cur != '}' && cur < _gSrcEnd )
743 {
744 skip_token( cur );
745 if ( !get_next_token( cur ) ) return false;
746 }
747
748 ++cur;
749
750 return true;
751 }
752
753 static bool is_class_token( char*& cur )
754 {
755 // FIXME:: the below mess should be cleaned in it's entirely
756
757 if ( *cur == 'i' )
758 if ( *(cur+1) == 'n' )
759
760 return cmp_tokens_fast( cur, "interface", 9 );
761
762 if ( *cur == 'c' )
763 if ( *(cur+1) == 'l' )
764
765 return cmp_tokens_fast( cur, "class", 5 );
766
767 if ( *cur == 's' )
768 if ( *(cur+1) == 't' )
769
770 return cmp_tokens_fast( cur, "struct", 6 );
771
772 if ( *cur == 'u' )
773 if ( *(cur+1) == 'n' )
774
775 return cmp_tokens_fast( cur, "union", 5 );
776
777 return false;
778 }
779
780 inline static bool is_forward_decl( char* cur )
781 {
782 do
783 {
784 switch( *cur )
785 {
786 case ':' : return false;
787 case '{' : return false;
788 case '(' : return false;
789
790 case ';' : return true;
791
792 default : break;
793 };
794
795 ++cur;
796
797 } while (cur < _gSrcEnd); // prevent running out of bounds
798
799 return false;
800 }
801
802 inline static bool is_function( char* cur, bool& isAMacro )
803 {
804 isAMacro = false;
805
806 int tmpLnNo;
807 store_line_no( tmpLnNo );
808
809 // NOTE:: comments and quoted strings are not checked here
810
811 // first,check for "single-line hanginging macros" like:
812 // ___UNICODE
813 //
814
815 char* eol = cur;
816 skip_to_eol( eol );
817
818 skip_token( cur );
819 get_next_token( cur );
820
821 if ( cur > eol )
822 {
823 isAMacro = true;
824 restore_line_no( tmpLnNo );
825
826 return true;
827 }
828
829 // it's not a macro, go to the begining of arg. list
830
831 do
832 {
833 // if bracket found, it's a function or a begining
834 // of some macro
835 if ( *cur == '(' )
836 {
837 restore_line_no( tmpLnNo );
838 return true;
839 }
840
841 // end of statement found without any brackets in it
842 // - it cannot be a function
843
844 if ( *cur == ';' )
845 {
846 restore_line_no( tmpLnNo );
847 return false;
848 }
849
850 ++cur;
851
852 } while( cur < _gSrcEnd);
853
854 isAMacro = 1;
855 restore_line_no( tmpLnNo );
856
857 return false;
858 }
859
860 // upon return the cursor is positioned after the
861 // terminating curly brace
862
863 static inline void skip_scope_block( char*& cur )
864 {
865 size_t level = 0;
866
867 for( ; cur < _gSrcEnd ; ++cur )
868
869 switch( *cur )
870 {
871 case '/' : skip_comments( cur );
872 --cur;
873 continue;
874 case '"' : skip_quoted_string( cur );
875 --cur;
876 continue;
877
878 case '{' : ++level;
879 continue;
880
881 case '}' :--level;
882 if ( level == 0 )
883 {
884 ++cur; // skip final closing curly brace
885 return;
886 }
887
888 case 10 : ++_gLineNo; continue;
889
890 default : continue;
891 };
892 }
893
894 // moves tokens like '*' '**', '***', '&' from the name
895 // to the type
896
897 static void arrange_indirection_tokens_between( wxString& type,
898 wxString& identifier )
899 {
900 // TBD:: FIXME:: return value of operators !
901
902 while ( identifier[0u] == _T('*') ||
903 identifier[0u] == _T('&')
904 )
905 {
906 type += identifier[0u];
907 identifier.erase(0,1);
908
909 if ( !identifier.length() ) return;
910 }
911 }
912
913
914 // the only function where multi-lang keyword map is accessed
915
916 static bool is_keyword( char* cur )
917 {
918 size_t len = get_token_len( cur );
919
920 // put a terminating zero after the given token
921 char tmp = *(cur + len);
922 *(cur+len) = '\0';
923
924 KeywordMapT::iterator i;
925
926 i = __gMultiLangMap.find( cur );
927
928 // restore original character suppresed by terminating zero
929 *(cur + len) = tmp;
930
931 return i == __gMultiLangMap.end() ? false : true;
932 }
933
934 static inline void get_string_between( wxChar* start, wxChar* end,
935 wxString* pStr )
936 {
937 char saved = *end;
938
939 *end = _T('\0');
940 *pStr = start;
941 *end = saved;
942 }
943
944 static wxChar* set_comment_text( wxString& text, wxChar* start )
945 {
946 wxChar* end = start;
947
948 // to avoid poluting the queue with this comment
949 _gLastSuppresedComment = start;
950
951 skip_comments( end );
952
953 if ( *(end-1) == _T('/') )
954 end -= 2;
955
956 start += 2;
957
958 // skip multiple leading '/''s or '*''s
959 while( *start == _T('/') && start < end ) ++start;
960 while( *start == _T('*') && start < end ) ++start;
961
962 get_string_between( start, end, &text );
963
964 return end;
965 }
966
967 /***** Implementation for class CJSourceParser *****/
968
969 CJSourceParser::CJSourceParser( bool collectCommnets, bool collectMacros )
970 : mpStart(0),
971 mpEnd(0),
972 mpCurCtx( 0 ),
973 mCommentsOn( collectCommnets ),
974 mMacrosOn ( collectMacros )
975 {
976 check_keyword_map();
977 }
978
979 spFile* CJSourceParser::Parse( char* start, char* end )
980 {
981 // set up state variables
982 mCurVis = SP_VIS_PRIVATE;
983
984 spFile* pTopCtx = new spFile();
985 mpCurCtx = pTopCtx;
986
987 mIsVirtual = 0;
988 mIsTemplate = 0;
989 mNestingLevel = 0;
990
991 m_cur = start;
992
993 mpStart = start;
994 mpEnd = end;
995
996 _gSrcEnd = mpEnd; // let all the C-functions "smell" the end of file
997 _gSrcStart = start;
998
999 _gLineNo = 0;
1000
1001 clear_commets_queue();
1002
1003 // main parsing loop
1004
1005 do
1006 {
1007 if ( !get_next_token( m_cur ) )
1008 // end of source reached
1009 return pTopCtx;
1010
1011 if ( memcmp( m_cur, "ScriptSection( const string&",
1012 strlen( "ScriptSection( const string&" )
1013 ) == 0
1014 )
1015 {
1016 // int o = 0;
1017 // ++o;
1018 }
1019
1020 switch (*m_cur)
1021 {
1022 case '#' :
1023 {
1024 AddMacroNode( m_cur );
1025 continue;
1026 }
1027
1028 case ':' :
1029 {
1030 skip_token( m_cur );
1031 continue;
1032 }
1033
1034 case ';' :
1035 {
1036 skip_token( m_cur );
1037 continue;
1038 }
1039
1040 case ')' :
1041 {
1042 skip_token( m_cur );
1043 continue;
1044 }
1045
1046 case '=' :
1047 {
1048 skip_token( m_cur );
1049 continue;
1050 }
1051
1052 default: break;
1053 }
1054
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 ) )
1057 {
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
1062
1063 ParseKeyword( m_cur );
1064 continue;
1065 }
1066
1067 if ( *m_cur >= _T('0') && *m_cur <= _T('9') )
1068 {
1069 skip_token( m_cur );
1070 continue;
1071 }
1072
1073 if ( *m_cur == _T('}') )
1074 {
1075 if ( mCurCtxType != SP_CTX_CLASS )
1076 {
1077 // FOR NOW:: disable the below assertion
1078
1079 // DBG:: unexpected closing-bracket found
1080 //ASSERT(0);
1081
1082 skip_token( m_cur ); // just skip it
1083 continue;
1084 }
1085
1086 if ( mpCurCtx->GetType() == SP_CTX_CLASS )
1087 {
1088 int curOfs = ( (m_cur+1) - _gSrcStart );
1089
1090 mpCurCtx->mContextLength = ( curOfs - mpCurCtx->mSrcOffset );
1091 }
1092
1093 --mNestingLevel;
1094
1095 // terminate operation/class/namespace context
1096 // TBD:: check if it's really this type of context
1097
1098 wxASSERT( mpCurCtx );
1099 mpCurCtx = mpCurCtx->GetOutterContext();
1100 wxASSERT( mpCurCtx );
1101
1102 if ( mNestingLevel == 0 )
1103 {
1104
1105 mCurCtxType = SP_CTX_FILE;
1106
1107 // not-nested class delclaration finished,
1108 // rest template flag in any case
1109 mIsTemplate = 0;
1110 }
1111
1112 skip_token( m_cur );
1113 continue;
1114 }
1115
1116 bool isAMacro = false;
1117
1118 if ( is_function( m_cur, isAMacro ) )
1119 {
1120 if ( isAMacro )
1121 {
1122 skip_token( m_cur );
1123 continue;
1124 }
1125
1126 char* savedPos = m_cur;
1127
1128 int tmpLnNo;
1129 store_line_no( tmpLnNo );
1130 wxUnusedVar( tmpLnNo );
1131
1132 isAMacro = false;
1133
1134 if ( !ParseNameAndRetVal( m_cur, isAMacro ) )
1135 {
1136 if ( !isAMacro )
1137 {
1138 m_cur = savedPos;
1139 SkipFunction( m_cur );
1140 }
1141 continue;
1142 }
1143
1144 if ( !ParseArguments( m_cur ) )
1145 {
1146 // failure while parsing arguments,
1147 // remove enclosing operation context
1148
1149 spContext* pFailed = mpCurCtx;
1150 mpCurCtx = mpCurCtx->GetOutterContext();
1151 mpCurCtx->RemoveChild( pFailed );
1152
1153 skip_to_eol( m_cur );
1154 //m_cur = savedPos;
1155 }
1156 else
1157 {
1158 // otherwise, successfully close operation context:
1159
1160 clear_commets_queue();
1161
1162 SkipFunctionBody( m_cur );
1163
1164 mpCurCtx = mpCurCtx->GetOutterContext();
1165
1166 // DBG::
1167 wxASSERT( mpCurCtx );
1168
1169 }
1170 }
1171 else // otherwise it's declaration of a variable;
1172 {
1173 // now, the cursor point to the end of statement (';' token)
1174
1175 if ( mCurCtxType != SP_CTX_CLASS )
1176 {
1177 // non-class members are ignored
1178
1179 skip_token( m_cur ); // skip the end of statement
1180 continue;
1181 }
1182
1183 ParseMemberVar( m_cur );
1184 }
1185
1186 } while( 1 );
1187 }
1188
1189 void CJSourceParser::AttachComments( spContext& ctx, wxChar* cur )
1190 {
1191 if ( !mCommentsOn ) return;
1192
1193 MCommentListT& lst = ctx.GetCommentList();
1194
1195 wxChar* prevComEnd = 0;
1196
1197 int tmpLnNo;
1198 store_line_no( tmpLnNo );
1199
1200 // attach comments which were found before the given context
1201
1202 for( int i = 0; i != _gCQSize; ++i )
1203 {
1204 spComment* pComment = new spComment();
1205 lst.push_back( pComment );
1206
1207 // find the end of comment
1208 wxChar* start = _gCommentsQueue[i];
1209
1210 pComment->mIsMultiline = ( *(start+1) == _T('*') );
1211
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
1215
1216 if ( i == 0 )
1217 {
1218 pComment->mStartsPar = true;
1219 }
1220 else if ( pComment->mIsMultiline )
1221 {
1222 pComment->mStartsPar = true;
1223 }
1224 else
1225 {
1226 // find out wheather there is a new-line
1227 // between to adjecent comments
1228
1229 wxChar* prevLine = start;
1230 skip_to_prev_line(prevLine);
1231
1232 if ( prevLine >= prevComEnd )
1233 pComment->mStartsPar = true;
1234 else
1235 pComment->mStartsPar = false;
1236 }
1237
1238 prevComEnd = set_comment_text( pComment->m_Text, start );
1239 }
1240
1241 // attach comments which are at the end of the line
1242 // of the given context (if any)
1243
1244 if ( skip_to_next_comment_in_the_line( cur ) )
1245 {
1246 spComment* pComment = new spComment();
1247 lst.push_back( pComment );
1248
1249 set_comment_text( pComment->m_Text, cur );
1250
1251 pComment->mStartsPar = 1;
1252 pComment->mIsMultiline = ( *(cur+1) == _T('*') );
1253
1254 // mark this comment, so that it would not
1255 // get in the comments list of the next context
1256 _gLastSuppresedComment = cur;
1257 }
1258
1259 restore_line_no( tmpLnNo );
1260
1261 clear_commets_queue();
1262 }
1263
1264 void CJSourceParser::AddMacroNode( wxChar*& cur )
1265 {
1266 wxChar* start = cur;
1267
1268 int lineNo = get_line_no();
1269
1270 skip_preprocessor_dir( cur );
1271
1272 int tmpLnNo;
1273 store_line_no( tmpLnNo );
1274
1275 if ( !mMacrosOn ) return;
1276
1277 spPreprocessorLine* pPL = new spPreprocessorLine();
1278 pPL->mSrcLineNo = lineNo;
1279
1280 AttachComments( *pPL, cur );
1281
1282 get_string_between( start, cur, &pPL->m_Line );
1283
1284 ++start; // skip '#'
1285 get_next_token( start );
1286
1287 pPL->mDefType = SP_PREP_DEF_OTHER;
1288
1289 // if we found a definition or redefinition,
1290 // determine the type exactly and assign
1291 // a name to the context
1292
1293 if ( *start == _T('d') )
1294 {
1295 if ( cmp_tokens_fast( start, _T("define"), 6 ) )
1296 {
1297 char* tok = start+6;
1298
1299 get_next_token( tok );
1300
1301 pPL->m_Name = get_token_str( tok );
1302
1303 skip_token( tok );
1304 get_next_token( tok);
1305
1306
1307 if ( tok > cur )
1308 pPL->mDefType = SP_PREP_DEF_DEFINE_SYMBOL;
1309 else
1310 pPL->mDefType = SP_PREP_DEF_REDEFINE_SYMBOL;
1311 }
1312 }
1313 else if ( *start == _T('i') )
1314 {
1315 if ( cmp_tokens_fast( start, _T("include"), 7 ) )
1316 {
1317 pPL->mDefType = SP_PREP_DEF_INCLUDE_FILE;
1318 }
1319 else if ( *++start == _T('f') )
1320 {
1321 // either "#if" or "#ifdef"
1322 cur = start;
1323 skip_token( cur );
1324 get_next_token( cur );
1325
1326 wxString condition = get_token_str( cur );
1327
1328 // currently, everything except '0' is true
1329 if ( condition == _T("0") ) {
1330 // skip until the following else or enif
1331 while ( cur < _gSrcEnd ) {
1332 skip_to_eol( cur );
1333 skip_eol( cur );
1334
1335 get_next_token( cur );
1336 if ( *cur++ == _T('#') && *cur == _T('e') )
1337 break;
1338 }
1339 }
1340
1341 // TODO parse the condition...
1342 }
1343 }
1344 else if ( cmp_tokens_fast( start, _T("else"), 4 ) )
1345 {
1346 // skip until "#endif"
1347 while ( cur < _gSrcEnd ) {
1348 skip_to_eol( cur );
1349 skip_eol( cur );
1350
1351 get_next_token( cur );
1352 if ( *cur++ == _T('#') && cmp_tokens_fast( cur, "endif", 5 ) )
1353 break;
1354 }
1355 }
1356
1357 mpCurCtx->AddMember( pPL );
1358
1359 skip_to_eol( cur );
1360 skip_eol( cur );
1361
1362 restore_line_no( tmpLnNo );
1363
1364 clear_commets_queue();
1365 }
1366
1367 void CJSourceParser::ParseKeyword( char*& cur )
1368 {
1369 // analyze token, which identifies the begining of a new context
1370
1371 if ( CheckVisibilty( cur ) )
1372 {
1373 skip_token( cur );
1374 return;
1375 }
1376
1377 if ( is_class_token( cur ) )
1378 {
1379 if ( is_forward_decl( cur ) )
1380 {
1381 // forward declarations are ignored;
1382 skip_token( cur );
1383 return;
1384 }
1385
1386 if ( mNestingLevel == 0 )
1387 {
1388 // change context form global class context
1389 mCurCtxType = SP_CTX_CLASS;
1390 }
1391
1392 ++mNestingLevel;
1393
1394 // add information about new class (name, inheritance, etc)
1395 AddClassNode( cur );
1396
1397 // the default visiblity for class members is 'private'
1398 mCurVis = SP_VIS_PRIVATE;
1399
1400 return;
1401 }
1402
1403 size_t len = get_token_len( cur );
1404
1405 if ( cmp_tokens_fast( cur, "typedef", len ) )
1406 {
1407 skip_token(cur);
1408 get_next_token(cur);
1409
1410 if ( cmp_tokens_fast( cur, "struct", len ) ||
1411 cmp_tokens_fast( cur, "union", len ) ||
1412 cmp_tokens_fast( cur, "class", len )
1413 )
1414 {
1415 if ( mNestingLevel == 0 )
1416 {
1417 // change context form global class context
1418 mCurCtxType = SP_CTX_CLASS;
1419 }
1420
1421 ++mNestingLevel;
1422
1423 // add information about new class (name, inheritance, etc)
1424 AddClassNode( cur );
1425
1426 // the default visiblity for class members is 'private'
1427 mCurVis = SP_VIS_PRIVATE;
1428
1429 return;
1430
1431 // FOR NOW:: typedef struct, etc are also ignored
1432 //skip_scope_block( cur );
1433 }
1434
1435 if ( cmp_tokens_fast( cur, "enum", len ) )
1436 {
1437 AddEnumNode( cur );
1438 return;
1439 }
1440
1441 AddTypeDefNode( cur );
1442
1443 return;
1444 }
1445
1446 if ( cmp_tokens_fast( cur, "enum", len ) )
1447 {
1448 AddEnumNode( cur );
1449 return;
1450 }
1451
1452 if ( cmp_tokens_fast( cur, "extern", len ) )
1453 {
1454 // extern's are ignored (both extern "C" and extern vars)
1455 while ( *cur != '{' &&
1456 *cur != ';' )
1457 {
1458 skip_token( cur );
1459 get_next_token( cur );
1460 }
1461 return;
1462
1463 }
1464 if ( cmp_tokens_fast( cur, "enum", len ) )
1465 {
1466 // enumeration blocks are ignored
1467
1468 skip_scope_block( cur );
1469
1470 get_next_token( cur );
1471 skip_token( cur ); // skip ';' token;
1472 return;
1473 }
1474
1475 if ( cmp_tokens_fast( cur, "package", len ) )
1476 {
1477 // packages are ignored
1478 skip_statement( cur );
1479 return;
1480 };
1481
1482 if ( cmp_tokens_fast( cur, "import", len ) )
1483 {
1484 // import statements are ignored
1485 skip_statement( cur );
1486 return;
1487 }
1488
1489 if ( cmp_tokens_fast( cur, "virtual", len ) )
1490 {
1491 // probably the virtual method is in front of us;
1492 mIsVirtual = 1;
1493 skip_token( cur );
1494 return;
1495 }
1496
1497 if ( cmp_tokens_fast( cur, "template", len ) )
1498 {
1499 mIsTemplate = 1;
1500 skip_tempalate_statement( cur );
1501 return;
1502 }
1503
1504 if ( cmp_tokens_fast( cur, "friend", len ) )
1505 {
1506 skip_statement( cur );
1507 return;
1508 }
1509
1510 // ingnore "unsigificant" tokens (i.e. which do not
1511 // affect the current parsing context)
1512
1513 skip_token( cur );
1514 }
1515
1516 bool CJSourceParser::ParseNameAndRetVal( char*& cur, bool& isAMacro )
1517 {
1518 isAMacro = false;
1519
1520 // FOR NOW:: all functions in the global
1521 // scope are ignored
1522
1523 int lineNo = get_line_no();
1524
1525 char* start = cur;
1526
1527 bool isVirtual = false;
1528 while( *cur != '(' )
1529 {
1530 if ( get_token_str( cur ) == "virtual" )
1531 isVirtual = true;
1532
1533 skip_token( cur );
1534 if ( !get_next_token( cur ) ) return false;
1535 }
1536
1537 char* bracketPos = cur;
1538 char* savedPos = cur + 1;
1539
1540 int tmpLnNo;
1541 store_line_no( tmpLnNo );
1542
1543 // skip gap between function name and start of paramters list
1544 while ( *(cur-1) == ' ' )
1545 --cur;
1546
1547 // check if it's not a macro, and let plugin handle it, if so
1548
1549 if ( mpPlugin )
1550 {
1551 skip_token_back( cur );
1552
1553 char* tmp = cur;
1554
1555 if ( mpPlugin->CanUnderstandContext( tmp, _gSrcEnd, mpCurCtx ) )
1556 {
1557 cur = tmp;
1558
1559 mpPlugin->ParseContext( _gSrcStart, cur, _gSrcEnd, mpCurCtx );
1560
1561 isAMacro = true;
1562
1563 return false;
1564 }
1565 }
1566
1567 spOperation* pOp = new spOperation();
1568
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;
1574
1575 mpCurCtx->AddMember( pOp );
1576 pOp->mVisibility = mCurVis;
1577 pOp->mIsVirtual = isVirtual;
1578
1579 // add comments about operation
1580 AttachComments( *pOp, cur );
1581
1582 // go backwards to method name
1583 skip_token_back( cur );
1584
1585 pOp->m_Name = get_token_str( cur );
1586
1587 // checker whether it's not an operator
1588 char chFirst = *pOp->m_Name.c_str();
1589 if ( !isalpha(chFirst) && chFirst != '_' && chFirst != '~' ) {
1590 // skip 'operator'
1591 skip_next_token_back( cur );
1592 skip_token_back( cur );
1593
1594 wxString lastToken = get_token_str( cur );
1595 if ( lastToken == "operator" ) {
1596 lastToken += pOp->m_Name;
1597 pOp->m_Name = lastToken;
1598 }
1599 else {
1600 // ok, it wasn't an operator after all
1601 skip_token( cur );
1602 }
1603 }
1604 else if ( pOp->m_Name == "operator" ) {
1605 skip_token( cur );
1606 get_next_token( cur );
1607 wxString oper = get_token_str( cur );
1608
1609 pOp->m_Name += oper;
1610 }
1611
1612 // go backwards to method return type
1613 skip_next_token_back( cur );
1614
1615 if ( cur >= start )
1616 {
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;
1624 }
1625
1626 arrange_indirection_tokens_between( pOp->m_RetType, pOp->m_Name );
1627
1628 cur = savedPos;
1629 restore_line_no( tmpLnNo );
1630
1631 // now, enter operation context
1632 mpCurCtx = pOp;
1633
1634 return true;
1635 }
1636
1637 bool CJSourceParser::ParseArguments( char*& cur )
1638 {
1639 // DANGER-MACROS::
1640
1641 // now cursor position is right after the first opening bracket
1642 // of the function declaration
1643
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)
1648 int blockSizes[16];
1649
1650 do
1651 {
1652 size_t blocksSkipped = 0;
1653
1654 get_next_token( cur );
1655
1656 bool first_blk = true;
1657
1658 while( *cur != ')' && *cur != ',' )
1659 {
1660 blocks[blocksSkipped] = cur;
1661
1662 if ( first_blk )
1663 {
1664 char* prev = cur;
1665 skip_token( cur );
1666
1667 blockSizes[blocksSkipped] = size_t(cur-prev);
1668
1669 first_blk = 0;
1670 }
1671 else
1672 blockSizes[blocksSkipped] = skip_block( cur );
1673
1674 get_next_token( cur );
1675 ++blocksSkipped;
1676 }
1677
1678
1679 if ( blocksSkipped == 1 )
1680 {
1681 // check if the empty arg. list stressed with "void" inside
1682 if ( cmp_tokens_fast( blocks[0] , "void", 4 ) )
1683 {
1684 cur++; // skip ')'
1685
1686 break;
1687 }
1688
1689 // FIXME:: TBD:: K&R-style function declarations!
1690
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
1694 return false;
1695 }
1696
1697 if ( blocksSkipped == 0 )
1698 {
1699 if ( *cur == 10 ) ++_gLineNo;
1700 ++cur; // skip ')'
1701
1702 break; // function without paramters
1703 }
1704
1705 // we should be in the operation context now
1706 spOperation* pOp = (spOperation*)mpCurCtx;
1707
1708 spParameter* pPar = new spParameter();
1709
1710 pOp->AddMember( pPar );
1711 // FOR NOW:: line number is not exact if argument list is mutiline
1712 pPar->mSrcLineNo = get_line_no();
1713
1714 size_t nameBlock = blocksSkipped - 1;
1715 size_t typeBlock = nameBlock - 1;
1716
1717 // check if default values present
1718 if ( *blocks[typeBlock] == '=' )
1719 {
1720 // expressions like "int = 5" are ignored,
1721 // since name for paramters is required
1722 if ( blocksSkipped == 3 )
1723 {
1724 if ( *cur == ')' )
1725 {
1726 ++cur;
1727 break;
1728 }
1729 else
1730 continue;
1731 }
1732
1733 pPar->m_InitVal = wxString( blocks[nameBlock], blockSizes[nameBlock] );
1734
1735 nameBlock = nameBlock - 2; // skip '=' token and default value block
1736 typeBlock = nameBlock - 1;
1737 }
1738
1739 // attach comments about the parameter
1740 AttachComments( *pPar, blocks[nameBlock] );
1741
1742 // retrieve argument name
1743 pPar->m_Name = wxString( blocks[nameBlock], blockSizes[nameBlock] );
1744
1745 // retreive argument type
1746
1747 size_t len = blockSizes[ typeBlock ];
1748 len = size_t ( (blocks[ typeBlock ] + len) - blocks[ 0 ] );
1749
1750 pPar->m_Type = wxString( blocks[0], len );
1751
1752 arrange_indirection_tokens_between( pPar->m_Type, pPar->m_Name );
1753
1754 if ( *cur == ')' )
1755 {
1756 ++cur;
1757 break;
1758 }
1759
1760 ++cur; // skip comma
1761 get_next_token(cur);
1762
1763 } while(1);
1764
1765 // skip possible whitespace between ')' and following "const"
1766 while ( isspace(*cur) )
1767 cur++;
1768
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 '{'
1772
1773 char* tok = cur;
1774
1775 int tmpLnNo;
1776 store_line_no( tmpLnNo );
1777
1778 bool result = true;
1779
1780 do
1781 {
1782 if ( *tok == '{' || *tok == ';' )
1783 {
1784 restore_line_no(tmpLnNo);
1785 break;
1786 }
1787
1788 // check for unexpected tokens
1789 if ( *tok == '=' || *tok == '0' )
1790 {
1791 skip_token(tok);
1792 if ( !get_next_token(tok) ) return false;
1793 continue;
1794 }
1795
1796 if ( *tok == '}' ) return false;
1797
1798 // if initialization list found
1799 if ( *tok == ':' )
1800 {
1801 restore_line_no(tmpLnNo);
1802 break;
1803 }
1804
1805 if ( cmp_tokens_fast( tok, "const", 5 ) )
1806 {
1807 ((spOperation*)mpCurCtx)->mIsConstant = true;
1808
1809 skip_token(tok);
1810 if ( !get_next_token(tok) ) return false;
1811 continue;
1812 }
1813
1814 if ( CheckVisibilty( tok ) ) return false;
1815
1816 // if next context found
1817 if ( is_keyword( tok ) ) return false;
1818
1819 skip_token(tok);
1820 if ( !get_next_token(tok) ) return false;
1821
1822 } while(1);
1823
1824 return result;
1825 }
1826
1827 void CJSourceParser::ParseMemberVar( char*& cur )
1828 {
1829 MMemberListT& members = mpCurCtx->GetMembers();
1830
1831 bool firstMember = true;
1832
1833 wxString type;
1834
1835 // jump to the end of statement
1836 // and start collecting same-type varibles
1837 // back-to-front towards the type identifier
1838
1839 skip_statement( cur );
1840 char* savedPos = cur;
1841
1842 int tmpLnNo;
1843 store_line_no( tmpLnNo );
1844
1845 --cur; // rewind back to ';'
1846
1847 do
1848 {
1849 spAttribute* pAttr = new spAttribute();
1850 // FOR NOW:: line not is not exact, if member declaration is multiline
1851 pAttr->mSrcLineNo = get_line_no();
1852
1853 mpCurCtx->AddMember( pAttr );
1854 pAttr->mVisibility = mCurVis;
1855
1856 pAttr->mIsConstant = 0;
1857
1858 if ( firstMember )
1859 {
1860 firstMember = 0;
1861 }
1862
1863 skip_token_back( cur );
1864
1865 // attach comments about the attribute
1866 AttachComments( *pAttr, cur );
1867
1868 pAttr->m_Name = get_token_str( cur );
1869
1870 // guessing that this going to be variable type
1871 skip_next_token_back( cur );
1872 skip_token_back( cur );
1873
1874 pAttr->m_Type = get_token_str( cur );
1875
1876 // if comma, than variable list continues
1877 // otherwise the variable type reached - stop
1878
1879 if ( *cur == _T('=') )
1880 {
1881 // yes, we've mistaken, it was not a identifier,
1882 // but it's default value
1883 pAttr->m_InitVal = pAttr->m_Name;
1884
1885 // skip default value and '=' symbol
1886 skip_next_token_back( cur );
1887 skip_token_back( cur );
1888
1889 pAttr->m_Name = get_token_str( cur );
1890
1891 skip_next_token_back( cur );
1892 skip_token_back( cur );
1893 }
1894
1895 if ( *cur != ',' )
1896 {
1897 type = get_token_str( cur );
1898 break;
1899 }
1900
1901 } while(1);
1902
1903 size_t first = 0;
1904
1905 // set up types for all collected (same-type) attributes;
1906 while ( first != members.size() - 1 )
1907 {
1908 spAttribute* pAttr = members[first++]->CastToAttribute();
1909 if ( !pAttr )
1910 continue;
1911
1912 if ( pAttr->m_Type.empty() )
1913 pAttr->m_Type = type;
1914 pAttr->mVisibility = mCurVis;
1915
1916 if ( !pAttr->m_Name.empty() )
1917 arrange_indirection_tokens_between( pAttr->m_Type, pAttr->m_Name );
1918 }
1919
1920 cur = savedPos;
1921 restore_line_no( tmpLnNo );
1922
1923 clear_commets_queue();
1924
1925
1926 }
1927
1928 void CJSourceParser::SkipFunction( char*& cur )
1929 {
1930 while ( *cur != '(' && cur < _gSrcEnd )
1931 {
1932 if (*cur == 10 ) ++_gLineNo;
1933 ++cur;
1934 }
1935
1936 skip_next_token_back( cur ); // go back and skip function identifier
1937 skip_token_back( cur ); // go back and skip return type
1938
1939 skip_block( cur ); // now, go ahead and skip whole declaration
1940
1941 SkipFunctionBody( cur );
1942
1943 }
1944
1945 void CJSourceParser::SkipFunctionBody( char*& cur )
1946 {
1947 // FIXME:: check for comments and quoted stirngs here
1948
1949 bool hasDefinition = false;
1950
1951 while( *cur != '{' && *cur != ';' )
1952 {
1953 if (*cur == 10 ) ++_gLineNo;
1954 ++cur;
1955 }
1956
1957 if ( *cur == ';' )
1958 {
1959 ++cur;
1960 }
1961 else
1962 {
1963 hasDefinition = true;
1964
1965 skip_scope_block( cur ); // skip the whole imp.
1966 }
1967
1968 if ( mpCurCtx->GetType() == SP_CTX_OPERATION )
1969 {
1970 spOperation& op = *((spOperation*)mpCurCtx);
1971
1972 int curOfs = int ( cur - _gSrcStart );
1973
1974 op.mContextLength = curOfs - mpCurCtx->mSrcOffset;
1975
1976 op.mHasDefinition = hasDefinition;
1977
1978 // separate scope resolution token from the name of operation
1979
1980 for( size_t i = 0; i != op.m_Name.length(); ++i )
1981 {
1982 if ( op.m_Name[i] == ':' && op.m_Name[i+1] == ':' )
1983 {
1984 wxString unscoped( op.m_Name, i+2, op.m_Name.length() - ( i + 2 ) );
1985
1986 op.mScope = wxString( op.m_Name, 0, i );
1987
1988 op.m_Name = unscoped;
1989
1990 break;
1991 }
1992 }
1993 }
1994 }
1995
1996 bool CJSourceParser::CheckVisibilty( char*& cur )
1997 {
1998 size_t len = get_token_len( cur );
1999
2000 if ( cmp_tokens_fast( cur, "public:", len ) )
2001 {
2002 mCurVis = SP_VIS_PUBLIC;
2003 return true;
2004 }
2005
2006 if ( cmp_tokens_fast( cur, "protected:", len ) )
2007 {
2008 mCurVis = SP_VIS_PROTECTED;
2009 return true;
2010 }
2011
2012 if ( cmp_tokens_fast( cur, "private:", len ) )
2013 {
2014 mCurVis = SP_VIS_PRIVATE;
2015 return true;
2016 }
2017
2018 return false;
2019 }
2020
2021 void CJSourceParser::AddClassNode( char*& cur )
2022 {
2023 char* ctxStart = cur;
2024
2025 wxString classkeyword = get_token_str( cur );
2026
2027 skip_token( cur ); // skip 'class' keyword
2028 if ( !get_next_token( cur ) ) return;
2029
2030 // in C++
2031 if ( *cur == ':' )
2032 {
2033 skip_token( cur );
2034 get_next_token( cur );
2035 }
2036
2037 // by default all class members are private
2038 mCurVis = SP_VIS_PRIVATE;
2039
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;
2045
2046 mCurVis = SP_VIS_PUBLIC;
2047 }
2048 else if ( classkeyword == "union" ) {
2049 pClass->mClassSubType = SP_CLTYPE_UNION;
2050
2051 mCurVis = SP_VIS_PUBLIC;
2052 }
2053 else if ( classkeyword == "interface" )
2054 pClass->mClassSubType = SP_CLTYPE_INTERFACE;
2055 else {
2056 pClass->mClassSubType = SP_CLTYPE_INVALID;
2057
2058 wxFAIL_MSG("unknown class keyword");
2059 }
2060
2061 mpCurCtx->AddMember( pClass );
2062
2063 // attach comments about the class
2064 AttachComments( *pClass, cur );
2065
2066 pClass->mSrcLineNo = get_line_no();
2067
2068 pClass->mSrcOffset = int( ctxStart - _gSrcStart );
2069
2070 char* nameTok = cur;
2071 pClass->m_Name = get_token_str( cur );
2072
2073 bool isDerived = 0;
2074
2075 // DANGER-MACROS::
2076
2077 do
2078 {
2079 skip_token( cur );
2080 if ( !get_next_token( cur ) ) return;
2081
2082 if ( *cur == ':' )
2083 {
2084 isDerived = 1;
2085
2086 char* tok = cur;
2087
2088 int tmpLn;
2089 store_line_no( tmpLn );
2090
2091 skip_next_token_back( tok );
2092 skip_token_back( tok );
2093
2094 restore_line_no( tmpLn );
2095
2096 // class name should precend ':' colon, thus
2097 // the one which was captured before was
2098 // proablty something else (like __dllexport MyClass : ... )
2099
2100 if ( nameTok != tok )
2101 {
2102 pClass->m_Name = get_token_str( tok );
2103 }
2104
2105 }
2106
2107 if ( *cur == '{' )
2108 break;
2109
2110 if ( *cur == ',' )
2111 continue;
2112
2113 size_t len = get_token_len( cur );
2114
2115 // skip neglectable C++ modifieres
2116 if ( cmp_tokens_fast( cur, "public", len ) )
2117 continue;
2118
2119 if ( cmp_tokens_fast( cur, "protected", len ) )
2120 continue;
2121
2122 if ( cmp_tokens_fast( cur, "private", len ) )
2123 continue;
2124
2125 if ( cmp_tokens_fast( cur, "virtual", len ) )
2126 continue;
2127
2128 // skip neglectable JAVA modifieres
2129
2130 if ( cmp_tokens_fast( cur, "extends", len ) )
2131 {
2132 isDerived = 1;
2133 continue;
2134 }
2135
2136 if ( cmp_tokens_fast( cur, "implements", len ) )
2137 {
2138 isDerived = 1;
2139 continue;
2140 }
2141
2142 // all we need to know is superclass or interface
2143
2144 char* tok = cur;
2145 int tmpLn;
2146 store_line_no( tmpLn );
2147
2148 skip_token(tok);
2149 get_next_token(tok);
2150
2151 restore_line_no( tmpLn );
2152
2153 if ( *tok != ':' && *cur != ':' )
2154
2155 pClass->m_SuperClassNames.push_back( wxString( cur, len ) );
2156
2157 } while(1);
2158
2159 if ( !isDerived )
2160 {
2161 int tmpLn;
2162 store_line_no( tmpLn );
2163
2164 while ( pClass->m_SuperClassNames.size() )
2165
2166 pClass->m_SuperClassNames.erase( &pClass->m_SuperClassNames[0] );
2167
2168 char* tok = cur;
2169
2170 // some non-obviouse token was following "class" keyword -
2171 // we've confused it with class name - thus now we're reverting this mistake
2172
2173 skip_next_token_back( tok );
2174 skip_token_back( tok );
2175
2176 pClass->m_Name = get_token_str( tok );
2177
2178 restore_line_no( tmpLn );
2179 }
2180
2181
2182 ++cur; // skip opening curly brace
2183
2184 pClass->mHeaderLength = ( cur - ctxStart );
2185
2186 // now, enter the class context
2187 mpCurCtx = pClass;
2188
2189 clear_commets_queue();
2190 }
2191
2192 void CJSourceParser::AddEnumNode( wxChar*& cur )
2193 {
2194 // now the cursor is at "enum" keyword
2195 wxChar* start = cur;
2196
2197 spEnumeration* pEnum = new spEnumeration();
2198 mpCurCtx->AddMember( pEnum );
2199
2200 pEnum->mSrcLineNo = get_line_no();
2201
2202
2203 AttachComments( *pEnum, cur );
2204
2205 skip_token( cur );
2206 if ( !get_next_token( cur ) ) return;
2207
2208 // check if enumeration has got it's identifier
2209 if ( *cur != '{' )
2210 {
2211 pEnum->m_Name = get_token_str( cur );
2212 }
2213
2214 if ( !skip_imp_block( cur ) ) return;
2215
2216 get_string_between( start, cur, &pEnum->m_EnumContent );
2217
2218 if ( get_next_token(cur) )
2219 {
2220 // check if the identifier if after the {...} block
2221 if ( *cur != ';' )
2222
2223 pEnum->m_Name = get_token_str( cur );
2224 }
2225
2226 clear_commets_queue();
2227 }
2228
2229 void CJSourceParser::AddTypeDefNode( wxChar*& cur )
2230 {
2231 // now the cursor at the token next to "typedef" keyword
2232
2233 if ( !get_next_token(cur) ) return;
2234
2235 wxChar* start = cur;
2236
2237 spTypeDef* pTDef = new spTypeDef();
2238 mpCurCtx->AddMember( pTDef );
2239
2240 pTDef->mSrcLineNo = get_line_no();
2241
2242 AttachComments( *pTDef, cur );
2243
2244 skip_statement( cur );
2245
2246 int tmpLnNo;
2247 store_line_no( tmpLnNo );
2248
2249 wxChar* tok = cur-1;
2250 skip_next_token_back( tok );
2251
2252 wxChar* nameEnd = tok;
2253
2254 skip_token_back( tok );
2255
2256 wxChar* nameStart = tok;
2257
2258 skip_next_token_back( tok );
2259
2260 wxChar* typeEnd = tok;
2261
2262 // check if it's function prototype
2263 if ( *nameStart == ')' )
2264 {
2265 typeEnd = nameStart+1;
2266
2267 // skip argument list
2268 while ( *nameStart != '(' ) --nameStart;
2269
2270 // skip to function type definition
2271 while ( *nameStart != ')' ) --nameStart;
2272
2273 skip_next_token_back( nameStart );
2274
2275 nameEnd = nameStart;
2276
2277 skip_token_back( nameStart );
2278
2279 if ( *nameStart == '*' ) ++nameStart;
2280 }
2281
2282 get_string_between( start, typeEnd, &pTDef->m_OriginalType );
2283
2284 get_string_between( nameStart, nameEnd, &pTDef->m_Name );
2285
2286 clear_commets_queue();
2287
2288 restore_line_no( tmpLnNo );
2289 }