]> git.saurik.com Git - wxWidgets.git/blame_incremental - utils/HelpGen/src/cjparser.cpp
Added more makefiles
[wxWidgets.git] / utils / HelpGen / src / cjparser.cpp
... / ...
CommitLineData
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
44static char* _gSrcStart = 0;
45static char* _gSrcEnd = 0;
46static char* _gLastSuppresedComment = 0;
47static int _gLineNo = 0;
48
49// FOR NOW:: comments queue is static
50#define MAX_CQ_ENTRIES 128
51static char* _gCommentsQueue[MAX_CQ_ENTRIES];
52static int _gCQSize = 0;
53
54/***** keyword map related structures *****/
55
56struct 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
76static KeywordMapT __gMultiLangMap;
77static int __gMapReady = 0;
78
79static 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
115static 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
139static inline void skip_to_eol( char*& cur )
140{
141 while( *(cur) != 10 && *cur != 13 && cur < _gSrcEnd) ++cur;
142}
143
144static 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
155static 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
183inline static void store_line_no( int& toVar )
184{
185 toVar = _gLineNo;
186}
187
188inline static void restore_line_no( int storedLineNo )
189{
190 _gLineNo = storedLineNo;
191}
192
193inline static int get_line_no()
194{
195 return _gLineNo;
196}
197
198static 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
229static 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
326static inline void clear_commets_queue()
327{
328 _gCQSize = 0;
329}
330
331static 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
362static 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
391static 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
408static 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
467static 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
478static 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
499static 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
511static 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
546static 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
571static 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
605static 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
638static 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
650static 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
729static 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
748static 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
775inline 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
797inline 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
858static 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
892static 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
911static 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() );
927}
928
929static 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
939static 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
964CJSourceParser::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
974spFile* 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 mIsVirtaul = 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;
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 if ( is_keyword( cur ) )
1051 {
1052 // parses, token, if token identifies
1053 // the container context (e.g. class/namespace)
1054 // the corresponding context object is created
1055 // and set as current context
1056
1057 ParseKeyword( cur );
1058 continue;
1059 }
1060
1061 if ( *cur >= '0' && *cur <= '9' )
1062 {
1063 skip_token( cur );
1064 continue;
1065 }
1066
1067 if ( *cur == '}' )
1068 {
1069 if ( mCurCtxType != SP_CTX_CLASS )
1070 {
1071 // FOR NOW:: disable the below assertion
1072
1073 // DBG:: unexpected closing-bracket found
1074 //ASSERT(0);
1075
1076 skip_token( cur ); // just skip it
1077 continue;
1078 }
1079
1080 if ( mpCurCtx->GetType() == SP_CTX_CLASS )
1081 {
1082 int curOfs = ( (cur+1) - _gSrcStart );
1083
1084 mpCurCtx->mContextLength = ( curOfs - mpCurCtx->mSrcOffset );
1085 }
1086
1087 --mNestingLevel;
1088
1089 // terminate operation/class/namespace context
1090 // TBD:: check if it's really this type of context
1091
1092 wxASSERT( mpCurCtx );
1093 mpCurCtx = mpCurCtx->GetOutterContext();
1094 wxASSERT( mpCurCtx );
1095
1096 if ( mNestingLevel == 0 )
1097 {
1098
1099 mCurCtxType = SP_CTX_FILE;
1100
1101 // not-nested class delclaration finished,
1102 // rest template flag in any case
1103 mIsTemplate = 0;
1104 }
1105
1106 skip_token( cur );
1107 continue;
1108 }
1109
1110 bool isAMacro = 0;
1111
1112 if ( is_function( cur, isAMacro ) )
1113 {
1114 if ( isAMacro )
1115 {
1116 skip_token( cur );
1117 continue;
1118 }
1119
1120 char* savedPos = cur;
1121
1122 int tmpLnNo;
1123 store_line_no( tmpLnNo );
1124
1125 isAMacro = FALSE;
1126
1127 if ( !ParseNameAndRetVal( cur, isAMacro ) )
1128 {
1129 if ( !isAMacro )
1130 {
1131 cur = savedPos;
1132 SkipFunction( cur );
1133 }
1134 continue;
1135 }
1136
1137 if ( !ParseArguments( cur ) )
1138 {
1139 // failure while parsing arguments,
1140 // remove enclosing operation context
1141
1142 spContext* pFailed = mpCurCtx;
1143 mpCurCtx = mpCurCtx->GetOutterContext();
1144 mpCurCtx->RemoveChild( pFailed );
1145
1146 skip_to_eol( cur );
1147 //cur = savedPos;
1148 }
1149 else
1150 {
1151 // otherwise, successfully close operation context:
1152
1153 clear_commets_queue();
1154
1155 SkipFunctionBody( cur );
1156
1157 mpCurCtx = mpCurCtx->GetOutterContext();
1158
1159 // DBG::
1160 wxASSERT( mpCurCtx );
1161
1162 }
1163 }
1164 else // otherwise it's declaration of a variable;
1165 {
1166 // now, the cursor point to the end of statement (';' token)
1167
1168 if ( mCurCtxType != SP_CTX_CLASS )
1169 {
1170 // non-class members are ignored
1171
1172 skip_token( cur ); // skip the end of statement
1173 continue;
1174 }
1175
1176 ParseMemberVar( cur );
1177 }
1178
1179 } while( 1 );
1180}
1181
1182void CJSourceParser::AttachComments( spContext& ctx, char* cur )
1183{
1184 if ( !mCommentsOn ) return;
1185
1186 MCommentListT& lst = ctx.GetCommentList();
1187
1188 char* prevComEnd = 0;
1189
1190 int tmpLnNo;
1191 store_line_no( tmpLnNo );
1192
1193 // attach comments which were found before the given context
1194
1195 for( int i = 0; i != _gCQSize; ++i )
1196 {
1197 spComment* pComment = new spComment();
1198 lst.push_back( pComment );
1199
1200 // find the end of comment
1201 char* start = _gCommentsQueue[i];
1202
1203 pComment->mIsMultiline = ( *(start+1) == '*' );
1204
1205 // first comment in the queue and multiline
1206 // comments are always treated as a begining
1207 // of the new paragraph in the comment text
1208
1209 if ( i == 0 )
1210
1211 pComment->mStartsPar = TRUE;
1212 else
1213 if ( pComment->mIsMultiline )
1214
1215 pComment->mStartsPar = TRUE;
1216 else
1217 {
1218 // find out wheather there is a new-line
1219 // between to adjecent comments
1220
1221
1222 char* prevLine = start;
1223 skip_to_prev_line(prevLine);
1224
1225 if ( prevLine >= prevComEnd )
1226
1227 pComment->mStartsPar = TRUE;
1228 else
1229 pComment->mStartsPar = FALSE;
1230 }
1231
1232 prevComEnd = set_comment_text( pComment->mText, start );
1233 }
1234
1235
1236 // attach comments which are at the end of the line
1237 // of the given context (if any)
1238
1239 if ( skip_to_next_comment_in_the_line( cur ) )
1240 {
1241 spComment* pComment = new spComment();
1242 lst.push_back( pComment );
1243
1244 set_comment_text( pComment->mText, cur );
1245
1246 pComment->mStartsPar = 1;
1247 pComment->mIsMultiline = ( *(cur+1) == '*' );
1248
1249 // mark this comment, so that it would not
1250 // get in the comments list of the next context
1251 _gLastSuppresedComment = cur;
1252 }
1253
1254 restore_line_no( tmpLnNo );
1255
1256 clear_commets_queue();
1257}
1258
1259void CJSourceParser::AddMacroNode( char*& cur )
1260{
1261 char* start = cur;
1262
1263 int lineNo = get_line_no();
1264
1265 skip_preprocessor_dir( cur );
1266
1267 int tmpLnNo;
1268 store_line_no( tmpLnNo );
1269
1270 if ( !mMacrosOn ) return;
1271
1272 spPreprocessorLine* pPL = new spPreprocessorLine();
1273 pPL->mSrcLineNo = lineNo;
1274
1275 AttachComments( *pPL, cur );
1276
1277 get_string_between( start, cur, &pPL->mLine );
1278
1279 ++start; // skip '#'
1280 get_next_token( start );
1281
1282 pPL->mDefType = SP_PREP_DEF_OTHER;
1283
1284 // if we found a definition or redefinition,
1285 // determine the type exactly and assign
1286 // a name to the context
1287
1288 if ( *start == 'd' )
1289 {
1290 if ( cmp_tokens_fast( start, "define", 6 ) )
1291 {
1292 char* tok = start+6;
1293
1294 get_next_token( tok );
1295
1296 pPL->mName = get_token_str( tok );
1297
1298 skip_token( tok );
1299 get_next_token( tok);
1300
1301
1302 if ( tok > cur )
1303 pPL->mDefType = SP_PREP_DEF_DEFINE_SYMBOL;
1304 else
1305 pPL->mDefType = SP_PREP_DEF_REDEFINE_SYMBOL;
1306 }
1307 }
1308 else
1309 if ( *start == 'i' )
1310
1311 if ( cmp_tokens_fast( start, "include", 7 ) )
1312 {
1313 pPL->mDefType = SP_PREP_DEF_INCLUDE_FILE;
1314 }
1315
1316 mpCurCtx->AddMember( pPL );
1317
1318 restore_line_no( tmpLnNo );
1319
1320 clear_commets_queue();
1321}
1322
1323void CJSourceParser::ParseKeyword( char*& cur )
1324{
1325 // analyze token, which identifies the begining of a new context
1326
1327 if ( CheckVisibilty( cur ) )
1328 {
1329 skip_token( cur );
1330 return;
1331 }
1332
1333 if ( is_class_token( cur ) )
1334 {
1335 if ( is_forward_decl( cur ) )
1336 {
1337 // forward declarations are ignored;
1338 skip_token( cur );
1339 return;
1340 }
1341
1342 if ( mNestingLevel == 0 )
1343 {
1344 // change context form global class context
1345 mCurCtxType = SP_CTX_CLASS;
1346 }
1347
1348 ++mNestingLevel;
1349
1350 // add information about new class (name, inheritance, etc)
1351 AddClassNode( cur );
1352
1353 // the default visiblity for class members is 'private'
1354 mCurVis = SP_VIS_PRIVATE;
1355
1356 return;
1357 }
1358
1359 size_t len = get_token_len( cur );
1360
1361 if ( cmp_tokens_fast( cur, "typedef", len ) )
1362 {
1363 skip_token(cur);
1364 get_next_token(cur);
1365
1366 if ( cmp_tokens_fast( cur, "struct", len ) ||
1367 cmp_tokens_fast( cur, "union", len ) ||
1368 cmp_tokens_fast( cur, "class", len )
1369 )
1370 {
1371 if ( mNestingLevel == 0 )
1372 {
1373 // change context form global class context
1374 mCurCtxType = SP_CTX_CLASS;
1375 }
1376
1377 ++mNestingLevel;
1378
1379 // add information about new class (name, inheritance, etc)
1380 AddClassNode( cur );
1381
1382 // the default visiblity for class members is 'private'
1383 mCurVis = SP_VIS_PRIVATE;
1384
1385 return;
1386
1387 // FOR NOW:: typedef struct, etc are also ignored
1388 //skip_scope_block( cur );
1389 }
1390
1391 if ( cmp_tokens_fast( cur, "enum", len ) )
1392 {
1393 AddEnumNode( cur );
1394 return;
1395 }
1396
1397 AddTypeDefNode( cur );
1398
1399 return;
1400 }
1401
1402 if ( cmp_tokens_fast( cur, "enum", len ) )
1403 {
1404 AddEnumNode( cur );
1405 return;
1406 }
1407
1408 if ( cmp_tokens_fast( cur, "extern", len ) )
1409 {
1410 // extern's are ignored (both extern "C" and extern vars)
1411 while ( *cur != '{' &&
1412 *cur != ';' )
1413 {
1414 skip_token( cur );
1415 get_next_token( cur );
1416 }
1417 return;
1418
1419 }
1420 if ( cmp_tokens_fast( cur, "enum", len ) )
1421 {
1422 // enumeration blocks are ignored
1423
1424 skip_scope_block( cur );
1425
1426 get_next_token( cur );
1427 skip_token( cur ); // skip ';' token;
1428 return;
1429 }
1430
1431 if ( cmp_tokens_fast( cur, "package", len ) )
1432 {
1433 // packages are ignored
1434 skip_statement( cur );
1435 return;
1436 };
1437
1438 if ( cmp_tokens_fast( cur, "import", len ) )
1439 {
1440 // import statements are ignored
1441 skip_statement( cur );
1442 return;
1443 }
1444
1445 if ( cmp_tokens_fast( cur, "virtual", len ) )
1446 {
1447 // probably the virtual method is in front of us;
1448 mIsVirtaul = 1;
1449 skip_token( cur );
1450 return;
1451 }
1452
1453 if ( cmp_tokens_fast( cur, "template", len ) )
1454 {
1455 mIsTemplate = 1;
1456 skip_tempalate_statement( cur );
1457 return;
1458 }
1459
1460 if ( cmp_tokens_fast( cur, "friend", len ) )
1461 {
1462 skip_statement( cur );
1463 return;
1464 }
1465
1466 // ingnore "unsigificant" tokens (i.e. which do not
1467 // affect the current parsing context)
1468
1469 skip_token( cur );
1470}
1471
1472bool CJSourceParser::ParseNameAndRetVal( char*& cur, bool& isAMacro )
1473{
1474 isAMacro = FALSE;
1475
1476 // FOR NOW:: all functions in the global
1477 // scope are ignored
1478
1479 int lineNo = get_line_no();
1480
1481 char* start = cur;
1482
1483 while( *cur != '(' )
1484 {
1485 skip_token( cur );
1486 if ( !get_next_token( cur ) ) return FALSE;
1487 }
1488
1489 char* bracketPos = cur;
1490 char* savedPos = cur + 1;
1491
1492 int tmpLnNo;
1493 store_line_no( tmpLnNo );
1494
1495 // skip gap between function name and start of paramters list
1496 while ( *(cur-1) == ' ' )
1497 --cur;
1498
1499 // check if it's not a macro, and let plugin handle it, if so
1500
1501 if ( mpPlugin )
1502 {
1503 skip_token_back( cur );
1504
1505 char* tmp = cur;
1506
1507 if ( mpPlugin->CanUnderstandContext( tmp, _gSrcEnd, mpCurCtx ) )
1508 {
1509 cur = tmp;
1510
1511 mpPlugin->ParseContext( _gSrcStart, cur, _gSrcEnd, mpCurCtx );
1512
1513 isAMacro = TRUE;
1514
1515 return FALSE;
1516 }
1517 }
1518
1519 spOperation* pOp = new spOperation();
1520
1521 pOp->mSrcLineNo = lineNo;
1522 pOp->mSrcOffset = int( start - _gSrcStart );
1523 pOp->mHeaderLength = int( bracketPos - start );
1524
1525 mpCurCtx->AddMember( pOp );
1526 pOp->mVisibility = mCurVis;
1527
1528 // add comments about operation
1529 AttachComments( *pOp, cur );
1530
1531 // go backwards to method name
1532 skip_token_back( cur );
1533
1534 pOp->mName = get_token_str( cur );
1535
1536 // go backwards to method return type
1537 skip_next_token_back( cur );
1538
1539 if ( cur >= start )
1540
1541 pOp->mRetType = string( start, size_t( cur-start ) );
1542
1543 arrange_indirection_tokens_between( pOp->mRetType, pOp->mName );
1544
1545 cur = savedPos;
1546 restore_line_no( tmpLnNo );
1547
1548 // now, enter operation context
1549 mpCurCtx = pOp;
1550
1551 return TRUE;
1552}
1553
1554bool CJSourceParser::ParseArguments( char*& cur )
1555{
1556 // DANGER-MACROS::
1557
1558 // now cursor position is right after the first opening bracket
1559 // of the function declaration
1560
1561 char* blocks [16]; // used exclusivelly for iterative "lean out"
1562 // of macros and misc. not-obviouse grammar
1563 // (dirty,, but we cannot do it very nice,
1564 // we're not preprocessor-free C/C++ code)
1565 int blockSizes[16];
1566
1567 do
1568 {
1569 size_t blocksSkipped = 0;
1570
1571 get_next_token( cur );
1572
1573 bool first_blk = 1;
1574
1575 while( *cur != ')' && *cur != ',' )
1576 {
1577 blocks[blocksSkipped] = cur;
1578
1579 if ( first_blk )
1580 {
1581 char* prev = cur;
1582 skip_token( cur );
1583
1584 blockSizes[blocksSkipped] = size_t(cur-prev);
1585
1586 first_blk = 0;
1587 }
1588 else
1589 blockSizes[blocksSkipped] = skip_block( cur );
1590
1591 get_next_token( cur );
1592 ++blocksSkipped;
1593 }
1594
1595
1596 if ( blocksSkipped == 1 )
1597 {
1598 // check if the empty arg. list stressed with "void" inside
1599 if ( cmp_tokens_fast( blocks[0] , "void", 4 ) )
1600 return TRUE;
1601
1602 // FIXME:: TBD:: K&R-style function declarations!
1603
1604 // if only one block enclosed, than it's probably
1605 // some macro, there should be at least two blocks,
1606 // one for argument type and another for it's identifier
1607 return FALSE;
1608 }
1609
1610 if ( blocksSkipped == 0 )
1611 {
1612 if ( *cur == 10 ) ++_gLineNo;
1613 ++cur;
1614 break; // function without paramters
1615 }
1616
1617 // we should be in the operation context now
1618 spOperation* pOp = (spOperation*)mpCurCtx;
1619
1620 spParameter* pPar = new spParameter();
1621
1622 pOp->AddMember( pPar );
1623 // FOR NOW:: line number is not exact if argument list is mutiline
1624 pPar->mSrcLineNo = get_line_no();
1625
1626 size_t nameBlock = blocksSkipped - 1;
1627 size_t typeBlock = nameBlock - 1;
1628
1629 // check if default values present
1630 if ( *blocks[typeBlock] == '=' )
1631 {
1632 // expressions like "int = 5" are ignored,
1633 // since name for paramters is required
1634 if ( blocksSkipped == 3 )
1635 {
1636 if ( *cur == ')' )
1637 {
1638 ++cur;
1639 break;
1640 }
1641 else
1642 continue;
1643 }
1644
1645 pPar->mInitVal = string( blocks[nameBlock], blockSizes[nameBlock] );
1646
1647 nameBlock = nameBlock - 2; // skip '=' token and default value block
1648 typeBlock = nameBlock - 1;
1649 }
1650
1651 // attach comments about the parameter
1652 AttachComments( *pPar, blocks[nameBlock] );
1653
1654 // retrieve argument name
1655 pPar->mName = string( blocks[nameBlock], blockSizes[nameBlock] );
1656
1657 // retreive argument type
1658
1659 size_t len = blockSizes[ typeBlock ];
1660 len = size_t ( (blocks[ typeBlock ] + len) - blocks[ 0 ] );
1661
1662 pPar->mType = string( blocks[0], len );
1663
1664 arrange_indirection_tokens_between( pPar->mType, pOp->mName );
1665
1666 if ( *cur == ')' )
1667 {
1668 ++cur;
1669 break;
1670 }
1671
1672 ++cur; // skip comma
1673 get_next_token(cur);
1674
1675 } while(1);
1676
1677 // check if it was really a function not a macro,
1678 // if so, than it should be terminated with semicolon ';'
1679 // or opening implemenetaton bracket '{'
1680
1681 char* tok = cur;
1682
1683 int tmpLnNo;
1684 store_line_no( tmpLnNo );
1685
1686 do
1687 {
1688 if ( *tok == '{' || *tok == ';' )
1689 {
1690 restore_line_no(tmpLnNo);
1691 return TRUE;
1692 }
1693
1694 // check for unexpected tokens
1695 if ( *tok == '=' || *tok == '0' )
1696 {
1697 skip_token(tok);
1698 if ( !get_next_token(tok) ) return FALSE;
1699 continue;
1700 }
1701
1702 if ( *tok == '}' ) return FALSE;
1703
1704 // if initialization list found
1705 if ( *tok == ':' )
1706 {
1707 restore_line_no(tmpLnNo);
1708 return TRUE;
1709 }
1710
1711 if ( cmp_tokens_fast( tok, "const", 5 ) )
1712 {
1713 skip_token(tok);
1714 if ( !get_next_token(tok) ) return FALSE;
1715 continue;
1716 }
1717
1718 if ( CheckVisibilty( tok ) ) return FALSE;
1719
1720 // if next context found
1721 if ( is_keyword( tok ) ) return FALSE;
1722
1723 skip_token(tok);
1724 if ( !get_next_token(tok) ) return FALSE;
1725
1726 } while(1);
1727
1728 return TRUE;
1729}
1730
1731void CJSourceParser::ParseMemberVar( char*& cur )
1732{
1733 MMemberListT& members = mpCurCtx->GetMembers();
1734
1735 bool firstMember = 1;
1736
1737 size_t first = 0;
1738
1739 string type;
1740
1741 // jump to the end of statement
1742 // and start collecting same-type varibles
1743 // back-to-front towards the type identifier
1744
1745 skip_statement( cur );
1746 char* savedPos = cur;
1747
1748 int tmpLnNo;
1749 store_line_no( tmpLnNo );
1750
1751 --cur; // rewind back to ';'
1752
1753 do
1754 {
1755 spAttribute* pAttr = new spAttribute();
1756 // FOR NOW:: line not is not exact, if member declaration is multiline
1757 pAttr->mSrcLineNo = get_line_no();
1758
1759 mpCurCtx->AddMember( pAttr );
1760 pAttr->mVisibility = mCurVis;
1761
1762 pAttr->mIsConstant = 0;
1763
1764 if ( firstMember )
1765 {
1766 firstMember = 0;
1767 first = members.size() - 1;;
1768 }
1769
1770 skip_token_back( cur );
1771
1772 // attach comments about the attribute
1773 AttachComments( *pAttr, cur );
1774
1775 pAttr->mName = get_token_str( cur );
1776
1777 // guessing that this going to be variable type
1778 skip_next_token_back( cur );
1779 skip_token_back( cur );
1780
1781 pAttr->mType = get_token_str( cur );
1782
1783 // if comma, than variable list continues
1784 // otherwise the variable type reached - stop
1785
1786 if ( *cur == '=' )
1787 {
1788 // yes, we've mistaken, it was not a identifier,
1789 // but it's default value
1790 pAttr->mInitVal =
1791 pAttr->mName;
1792
1793 // skip default value and '=' symbol
1794 skip_next_token_back( cur );
1795 skip_token_back( cur );
1796
1797 pAttr->mName = get_token_str( cur );
1798
1799 skip_next_token_back( cur );
1800 skip_token_back( cur );
1801 }
1802
1803 if ( *cur != ',' )
1804 {
1805 type = get_token_str( cur );
1806 break;
1807 }
1808
1809 } while(1);
1810
1811 // set up types for all collected (same-type) attributes;
1812 while ( first != members.size() - 1 )
1813 {
1814 spAttribute* pAttr = (spAttribute*)members[first];
1815
1816 pAttr->mType = type;
1817 pAttr->mVisibility = mCurVis;
1818
1819 arrange_indirection_tokens_between( pAttr->mType, pAttr->mName );
1820
1821 ++first;
1822 }
1823
1824 cur = savedPos;
1825 restore_line_no( tmpLnNo );
1826
1827 clear_commets_queue();
1828
1829
1830}
1831
1832void CJSourceParser::SkipFunction( char*& cur )
1833{
1834 while ( *cur != '(' && cur < _gSrcEnd )
1835 {
1836 if (*cur == 10 ) ++_gLineNo;
1837 ++cur;
1838 }
1839
1840 skip_next_token_back( cur ); // go back and skip function identifier
1841 skip_token_back( cur ); // go back and skip return type
1842
1843 skip_block( cur ); // now, go ahead and skip whole declaration
1844
1845 SkipFunctionBody( cur );
1846
1847}
1848
1849void CJSourceParser::SkipFunctionBody( char*& cur )
1850{
1851 // FIXME:: check for comments and quoted stirngs here
1852
1853 bool hasDefinition = FALSE;
1854
1855 while( *cur != '{' && *cur != ';' )
1856 {
1857 if (*cur == 10 ) ++_gLineNo;
1858 ++cur;
1859 }
1860
1861 if ( *cur == ';' )
1862 {
1863 ++cur;
1864 }
1865 else
1866 {
1867 hasDefinition = TRUE;
1868
1869 skip_scope_block( cur ); // skip the whole imp.
1870 }
1871
1872 if ( mpCurCtx->GetType() == SP_CTX_OPERATION )
1873 {
1874 spOperation& op = *((spOperation*)mpCurCtx);
1875
1876 int curOfs = int ( cur - _gSrcStart );
1877
1878 op.mContextLength = curOfs - mpCurCtx->mSrcOffset;
1879
1880 op.mHasDefinition = hasDefinition;
1881
1882 // separate scope resolution token from the name of operation
1883
1884 for( size_t i = 0; i != op.mName.length(); ++i )
1885 {
1886 if ( op.mName[i] == ':' && op.mName[i+1] == ':' )
1887 {
1888 string unscoped( op.mName, i+2, op.mName.length() - ( i + 2 ) );
1889
1890 op.mScope = string( op.mName, 0, i );
1891
1892 op.mName = unscoped;
1893
1894 break;
1895 }
1896 }
1897 }
1898}
1899
1900bool CJSourceParser::CheckVisibilty( char*& cur )
1901{
1902 size_t len = get_token_len( cur );
1903
1904 if ( cmp_tokens_fast( cur, "public:", len ) )
1905 {
1906 mCurVis = SP_VIS_PUBLIC;
1907 return TRUE;
1908 }
1909
1910 if ( cmp_tokens_fast( cur, "protected:", len ) )
1911 {
1912 mCurVis = SP_VIS_PROTECTED;
1913 return TRUE;
1914 }
1915
1916 if ( cmp_tokens_fast( cur, "private:", len ) )
1917 {
1918 mCurVis = SP_VIS_PRIVATE;
1919 return TRUE;
1920 }
1921
1922 return FALSE;
1923}
1924
1925void CJSourceParser::AddClassNode( char*& cur )
1926{
1927 char* ctxStart = cur;
1928
1929 skip_token( cur ); // skip 'class' keyword
1930 if ( !get_next_token( cur ) ) return;
1931
1932 // in C++
1933 if ( *cur == ':' )
1934 {
1935 skip_token( cur );
1936 get_next_token( cur );
1937 }
1938
1939 spClass* pClass = new spClass();
1940
1941
1942 mpCurCtx->AddMember( pClass );
1943
1944 // by default all class members are private
1945 mCurVis = SP_VIS_PRIVATE;
1946
1947 // attach comments about the class
1948 AttachComments( *pClass, cur );
1949
1950 pClass->mSrcLineNo = get_line_no();
1951
1952 pClass->mSrcOffset = int( ctxStart - _gSrcStart );
1953
1954 char* nameTok = cur;
1955 pClass->mName = get_token_str( cur );
1956
1957 bool isDerived = 0;
1958
1959 // DANGER-MACROS::
1960
1961 do
1962 {
1963 skip_token( cur );
1964 if ( !get_next_token( cur ) ) return;
1965
1966 if ( *cur == ':' )
1967 {
1968 isDerived = 1;
1969
1970 char* tok = cur;
1971
1972 int tmpLn;
1973 store_line_no( tmpLn );
1974
1975 skip_next_token_back( tok );
1976 skip_token_back( tok );
1977
1978 restore_line_no( tmpLn );
1979
1980 // class name should precend ':' colon, thus
1981 // the one which was captured before was
1982 // proablty something else (like __dllexport MyClass : ... )
1983
1984 if ( nameTok != tok )
1985 {
1986 pClass->mName = get_token_str( tok );
1987 }
1988
1989 }
1990
1991 if ( *cur == '{' )
1992 break;
1993
1994 if ( *cur == ',' )
1995 continue;
1996
1997 size_t len = get_token_len( cur );
1998
1999 // skip neglectable C++ modifieres
2000 if ( cmp_tokens_fast( cur, "public", len ) )
2001 continue;
2002
2003 if ( cmp_tokens_fast( cur, "protected", len ) )
2004 continue;
2005
2006 if ( cmp_tokens_fast( cur, "private", len ) )
2007 continue;
2008
2009 if ( cmp_tokens_fast( cur, "virtual", len ) )
2010 continue;
2011
2012 // skip neglectable JAVA modifieres
2013
2014 if ( cmp_tokens_fast( cur, "extends", len ) )
2015 {
2016 isDerived = 1;
2017 continue;
2018 }
2019
2020 if ( cmp_tokens_fast( cur, "implements", len ) )
2021 {
2022 isDerived = 1;
2023 continue;
2024 }
2025
2026 // all we need to know is superclass or interface
2027
2028 char* tok = cur;
2029 int tmpLn;
2030 store_line_no( tmpLn );
2031
2032 skip_token(tok);
2033 get_next_token(tok);
2034
2035 restore_line_no( tmpLn );
2036
2037 if ( *tok != ':' && *cur != ':' )
2038
2039 pClass->mSuperClassNames.push_back( string( cur, len ) );
2040
2041 } while(1);
2042
2043 if ( !isDerived )
2044 {
2045 int tmpLn;
2046 store_line_no( tmpLn );
2047
2048 while ( pClass->mSuperClassNames.size() )
2049
2050 pClass->mSuperClassNames.erase( &pClass->mSuperClassNames[0] );
2051
2052 char* tok = cur;
2053
2054 // some non-obviouse token was following "class" keyword -
2055 // we've confused it with class name - thus now we're reverting this mistake
2056
2057 skip_next_token_back( tok );
2058 skip_token_back( tok );
2059
2060 pClass->mName = get_token_str( tok );
2061
2062 restore_line_no( tmpLn );
2063 }
2064
2065
2066 ++cur; // skip opening curly brace
2067
2068 pClass->mHeaderLength = ( cur - ctxStart );
2069
2070 // now, enter the class context
2071 mpCurCtx = pClass;
2072
2073 clear_commets_queue();
2074}
2075
2076void CJSourceParser::AddEnumNode( char*& cur )
2077{
2078 // now the cursor is at "enum" keyword
2079 char* start = cur;
2080
2081 spEnumeration* pEnum = new spEnumeration();
2082 mpCurCtx->AddMember( pEnum );
2083
2084 pEnum->mSrcLineNo = get_line_no();
2085
2086
2087 AttachComments( *pEnum, cur );
2088
2089 skip_token( cur );
2090 if ( !get_next_token( cur ) ) return;
2091
2092 // check if enumeration has got it's identifier
2093 if ( *cur != '{' )
2094 {
2095 pEnum->mName = get_token_str( cur );
2096 }
2097
2098 if ( !skip_imp_block( cur ) ) return;
2099
2100 get_string_between( start, cur, &pEnum->mEnumContent );
2101
2102 if ( get_next_token(cur) )
2103 {
2104 // check if the identifier if after the {...} block
2105 if ( *cur != ';' )
2106
2107 pEnum->mName = get_token_str( cur );
2108 }
2109
2110 clear_commets_queue();
2111}
2112
2113void CJSourceParser::AddTypeDefNode( char*& cur )
2114{
2115 // now the cursor at the token next to "typedef" keyword
2116
2117 if ( !get_next_token(cur) ) return;
2118
2119 char* start = cur;
2120
2121 spTypeDef* pTDef = new spTypeDef();
2122 mpCurCtx->AddMember( pTDef );
2123
2124 pTDef->mSrcLineNo = get_line_no();
2125
2126 AttachComments( *pTDef, cur );
2127
2128 skip_statement( cur );
2129
2130 int tmpLnNo;
2131 store_line_no( tmpLnNo );
2132
2133 char* tok = cur-1;
2134 skip_next_token_back( tok );
2135
2136 char* nameEnd = tok;
2137
2138 skip_token_back( tok );
2139
2140 char* nameStart = tok;
2141
2142 skip_next_token_back( tok );
2143
2144 char* typeEnd = tok;
2145
2146 // check if it's function prototype
2147 if ( *nameStart == ')' )
2148 {
2149 typeEnd = nameStart+1;
2150
2151 // skip argument list
2152 while ( *nameStart != '(' ) --nameStart;
2153
2154 // skip to function type definition
2155 while ( *nameStart != ')' ) --nameStart;
2156
2157 skip_next_token_back( nameStart );
2158
2159 nameEnd = nameStart;
2160
2161 skip_token_back( nameStart );
2162
2163 if ( *nameStart == '*' ) ++nameStart;
2164 }
2165
2166 get_string_between( start, typeEnd, &pTDef->mOriginalType );
2167
2168 get_string_between( nameStart, nameEnd, &pTDef->mName );
2169
2170 clear_commets_queue();
2171
2172 restore_line_no( tmpLnNo );
2173}