]> git.saurik.com Git - wxWidgets.git/blame_incremental - utils/HelpGen/src/cjparser.cpp
Updated PyCrust from Patrick O'Brien
[wxWidgets.git] / utils / HelpGen / src / cjparser.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: No names yet.
3// Purpose: Contrib. demo
4// Author: Aleksandras Gluchovas
5// Modified by:
6// Created: 22/09/98
7// RCS-ID: $Id$
8// Copyright: (c) Aleskandars Gluchovas
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13# pragma implementation "acell.h"
14#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
43static char* _gSrcStart = 0;
44static char* _gSrcEnd = 0;
45static char* _gLastSuppresedComment = 0;
46static int _gLineNo = 0;
47
48// FOR NOW:: comments queue is static
49#define MAX_CQ_ENTRIES 128
50static char* _gCommentsQueue[MAX_CQ_ENTRIES];
51static int _gCQSize = 0;
52
53/***** keyword map related structures *****/
54
55struct 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
75static KeywordMapT __gMultiLangMap;
76static int __gMapReady = 0;
77
78static 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
114static 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
138static inline void skip_to_eol( char*& cur )
139{
140 while( *(cur) != 10 && *cur != 13 && cur < _gSrcEnd) ++cur;
141}
142
143static 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
154static 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
182inline static void store_line_no( int& toVar )
183{
184 toVar = _gLineNo;
185}
186
187inline static void restore_line_no( int storedLineNo )
188{
189 _gLineNo = storedLineNo;
190}
191
192inline static int get_line_no()
193{
194 return _gLineNo;
195}
196
197static 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
228static 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
325static inline void clear_commets_queue()
326{
327 _gCQSize = 0;
328}
329
330static 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
361static 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
385 return FALSE;
386 else
387 return TRUE;
388}
389
390static inline void skip_preprocessor_dir( char*& cur )
391{
392 do
393 {
394 skip_to_eol(cur);
395
396 if ( *(cur-1) != '\\' )
397 break;
398
399 if ( cur < _gSrcEnd )
400 skip_eol( cur );
401 else
402 break;
403
404 } while(1);
405}
406
407static void skip_token( char*& cur )
408{
409 if ( *cur == '"' )
410 {
411 skip_quoted_string( cur );
412 return;
413 }
414
415 if ( *cur == ',' ||
416 *cur == ';' ||
417 *cur == ')' ||
418 *cur == '('
419 )
420 {
421 ++cur;
422 return;
423 }
424
425 // special case of "!=", "<=", ... 2 character composite tokens
426 if ( *cur == '<' ||
427 *cur == '>' ||
428 *cur == '=' ||
429 *cur == '!'
430 )
431 {
432 cur++;
433 if ( *cur == '=' )
434 cur++;
435
436 return;
437 }
438
439 ++cur; // leading character is always skipped
440
441 for( ; cur < _gSrcEnd ; ++cur )
442 {
443 switch ( *cur )
444 {
445 case ' ' : break;
446 case '\t': break;
447 case 13 : break;
448 case 10 : break;
449 case ',' : break;
450 case ';' : break;
451 case '<' : break;
452 case '>' : break;
453
454 // FIXME:: QUICK-HACK:: to treat scope resolution
455 // tokens are a part of the string - e.g. SomeSpace::SubName would
456 // become one token
457
458 case ':' : if ( *(cur+1) == ':' )
459 {
460 ++cur;
461 continue;
462 }
463
464 break;
465 case '=' : break;
466 case '(' : break;
467 case ')' : break;
468 case '{' : break;
469 case '}' : break;
470
471 default : continue;
472 };
473 break;
474 }
475}
476
477static inline size_t get_token_len( char* tok )
478{
479 char* start = tok;
480
481 skip_token( tok );
482
483 return size_t( tok - start );
484}
485
486// returns true, if given tokens are equel
487
488static inline bool cmp_tokens( char* tok1, char* tok2 )
489{
490 // NOTE:: the case one token includes
491 // other in it's entirely is not handled
492
493 size_t len = get_token_len( tok1 );
494
495 // assuming that tokens are non-zero length
496
497 do
498 {
499 if ( *(tok1++) != *(tok2++) )
500 return FALSE;
501
502 --len;
503
504 } while ( --len );
505
506 return TRUE;
507}
508
509static inline bool cmp_tokens_fast( char* tok1, char* tok2, size_t len )
510{
511 do
512 {
513 if ( *(tok1++) != *(tok2++) )
514 return FALSE;
515
516 } while ( --len );
517
518 return TRUE;
519}
520
521static inline void skip_tempalate_statement( char*& cur )
522{
523 size_t level = 0;
524
525 // go one level deeper
526 while( *cur != '<' && cur < _gSrcEnd )
527 {
528 if (*cur == 10 ) ++_gLineNo;
529 ++cur;
530 }
531
532 // FIXME:: template should be checked statement for
533 // comments inside of it
534
535 do
536 {
537 if ( *cur == '<' )
538 ++level;
539 else
540 --level;
541
542 ++cur; // skip '<' or '>' token
543
544 if ( level == 0 )
545 return;
546
547 while( *cur != '<' && *cur != '>' && cur < _gSrcEnd )
548 {
549 if (*cur == 10 ) ++_gLineNo;
550 ++cur;
551 }
552
553 } while (1);
554}
555
556static inline void skip_statement( char*& cur )
557{
558 for( ; cur < _gSrcEnd; ++cur )
559
560 switch (*cur)
561 {
562 case ';' : ++cur; // skip statement-terminator token
563 return;
564
565 case '"' : skip_quoted_string(cur);
566 --cur;
567 continue;
568
569 case 10 : ++_gLineNo;
570
571 continue;
572 case '/' : skip_comments( cur );
573 --cur;
574 continue;
575 default : continue;
576 }
577}
578
579// "reversed" versions of skip_token() and get_next_token()
580
581static inline void skip_token_back( char*& cur )
582{
583 // FIXME:: now, when moving backwards, neither strings nor
584 // comment blocks are checked
585
586 --cur; // skip to the trailing character
587
588 if ( *cur == ',' ||
589 *cur == ')' ||
590 *cur == '('
591 )
592 return;
593
594
595 for( ; cur < _gSrcEnd ; --cur )
596 {
597 switch ( *cur )
598 {
599 case ' ' : break;
600 case '\t': break;
601 case 13 : break;
602 case 10 : break;
603 case ',' : break;
604 case '(' : break;
605
606 default : continue;
607 };
608
609 break;
610 }
611
612 ++cur; // get to the leading character of the token
613}
614
615static inline void skip_next_token_back( char*& cur )
616{
617 --cur; // skip leading character of the current token
618
619 if ( *cur == ',' ||
620 *cur == ')' ||
621 *cur == '('
622 )
623 {
624 ++cur;
625 return;
626 }
627
628 for( ; cur < _gSrcEnd; --cur )
629 {
630 switch ( *cur )
631 {
632 case ' ' : continue;
633 case '\t': continue;
634 case 13 : continue;
635 case 10 : continue;
636 case ',' : continue;
637 case '(' : continue;
638
639 default : break;
640 };
641
642 break;
643 }
644
645 ++cur; // position after the trailing charcter of the prev token
646}
647
648static string get_token_str( char* cur )
649{
650 return string( cur, get_token_len( cur ) );
651}
652
653// skips token or whole expression which may have
654// nested expressions between '(' ')' brackets.
655//
656// Upon return, the cursor points to the terminating bracket ')',
657//
658// Return value is the size of the block
659
660static size_t skip_block( char*& cur )
661{
662 size_t level = 0; // nesting level
663
664 char* start = cur;
665
666 // NOTE:: assumed that block not necessarely starts
667 // with bracket rightaway
668
669 if ( *cur == '(' )
670 {
671 ++level;
672 }
673
674 do
675 {
676 skip_token( cur );
677
678 char* savedPos = cur;
679 int tmpLnNo;
680 store_line_no( tmpLnNo );
681
682 get_next_token( cur );
683
684 if ( cur >= _gSrcEnd ) return 0;
685
686 if ( *cur == '(' )
687 {
688 ++level;
689 }
690 else
691 if ( *cur == ')' )
692 {
693 if ( level == 0 )
694 {
695 cur = savedPos;
696 restore_line_no( tmpLnNo );
697
698 return size_t(cur-start);
699 }
700
701 --level;
702
703 if ( level == 0 )
704 {
705 ++cur;
706
707 // QUICK-HACK::to easily handle function prototypes ,
708 // it works, besause theoretically there should
709 // be no cast-expressions in non-implementation
710 // scope (e.g. "time( (long*)(ptr+1) )" should not
711 // appear in the declarations, thus it is most likelly
712 // for the ")(" fragment to be within a function
713 // prototype in the declarations scope
714
715 if ( *cur == '(' )
716 {
717 ++level;
718 continue;
719 }
720
721 else return size_t(cur-start);
722 }
723 }
724 else
725 {
726 if ( level == 0 )
727 {
728 cur = savedPos;
729 restore_line_no( tmpLnNo );
730
731 return size_t(cur-start);
732 }
733 }
734
735 } while(1);
736}
737
738// returns 0, if end of source reached
739static inline bool skip_imp_block( char*& cur )
740{
741 while( *cur != '{' && cur < _gSrcEnd )
742 {
743 skip_token( cur );
744 if ( !get_next_token( cur ) ) return FALSE;
745 }
746
747 while( *cur != '}' && cur < _gSrcEnd )
748 {
749 skip_token( cur );
750 if ( !get_next_token( cur ) ) return FALSE;
751 }
752
753 ++cur;
754
755 return TRUE;
756}
757
758static bool is_class_token( char*& cur )
759{
760 // FIXME:: the below mess should be cleaned in it's entirely
761
762 if ( *cur == 'i' )
763 if ( *(cur+1) == 'n' )
764
765 return cmp_tokens_fast( cur, "interface", 9 );
766
767 if ( *cur == 'c' )
768 if ( *(cur+1) == 'l' )
769
770 return cmp_tokens_fast( cur, "class", 5 );
771
772 if ( *cur == 's' )
773 if ( *(cur+1) == 't' )
774
775 return cmp_tokens_fast( cur, "struct", 6 );
776
777 if ( *cur == 'u' )
778 if ( *(cur+1) == 'n' )
779
780 return cmp_tokens_fast( cur, "union", 5 );
781
782 return FALSE;
783}
784
785inline static bool is_forward_decl( char* cur )
786{
787 do
788 {
789 switch( *cur )
790 {
791 case ':' : return FALSE;
792 case '{' : return FALSE;
793 case '(' : return FALSE;
794
795 case ';' : return TRUE;
796
797 default : break;
798 };
799
800 ++cur;
801
802 } while (cur < _gSrcEnd); // prevent running out of bounds
803
804 return FALSE;
805}
806
807inline static bool is_function( char* cur, bool& isAMacro )
808{
809 isAMacro = FALSE;
810
811 int tmpLnNo;
812 store_line_no( tmpLnNo );
813
814 // NOTE:: comments and quoted strings are not checked here
815
816 // first,check for "single-line hanginging macros" like:
817 // ___UNICODE
818 //
819
820 char* eol = cur;
821 skip_to_eol( eol );
822
823 skip_token( cur );
824 get_next_token( cur );
825
826 if ( cur > eol )
827 {
828 isAMacro = TRUE;
829 restore_line_no( tmpLnNo );
830
831 return TRUE;
832 }
833
834 // it's not a macro, go to the begining of arg. list
835
836 do
837 {
838 // if bracket found, it's a function or a begining
839 // of some macro
840 if ( *cur == '(' )
841 {
842 restore_line_no( tmpLnNo );
843 return TRUE;
844 }
845
846 // end of statement found without any brackets in it
847 // - it cannot be a function
848
849 if ( *cur == ';' )
850 {
851 restore_line_no( tmpLnNo );
852 return FALSE;
853 }
854
855 ++cur;
856
857 } while( cur < _gSrcEnd);
858
859 isAMacro = 1;
860 restore_line_no( tmpLnNo );
861
862 return FALSE;
863}
864
865// upon return the cursor is positioned after the
866// terminating curly brace
867
868static inline void skip_scope_block( char*& cur )
869{
870 size_t level = 0;
871
872 for( ; cur < _gSrcEnd ; ++cur )
873
874 switch( *cur )
875 {
876 case '/' : skip_comments( cur );
877 --cur;
878 continue;
879 case '"' : skip_quoted_string( cur );
880 --cur;
881 continue;
882
883 case '{' : ++level;
884 continue;
885
886 case '}' :--level;
887 if ( level == 0 )
888 {
889 ++cur; // skip final closing curly brace
890 return;
891 }
892
893 case 10 : ++_gLineNo; continue;
894
895 default : continue;
896 };
897}
898
899// moves tokens like '*' '**', '***', '&' from the name
900// to the type
901
902static void arrange_indirection_tokens_between( string& type,
903 string& identifier )
904{
905 // TBD:: FIXME:: return value of operators !
906
907 while ( identifier[0] == '*' ||
908 identifier[0] == '&'
909 )
910 {
911 type += identifier[0];
912 identifier.erase(0,1);
913
914 if ( !identifier.length() ) return;
915 }
916}
917
918
919// the only function where multi-lang keyword map is accessed
920
921static bool is_keyword( char* cur )
922{
923 size_t len = get_token_len( cur );
924
925 // put a terminating zero after the given token
926 char tmp = *(cur + len);
927 *(cur+len) = '\0';
928
929 KeywordMapT::iterator i;
930
931 i = __gMultiLangMap.find( cur );
932
933 // restore original character suppresed by terminating zero
934 *(cur + len) = tmp;
935
936 return i == __gMultiLangMap.end() ? false : true;
937}
938
939static inline void get_string_between( char* start, char* end,
940 string* pStr )
941{
942 char saved = *end;
943
944 *end = '\0';
945 *pStr = start;
946 *end = saved;
947}
948
949static char* set_comment_text( string& text, char* start )
950{
951 char* end = start;
952
953 // to avoid poluting the queue with this comment
954 _gLastSuppresedComment = start;
955
956 skip_comments( end );
957
958 if ( *(end-1) == '/' )
959 end -= 2;
960
961 start += 2;
962
963 // skip multiple leading '/''s or '*''s
964 while( *start == '/' && start < end ) ++start;
965 while( *start == '*' && start < end ) ++start;
966
967 get_string_between( start, end, &text );
968
969 return end;
970}
971
972/***** Implementation for class CJSourceParser *****/
973
974CJSourceParser::CJSourceParser( bool collectCommnets, bool collectMacros )
975 : mpStart(0),
976 mpEnd(0),
977 mpCurCtx( 0 ),
978 mCommentsOn( collectCommnets ),
979 mMacrosOn ( collectMacros )
980{
981 check_keyword_map();
982}
983
984spFile* CJSourceParser::Parse( char* start, char* end )
985{
986 // set up state variables
987 mCurVis = SP_VIS_PRIVATE;
988
989 spFile* pTopCtx = new spFile();
990 mpCurCtx = pTopCtx;
991
992 mIsVirtual = 0;
993 mIsTemplate = 0;
994 mNestingLevel = 0;
995
996 cur = start;
997
998 mpStart = start;
999 mpEnd = end;
1000
1001 _gSrcEnd = mpEnd; // let all the C-functions "smell" the end of file
1002 _gSrcStart = start;
1003
1004 _gLineNo = 0;
1005
1006 clear_commets_queue();
1007
1008 // main parsing loop
1009
1010 do
1011 {
1012 if ( !get_next_token( cur ) )
1013 // end of source reached
1014 return pTopCtx;
1015
1016 if ( memcmp( cur, "ScriptSection( const string&",
1017 strlen( "ScriptSection( const string&" )
1018 ) == 0
1019 )
1020 {
1021 int o = 0;
1022 ++o;
1023 }
1024
1025 switch (*cur)
1026 {
1027 case '#' :
1028 {
1029 AddMacroNode( cur );
1030 continue;
1031 }
1032
1033 case ':' :
1034 {
1035 skip_token( cur );
1036 continue;
1037 }
1038
1039 case ';' :
1040 {
1041 skip_token( cur );
1042 continue;
1043 }
1044
1045 case ')' :
1046 {
1047 skip_token( cur );
1048 continue;
1049 }
1050
1051 case '=' :
1052 {
1053 skip_token( cur );
1054 continue;
1055 }
1056
1057 default: break;
1058 }
1059
1060 // 'const' is a part of the return type, not a keyword here
1061 if ( strncmp(cur, "const", 5) != 0 && is_keyword( cur ) )
1062 {
1063 // parses, token, if token identifies
1064 // the container context (e.g. class/namespace)
1065 // the corresponding context object is created
1066 // and set as current context
1067
1068 ParseKeyword( cur );
1069 continue;
1070 }
1071
1072 if ( *cur >= '0' && *cur <= '9' )
1073 {
1074 skip_token( cur );
1075 continue;
1076 }
1077
1078 if ( *cur == '}' )
1079 {
1080 if ( mCurCtxType != SP_CTX_CLASS )
1081 {
1082 // FOR NOW:: disable the below assertion
1083
1084 // DBG:: unexpected closing-bracket found
1085 //ASSERT(0);
1086
1087 skip_token( cur ); // just skip it
1088 continue;
1089 }
1090
1091 if ( mpCurCtx->GetType() == SP_CTX_CLASS )
1092 {
1093 int curOfs = ( (cur+1) - _gSrcStart );
1094
1095 mpCurCtx->mContextLength = ( curOfs - mpCurCtx->mSrcOffset );
1096 }
1097
1098 --mNestingLevel;
1099
1100 // terminate operation/class/namespace context
1101 // TBD:: check if it's really this type of context
1102
1103 wxASSERT( mpCurCtx );
1104 mpCurCtx = mpCurCtx->GetOutterContext();
1105 wxASSERT( mpCurCtx );
1106
1107 if ( mNestingLevel == 0 )
1108 {
1109
1110 mCurCtxType = SP_CTX_FILE;
1111
1112 // not-nested class delclaration finished,
1113 // rest template flag in any case
1114 mIsTemplate = 0;
1115 }
1116
1117 skip_token( cur );
1118 continue;
1119 }
1120
1121 bool isAMacro = 0;
1122
1123 if ( is_function( cur, isAMacro ) )
1124 {
1125 if ( isAMacro )
1126 {
1127 skip_token( cur );
1128 continue;
1129 }
1130
1131 char* savedPos = cur;
1132
1133 int tmpLnNo;
1134 store_line_no( 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
1193void 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
1270void 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
1373void 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
1522bool 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
1639bool 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 = 1;
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 do
1781 {
1782 if ( *tok == '{' || *tok == ';' )
1783 {
1784 restore_line_no(tmpLnNo);
1785 return TRUE;
1786 }
1787
1788 // check for unexpected tokens
1789 if ( *tok == '=' || *tok == '0' )
1790 {
1791 skip_token(tok);
1792 if ( !get_next_token(tok) ) return FALSE;
1793 continue;
1794 }
1795
1796 if ( *tok == '}' ) return FALSE;
1797
1798 // if initialization list found
1799 if ( *tok == ':' )
1800 {
1801 restore_line_no(tmpLnNo);
1802 return TRUE;
1803 }
1804
1805 if ( cmp_tokens_fast( tok, "const", 5 ) )
1806 {
1807 ((spOperation*)mpCurCtx)->mIsConstant = true;
1808
1809 skip_token(tok);
1810 if ( !get_next_token(tok) ) return FALSE;
1811 continue;
1812 }
1813
1814 if ( CheckVisibilty( tok ) ) return FALSE;
1815
1816 // if next context found
1817 if ( is_keyword( tok ) ) return FALSE;
1818
1819 skip_token(tok);
1820 if ( !get_next_token(tok) ) return FALSE;
1821
1822 } while(1);
1823
1824 return TRUE;
1825}
1826
1827void CJSourceParser::ParseMemberVar( char*& cur )
1828{
1829 MMemberListT& members = mpCurCtx->GetMembers();
1830
1831 bool firstMember = 1;
1832
1833 size_t first = 0;
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 first = members.size() - 1;;
1864 }
1865
1866 skip_token_back( cur );
1867
1868 // attach comments about the attribute
1869 AttachComments( *pAttr, cur );
1870
1871 pAttr->mName = get_token_str( cur );
1872
1873 // guessing that this going to be variable type
1874 skip_next_token_back( cur );
1875 skip_token_back( cur );
1876
1877 pAttr->mType = get_token_str( cur );
1878
1879 // if comma, than variable list continues
1880 // otherwise the variable type reached - stop
1881
1882 if ( *cur == '=' )
1883 {
1884 // yes, we've mistaken, it was not a identifier,
1885 // but it's default value
1886 pAttr->mInitVal =
1887 pAttr->mName;
1888
1889 // skip default value and '=' symbol
1890 skip_next_token_back( cur );
1891 skip_token_back( cur );
1892
1893 pAttr->mName = 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 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->mType )
1917 pAttr->mType = type;
1918 pAttr->mVisibility = mCurVis;
1919
1920 if ( !!pAttr->mName )
1921 arrange_indirection_tokens_between( pAttr->mType, pAttr->mName );
1922 }
1923
1924 cur = savedPos;
1925 restore_line_no( tmpLnNo );
1926
1927 clear_commets_queue();
1928
1929
1930}
1931
1932void 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
1949void 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.mName.length(); ++i )
1985 {
1986 if ( op.mName[i] == ':' && op.mName[i+1] == ':' )
1987 {
1988 string unscoped( op.mName, i+2, op.mName.length() - ( i + 2 ) );
1989
1990 op.mScope = string( op.mName, 0, i );
1991
1992 op.mName = unscoped;
1993
1994 break;
1995 }
1996 }
1997 }
1998}
1999
2000bool 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
2025void CJSourceParser::AddClassNode( char*& cur )
2026{
2027 char* ctxStart = cur;
2028
2029 string 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->mName = 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->mName = 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->mSuperClassNames.push_back( string( cur, len ) );
2160
2161 } while(1);
2162
2163 if ( !isDerived )
2164 {
2165 int tmpLn;
2166 store_line_no( tmpLn );
2167
2168 while ( pClass->mSuperClassNames.size() )
2169
2170 pClass->mSuperClassNames.erase( &pClass->mSuperClassNames[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->mName = 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
2196void CJSourceParser::AddEnumNode( char*& cur )
2197{
2198 // now the cursor is at "enum" keyword
2199 char* 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->mName = get_token_str( cur );
2216 }
2217
2218 if ( !skip_imp_block( cur ) ) return;
2219
2220 get_string_between( start, cur, &pEnum->mEnumContent );
2221
2222 if ( get_next_token(cur) )
2223 {
2224 // check if the identifier if after the {...} block
2225 if ( *cur != ';' )
2226
2227 pEnum->mName = get_token_str( cur );
2228 }
2229
2230 clear_commets_queue();
2231}
2232
2233void CJSourceParser::AddTypeDefNode( char*& cur )
2234{
2235 // now the cursor at the token next to "typedef" keyword
2236
2237 if ( !get_next_token(cur) ) return;
2238
2239 char* 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 char* tok = cur-1;
2254 skip_next_token_back( tok );
2255
2256 char* nameEnd = tok;
2257
2258 skip_token_back( tok );
2259
2260 char* nameStart = tok;
2261
2262 skip_next_token_back( tok );
2263
2264 char* 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->mOriginalType );
2287
2288 get_string_between( nameStart, nameEnd, &pTDef->mName );
2289
2290 clear_commets_queue();
2291
2292 restore_line_no( tmpLnNo );
2293}