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