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