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