]> git.saurik.com Git - wxWidgets.git/blob - utils/HelpGen/src/cjparser.cpp
e3ae0cbe4ea95d4e5360011f1883e24dd7db48b0
[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
1321 if ( *start == 'i' )
1322
1323 if ( cmp_tokens_fast( start, "include", 7 ) )
1324 {
1325 pPL->mDefType = SP_PREP_DEF_INCLUDE_FILE;
1326 }
1327
1328 mpCurCtx->AddMember( pPL );
1329
1330 restore_line_no( tmpLnNo );
1331
1332 clear_commets_queue();
1333 }
1334
1335 void CJSourceParser::ParseKeyword( char*& cur )
1336 {
1337 // analyze token, which identifies the begining of a new context
1338
1339 if ( CheckVisibilty( cur ) )
1340 {
1341 skip_token( cur );
1342 return;
1343 }
1344
1345 if ( is_class_token( cur ) )
1346 {
1347 if ( is_forward_decl( cur ) )
1348 {
1349 // forward declarations are ignored;
1350 skip_token( cur );
1351 return;
1352 }
1353
1354 if ( mNestingLevel == 0 )
1355 {
1356 // change context form global class context
1357 mCurCtxType = SP_CTX_CLASS;
1358 }
1359
1360 ++mNestingLevel;
1361
1362 // add information about new class (name, inheritance, etc)
1363 AddClassNode( cur );
1364
1365 // the default visiblity for class members is 'private'
1366 mCurVis = SP_VIS_PRIVATE;
1367
1368 return;
1369 }
1370
1371 size_t len = get_token_len( cur );
1372
1373 if ( cmp_tokens_fast( cur, "typedef", len ) )
1374 {
1375 skip_token(cur);
1376 get_next_token(cur);
1377
1378 if ( cmp_tokens_fast( cur, "struct", len ) ||
1379 cmp_tokens_fast( cur, "union", len ) ||
1380 cmp_tokens_fast( cur, "class", len )
1381 )
1382 {
1383 if ( mNestingLevel == 0 )
1384 {
1385 // change context form global class context
1386 mCurCtxType = SP_CTX_CLASS;
1387 }
1388
1389 ++mNestingLevel;
1390
1391 // add information about new class (name, inheritance, etc)
1392 AddClassNode( cur );
1393
1394 // the default visiblity for class members is 'private'
1395 mCurVis = SP_VIS_PRIVATE;
1396
1397 return;
1398
1399 // FOR NOW:: typedef struct, etc are also ignored
1400 //skip_scope_block( cur );
1401 }
1402
1403 if ( cmp_tokens_fast( cur, "enum", len ) )
1404 {
1405 AddEnumNode( cur );
1406 return;
1407 }
1408
1409 AddTypeDefNode( cur );
1410
1411 return;
1412 }
1413
1414 if ( cmp_tokens_fast( cur, "enum", len ) )
1415 {
1416 AddEnumNode( cur );
1417 return;
1418 }
1419
1420 if ( cmp_tokens_fast( cur, "extern", len ) )
1421 {
1422 // extern's are ignored (both extern "C" and extern vars)
1423 while ( *cur != '{' &&
1424 *cur != ';' )
1425 {
1426 skip_token( cur );
1427 get_next_token( cur );
1428 }
1429 return;
1430
1431 }
1432 if ( cmp_tokens_fast( cur, "enum", len ) )
1433 {
1434 // enumeration blocks are ignored
1435
1436 skip_scope_block( cur );
1437
1438 get_next_token( cur );
1439 skip_token( cur ); // skip ';' token;
1440 return;
1441 }
1442
1443 if ( cmp_tokens_fast( cur, "package", len ) )
1444 {
1445 // packages are ignored
1446 skip_statement( cur );
1447 return;
1448 };
1449
1450 if ( cmp_tokens_fast( cur, "import", len ) )
1451 {
1452 // import statements are ignored
1453 skip_statement( cur );
1454 return;
1455 }
1456
1457 if ( cmp_tokens_fast( cur, "virtual", len ) )
1458 {
1459 // probably the virtual method is in front of us;
1460 mIsVirtual = 1;
1461 skip_token( cur );
1462 return;
1463 }
1464
1465 if ( cmp_tokens_fast( cur, "template", len ) )
1466 {
1467 mIsTemplate = 1;
1468 skip_tempalate_statement( cur );
1469 return;
1470 }
1471
1472 if ( cmp_tokens_fast( cur, "friend", len ) )
1473 {
1474 skip_statement( cur );
1475 return;
1476 }
1477
1478 // ingnore "unsigificant" tokens (i.e. which do not
1479 // affect the current parsing context)
1480
1481 skip_token( cur );
1482 }
1483
1484 bool CJSourceParser::ParseNameAndRetVal( char*& cur, bool& isAMacro )
1485 {
1486 isAMacro = FALSE;
1487
1488 // FOR NOW:: all functions in the global
1489 // scope are ignored
1490
1491 int lineNo = get_line_no();
1492
1493 char* start = cur;
1494
1495 bool isVirtual = false;
1496 while( *cur != '(' )
1497 {
1498 if ( get_token_str( cur ) == "virtual" )
1499 isVirtual = true;
1500
1501 skip_token( cur );
1502 if ( !get_next_token( cur ) ) return FALSE;
1503 }
1504
1505 char* bracketPos = cur;
1506 char* savedPos = cur + 1;
1507
1508 int tmpLnNo;
1509 store_line_no( tmpLnNo );
1510
1511 // skip gap between function name and start of paramters list
1512 while ( *(cur-1) == ' ' )
1513 --cur;
1514
1515 // check if it's not a macro, and let plugin handle it, if so
1516
1517 if ( mpPlugin )
1518 {
1519 skip_token_back( cur );
1520
1521 char* tmp = cur;
1522
1523 if ( mpPlugin->CanUnderstandContext( tmp, _gSrcEnd, mpCurCtx ) )
1524 {
1525 cur = tmp;
1526
1527 mpPlugin->ParseContext( _gSrcStart, cur, _gSrcEnd, mpCurCtx );
1528
1529 isAMacro = TRUE;
1530
1531 return FALSE;
1532 }
1533 }
1534
1535 spOperation* pOp = new spOperation();
1536
1537 pOp->mSrcLineNo = lineNo;
1538 pOp->mSrcOffset = int( start - _gSrcStart );
1539 pOp->mHeaderLength = int( bracketPos - start );
1540
1541 mpCurCtx->AddMember( pOp );
1542 pOp->mVisibility = mCurVis;
1543 pOp->mIsVirtual = isVirtual;
1544
1545 // add comments about operation
1546 AttachComments( *pOp, cur );
1547
1548 // go backwards to method name
1549 skip_token_back( cur );
1550
1551 pOp->mName = get_token_str( cur );
1552
1553 // checker whether it's not an operator
1554 char chFirst = *pOp->mName.c_str();
1555 if ( !isalpha(chFirst) && chFirst != '_' && chFirst != '~' )
1556 {
1557 // skip 'operator'
1558 skip_next_token_back( cur );
1559 skip_token_back( cur );
1560
1561 string lastToken = get_token_str( cur );
1562 if ( lastToken == "operator" )
1563 {
1564 lastToken += pOp->mName;
1565 pOp->mName = lastToken;
1566 }
1567 else
1568 {
1569 // ok, it wasn't an operator after all
1570 skip_token( cur );
1571 }
1572 }
1573
1574 // go backwards to method return type
1575 skip_next_token_back( cur );
1576
1577 if ( cur >= start )
1578
1579 pOp->mRetType = string( start, size_t( cur-start ) );
1580
1581 arrange_indirection_tokens_between( pOp->mRetType, pOp->mName );
1582
1583 cur = savedPos;
1584 restore_line_no( tmpLnNo );
1585
1586 // now, enter operation context
1587 mpCurCtx = pOp;
1588
1589 return TRUE;
1590 }
1591
1592 bool CJSourceParser::ParseArguments( char*& cur )
1593 {
1594 // DANGER-MACROS::
1595
1596 // now cursor position is right after the first opening bracket
1597 // of the function declaration
1598
1599 char* blocks [16]; // used exclusivelly for iterative "lean out"
1600 // of macros and misc. not-obviouse grammar
1601 // (dirty,, but we cannot do it very nice,
1602 // we're not preprocessor-free C/C++ code)
1603 int blockSizes[16];
1604
1605 do
1606 {
1607 size_t blocksSkipped = 0;
1608
1609 get_next_token( cur );
1610
1611 bool first_blk = 1;
1612
1613 while( *cur != ')' && *cur != ',' )
1614 {
1615 blocks[blocksSkipped] = cur;
1616
1617 if ( first_blk )
1618 {
1619 char* prev = cur;
1620 skip_token( cur );
1621
1622 blockSizes[blocksSkipped] = size_t(cur-prev);
1623
1624 first_blk = 0;
1625 }
1626 else
1627 blockSizes[blocksSkipped] = skip_block( cur );
1628
1629 get_next_token( cur );
1630 ++blocksSkipped;
1631 }
1632
1633
1634 if ( blocksSkipped == 1 )
1635 {
1636 // check if the empty arg. list stressed with "void" inside
1637 if ( cmp_tokens_fast( blocks[0] , "void", 4 ) )
1638 {
1639 cur++; // skip ')'
1640
1641 break;
1642 }
1643
1644 // FIXME:: TBD:: K&R-style function declarations!
1645
1646 // if only one block enclosed, than it's probably
1647 // some macro, there should be at least two blocks,
1648 // one for argument type and another for it's identifier
1649 return FALSE;
1650 }
1651
1652 if ( blocksSkipped == 0 )
1653 {
1654 if ( *cur == 10 ) ++_gLineNo;
1655 ++cur; // skip ')'
1656
1657 break; // function without paramters
1658 }
1659
1660 // we should be in the operation context now
1661 spOperation* pOp = (spOperation*)mpCurCtx;
1662
1663 spParameter* pPar = new spParameter();
1664
1665 pOp->AddMember( pPar );
1666 // FOR NOW:: line number is not exact if argument list is mutiline
1667 pPar->mSrcLineNo = get_line_no();
1668
1669 size_t nameBlock = blocksSkipped - 1;
1670 size_t typeBlock = nameBlock - 1;
1671
1672 // check if default values present
1673 if ( *blocks[typeBlock] == '=' )
1674 {
1675 // expressions like "int = 5" are ignored,
1676 // since name for paramters is required
1677 if ( blocksSkipped == 3 )
1678 {
1679 if ( *cur == ')' )
1680 {
1681 ++cur;
1682 break;
1683 }
1684 else
1685 continue;
1686 }
1687
1688 pPar->mInitVal = string( blocks[nameBlock], blockSizes[nameBlock] );
1689
1690 nameBlock = nameBlock - 2; // skip '=' token and default value block
1691 typeBlock = nameBlock - 1;
1692 }
1693
1694 // attach comments about the parameter
1695 AttachComments( *pPar, blocks[nameBlock] );
1696
1697 // retrieve argument name
1698 pPar->mName = string( blocks[nameBlock], blockSizes[nameBlock] );
1699
1700 // retreive argument type
1701
1702 size_t len = blockSizes[ typeBlock ];
1703 len = size_t ( (blocks[ typeBlock ] + len) - blocks[ 0 ] );
1704
1705 pPar->mType = string( blocks[0], len );
1706
1707 arrange_indirection_tokens_between( pPar->mType, pOp->mName );
1708
1709 if ( *cur == ')' )
1710 {
1711 ++cur;
1712 break;
1713 }
1714
1715 ++cur; // skip comma
1716 get_next_token(cur);
1717
1718 } while(1);
1719
1720 // skip possible whitespace between ')' and following "const"
1721 while ( isspace(*cur) )
1722 cur++;
1723
1724 // check if it was really a function not a macro,
1725 // if so, than it should be terminated with semicolon ';'
1726 // or opening implemenetaton bracket '{'
1727
1728 char* tok = cur;
1729
1730 int tmpLnNo;
1731 store_line_no( tmpLnNo );
1732
1733 do
1734 {
1735 if ( *tok == '{' || *tok == ';' )
1736 {
1737 restore_line_no(tmpLnNo);
1738 return TRUE;
1739 }
1740
1741 // check for unexpected tokens
1742 if ( *tok == '=' || *tok == '0' )
1743 {
1744 skip_token(tok);
1745 if ( !get_next_token(tok) ) return FALSE;
1746 continue;
1747 }
1748
1749 if ( *tok == '}' ) return FALSE;
1750
1751 // if initialization list found
1752 if ( *tok == ':' )
1753 {
1754 restore_line_no(tmpLnNo);
1755 return TRUE;
1756 }
1757
1758 if ( cmp_tokens_fast( tok, "const", 5 ) )
1759 {
1760 ((spOperation*)mpCurCtx)->mIsConstant = true;
1761
1762 skip_token(tok);
1763 if ( !get_next_token(tok) ) return FALSE;
1764 continue;
1765 }
1766
1767 if ( CheckVisibilty( tok ) ) return FALSE;
1768
1769 // if next context found
1770 if ( is_keyword( tok ) ) return FALSE;
1771
1772 skip_token(tok);
1773 if ( !get_next_token(tok) ) return FALSE;
1774
1775 } while(1);
1776
1777 return TRUE;
1778 }
1779
1780 void CJSourceParser::ParseMemberVar( char*& cur )
1781 {
1782 MMemberListT& members = mpCurCtx->GetMembers();
1783
1784 bool firstMember = 1;
1785
1786 size_t first = 0;
1787
1788 string type;
1789
1790 // jump to the end of statement
1791 // and start collecting same-type varibles
1792 // back-to-front towards the type identifier
1793
1794 skip_statement( cur );
1795 char* savedPos = cur;
1796
1797 int tmpLnNo;
1798 store_line_no( tmpLnNo );
1799
1800 --cur; // rewind back to ';'
1801
1802 do
1803 {
1804 spAttribute* pAttr = new spAttribute();
1805 // FOR NOW:: line not is not exact, if member declaration is multiline
1806 pAttr->mSrcLineNo = get_line_no();
1807
1808 mpCurCtx->AddMember( pAttr );
1809 pAttr->mVisibility = mCurVis;
1810
1811 pAttr->mIsConstant = 0;
1812
1813 if ( firstMember )
1814 {
1815 firstMember = 0;
1816 first = members.size() - 1;;
1817 }
1818
1819 skip_token_back( cur );
1820
1821 // attach comments about the attribute
1822 AttachComments( *pAttr, cur );
1823
1824 pAttr->mName = get_token_str( cur );
1825
1826 // guessing that this going to be variable type
1827 skip_next_token_back( cur );
1828 skip_token_back( cur );
1829
1830 pAttr->mType = get_token_str( cur );
1831
1832 // if comma, than variable list continues
1833 // otherwise the variable type reached - stop
1834
1835 if ( *cur == '=' )
1836 {
1837 // yes, we've mistaken, it was not a identifier,
1838 // but it's default value
1839 pAttr->mInitVal =
1840 pAttr->mName;
1841
1842 // skip default value and '=' symbol
1843 skip_next_token_back( cur );
1844 skip_token_back( cur );
1845
1846 pAttr->mName = get_token_str( cur );
1847
1848 skip_next_token_back( cur );
1849 skip_token_back( cur );
1850 }
1851
1852 if ( *cur != ',' )
1853 {
1854 type = get_token_str( cur );
1855 break;
1856 }
1857
1858 } while(1);
1859
1860 // set up types for all collected (same-type) attributes;
1861 while ( first != members.size() - 1 )
1862 {
1863 spAttribute* pAttr = (spAttribute*)members[first];
1864
1865 pAttr->mType = type;
1866 pAttr->mVisibility = mCurVis;
1867
1868 arrange_indirection_tokens_between( pAttr->mType, pAttr->mName );
1869
1870 ++first;
1871 }
1872
1873 cur = savedPos;
1874 restore_line_no( tmpLnNo );
1875
1876 clear_commets_queue();
1877
1878
1879 }
1880
1881 void CJSourceParser::SkipFunction( char*& cur )
1882 {
1883 while ( *cur != '(' && cur < _gSrcEnd )
1884 {
1885 if (*cur == 10 ) ++_gLineNo;
1886 ++cur;
1887 }
1888
1889 skip_next_token_back( cur ); // go back and skip function identifier
1890 skip_token_back( cur ); // go back and skip return type
1891
1892 skip_block( cur ); // now, go ahead and skip whole declaration
1893
1894 SkipFunctionBody( cur );
1895
1896 }
1897
1898 void CJSourceParser::SkipFunctionBody( char*& cur )
1899 {
1900 // FIXME:: check for comments and quoted stirngs here
1901
1902 bool hasDefinition = FALSE;
1903
1904 while( *cur != '{' && *cur != ';' )
1905 {
1906 if (*cur == 10 ) ++_gLineNo;
1907 ++cur;
1908 }
1909
1910 if ( *cur == ';' )
1911 {
1912 ++cur;
1913 }
1914 else
1915 {
1916 hasDefinition = TRUE;
1917
1918 skip_scope_block( cur ); // skip the whole imp.
1919 }
1920
1921 if ( mpCurCtx->GetType() == SP_CTX_OPERATION )
1922 {
1923 spOperation& op = *((spOperation*)mpCurCtx);
1924
1925 int curOfs = int ( cur - _gSrcStart );
1926
1927 op.mContextLength = curOfs - mpCurCtx->mSrcOffset;
1928
1929 op.mHasDefinition = hasDefinition;
1930
1931 // separate scope resolution token from the name of operation
1932
1933 for( size_t i = 0; i != op.mName.length(); ++i )
1934 {
1935 if ( op.mName[i] == ':' && op.mName[i+1] == ':' )
1936 {
1937 string unscoped( op.mName, i+2, op.mName.length() - ( i + 2 ) );
1938
1939 op.mScope = string( op.mName, 0, i );
1940
1941 op.mName = unscoped;
1942
1943 break;
1944 }
1945 }
1946 }
1947 }
1948
1949 bool CJSourceParser::CheckVisibilty( char*& cur )
1950 {
1951 size_t len = get_token_len( cur );
1952
1953 if ( cmp_tokens_fast( cur, "public:", len ) )
1954 {
1955 mCurVis = SP_VIS_PUBLIC;
1956 return TRUE;
1957 }
1958
1959 if ( cmp_tokens_fast( cur, "protected:", len ) )
1960 {
1961 mCurVis = SP_VIS_PROTECTED;
1962 return TRUE;
1963 }
1964
1965 if ( cmp_tokens_fast( cur, "private:", len ) )
1966 {
1967 mCurVis = SP_VIS_PRIVATE;
1968 return TRUE;
1969 }
1970
1971 return FALSE;
1972 }
1973
1974 void CJSourceParser::AddClassNode( char*& cur )
1975 {
1976 char* ctxStart = cur;
1977
1978 skip_token( cur ); // skip 'class' keyword
1979 if ( !get_next_token( cur ) ) return;
1980
1981 // in C++
1982 if ( *cur == ':' )
1983 {
1984 skip_token( cur );
1985 get_next_token( cur );
1986 }
1987
1988 spClass* pClass = new spClass();
1989
1990
1991 mpCurCtx->AddMember( pClass );
1992
1993 // by default all class members are private
1994 mCurVis = SP_VIS_PRIVATE;
1995
1996 // attach comments about the class
1997 AttachComments( *pClass, cur );
1998
1999 pClass->mSrcLineNo = get_line_no();
2000
2001 pClass->mSrcOffset = int( ctxStart - _gSrcStart );
2002
2003 char* nameTok = cur;
2004 pClass->mName = get_token_str( cur );
2005
2006 bool isDerived = 0;
2007
2008 // DANGER-MACROS::
2009
2010 do
2011 {
2012 skip_token( cur );
2013 if ( !get_next_token( cur ) ) return;
2014
2015 if ( *cur == ':' )
2016 {
2017 isDerived = 1;
2018
2019 char* tok = cur;
2020
2021 int tmpLn;
2022 store_line_no( tmpLn );
2023
2024 skip_next_token_back( tok );
2025 skip_token_back( tok );
2026
2027 restore_line_no( tmpLn );
2028
2029 // class name should precend ':' colon, thus
2030 // the one which was captured before was
2031 // proablty something else (like __dllexport MyClass : ... )
2032
2033 if ( nameTok != tok )
2034 {
2035 pClass->mName = get_token_str( tok );
2036 }
2037
2038 }
2039
2040 if ( *cur == '{' )
2041 break;
2042
2043 if ( *cur == ',' )
2044 continue;
2045
2046 size_t len = get_token_len( cur );
2047
2048 // skip neglectable C++ modifieres
2049 if ( cmp_tokens_fast( cur, "public", len ) )
2050 continue;
2051
2052 if ( cmp_tokens_fast( cur, "protected", len ) )
2053 continue;
2054
2055 if ( cmp_tokens_fast( cur, "private", len ) )
2056 continue;
2057
2058 if ( cmp_tokens_fast( cur, "virtual", len ) )
2059 continue;
2060
2061 // skip neglectable JAVA modifieres
2062
2063 if ( cmp_tokens_fast( cur, "extends", len ) )
2064 {
2065 isDerived = 1;
2066 continue;
2067 }
2068
2069 if ( cmp_tokens_fast( cur, "implements", len ) )
2070 {
2071 isDerived = 1;
2072 continue;
2073 }
2074
2075 // all we need to know is superclass or interface
2076
2077 char* tok = cur;
2078 int tmpLn;
2079 store_line_no( tmpLn );
2080
2081 skip_token(tok);
2082 get_next_token(tok);
2083
2084 restore_line_no( tmpLn );
2085
2086 if ( *tok != ':' && *cur != ':' )
2087
2088 pClass->mSuperClassNames.push_back( string( cur, len ) );
2089
2090 } while(1);
2091
2092 if ( !isDerived )
2093 {
2094 int tmpLn;
2095 store_line_no( tmpLn );
2096
2097 while ( pClass->mSuperClassNames.size() )
2098
2099 pClass->mSuperClassNames.erase( &pClass->mSuperClassNames[0] );
2100
2101 char* tok = cur;
2102
2103 // some non-obviouse token was following "class" keyword -
2104 // we've confused it with class name - thus now we're reverting this mistake
2105
2106 skip_next_token_back( tok );
2107 skip_token_back( tok );
2108
2109 pClass->mName = get_token_str( tok );
2110
2111 restore_line_no( tmpLn );
2112 }
2113
2114
2115 ++cur; // skip opening curly brace
2116
2117 pClass->mHeaderLength = ( cur - ctxStart );
2118
2119 // now, enter the class context
2120 mpCurCtx = pClass;
2121
2122 clear_commets_queue();
2123 }
2124
2125 void CJSourceParser::AddEnumNode( char*& cur )
2126 {
2127 // now the cursor is at "enum" keyword
2128 char* start = cur;
2129
2130 spEnumeration* pEnum = new spEnumeration();
2131 mpCurCtx->AddMember( pEnum );
2132
2133 pEnum->mSrcLineNo = get_line_no();
2134
2135
2136 AttachComments( *pEnum, cur );
2137
2138 skip_token( cur );
2139 if ( !get_next_token( cur ) ) return;
2140
2141 // check if enumeration has got it's identifier
2142 if ( *cur != '{' )
2143 {
2144 pEnum->mName = get_token_str( cur );
2145 }
2146
2147 if ( !skip_imp_block( cur ) ) return;
2148
2149 get_string_between( start, cur, &pEnum->mEnumContent );
2150
2151 if ( get_next_token(cur) )
2152 {
2153 // check if the identifier if after the {...} block
2154 if ( *cur != ';' )
2155
2156 pEnum->mName = get_token_str( cur );
2157 }
2158
2159 clear_commets_queue();
2160 }
2161
2162 void CJSourceParser::AddTypeDefNode( char*& cur )
2163 {
2164 // now the cursor at the token next to "typedef" keyword
2165
2166 if ( !get_next_token(cur) ) return;
2167
2168 char* start = cur;
2169
2170 spTypeDef* pTDef = new spTypeDef();
2171 mpCurCtx->AddMember( pTDef );
2172
2173 pTDef->mSrcLineNo = get_line_no();
2174
2175 AttachComments( *pTDef, cur );
2176
2177 skip_statement( cur );
2178
2179 int tmpLnNo;
2180 store_line_no( tmpLnNo );
2181
2182 char* tok = cur-1;
2183 skip_next_token_back( tok );
2184
2185 char* nameEnd = tok;
2186
2187 skip_token_back( tok );
2188
2189 char* nameStart = tok;
2190
2191 skip_next_token_back( tok );
2192
2193 char* typeEnd = tok;
2194
2195 // check if it's function prototype
2196 if ( *nameStart == ')' )
2197 {
2198 typeEnd = nameStart+1;
2199
2200 // skip argument list
2201 while ( *nameStart != '(' ) --nameStart;
2202
2203 // skip to function type definition
2204 while ( *nameStart != ')' ) --nameStart;
2205
2206 skip_next_token_back( nameStart );
2207
2208 nameEnd = nameStart;
2209
2210 skip_token_back( nameStart );
2211
2212 if ( *nameStart == '*' ) ++nameStart;
2213 }
2214
2215 get_string_between( start, typeEnd, &pTDef->mOriginalType );
2216
2217 get_string_between( nameStart, nameEnd, &pTDef->mName );
2218
2219 clear_commets_queue();
2220
2221 restore_line_no( tmpLnNo );
2222 }