]> git.saurik.com Git - wxWidgets.git/blob - utils/HelpGen/src/cjparser.cpp
don't force excessively large minsize, it makes the sample nearly unusable on X11
[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 char* _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( char*& cur )
390 {
391 do
392 {
393 skip_to_eol(cur);
394
395 if ( *(cur-1) != '\\' )
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 string get_token_str( char* cur )
648 {
649 return string( 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( string& type,
902 string& identifier )
903 {
904 // TBD:: FIXME:: return value of operators !
905
906 while ( identifier[0u] == '*' ||
907 identifier[0u] == '&'
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( char* start, char* end,
939 string* pStr )
940 {
941 char saved = *end;
942
943 *end = '\0';
944 *pStr = start;
945 *end = saved;
946 }
947
948 static char* set_comment_text( string& text, char* start )
949 {
950 char* 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) == '/' )
958 end -= 2;
959
960 start += 2;
961
962 // skip multiple leading '/''s or '*''s
963 while( *start == '/' && start < end ) ++start;
964 while( *start == '*' && 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 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( cur ) )
1012 // end of source reached
1013 return pTopCtx;
1014
1015 if ( memcmp( cur, "ScriptSection( const string&",
1016 strlen( "ScriptSection( const string&" )
1017 ) == 0
1018 )
1019 {
1020 // int o = 0;
1021 // ++o;
1022 }
1023
1024 switch (*cur)
1025 {
1026 case '#' :
1027 {
1028 AddMacroNode( cur );
1029 continue;
1030 }
1031
1032 case ':' :
1033 {
1034 skip_token( cur );
1035 continue;
1036 }
1037
1038 case ';' :
1039 {
1040 skip_token( cur );
1041 continue;
1042 }
1043
1044 case ')' :
1045 {
1046 skip_token( cur );
1047 continue;
1048 }
1049
1050 case '=' :
1051 {
1052 skip_token( 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(cur, "const", 5) != 0 && is_keyword( 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( cur );
1068 continue;
1069 }
1070
1071 if ( *cur >= '0' && *cur <= '9' )
1072 {
1073 skip_token( cur );
1074 continue;
1075 }
1076
1077 if ( *cur == '}' )
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( cur ); // just skip it
1087 continue;
1088 }
1089
1090 if ( mpCurCtx->GetType() == SP_CTX_CLASS )
1091 {
1092 int curOfs = ( (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( cur );
1117 continue;
1118 }
1119
1120 bool isAMacro = false;
1121
1122 if ( is_function( cur, isAMacro ) )
1123 {
1124 if ( isAMacro )
1125 {
1126 skip_token( cur );
1127 continue;
1128 }
1129
1130 char* savedPos = cur;
1131
1132 int tmpLnNo;
1133 store_line_no( tmpLnNo );
1134 wxUnusedVar( tmpLnNo );
1135
1136 isAMacro = false;
1137
1138 if ( !ParseNameAndRetVal( cur, isAMacro ) )
1139 {
1140 if ( !isAMacro )
1141 {
1142 cur = savedPos;
1143 SkipFunction( cur );
1144 }
1145 continue;
1146 }
1147
1148 if ( !ParseArguments( 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( cur );
1158 //cur = savedPos;
1159 }
1160 else
1161 {
1162 // otherwise, successfully close operation context:
1163
1164 clear_commets_queue();
1165
1166 SkipFunctionBody( 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( cur ); // skip the end of statement
1184 continue;
1185 }
1186
1187 ParseMemberVar( cur );
1188 }
1189
1190 } while( 1 );
1191 }
1192
1193 void CJSourceParser::AttachComments( spContext& ctx, char* cur )
1194 {
1195 if ( !mCommentsOn ) return;
1196
1197 MCommentListT& lst = ctx.GetCommentList();
1198
1199 char* 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 char* start = _gCommentsQueue[i];
1213
1214 pComment->mIsMultiline = ( *(start+1) == '*' );
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 else
1224 if ( pComment->mIsMultiline )
1225
1226 pComment->mStartsPar = true;
1227 else
1228 {
1229 // find out wheather there is a new-line
1230 // between to adjecent comments
1231
1232
1233 char* prevLine = start;
1234 skip_to_prev_line(prevLine);
1235
1236 if ( prevLine >= prevComEnd )
1237
1238 pComment->mStartsPar = true;
1239 else
1240 pComment->mStartsPar = false;
1241 }
1242
1243 prevComEnd = set_comment_text( pComment->mText, start );
1244 }
1245
1246
1247 // attach comments which are at the end of the line
1248 // of the given context (if any)
1249
1250 if ( skip_to_next_comment_in_the_line( cur ) )
1251 {
1252 spComment* pComment = new spComment();
1253 lst.push_back( pComment );
1254
1255 set_comment_text( pComment->mText, cur );
1256
1257 pComment->mStartsPar = 1;
1258 pComment->mIsMultiline = ( *(cur+1) == '*' );
1259
1260 // mark this comment, so that it would not
1261 // get in the comments list of the next context
1262 _gLastSuppresedComment = cur;
1263 }
1264
1265 restore_line_no( tmpLnNo );
1266
1267 clear_commets_queue();
1268 }
1269
1270 void CJSourceParser::AddMacroNode( char*& cur )
1271 {
1272 char* start = cur;
1273
1274 int lineNo = get_line_no();
1275
1276 skip_preprocessor_dir( cur );
1277
1278 int tmpLnNo;
1279 store_line_no( tmpLnNo );
1280
1281 if ( !mMacrosOn ) return;
1282
1283 spPreprocessorLine* pPL = new spPreprocessorLine();
1284 pPL->mSrcLineNo = lineNo;
1285
1286 AttachComments( *pPL, cur );
1287
1288 get_string_between( start, cur, &pPL->mLine );
1289
1290 ++start; // skip '#'
1291 get_next_token( start );
1292
1293 pPL->mDefType = SP_PREP_DEF_OTHER;
1294
1295 // if we found a definition or redefinition,
1296 // determine the type exactly and assign
1297 // a name to the context
1298
1299 if ( *start == 'd' )
1300 {
1301 if ( cmp_tokens_fast( start, "define", 6 ) )
1302 {
1303 char* tok = start+6;
1304
1305 get_next_token( tok );
1306
1307 pPL->mName = get_token_str( tok );
1308
1309 skip_token( tok );
1310 get_next_token( tok);
1311
1312
1313 if ( tok > cur )
1314 pPL->mDefType = SP_PREP_DEF_DEFINE_SYMBOL;
1315 else
1316 pPL->mDefType = SP_PREP_DEF_REDEFINE_SYMBOL;
1317 }
1318 }
1319 else if ( *start == 'i' )
1320 {
1321 if ( cmp_tokens_fast( start, "include", 7 ) )
1322 {
1323 pPL->mDefType = SP_PREP_DEF_INCLUDE_FILE;
1324 }
1325 else if ( *++start == 'f' )
1326 {
1327 // either "#if" or "#ifdef"
1328 cur = start;
1329 skip_token( cur );
1330 get_next_token( cur );
1331
1332 string condition = get_token_str( cur );
1333
1334 // currently, everything except '0' is true
1335 if ( condition == "0" ) {
1336 // skip until the following else or enif
1337 while ( cur < _gSrcEnd ) {
1338 skip_to_eol( cur );
1339 skip_eol( cur );
1340
1341 get_next_token( cur );
1342 if ( *cur++ == '#' && *cur == 'e' )
1343 break;
1344 }
1345 }
1346
1347 // TODO parse the condition...
1348 }
1349 }
1350 else if ( cmp_tokens_fast( start, "else", 4 ) )
1351 {
1352 // skip until "#endif"
1353 while ( cur < _gSrcEnd ) {
1354 skip_to_eol( cur );
1355 skip_eol( cur );
1356
1357 get_next_token( cur );
1358 if ( *cur++ == '#' && cmp_tokens_fast( cur, "endif", 5 ) )
1359 break;
1360 }
1361 }
1362
1363 mpCurCtx->AddMember( pPL );
1364
1365 skip_to_eol( cur );
1366 skip_eol( cur );
1367
1368 restore_line_no( tmpLnNo );
1369
1370 clear_commets_queue();
1371 }
1372
1373 void CJSourceParser::ParseKeyword( char*& cur )
1374 {
1375 // analyze token, which identifies the begining of a new context
1376
1377 if ( CheckVisibilty( cur ) )
1378 {
1379 skip_token( cur );
1380 return;
1381 }
1382
1383 if ( is_class_token( cur ) )
1384 {
1385 if ( is_forward_decl( cur ) )
1386 {
1387 // forward declarations are ignored;
1388 skip_token( cur );
1389 return;
1390 }
1391
1392 if ( mNestingLevel == 0 )
1393 {
1394 // change context form global class context
1395 mCurCtxType = SP_CTX_CLASS;
1396 }
1397
1398 ++mNestingLevel;
1399
1400 // add information about new class (name, inheritance, etc)
1401 AddClassNode( cur );
1402
1403 // the default visiblity for class members is 'private'
1404 mCurVis = SP_VIS_PRIVATE;
1405
1406 return;
1407 }
1408
1409 size_t len = get_token_len( cur );
1410
1411 if ( cmp_tokens_fast( cur, "typedef", len ) )
1412 {
1413 skip_token(cur);
1414 get_next_token(cur);
1415
1416 if ( cmp_tokens_fast( cur, "struct", len ) ||
1417 cmp_tokens_fast( cur, "union", len ) ||
1418 cmp_tokens_fast( cur, "class", len )
1419 )
1420 {
1421 if ( mNestingLevel == 0 )
1422 {
1423 // change context form global class context
1424 mCurCtxType = SP_CTX_CLASS;
1425 }
1426
1427 ++mNestingLevel;
1428
1429 // add information about new class (name, inheritance, etc)
1430 AddClassNode( cur );
1431
1432 // the default visiblity for class members is 'private'
1433 mCurVis = SP_VIS_PRIVATE;
1434
1435 return;
1436
1437 // FOR NOW:: typedef struct, etc are also ignored
1438 //skip_scope_block( cur );
1439 }
1440
1441 if ( cmp_tokens_fast( cur, "enum", len ) )
1442 {
1443 AddEnumNode( cur );
1444 return;
1445 }
1446
1447 AddTypeDefNode( cur );
1448
1449 return;
1450 }
1451
1452 if ( cmp_tokens_fast( cur, "enum", len ) )
1453 {
1454 AddEnumNode( cur );
1455 return;
1456 }
1457
1458 if ( cmp_tokens_fast( cur, "extern", len ) )
1459 {
1460 // extern's are ignored (both extern "C" and extern vars)
1461 while ( *cur != '{' &&
1462 *cur != ';' )
1463 {
1464 skip_token( cur );
1465 get_next_token( cur );
1466 }
1467 return;
1468
1469 }
1470 if ( cmp_tokens_fast( cur, "enum", len ) )
1471 {
1472 // enumeration blocks are ignored
1473
1474 skip_scope_block( cur );
1475
1476 get_next_token( cur );
1477 skip_token( cur ); // skip ';' token;
1478 return;
1479 }
1480
1481 if ( cmp_tokens_fast( cur, "package", len ) )
1482 {
1483 // packages are ignored
1484 skip_statement( cur );
1485 return;
1486 };
1487
1488 if ( cmp_tokens_fast( cur, "import", len ) )
1489 {
1490 // import statements are ignored
1491 skip_statement( cur );
1492 return;
1493 }
1494
1495 if ( cmp_tokens_fast( cur, "virtual", len ) )
1496 {
1497 // probably the virtual method is in front of us;
1498 mIsVirtual = 1;
1499 skip_token( cur );
1500 return;
1501 }
1502
1503 if ( cmp_tokens_fast( cur, "template", len ) )
1504 {
1505 mIsTemplate = 1;
1506 skip_tempalate_statement( cur );
1507 return;
1508 }
1509
1510 if ( cmp_tokens_fast( cur, "friend", len ) )
1511 {
1512 skip_statement( cur );
1513 return;
1514 }
1515
1516 // ingnore "unsigificant" tokens (i.e. which do not
1517 // affect the current parsing context)
1518
1519 skip_token( cur );
1520 }
1521
1522 bool CJSourceParser::ParseNameAndRetVal( char*& cur, bool& isAMacro )
1523 {
1524 isAMacro = false;
1525
1526 // FOR NOW:: all functions in the global
1527 // scope are ignored
1528
1529 int lineNo = get_line_no();
1530
1531 char* start = cur;
1532
1533 bool isVirtual = false;
1534 while( *cur != '(' )
1535 {
1536 if ( get_token_str( cur ) == "virtual" )
1537 isVirtual = true;
1538
1539 skip_token( cur );
1540 if ( !get_next_token( cur ) ) return false;
1541 }
1542
1543 char* bracketPos = cur;
1544 char* savedPos = cur + 1;
1545
1546 int tmpLnNo;
1547 store_line_no( tmpLnNo );
1548
1549 // skip gap between function name and start of paramters list
1550 while ( *(cur-1) == ' ' )
1551 --cur;
1552
1553 // check if it's not a macro, and let plugin handle it, if so
1554
1555 if ( mpPlugin )
1556 {
1557 skip_token_back( cur );
1558
1559 char* tmp = cur;
1560
1561 if ( mpPlugin->CanUnderstandContext( tmp, _gSrcEnd, mpCurCtx ) )
1562 {
1563 cur = tmp;
1564
1565 mpPlugin->ParseContext( _gSrcStart, cur, _gSrcEnd, mpCurCtx );
1566
1567 isAMacro = true;
1568
1569 return false;
1570 }
1571 }
1572
1573 spOperation* pOp = new spOperation();
1574
1575 pOp->mSrcLineNo = lineNo;
1576 pOp->mSrcOffset = int( start - _gSrcStart );
1577 pOp->mHeaderLength = int( bracketPos - start );
1578 if ( mpCurCtx->GetContextType() == SP_CTX_CLASS )
1579 pOp->mScope = mpCurCtx->mName;
1580
1581 mpCurCtx->AddMember( pOp );
1582 pOp->mVisibility = mCurVis;
1583 pOp->mIsVirtual = isVirtual;
1584
1585 // add comments about operation
1586 AttachComments( *pOp, cur );
1587
1588 // go backwards to method name
1589 skip_token_back( cur );
1590
1591 pOp->mName = get_token_str( cur );
1592
1593 // checker whether it's not an operator
1594 char chFirst = *pOp->mName.c_str();
1595 if ( !isalpha(chFirst) && chFirst != '_' && chFirst != '~' ) {
1596 // skip 'operator'
1597 skip_next_token_back( cur );
1598 skip_token_back( cur );
1599
1600 string lastToken = get_token_str( cur );
1601 if ( lastToken == "operator" ) {
1602 lastToken += pOp->mName;
1603 pOp->mName = lastToken;
1604 }
1605 else {
1606 // ok, it wasn't an operator after all
1607 skip_token( cur );
1608 }
1609 }
1610 else if ( pOp->mName == "operator" ) {
1611 skip_token( cur );
1612 get_next_token( cur );
1613 string oper = get_token_str( cur );
1614
1615 pOp->mName += oper;
1616 }
1617
1618 // go backwards to method return type
1619 skip_next_token_back( cur );
1620
1621 if ( cur >= start )
1622 {
1623 string rettype = string( start, size_t( cur-start ) );
1624 rettype.Replace("WXDLLEXPORT ", ""); // FIXME just for now...
1625 pOp->mRetType = rettype;
1626 }
1627
1628 arrange_indirection_tokens_between( pOp->mRetType, pOp->mName );
1629
1630 cur = savedPos;
1631 restore_line_no( tmpLnNo );
1632
1633 // now, enter operation context
1634 mpCurCtx = pOp;
1635
1636 return true;
1637 }
1638
1639 bool CJSourceParser::ParseArguments( char*& cur )
1640 {
1641 // DANGER-MACROS::
1642
1643 // now cursor position is right after the first opening bracket
1644 // of the function declaration
1645
1646 char* blocks [16]; // used exclusivelly for iterative "lean out"
1647 // of macros and misc. not-obviouse grammar
1648 // (dirty,, but we cannot do it very nice,
1649 // we're not preprocessor-free C/C++ code)
1650 int blockSizes[16];
1651
1652 do
1653 {
1654 size_t blocksSkipped = 0;
1655
1656 get_next_token( cur );
1657
1658 bool first_blk = true;
1659
1660 while( *cur != ')' && *cur != ',' )
1661 {
1662 blocks[blocksSkipped] = cur;
1663
1664 if ( first_blk )
1665 {
1666 char* prev = cur;
1667 skip_token( cur );
1668
1669 blockSizes[blocksSkipped] = size_t(cur-prev);
1670
1671 first_blk = 0;
1672 }
1673 else
1674 blockSizes[blocksSkipped] = skip_block( cur );
1675
1676 get_next_token( cur );
1677 ++blocksSkipped;
1678 }
1679
1680
1681 if ( blocksSkipped == 1 )
1682 {
1683 // check if the empty arg. list stressed with "void" inside
1684 if ( cmp_tokens_fast( blocks[0] , "void", 4 ) )
1685 {
1686 cur++; // skip ')'
1687
1688 break;
1689 }
1690
1691 // FIXME:: TBD:: K&R-style function declarations!
1692
1693 // if only one block enclosed, than it's probably
1694 // some macro, there should be at least two blocks,
1695 // one for argument type and another for it's identifier
1696 return false;
1697 }
1698
1699 if ( blocksSkipped == 0 )
1700 {
1701 if ( *cur == 10 ) ++_gLineNo;
1702 ++cur; // skip ')'
1703
1704 break; // function without paramters
1705 }
1706
1707 // we should be in the operation context now
1708 spOperation* pOp = (spOperation*)mpCurCtx;
1709
1710 spParameter* pPar = new spParameter();
1711
1712 pOp->AddMember( pPar );
1713 // FOR NOW:: line number is not exact if argument list is mutiline
1714 pPar->mSrcLineNo = get_line_no();
1715
1716 size_t nameBlock = blocksSkipped - 1;
1717 size_t typeBlock = nameBlock - 1;
1718
1719 // check if default values present
1720 if ( *blocks[typeBlock] == '=' )
1721 {
1722 // expressions like "int = 5" are ignored,
1723 // since name for paramters is required
1724 if ( blocksSkipped == 3 )
1725 {
1726 if ( *cur == ')' )
1727 {
1728 ++cur;
1729 break;
1730 }
1731 else
1732 continue;
1733 }
1734
1735 pPar->mInitVal = string( blocks[nameBlock], blockSizes[nameBlock] );
1736
1737 nameBlock = nameBlock - 2; // skip '=' token and default value block
1738 typeBlock = nameBlock - 1;
1739 }
1740
1741 // attach comments about the parameter
1742 AttachComments( *pPar, blocks[nameBlock] );
1743
1744 // retrieve argument name
1745 pPar->mName = string( blocks[nameBlock], blockSizes[nameBlock] );
1746
1747 // retreive argument type
1748
1749 size_t len = blockSizes[ typeBlock ];
1750 len = size_t ( (blocks[ typeBlock ] + len) - blocks[ 0 ] );
1751
1752 pPar->mType = string( blocks[0], len );
1753
1754 arrange_indirection_tokens_between( pPar->mType, pPar->mName );
1755
1756 if ( *cur == ')' )
1757 {
1758 ++cur;
1759 break;
1760 }
1761
1762 ++cur; // skip comma
1763 get_next_token(cur);
1764
1765 } while(1);
1766
1767 // skip possible whitespace between ')' and following "const"
1768 while ( isspace(*cur) )
1769 cur++;
1770
1771 // check if it was really a function not a macro,
1772 // if so, than it should be terminated with semicolon ';'
1773 // or opening implemenetaton bracket '{'
1774
1775 char* tok = cur;
1776
1777 int tmpLnNo;
1778 store_line_no( tmpLnNo );
1779
1780 bool result = true;
1781
1782 do
1783 {
1784 if ( *tok == '{' || *tok == ';' )
1785 {
1786 restore_line_no(tmpLnNo);
1787 break;
1788 }
1789
1790 // check for unexpected tokens
1791 if ( *tok == '=' || *tok == '0' )
1792 {
1793 skip_token(tok);
1794 if ( !get_next_token(tok) ) return false;
1795 continue;
1796 }
1797
1798 if ( *tok == '}' ) return false;
1799
1800 // if initialization list found
1801 if ( *tok == ':' )
1802 {
1803 restore_line_no(tmpLnNo);
1804 break;
1805 }
1806
1807 if ( cmp_tokens_fast( tok, "const", 5 ) )
1808 {
1809 ((spOperation*)mpCurCtx)->mIsConstant = true;
1810
1811 skip_token(tok);
1812 if ( !get_next_token(tok) ) return false;
1813 continue;
1814 }
1815
1816 if ( CheckVisibilty( tok ) ) return false;
1817
1818 // if next context found
1819 if ( is_keyword( tok ) ) return false;
1820
1821 skip_token(tok);
1822 if ( !get_next_token(tok) ) return false;
1823
1824 } while(1);
1825
1826 return result;
1827 }
1828
1829 void CJSourceParser::ParseMemberVar( char*& cur )
1830 {
1831 MMemberListT& members = mpCurCtx->GetMembers();
1832
1833 bool firstMember = true;
1834
1835 string type;
1836
1837 // jump to the end of statement
1838 // and start collecting same-type varibles
1839 // back-to-front towards the type identifier
1840
1841 skip_statement( cur );
1842 char* savedPos = cur;
1843
1844 int tmpLnNo;
1845 store_line_no( tmpLnNo );
1846
1847 --cur; // rewind back to ';'
1848
1849 do
1850 {
1851 spAttribute* pAttr = new spAttribute();
1852 // FOR NOW:: line not is not exact, if member declaration is multiline
1853 pAttr->mSrcLineNo = get_line_no();
1854
1855 mpCurCtx->AddMember( pAttr );
1856 pAttr->mVisibility = mCurVis;
1857
1858 pAttr->mIsConstant = 0;
1859
1860 if ( firstMember )
1861 {
1862 firstMember = 0;
1863 }
1864
1865 skip_token_back( cur );
1866
1867 // attach comments about the attribute
1868 AttachComments( *pAttr, cur );
1869
1870 pAttr->mName = get_token_str( cur );
1871
1872 // guessing that this going to be variable type
1873 skip_next_token_back( cur );
1874 skip_token_back( cur );
1875
1876 pAttr->mType = get_token_str( cur );
1877
1878 // if comma, than variable list continues
1879 // otherwise the variable type reached - stop
1880
1881 if ( *cur == '=' )
1882 {
1883 // yes, we've mistaken, it was not a identifier,
1884 // but it's default value
1885 pAttr->mInitVal =
1886 pAttr->mName;
1887
1888 // skip default value and '=' symbol
1889 skip_next_token_back( cur );
1890 skip_token_back( cur );
1891
1892 pAttr->mName = get_token_str( cur );
1893
1894 skip_next_token_back( cur );
1895 skip_token_back( cur );
1896 }
1897
1898 if ( *cur != ',' )
1899 {
1900 type = get_token_str( cur );
1901 break;
1902 }
1903
1904 } while(1);
1905
1906 size_t first = 0;
1907
1908 // set up types for all collected (same-type) attributes;
1909 while ( first != members.size() - 1 )
1910 {
1911 spAttribute* pAttr = members[first++]->CastToAttribute();
1912 if ( !pAttr )
1913 continue;
1914
1915 if ( !pAttr->mType )
1916 pAttr->mType = type;
1917 pAttr->mVisibility = mCurVis;
1918
1919 if ( !!pAttr->mName )
1920 arrange_indirection_tokens_between( pAttr->mType, pAttr->mName );
1921 }
1922
1923 cur = savedPos;
1924 restore_line_no( tmpLnNo );
1925
1926 clear_commets_queue();
1927
1928
1929 }
1930
1931 void CJSourceParser::SkipFunction( char*& cur )
1932 {
1933 while ( *cur != '(' && cur < _gSrcEnd )
1934 {
1935 if (*cur == 10 ) ++_gLineNo;
1936 ++cur;
1937 }
1938
1939 skip_next_token_back( cur ); // go back and skip function identifier
1940 skip_token_back( cur ); // go back and skip return type
1941
1942 skip_block( cur ); // now, go ahead and skip whole declaration
1943
1944 SkipFunctionBody( cur );
1945
1946 }
1947
1948 void CJSourceParser::SkipFunctionBody( char*& cur )
1949 {
1950 // FIXME:: check for comments and quoted stirngs here
1951
1952 bool hasDefinition = false;
1953
1954 while( *cur != '{' && *cur != ';' )
1955 {
1956 if (*cur == 10 ) ++_gLineNo;
1957 ++cur;
1958 }
1959
1960 if ( *cur == ';' )
1961 {
1962 ++cur;
1963 }
1964 else
1965 {
1966 hasDefinition = true;
1967
1968 skip_scope_block( cur ); // skip the whole imp.
1969 }
1970
1971 if ( mpCurCtx->GetType() == SP_CTX_OPERATION )
1972 {
1973 spOperation& op = *((spOperation*)mpCurCtx);
1974
1975 int curOfs = int ( cur - _gSrcStart );
1976
1977 op.mContextLength = curOfs - mpCurCtx->mSrcOffset;
1978
1979 op.mHasDefinition = hasDefinition;
1980
1981 // separate scope resolution token from the name of operation
1982
1983 for( size_t i = 0; i != op.mName.length(); ++i )
1984 {
1985 if ( op.mName[i] == ':' && op.mName[i+1] == ':' )
1986 {
1987 string unscoped( op.mName, i+2, op.mName.length() - ( i + 2 ) );
1988
1989 op.mScope = string( op.mName, 0, i );
1990
1991 op.mName = unscoped;
1992
1993 break;
1994 }
1995 }
1996 }
1997 }
1998
1999 bool CJSourceParser::CheckVisibilty( char*& cur )
2000 {
2001 size_t len = get_token_len( cur );
2002
2003 if ( cmp_tokens_fast( cur, "public:", len ) )
2004 {
2005 mCurVis = SP_VIS_PUBLIC;
2006 return true;
2007 }
2008
2009 if ( cmp_tokens_fast( cur, "protected:", len ) )
2010 {
2011 mCurVis = SP_VIS_PROTECTED;
2012 return true;
2013 }
2014
2015 if ( cmp_tokens_fast( cur, "private:", len ) )
2016 {
2017 mCurVis = SP_VIS_PRIVATE;
2018 return true;
2019 }
2020
2021 return false;
2022 }
2023
2024 void CJSourceParser::AddClassNode( char*& cur )
2025 {
2026 char* ctxStart = cur;
2027
2028 string classkeyword = get_token_str( cur );
2029
2030 skip_token( cur ); // skip 'class' keyword
2031 if ( !get_next_token( cur ) ) return;
2032
2033 // in C++
2034 if ( *cur == ':' )
2035 {
2036 skip_token( cur );
2037 get_next_token( cur );
2038 }
2039
2040 // by default all class members are private
2041 mCurVis = SP_VIS_PRIVATE;
2042
2043 spClass* pClass = new spClass();
2044 if ( classkeyword == "class" )
2045 pClass->mClassSubType = SP_CLTYPE_CLASS;
2046 else if ( classkeyword == "struct" ) {
2047 pClass->mClassSubType = SP_CLTYPE_STRUCTURE;
2048
2049 mCurVis = SP_VIS_PUBLIC;
2050 }
2051 else if ( classkeyword == "union" ) {
2052 pClass->mClassSubType = SP_CLTYPE_UNION;
2053
2054 mCurVis = SP_VIS_PUBLIC;
2055 }
2056 else if ( classkeyword == "interface" )
2057 pClass->mClassSubType = SP_CLTYPE_INTERFACE;
2058 else {
2059 pClass->mClassSubType = SP_CLTYPE_INVALID;
2060
2061 wxFAIL_MSG("unknown class keyword");
2062 }
2063
2064 mpCurCtx->AddMember( pClass );
2065
2066 // attach comments about the class
2067 AttachComments( *pClass, cur );
2068
2069 pClass->mSrcLineNo = get_line_no();
2070
2071 pClass->mSrcOffset = int( ctxStart - _gSrcStart );
2072
2073 char* nameTok = cur;
2074 pClass->mName = get_token_str( cur );
2075
2076 bool isDerived = 0;
2077
2078 // DANGER-MACROS::
2079
2080 do
2081 {
2082 skip_token( cur );
2083 if ( !get_next_token( cur ) ) return;
2084
2085 if ( *cur == ':' )
2086 {
2087 isDerived = 1;
2088
2089 char* tok = cur;
2090
2091 int tmpLn;
2092 store_line_no( tmpLn );
2093
2094 skip_next_token_back( tok );
2095 skip_token_back( tok );
2096
2097 restore_line_no( tmpLn );
2098
2099 // class name should precend ':' colon, thus
2100 // the one which was captured before was
2101 // proablty something else (like __dllexport MyClass : ... )
2102
2103 if ( nameTok != tok )
2104 {
2105 pClass->mName = get_token_str( tok );
2106 }
2107
2108 }
2109
2110 if ( *cur == '{' )
2111 break;
2112
2113 if ( *cur == ',' )
2114 continue;
2115
2116 size_t len = get_token_len( cur );
2117
2118 // skip neglectable C++ modifieres
2119 if ( cmp_tokens_fast( cur, "public", len ) )
2120 continue;
2121
2122 if ( cmp_tokens_fast( cur, "protected", len ) )
2123 continue;
2124
2125 if ( cmp_tokens_fast( cur, "private", len ) )
2126 continue;
2127
2128 if ( cmp_tokens_fast( cur, "virtual", len ) )
2129 continue;
2130
2131 // skip neglectable JAVA modifieres
2132
2133 if ( cmp_tokens_fast( cur, "extends", len ) )
2134 {
2135 isDerived = 1;
2136 continue;
2137 }
2138
2139 if ( cmp_tokens_fast( cur, "implements", len ) )
2140 {
2141 isDerived = 1;
2142 continue;
2143 }
2144
2145 // all we need to know is superclass or interface
2146
2147 char* tok = cur;
2148 int tmpLn;
2149 store_line_no( tmpLn );
2150
2151 skip_token(tok);
2152 get_next_token(tok);
2153
2154 restore_line_no( tmpLn );
2155
2156 if ( *tok != ':' && *cur != ':' )
2157
2158 pClass->mSuperClassNames.push_back( string( cur, len ) );
2159
2160 } while(1);
2161
2162 if ( !isDerived )
2163 {
2164 int tmpLn;
2165 store_line_no( tmpLn );
2166
2167 while ( pClass->mSuperClassNames.size() )
2168
2169 pClass->mSuperClassNames.erase( &pClass->mSuperClassNames[0] );
2170
2171 char* tok = cur;
2172
2173 // some non-obviouse token was following "class" keyword -
2174 // we've confused it with class name - thus now we're reverting this mistake
2175
2176 skip_next_token_back( tok );
2177 skip_token_back( tok );
2178
2179 pClass->mName = get_token_str( tok );
2180
2181 restore_line_no( tmpLn );
2182 }
2183
2184
2185 ++cur; // skip opening curly brace
2186
2187 pClass->mHeaderLength = ( cur - ctxStart );
2188
2189 // now, enter the class context
2190 mpCurCtx = pClass;
2191
2192 clear_commets_queue();
2193 }
2194
2195 void CJSourceParser::AddEnumNode( char*& cur )
2196 {
2197 // now the cursor is at "enum" keyword
2198 char* start = cur;
2199
2200 spEnumeration* pEnum = new spEnumeration();
2201 mpCurCtx->AddMember( pEnum );
2202
2203 pEnum->mSrcLineNo = get_line_no();
2204
2205
2206 AttachComments( *pEnum, cur );
2207
2208 skip_token( cur );
2209 if ( !get_next_token( cur ) ) return;
2210
2211 // check if enumeration has got it's identifier
2212 if ( *cur != '{' )
2213 {
2214 pEnum->mName = get_token_str( cur );
2215 }
2216
2217 if ( !skip_imp_block( cur ) ) return;
2218
2219 get_string_between( start, cur, &pEnum->mEnumContent );
2220
2221 if ( get_next_token(cur) )
2222 {
2223 // check if the identifier if after the {...} block
2224 if ( *cur != ';' )
2225
2226 pEnum->mName = get_token_str( cur );
2227 }
2228
2229 clear_commets_queue();
2230 }
2231
2232 void CJSourceParser::AddTypeDefNode( char*& cur )
2233 {
2234 // now the cursor at the token next to "typedef" keyword
2235
2236 if ( !get_next_token(cur) ) return;
2237
2238 char* start = cur;
2239
2240 spTypeDef* pTDef = new spTypeDef();
2241 mpCurCtx->AddMember( pTDef );
2242
2243 pTDef->mSrcLineNo = get_line_no();
2244
2245 AttachComments( *pTDef, cur );
2246
2247 skip_statement( cur );
2248
2249 int tmpLnNo;
2250 store_line_no( tmpLnNo );
2251
2252 char* tok = cur-1;
2253 skip_next_token_back( tok );
2254
2255 char* nameEnd = tok;
2256
2257 skip_token_back( tok );
2258
2259 char* nameStart = tok;
2260
2261 skip_next_token_back( tok );
2262
2263 char* typeEnd = tok;
2264
2265 // check if it's function prototype
2266 if ( *nameStart == ')' )
2267 {
2268 typeEnd = nameStart+1;
2269
2270 // skip argument list
2271 while ( *nameStart != '(' ) --nameStart;
2272
2273 // skip to function type definition
2274 while ( *nameStart != ')' ) --nameStart;
2275
2276 skip_next_token_back( nameStart );
2277
2278 nameEnd = nameStart;
2279
2280 skip_token_back( nameStart );
2281
2282 if ( *nameStart == '*' ) ++nameStart;
2283 }
2284
2285 get_string_between( start, typeEnd, &pTDef->mOriginalType );
2286
2287 get_string_between( nameStart, nameEnd, &pTDef->mName );
2288
2289 clear_commets_queue();
2290
2291 restore_line_no( tmpLnNo );
2292 }