]> git.saurik.com Git - wxWidgets.git/blob - utils/HelpGen/src/cjparser.cpp
b6d1dd751469d0d49d1cf67c8a98da0931095a50
[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 *cur == '=' ||
421 *cur == ')' ||
422 *cur == '('
423 )
424 {
425 ++cur;
426 return;
427 }
428
429 ++cur; // leading character is always skipped
430
431 for( ; cur < _gSrcEnd ; ++cur )
432 {
433 switch ( *cur )
434 {
435 case ' ' : break;
436 case '\t': break;
437 case 13 : break;
438 case 10 : break;
439 case ',' : break;
440 case ';' : break;
441 case '<' : break;
442 case '>' : break;
443
444 // FIXME:: QUICK-HACK:: to treat scope resolution
445 // tokens are a part of the string - e.g. SomeSpace::SubName would
446 // become one token
447
448 case ':' : if ( *(cur+1) == ':' )
449 {
450 ++cur;
451 continue;
452 }
453
454 break;
455 case '=' : break;
456 case '(' : break;
457 case ')' : break;
458 case '{' : break;
459 case '}' : break;
460
461 default : continue;
462 };
463 break;
464 }
465 }
466
467 static inline size_t get_token_len( char* tok )
468 {
469 char* start = tok;
470
471 skip_token( tok );
472
473 return size_t( tok - start );
474 }
475
476 // returns true, if given tokens are equel
477
478 static inline bool cmp_tokens( char* tok1, char* tok2 )
479 {
480 // NOTE:: the case one token includes
481 // other in it's entirely is not handled
482
483 size_t len = get_token_len( tok1 );
484
485 // assuming that tokens are non-zero length
486
487 do
488 {
489 if ( *(tok1++) != *(tok2++) )
490 return FALSE;
491
492 --len;
493
494 } while ( --len );
495
496 return TRUE;
497 }
498
499 static inline bool cmp_tokens_fast( char* tok1, char* tok2, size_t len )
500 {
501 do
502 {
503 if ( *(tok1++) != *(tok2++) )
504 return FALSE;
505
506 } while ( --len );
507
508 return TRUE;
509 }
510
511 static inline void skip_tempalate_statement( char*& cur )
512 {
513 size_t level = 0;
514
515 // go one level deeper
516 while( *cur != '<' && cur < _gSrcEnd )
517 {
518 if (*cur == 10 ) ++_gLineNo;
519 ++cur;
520 }
521
522 // FIXME:: template should be checked statement for
523 // comments inside of it
524
525 do
526 {
527 if ( *cur == '<' )
528 ++level;
529 else
530 --level;
531
532 ++cur; // skip '<' or '>' token
533
534 if ( level == 0 )
535 return;
536
537 while( *cur != '<' && *cur != '>' && cur < _gSrcEnd )
538 {
539 if (*cur == 10 ) ++_gLineNo;
540 ++cur;
541 }
542
543 } while (1);
544 }
545
546 static inline void skip_statement( char*& cur )
547 {
548 for( ; cur < _gSrcEnd; ++cur )
549
550 switch (*cur)
551 {
552 case ';' : ++cur; // skip statement-terminator token
553 return;
554
555 case '"' : skip_quoted_string(cur);
556 --cur;
557 continue;
558
559 case 10 : ++_gLineNo;
560
561 continue;
562 case '/' : skip_comments( cur );
563 --cur;
564 continue;
565 default : continue;
566 }
567 }
568
569 // "reversed" versions of skip_token() and get_next_token()
570
571 static inline void skip_token_back( char*& cur )
572 {
573 // FIXME:: now, when moving backwards, neither strings nor
574 // comment blocks are checked
575
576 --cur; // skip to the trailing character
577
578 if ( *cur == ',' ||
579 *cur == ')' ||
580 *cur == '('
581 )
582 return;
583
584
585 for( ; cur < _gSrcEnd ; --cur )
586 {
587 switch ( *cur )
588 {
589 case ' ' : break;
590 case '\t': break;
591 case 13 : break;
592 case 10 : break;
593 case ',' : break;
594 case '(' : break;
595
596 default : continue;
597 };
598
599 break;
600 }
601
602 ++cur; // get to the leading character of the token
603 }
604
605 static inline void skip_next_token_back( char*& cur )
606 {
607 --cur; // skip leading character of the current token
608
609 if ( *cur == ',' ||
610 *cur == ')' ||
611 *cur == '('
612 )
613 {
614 ++cur;
615 return;
616 }
617
618 for( ; cur < _gSrcEnd; --cur )
619 {
620 switch ( *cur )
621 {
622 case ' ' : continue;
623 case '\t': continue;
624 case 13 : continue;
625 case 10 : continue;
626 case ',' : continue;
627 case '(' : continue;
628
629 default : break;
630 };
631
632 break;
633 }
634
635 ++cur; // position after the trailing charcter of the prev token
636 }
637
638 static string get_token_str( char* cur )
639 {
640 return string( cur, get_token_len( cur ) );
641 }
642
643 // skips token or whole expression which may have
644 // nested expressions between '(' ')' brackets.
645 //
646 // Upon return, the cursor points to the terminating bracket ')',
647 //
648 // Return value is the size of the block
649
650 static size_t skip_block( char*& cur )
651 {
652 size_t level = 0; // nesting level
653
654 char* start = cur;
655
656 // NOTE:: assumed that block not necessarely starts
657 // with bracket rightaway
658
659 if ( *cur == '(' )
660 {
661 ++level;
662 }
663
664 do
665 {
666 skip_token( cur );
667
668 char* savedPos = cur;
669 int tmpLnNo;
670 store_line_no( tmpLnNo );
671
672 get_next_token( cur );
673
674 if ( cur >= _gSrcEnd ) return 0;
675
676 if ( *cur == '(' )
677 {
678 ++level;
679 }
680 else
681 if ( *cur == ')' )
682 {
683 if ( level == 0 )
684 {
685 cur = savedPos;
686 restore_line_no( tmpLnNo );
687
688 return size_t(cur-start);
689 }
690
691 --level;
692
693 if ( level == 0 )
694 {
695 ++cur;
696
697 // QUICK-HACK::to easily handle function prototypes ,
698 // it works, besause theoretically there should
699 // be no cast-expressions in non-implementation
700 // scope (e.g. "time( (long*)(ptr+1) )" should not
701 // appear in the declarations, thus it is most likelly
702 // for the ")(" fragment to be within a function
703 // prototype in the declarations scope
704
705 if ( *cur == '(' )
706 {
707 ++level;
708 continue;
709 }
710
711 else return size_t(cur-start);
712 }
713 }
714 else
715 {
716 if ( level == 0 )
717 {
718 cur = savedPos;
719 restore_line_no( tmpLnNo );
720
721 return size_t(cur-start);
722 }
723 }
724
725 } while(1);
726 }
727
728 // returns 0, if end of source reached
729 static inline bool skip_imp_block( char*& cur )
730 {
731 while( *cur != '{' && cur < _gSrcEnd )
732 {
733 skip_token( cur );
734 if ( !get_next_token( cur ) ) return FALSE;
735 }
736
737 while( *cur != '}' && cur < _gSrcEnd )
738 {
739 skip_token( cur );
740 if ( !get_next_token( cur ) ) return FALSE;
741 }
742
743 ++cur;
744
745 return TRUE;
746 }
747
748 static bool is_class_token( char*& cur )
749 {
750 // FIXME:: the below mess should be cleaned in it's entirely
751
752 if ( *cur == 'i' )
753 if ( *(cur+1) == 'n' )
754
755 return cmp_tokens_fast( cur, "interface", 9 );
756
757 if ( *cur == 'c' )
758 if ( *(cur+1) == 'l' )
759
760 return cmp_tokens_fast( cur, "class", 5 );
761
762 if ( *cur == 's' )
763 if ( *(cur+1) == 't' )
764
765 return cmp_tokens_fast( cur, "struct", 6 );
766
767 if ( *cur == 'u' )
768 if ( *(cur+1) == 'n' )
769
770 return cmp_tokens_fast( cur, "union", 5 );
771
772 return FALSE;
773 }
774
775 inline static bool is_forward_decl( char* cur )
776 {
777 do
778 {
779 switch( *cur )
780 {
781 case ':' : return FALSE;
782 case '{' : return FALSE;
783 case '(' : return FALSE;
784
785 case ';' : return TRUE;
786
787 default : break;
788 };
789
790 ++cur;
791
792 } while (cur < _gSrcEnd); // prevent running out of bounds
793
794 return FALSE;
795 }
796
797 inline static bool is_function( char* cur, bool& isAMacro )
798 {
799 isAMacro = FALSE;
800
801 int tmpLnNo;
802 store_line_no( tmpLnNo );
803
804 // NOTE:: comments and quoted strings are not checked here
805
806 // first,check for "single-line hanginging macros" like:
807 // ___UNICODE
808 //
809
810 char* eol = cur;
811 skip_to_eol( eol );
812
813 skip_token( cur );
814 get_next_token( cur );
815
816 if ( cur > eol )
817 {
818 isAMacro = TRUE;
819 restore_line_no( tmpLnNo );
820
821 return TRUE;
822 }
823
824 // it's not a macro, go to the begining of arg. list
825
826 do
827 {
828 // if bracket found, it's a function or a begining
829 // of some macro
830 if ( *cur == '(' )
831 {
832 restore_line_no( tmpLnNo );
833 return TRUE;
834 }
835
836 // end of statement found without any brackets in it
837 // - it cannot be a function
838
839 if ( *cur == ';' )
840 {
841 restore_line_no( tmpLnNo );
842 return FALSE;
843 }
844
845 ++cur;
846
847 } while( cur < _gSrcEnd);
848
849 isAMacro = 1;
850 restore_line_no( tmpLnNo );
851
852 return FALSE;
853 }
854
855 // upon return the cursor is positioned after the
856 // terminating curly brace
857
858 static inline void skip_scope_block( char*& cur )
859 {
860 size_t level = 0;
861
862 for( ; cur < _gSrcEnd ; ++cur )
863
864 switch( *cur )
865 {
866 case '/' : skip_comments( cur );
867 --cur;
868 continue;
869 case '"' : skip_quoted_string( cur );
870 --cur;
871 continue;
872
873 case '{' : ++level;
874 continue;
875
876 case '}' :--level;
877 if ( level == 0 )
878 {
879 ++cur; // skip final closing curly brace
880 return;
881 }
882
883 case 10 : ++_gLineNo; continue;
884
885 default : continue;
886 };
887 }
888
889 // moves tokens like '*' '**', '***', '&' from the name
890 // to the type
891
892 static void arrange_indirection_tokens_between( string& type,
893 string& identifier )
894 {
895 // TBD:: FIXME:: return value of operators !
896
897 while ( identifier[0] == '*' ||
898 identifier[0] == '&'
899 )
900 {
901 type += identifier[0];
902 identifier.erase(0,1);
903
904 if ( !identifier.length() ) return;
905 }
906 }
907
908
909 // the only function where multi-lang keyword map is accessed
910
911 static bool is_keyword( char* cur )
912 {
913 size_t len = get_token_len( cur );
914
915 // put a terminating zero after the given token
916 char tmp = *(cur + len);
917 *(cur+len) = '\0';
918
919 KeywordMapT::iterator i;
920
921 i = __gMultiLangMap.find( cur );
922
923 // restore original character suppresed by terminating zero
924 *(cur + len) = tmp;
925
926 return i == __gMultiLangMap.end() ? false : true;
927 }
928
929 static inline void get_string_between( char* start, char* end,
930 string* pStr )
931 {
932 char saved = *end;
933
934 *end = '\0';
935 *pStr = start;
936 *end = saved;
937 }
938
939 static char* set_comment_text( string& text, char* start )
940 {
941 char* end = start;
942
943 // to avoid poluting the queue with this comment
944 _gLastSuppresedComment = start;
945
946 skip_comments( end );
947
948 if ( *(end-1) == '/' )
949 end -= 2;
950
951 start += 2;
952
953 // skip multiple leading '/''s or '*''s
954 while( *start == '/' && start < end ) ++start;
955 while( *start == '*' && start < end ) ++start;
956
957 get_string_between( start, end, &text );
958
959 return end;
960 }
961
962 /***** Implementation for class CJSourceParser *****/
963
964 CJSourceParser::CJSourceParser( bool collectCommnets, bool collectMacros )
965 : mpStart(0),
966 mpEnd(0),
967 mpCurCtx( 0 ),
968 mCommentsOn( collectCommnets ),
969 mMacrosOn ( collectMacros )
970 {
971 check_keyword_map();
972 }
973
974 spFile* CJSourceParser::Parse( char* start, char* end )
975 {
976 // set up state variables
977 mCurVis = SP_VIS_PRIVATE;
978
979 spFile* pTopCtx = new spFile();
980 mpCurCtx = pTopCtx;
981
982 mIsVirtual = 0;
983 mIsTemplate = 0;
984 mNestingLevel = 0;
985
986 cur = start;
987
988 mpStart = start;
989 mpEnd = end;
990
991 _gSrcEnd = mpEnd; // let all the C-functions "smell" the end of file
992 _gSrcStart = start;
993
994 _gLineNo = 0;
995
996 clear_commets_queue();
997
998 // main parsing loop
999
1000 do
1001 {
1002 if ( !get_next_token( cur ) )
1003 // end of source reached
1004 return pTopCtx;
1005
1006 if ( memcmp( cur, "ScriptSection( const string&",
1007 strlen( "ScriptSection( const string&" )
1008 ) == 0
1009 )
1010 {
1011 int o = 0;
1012 ++o;
1013 }
1014
1015 switch (*cur)
1016 {
1017 case '#' :
1018 {
1019 AddMacroNode( cur );
1020 continue;
1021 }
1022
1023 case ':' :
1024 {
1025 skip_token( cur );
1026 continue;
1027 }
1028
1029 case ';' :
1030 {
1031 skip_token( cur );
1032 continue;
1033 }
1034
1035 case ')' :
1036 {
1037 skip_token( cur );
1038 continue;
1039 }
1040
1041 case '=' :
1042 {
1043 skip_token( cur );
1044 continue;
1045 }
1046
1047 default: break;
1048 }
1049
1050 // 'const' is a part of the return type, not a keyword here
1051 if ( strncmp(cur, "const", 5) != 0 && is_keyword( cur ) )
1052 {
1053 // parses, token, if token identifies
1054 // the container context (e.g. class/namespace)
1055 // the corresponding context object is created
1056 // and set as current context
1057
1058 ParseKeyword( cur );
1059 continue;
1060 }
1061
1062 if ( *cur >= '0' && *cur <= '9' )
1063 {
1064 skip_token( cur );
1065 continue;
1066 }
1067
1068 if ( *cur == '}' )
1069 {
1070 if ( mCurCtxType != SP_CTX_CLASS )
1071 {
1072 // FOR NOW:: disable the below assertion
1073
1074 // DBG:: unexpected closing-bracket found
1075 //ASSERT(0);
1076
1077 skip_token( cur ); // just skip it
1078 continue;
1079 }
1080
1081 if ( mpCurCtx->GetType() == SP_CTX_CLASS )
1082 {
1083 int curOfs = ( (cur+1) - _gSrcStart );
1084
1085 mpCurCtx->mContextLength = ( curOfs - mpCurCtx->mSrcOffset );
1086 }
1087
1088 --mNestingLevel;
1089
1090 // terminate operation/class/namespace context
1091 // TBD:: check if it's really this type of context
1092
1093 wxASSERT( mpCurCtx );
1094 mpCurCtx = mpCurCtx->GetOutterContext();
1095 wxASSERT( mpCurCtx );
1096
1097 if ( mNestingLevel == 0 )
1098 {
1099
1100 mCurCtxType = SP_CTX_FILE;
1101
1102 // not-nested class delclaration finished,
1103 // rest template flag in any case
1104 mIsTemplate = 0;
1105 }
1106
1107 skip_token( cur );
1108 continue;
1109 }
1110
1111 bool isAMacro = 0;
1112
1113 if ( is_function( cur, isAMacro ) )
1114 {
1115 if ( isAMacro )
1116 {
1117 skip_token( cur );
1118 continue;
1119 }
1120
1121 char* savedPos = cur;
1122
1123 int tmpLnNo;
1124 store_line_no( tmpLnNo );
1125
1126 isAMacro = FALSE;
1127
1128 if ( !ParseNameAndRetVal( cur, isAMacro ) )
1129 {
1130 if ( !isAMacro )
1131 {
1132 cur = savedPos;
1133 SkipFunction( cur );
1134 }
1135 continue;
1136 }
1137
1138 if ( !ParseArguments( cur ) )
1139 {
1140 // failure while parsing arguments,
1141 // remove enclosing operation context
1142
1143 spContext* pFailed = mpCurCtx;
1144 mpCurCtx = mpCurCtx->GetOutterContext();
1145 mpCurCtx->RemoveChild( pFailed );
1146
1147 skip_to_eol( cur );
1148 //cur = savedPos;
1149 }
1150 else
1151 {
1152 // otherwise, successfully close operation context:
1153
1154 clear_commets_queue();
1155
1156 SkipFunctionBody( cur );
1157
1158 mpCurCtx = mpCurCtx->GetOutterContext();
1159
1160 // DBG::
1161 wxASSERT( mpCurCtx );
1162
1163 }
1164 }
1165 else // otherwise it's declaration of a variable;
1166 {
1167 // now, the cursor point to the end of statement (';' token)
1168
1169 if ( mCurCtxType != SP_CTX_CLASS )
1170 {
1171 // non-class members are ignored
1172
1173 skip_token( cur ); // skip the end of statement
1174 continue;
1175 }
1176
1177 ParseMemberVar( cur );
1178 }
1179
1180 } while( 1 );
1181 }
1182
1183 void CJSourceParser::AttachComments( spContext& ctx, char* cur )
1184 {
1185 if ( !mCommentsOn ) return;
1186
1187 MCommentListT& lst = ctx.GetCommentList();
1188
1189 char* prevComEnd = 0;
1190
1191 int tmpLnNo;
1192 store_line_no( tmpLnNo );
1193
1194 // attach comments which were found before the given context
1195
1196 for( int i = 0; i != _gCQSize; ++i )
1197 {
1198 spComment* pComment = new spComment();
1199 lst.push_back( pComment );
1200
1201 // find the end of comment
1202 char* start = _gCommentsQueue[i];
1203
1204 pComment->mIsMultiline = ( *(start+1) == '*' );
1205
1206 // first comment in the queue and multiline
1207 // comments are always treated as a begining
1208 // of the new paragraph in the comment text
1209
1210 if ( i == 0 )
1211
1212 pComment->mStartsPar = TRUE;
1213 else
1214 if ( pComment->mIsMultiline )
1215
1216 pComment->mStartsPar = TRUE;
1217 else
1218 {
1219 // find out wheather there is a new-line
1220 // between to adjecent comments
1221
1222
1223 char* prevLine = start;
1224 skip_to_prev_line(prevLine);
1225
1226 if ( prevLine >= prevComEnd )
1227
1228 pComment->mStartsPar = TRUE;
1229 else
1230 pComment->mStartsPar = FALSE;
1231 }
1232
1233 prevComEnd = set_comment_text( pComment->mText, start );
1234 }
1235
1236
1237 // attach comments which are at the end of the line
1238 // of the given context (if any)
1239
1240 if ( skip_to_next_comment_in_the_line( cur ) )
1241 {
1242 spComment* pComment = new spComment();
1243 lst.push_back( pComment );
1244
1245 set_comment_text( pComment->mText, cur );
1246
1247 pComment->mStartsPar = 1;
1248 pComment->mIsMultiline = ( *(cur+1) == '*' );
1249
1250 // mark this comment, so that it would not
1251 // get in the comments list of the next context
1252 _gLastSuppresedComment = cur;
1253 }
1254
1255 restore_line_no( tmpLnNo );
1256
1257 clear_commets_queue();
1258 }
1259
1260 void CJSourceParser::AddMacroNode( char*& cur )
1261 {
1262 char* start = cur;
1263
1264 int lineNo = get_line_no();
1265
1266 skip_preprocessor_dir( cur );
1267
1268 int tmpLnNo;
1269 store_line_no( tmpLnNo );
1270
1271 if ( !mMacrosOn ) return;
1272
1273 spPreprocessorLine* pPL = new spPreprocessorLine();
1274 pPL->mSrcLineNo = lineNo;
1275
1276 AttachComments( *pPL, cur );
1277
1278 get_string_between( start, cur, &pPL->mLine );
1279
1280 ++start; // skip '#'
1281 get_next_token( start );
1282
1283 pPL->mDefType = SP_PREP_DEF_OTHER;
1284
1285 // if we found a definition or redefinition,
1286 // determine the type exactly and assign
1287 // a name to the context
1288
1289 if ( *start == 'd' )
1290 {
1291 if ( cmp_tokens_fast( start, "define", 6 ) )
1292 {
1293 char* tok = start+6;
1294
1295 get_next_token( tok );
1296
1297 pPL->mName = get_token_str( tok );
1298
1299 skip_token( tok );
1300 get_next_token( tok);
1301
1302
1303 if ( tok > cur )
1304 pPL->mDefType = SP_PREP_DEF_DEFINE_SYMBOL;
1305 else
1306 pPL->mDefType = SP_PREP_DEF_REDEFINE_SYMBOL;
1307 }
1308 }
1309 else
1310 if ( *start == 'i' )
1311
1312 if ( cmp_tokens_fast( start, "include", 7 ) )
1313 {
1314 pPL->mDefType = SP_PREP_DEF_INCLUDE_FILE;
1315 }
1316
1317 mpCurCtx->AddMember( pPL );
1318
1319 restore_line_no( tmpLnNo );
1320
1321 clear_commets_queue();
1322 }
1323
1324 void CJSourceParser::ParseKeyword( char*& cur )
1325 {
1326 // analyze token, which identifies the begining of a new context
1327
1328 if ( CheckVisibilty( cur ) )
1329 {
1330 skip_token( cur );
1331 return;
1332 }
1333
1334 if ( is_class_token( cur ) )
1335 {
1336 if ( is_forward_decl( cur ) )
1337 {
1338 // forward declarations are ignored;
1339 skip_token( cur );
1340 return;
1341 }
1342
1343 if ( mNestingLevel == 0 )
1344 {
1345 // change context form global class context
1346 mCurCtxType = SP_CTX_CLASS;
1347 }
1348
1349 ++mNestingLevel;
1350
1351 // add information about new class (name, inheritance, etc)
1352 AddClassNode( cur );
1353
1354 // the default visiblity for class members is 'private'
1355 mCurVis = SP_VIS_PRIVATE;
1356
1357 return;
1358 }
1359
1360 size_t len = get_token_len( cur );
1361
1362 if ( cmp_tokens_fast( cur, "typedef", len ) )
1363 {
1364 skip_token(cur);
1365 get_next_token(cur);
1366
1367 if ( cmp_tokens_fast( cur, "struct", len ) ||
1368 cmp_tokens_fast( cur, "union", len ) ||
1369 cmp_tokens_fast( cur, "class", len )
1370 )
1371 {
1372 if ( mNestingLevel == 0 )
1373 {
1374 // change context form global class context
1375 mCurCtxType = SP_CTX_CLASS;
1376 }
1377
1378 ++mNestingLevel;
1379
1380 // add information about new class (name, inheritance, etc)
1381 AddClassNode( cur );
1382
1383 // the default visiblity for class members is 'private'
1384 mCurVis = SP_VIS_PRIVATE;
1385
1386 return;
1387
1388 // FOR NOW:: typedef struct, etc are also ignored
1389 //skip_scope_block( cur );
1390 }
1391
1392 if ( cmp_tokens_fast( cur, "enum", len ) )
1393 {
1394 AddEnumNode( cur );
1395 return;
1396 }
1397
1398 AddTypeDefNode( cur );
1399
1400 return;
1401 }
1402
1403 if ( cmp_tokens_fast( cur, "enum", len ) )
1404 {
1405 AddEnumNode( cur );
1406 return;
1407 }
1408
1409 if ( cmp_tokens_fast( cur, "extern", len ) )
1410 {
1411 // extern's are ignored (both extern "C" and extern vars)
1412 while ( *cur != '{' &&
1413 *cur != ';' )
1414 {
1415 skip_token( cur );
1416 get_next_token( cur );
1417 }
1418 return;
1419
1420 }
1421 if ( cmp_tokens_fast( cur, "enum", len ) )
1422 {
1423 // enumeration blocks are ignored
1424
1425 skip_scope_block( cur );
1426
1427 get_next_token( cur );
1428 skip_token( cur ); // skip ';' token;
1429 return;
1430 }
1431
1432 if ( cmp_tokens_fast( cur, "package", len ) )
1433 {
1434 // packages are ignored
1435 skip_statement( cur );
1436 return;
1437 };
1438
1439 if ( cmp_tokens_fast( cur, "import", len ) )
1440 {
1441 // import statements are ignored
1442 skip_statement( cur );
1443 return;
1444 }
1445
1446 if ( cmp_tokens_fast( cur, "virtual", len ) )
1447 {
1448 // probably the virtual method is in front of us;
1449 mIsVirtual = 1;
1450 skip_token( cur );
1451 return;
1452 }
1453
1454 if ( cmp_tokens_fast( cur, "template", len ) )
1455 {
1456 mIsTemplate = 1;
1457 skip_tempalate_statement( cur );
1458 return;
1459 }
1460
1461 if ( cmp_tokens_fast( cur, "friend", len ) )
1462 {
1463 skip_statement( cur );
1464 return;
1465 }
1466
1467 // ingnore "unsigificant" tokens (i.e. which do not
1468 // affect the current parsing context)
1469
1470 skip_token( cur );
1471 }
1472
1473 bool CJSourceParser::ParseNameAndRetVal( char*& cur, bool& isAMacro )
1474 {
1475 isAMacro = FALSE;
1476
1477 // FOR NOW:: all functions in the global
1478 // scope are ignored
1479
1480 int lineNo = get_line_no();
1481
1482 char* start = cur;
1483
1484 bool isVirtual = false;
1485 while( *cur != '(' )
1486 {
1487 if ( get_token_str( cur ) == "virtual" )
1488 isVirtual = true;
1489
1490 skip_token( cur );
1491 if ( !get_next_token( cur ) ) return FALSE;
1492 }
1493
1494 char* bracketPos = cur;
1495 char* savedPos = cur + 1;
1496
1497 int tmpLnNo;
1498 store_line_no( tmpLnNo );
1499
1500 // skip gap between function name and start of paramters list
1501 while ( *(cur-1) == ' ' )
1502 --cur;
1503
1504 // check if it's not a macro, and let plugin handle it, if so
1505
1506 if ( mpPlugin )
1507 {
1508 skip_token_back( cur );
1509
1510 char* tmp = cur;
1511
1512 if ( mpPlugin->CanUnderstandContext( tmp, _gSrcEnd, mpCurCtx ) )
1513 {
1514 cur = tmp;
1515
1516 mpPlugin->ParseContext( _gSrcStart, cur, _gSrcEnd, mpCurCtx );
1517
1518 isAMacro = TRUE;
1519
1520 return FALSE;
1521 }
1522 }
1523
1524 spOperation* pOp = new spOperation();
1525
1526 pOp->mSrcLineNo = lineNo;
1527 pOp->mSrcOffset = int( start - _gSrcStart );
1528 pOp->mHeaderLength = int( bracketPos - start );
1529
1530 mpCurCtx->AddMember( pOp );
1531 pOp->mVisibility = mCurVis;
1532 pOp->mIsVirtual = isVirtual;
1533
1534 // add comments about operation
1535 AttachComments( *pOp, cur );
1536
1537 // go backwards to method name
1538 skip_token_back( cur );
1539
1540 pOp->mName = get_token_str( cur );
1541
1542 // go backwards to method return type
1543 skip_next_token_back( cur );
1544
1545 if ( cur >= start )
1546
1547 pOp->mRetType = string( start, size_t( cur-start ) );
1548
1549 arrange_indirection_tokens_between( pOp->mRetType, pOp->mName );
1550
1551 cur = savedPos;
1552 restore_line_no( tmpLnNo );
1553
1554 // now, enter operation context
1555 mpCurCtx = pOp;
1556
1557 return TRUE;
1558 }
1559
1560 bool CJSourceParser::ParseArguments( char*& cur )
1561 {
1562 // DANGER-MACROS::
1563
1564 // now cursor position is right after the first opening bracket
1565 // of the function declaration
1566
1567 char* blocks [16]; // used exclusivelly for iterative "lean out"
1568 // of macros and misc. not-obviouse grammar
1569 // (dirty,, but we cannot do it very nice,
1570 // we're not preprocessor-free C/C++ code)
1571 int blockSizes[16];
1572
1573 do
1574 {
1575 size_t blocksSkipped = 0;
1576
1577 get_next_token( cur );
1578
1579 bool first_blk = 1;
1580
1581 while( *cur != ')' && *cur != ',' )
1582 {
1583 blocks[blocksSkipped] = cur;
1584
1585 if ( first_blk )
1586 {
1587 char* prev = cur;
1588 skip_token( cur );
1589
1590 blockSizes[blocksSkipped] = size_t(cur-prev);
1591
1592 first_blk = 0;
1593 }
1594 else
1595 blockSizes[blocksSkipped] = skip_block( cur );
1596
1597 get_next_token( cur );
1598 ++blocksSkipped;
1599 }
1600
1601
1602 if ( blocksSkipped == 1 )
1603 {
1604 // check if the empty arg. list stressed with "void" inside
1605 if ( cmp_tokens_fast( blocks[0] , "void", 4 ) )
1606 return TRUE;
1607
1608 // FIXME:: TBD:: K&R-style function declarations!
1609
1610 // if only one block enclosed, than it's probably
1611 // some macro, there should be at least two blocks,
1612 // one for argument type and another for it's identifier
1613 return FALSE;
1614 }
1615
1616 if ( blocksSkipped == 0 )
1617 {
1618 if ( *cur == 10 ) ++_gLineNo;
1619 ++cur; // skip ')'
1620
1621 break; // function without paramters
1622 }
1623
1624 // we should be in the operation context now
1625 spOperation* pOp = (spOperation*)mpCurCtx;
1626
1627 spParameter* pPar = new spParameter();
1628
1629 pOp->AddMember( pPar );
1630 // FOR NOW:: line number is not exact if argument list is mutiline
1631 pPar->mSrcLineNo = get_line_no();
1632
1633 size_t nameBlock = blocksSkipped - 1;
1634 size_t typeBlock = nameBlock - 1;
1635
1636 // check if default values present
1637 if ( *blocks[typeBlock] == '=' )
1638 {
1639 // expressions like "int = 5" are ignored,
1640 // since name for paramters is required
1641 if ( blocksSkipped == 3 )
1642 {
1643 if ( *cur == ')' )
1644 {
1645 ++cur;
1646 break;
1647 }
1648 else
1649 continue;
1650 }
1651
1652 pPar->mInitVal = string( blocks[nameBlock], blockSizes[nameBlock] );
1653
1654 nameBlock = nameBlock - 2; // skip '=' token and default value block
1655 typeBlock = nameBlock - 1;
1656 }
1657
1658 // attach comments about the parameter
1659 AttachComments( *pPar, blocks[nameBlock] );
1660
1661 // retrieve argument name
1662 pPar->mName = string( blocks[nameBlock], blockSizes[nameBlock] );
1663
1664 // retreive argument type
1665
1666 size_t len = blockSizes[ typeBlock ];
1667 len = size_t ( (blocks[ typeBlock ] + len) - blocks[ 0 ] );
1668
1669 pPar->mType = string( blocks[0], len );
1670
1671 arrange_indirection_tokens_between( pPar->mType, pOp->mName );
1672
1673 if ( *cur == ')' )
1674 {
1675 ++cur;
1676 break;
1677 }
1678
1679 ++cur; // skip comma
1680 get_next_token(cur);
1681
1682 } while(1);
1683
1684 // skip possible whitespace between ')' and following "const"
1685 while ( isspace(*cur) )
1686 cur++;
1687
1688 // check if it was really a function not a macro,
1689 // if so, than it should be terminated with semicolon ';'
1690 // or opening implemenetaton bracket '{'
1691
1692 char* tok = cur;
1693
1694 int tmpLnNo;
1695 store_line_no( tmpLnNo );
1696
1697 do
1698 {
1699 if ( *tok == '{' || *tok == ';' )
1700 {
1701 restore_line_no(tmpLnNo);
1702 return TRUE;
1703 }
1704
1705 // check for unexpected tokens
1706 if ( *tok == '=' || *tok == '0' )
1707 {
1708 skip_token(tok);
1709 if ( !get_next_token(tok) ) return FALSE;
1710 continue;
1711 }
1712
1713 if ( *tok == '}' ) return FALSE;
1714
1715 // if initialization list found
1716 if ( *tok == ':' )
1717 {
1718 restore_line_no(tmpLnNo);
1719 return TRUE;
1720 }
1721
1722 if ( cmp_tokens_fast( tok, "const", 5 ) )
1723 {
1724 ((spOperation*)mpCurCtx)->mIsConstant = true;
1725
1726 skip_token(tok);
1727 if ( !get_next_token(tok) ) return FALSE;
1728 continue;
1729 }
1730
1731 if ( CheckVisibilty( tok ) ) return FALSE;
1732
1733 // if next context found
1734 if ( is_keyword( tok ) ) return FALSE;
1735
1736 skip_token(tok);
1737 if ( !get_next_token(tok) ) return FALSE;
1738
1739 } while(1);
1740
1741 return TRUE;
1742 }
1743
1744 void CJSourceParser::ParseMemberVar( char*& cur )
1745 {
1746 MMemberListT& members = mpCurCtx->GetMembers();
1747
1748 bool firstMember = 1;
1749
1750 size_t first = 0;
1751
1752 string type;
1753
1754 // jump to the end of statement
1755 // and start collecting same-type varibles
1756 // back-to-front towards the type identifier
1757
1758 skip_statement( cur );
1759 char* savedPos = cur;
1760
1761 int tmpLnNo;
1762 store_line_no( tmpLnNo );
1763
1764 --cur; // rewind back to ';'
1765
1766 do
1767 {
1768 spAttribute* pAttr = new spAttribute();
1769 // FOR NOW:: line not is not exact, if member declaration is multiline
1770 pAttr->mSrcLineNo = get_line_no();
1771
1772 mpCurCtx->AddMember( pAttr );
1773 pAttr->mVisibility = mCurVis;
1774
1775 pAttr->mIsConstant = 0;
1776
1777 if ( firstMember )
1778 {
1779 firstMember = 0;
1780 first = members.size() - 1;;
1781 }
1782
1783 skip_token_back( cur );
1784
1785 // attach comments about the attribute
1786 AttachComments( *pAttr, cur );
1787
1788 pAttr->mName = get_token_str( cur );
1789
1790 // guessing that this going to be variable type
1791 skip_next_token_back( cur );
1792 skip_token_back( cur );
1793
1794 pAttr->mType = get_token_str( cur );
1795
1796 // if comma, than variable list continues
1797 // otherwise the variable type reached - stop
1798
1799 if ( *cur == '=' )
1800 {
1801 // yes, we've mistaken, it was not a identifier,
1802 // but it's default value
1803 pAttr->mInitVal =
1804 pAttr->mName;
1805
1806 // skip default value and '=' symbol
1807 skip_next_token_back( cur );
1808 skip_token_back( cur );
1809
1810 pAttr->mName = get_token_str( cur );
1811
1812 skip_next_token_back( cur );
1813 skip_token_back( cur );
1814 }
1815
1816 if ( *cur != ',' )
1817 {
1818 type = get_token_str( cur );
1819 break;
1820 }
1821
1822 } while(1);
1823
1824 // set up types for all collected (same-type) attributes;
1825 while ( first != members.size() - 1 )
1826 {
1827 spAttribute* pAttr = (spAttribute*)members[first];
1828
1829 pAttr->mType = type;
1830 pAttr->mVisibility = mCurVis;
1831
1832 arrange_indirection_tokens_between( pAttr->mType, pAttr->mName );
1833
1834 ++first;
1835 }
1836
1837 cur = savedPos;
1838 restore_line_no( tmpLnNo );
1839
1840 clear_commets_queue();
1841
1842
1843 }
1844
1845 void CJSourceParser::SkipFunction( char*& cur )
1846 {
1847 while ( *cur != '(' && cur < _gSrcEnd )
1848 {
1849 if (*cur == 10 ) ++_gLineNo;
1850 ++cur;
1851 }
1852
1853 skip_next_token_back( cur ); // go back and skip function identifier
1854 skip_token_back( cur ); // go back and skip return type
1855
1856 skip_block( cur ); // now, go ahead and skip whole declaration
1857
1858 SkipFunctionBody( cur );
1859
1860 }
1861
1862 void CJSourceParser::SkipFunctionBody( char*& cur )
1863 {
1864 // FIXME:: check for comments and quoted stirngs here
1865
1866 bool hasDefinition = FALSE;
1867
1868 while( *cur != '{' && *cur != ';' )
1869 {
1870 if (*cur == 10 ) ++_gLineNo;
1871 ++cur;
1872 }
1873
1874 if ( *cur == ';' )
1875 {
1876 ++cur;
1877 }
1878 else
1879 {
1880 hasDefinition = TRUE;
1881
1882 skip_scope_block( cur ); // skip the whole imp.
1883 }
1884
1885 if ( mpCurCtx->GetType() == SP_CTX_OPERATION )
1886 {
1887 spOperation& op = *((spOperation*)mpCurCtx);
1888
1889 int curOfs = int ( cur - _gSrcStart );
1890
1891 op.mContextLength = curOfs - mpCurCtx->mSrcOffset;
1892
1893 op.mHasDefinition = hasDefinition;
1894
1895 // separate scope resolution token from the name of operation
1896
1897 for( size_t i = 0; i != op.mName.length(); ++i )
1898 {
1899 if ( op.mName[i] == ':' && op.mName[i+1] == ':' )
1900 {
1901 string unscoped( op.mName, i+2, op.mName.length() - ( i + 2 ) );
1902
1903 op.mScope = string( op.mName, 0, i );
1904
1905 op.mName = unscoped;
1906
1907 break;
1908 }
1909 }
1910 }
1911 }
1912
1913 bool CJSourceParser::CheckVisibilty( char*& cur )
1914 {
1915 size_t len = get_token_len( cur );
1916
1917 if ( cmp_tokens_fast( cur, "public:", len ) )
1918 {
1919 mCurVis = SP_VIS_PUBLIC;
1920 return TRUE;
1921 }
1922
1923 if ( cmp_tokens_fast( cur, "protected:", len ) )
1924 {
1925 mCurVis = SP_VIS_PROTECTED;
1926 return TRUE;
1927 }
1928
1929 if ( cmp_tokens_fast( cur, "private:", len ) )
1930 {
1931 mCurVis = SP_VIS_PRIVATE;
1932 return TRUE;
1933 }
1934
1935 return FALSE;
1936 }
1937
1938 void CJSourceParser::AddClassNode( char*& cur )
1939 {
1940 char* ctxStart = cur;
1941
1942 skip_token( cur ); // skip 'class' keyword
1943 if ( !get_next_token( cur ) ) return;
1944
1945 // in C++
1946 if ( *cur == ':' )
1947 {
1948 skip_token( cur );
1949 get_next_token( cur );
1950 }
1951
1952 spClass* pClass = new spClass();
1953
1954
1955 mpCurCtx->AddMember( pClass );
1956
1957 // by default all class members are private
1958 mCurVis = SP_VIS_PRIVATE;
1959
1960 // attach comments about the class
1961 AttachComments( *pClass, cur );
1962
1963 pClass->mSrcLineNo = get_line_no();
1964
1965 pClass->mSrcOffset = int( ctxStart - _gSrcStart );
1966
1967 char* nameTok = cur;
1968 pClass->mName = get_token_str( cur );
1969
1970 bool isDerived = 0;
1971
1972 // DANGER-MACROS::
1973
1974 do
1975 {
1976 skip_token( cur );
1977 if ( !get_next_token( cur ) ) return;
1978
1979 if ( *cur == ':' )
1980 {
1981 isDerived = 1;
1982
1983 char* tok = cur;
1984
1985 int tmpLn;
1986 store_line_no( tmpLn );
1987
1988 skip_next_token_back( tok );
1989 skip_token_back( tok );
1990
1991 restore_line_no( tmpLn );
1992
1993 // class name should precend ':' colon, thus
1994 // the one which was captured before was
1995 // proablty something else (like __dllexport MyClass : ... )
1996
1997 if ( nameTok != tok )
1998 {
1999 pClass->mName = get_token_str( tok );
2000 }
2001
2002 }
2003
2004 if ( *cur == '{' )
2005 break;
2006
2007 if ( *cur == ',' )
2008 continue;
2009
2010 size_t len = get_token_len( cur );
2011
2012 // skip neglectable C++ modifieres
2013 if ( cmp_tokens_fast( cur, "public", len ) )
2014 continue;
2015
2016 if ( cmp_tokens_fast( cur, "protected", len ) )
2017 continue;
2018
2019 if ( cmp_tokens_fast( cur, "private", len ) )
2020 continue;
2021
2022 if ( cmp_tokens_fast( cur, "virtual", len ) )
2023 continue;
2024
2025 // skip neglectable JAVA modifieres
2026
2027 if ( cmp_tokens_fast( cur, "extends", len ) )
2028 {
2029 isDerived = 1;
2030 continue;
2031 }
2032
2033 if ( cmp_tokens_fast( cur, "implements", len ) )
2034 {
2035 isDerived = 1;
2036 continue;
2037 }
2038
2039 // all we need to know is superclass or interface
2040
2041 char* tok = cur;
2042 int tmpLn;
2043 store_line_no( tmpLn );
2044
2045 skip_token(tok);
2046 get_next_token(tok);
2047
2048 restore_line_no( tmpLn );
2049
2050 if ( *tok != ':' && *cur != ':' )
2051
2052 pClass->mSuperClassNames.push_back( string( cur, len ) );
2053
2054 } while(1);
2055
2056 if ( !isDerived )
2057 {
2058 int tmpLn;
2059 store_line_no( tmpLn );
2060
2061 while ( pClass->mSuperClassNames.size() )
2062
2063 pClass->mSuperClassNames.erase( &pClass->mSuperClassNames[0] );
2064
2065 char* tok = cur;
2066
2067 // some non-obviouse token was following "class" keyword -
2068 // we've confused it with class name - thus now we're reverting this mistake
2069
2070 skip_next_token_back( tok );
2071 skip_token_back( tok );
2072
2073 pClass->mName = get_token_str( tok );
2074
2075 restore_line_no( tmpLn );
2076 }
2077
2078
2079 ++cur; // skip opening curly brace
2080
2081 pClass->mHeaderLength = ( cur - ctxStart );
2082
2083 // now, enter the class context
2084 mpCurCtx = pClass;
2085
2086 clear_commets_queue();
2087 }
2088
2089 void CJSourceParser::AddEnumNode( char*& cur )
2090 {
2091 // now the cursor is at "enum" keyword
2092 char* start = cur;
2093
2094 spEnumeration* pEnum = new spEnumeration();
2095 mpCurCtx->AddMember( pEnum );
2096
2097 pEnum->mSrcLineNo = get_line_no();
2098
2099
2100 AttachComments( *pEnum, cur );
2101
2102 skip_token( cur );
2103 if ( !get_next_token( cur ) ) return;
2104
2105 // check if enumeration has got it's identifier
2106 if ( *cur != '{' )
2107 {
2108 pEnum->mName = get_token_str( cur );
2109 }
2110
2111 if ( !skip_imp_block( cur ) ) return;
2112
2113 get_string_between( start, cur, &pEnum->mEnumContent );
2114
2115 if ( get_next_token(cur) )
2116 {
2117 // check if the identifier if after the {...} block
2118 if ( *cur != ';' )
2119
2120 pEnum->mName = get_token_str( cur );
2121 }
2122
2123 clear_commets_queue();
2124 }
2125
2126 void CJSourceParser::AddTypeDefNode( char*& cur )
2127 {
2128 // now the cursor at the token next to "typedef" keyword
2129
2130 if ( !get_next_token(cur) ) return;
2131
2132 char* start = cur;
2133
2134 spTypeDef* pTDef = new spTypeDef();
2135 mpCurCtx->AddMember( pTDef );
2136
2137 pTDef->mSrcLineNo = get_line_no();
2138
2139 AttachComments( *pTDef, cur );
2140
2141 skip_statement( cur );
2142
2143 int tmpLnNo;
2144 store_line_no( tmpLnNo );
2145
2146 char* tok = cur-1;
2147 skip_next_token_back( tok );
2148
2149 char* nameEnd = tok;
2150
2151 skip_token_back( tok );
2152
2153 char* nameStart = tok;
2154
2155 skip_next_token_back( tok );
2156
2157 char* typeEnd = tok;
2158
2159 // check if it's function prototype
2160 if ( *nameStart == ')' )
2161 {
2162 typeEnd = nameStart+1;
2163
2164 // skip argument list
2165 while ( *nameStart != '(' ) --nameStart;
2166
2167 // skip to function type definition
2168 while ( *nameStart != ')' ) --nameStart;
2169
2170 skip_next_token_back( nameStart );
2171
2172 nameEnd = nameStart;
2173
2174 skip_token_back( nameStart );
2175
2176 if ( *nameStart == '*' ) ++nameStart;
2177 }
2178
2179 get_string_between( start, typeEnd, &pTDef->mOriginalType );
2180
2181 get_string_between( nameStart, nameEnd, &pTDef->mName );
2182
2183 clear_commets_queue();
2184
2185 restore_line_no( tmpLnNo );
2186 }