]> git.saurik.com Git - wxWidgets.git/blame - utils/HelpGen/src/cjparser.cpp
Added missing 'break' which caused spurious </FONT></TD> markup before
[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__
ad053960 13# pragma implementation "acell.h"
cecfc5e7
VZ
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
d12e3536 31 #include <map>
cecfc5e7
VZ
32
33#else
34
d12e3536 35 #include "wxstlac.h"
cecfc5e7
VZ
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
d12e3536 55struct less_c_str
cecfc5e7 56{
d12e3536
VZ
57 inline bool operator()( char* x, char* y) const
58 { return ( strcmp( x,y ) < 0 );
59 }
cecfc5e7
VZ
60};
61
62//WXSTL_MAP(CharPtrT,CharPtrT, LESS_THEN_FUNCTOR(CharPtrT));
63
64#if defined( wxUSE_TEMPLATE_STL )
65
d12e3536 66 typedef map< char*, char*, less_c_str > KeywordMapT;
cecfc5e7
VZ
67
68#else
69
d12e3536
VZ
70 typedef char* CharPtrT;
71 typedef WXSTL_MAP( CharPtrT, CharPtrT ,less_c_str) KeywordMapT;
cecfc5e7
VZ
72
73#endif
74
75static KeywordMapT __gMultiLangMap;
76static int __gMapReady = 0;
77
78static char* __gKeyWords[] =
79{
d12e3536
VZ
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
cecfc5e7
VZ
112};
113
114static void check_keyword_map()
115{
d12e3536
VZ
116 if ( !__gMapReady )
117 {
118 __gMapReady = 1;
cecfc5e7 119
d12e3536
VZ
120 // "make sure" the address of the first member of non-polimorphic class
121 // coinsides with the address of the instance
cecfc5e7 122
d12e3536 123 char** keyword = __gKeyWords;
cecfc5e7 124
d12e3536
VZ
125 while ( (*keyword) != 0 )
126 {
127 __gMultiLangMap.insert(
128 KeywordMapT::value_type( *keyword, *keyword )
129 );
cecfc5e7 130
d12e3536
VZ
131 ++keyword;
132 }
133 }
cecfc5e7
VZ
134}
135
136/***** helper functions *****/
137
138static inline void skip_to_eol( char*& cur )
139{
d12e3536 140 while( *(cur) != 10 && *cur != 13 && cur < _gSrcEnd) ++cur;
cecfc5e7
VZ
141}
142
143static inline void skip_eol( char*& cur )
144{
d12e3536 145 if ( *cur == 13 )
cecfc5e7 146
d12e3536
VZ
147 cur += 2;
148 else
149 cur += 1;
cecfc5e7 150
d12e3536 151 ++_gLineNo;
cecfc5e7
VZ
152}
153
154static inline bool skip_to_next_comment_in_the_line( char*& cur )
155{
d12e3536
VZ
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);
cecfc5e7
VZ
180}
181
182inline static void store_line_no( int& toVar )
183{
d12e3536 184 toVar = _gLineNo;
cecfc5e7
VZ
185}
186
187inline static void restore_line_no( int storedLineNo )
188{
d12e3536 189 _gLineNo = storedLineNo;
cecfc5e7
VZ
190}
191
192inline static int get_line_no()
193{
d12e3536 194 return _gLineNo;
cecfc5e7
VZ
195}
196
197static void skip_to_prev_line( char*& cur )
198{
d12e3536
VZ
199 while( cur >= _gSrcStart &&
200 *cur != 10 &&
201 *cur != 13
202 ) --cur;
cecfc5e7 203
d12e3536
VZ
204 // NOTE:: '\n' is 13,10 for DOS
205 // '\n' is 10 for UNIX
cecfc5e7 206
d12e3536
VZ
207 // NOTE1: '\n' symbol is not used here,
208 // to provide possibility of loading
209 // file as binary
cecfc5e7 210
d12e3536
VZ
211 --cur;
212 if ( *cur == 10 )
213 {
214 ++cur;
215 return;
216 }
cecfc5e7 217
d12e3536 218 if ( *cur == 13 ) --cur;
cecfc5e7 219
d12e3536
VZ
220 while( cur >= _gSrcStart &&
221 *cur != 10 &&
222 *cur != 13
223 ) --cur;
cecfc5e7 224
d12e3536 225 ++cur; // move to the first character in the line
cecfc5e7
VZ
226}
227
228static inline void skip_comments( char*& cur )
229{
d12e3536 230 ++cur; // skip '/' token
cecfc5e7 231
d12e3536 232 if ( *cur != '/' && *cur != '*' ) return;
cecfc5e7 233
d12e3536
VZ
234 // first, store position of the comment into the queue
235 // (which further will be attached to the next context
236 // found)
cecfc5e7 237
d12e3536
VZ
238 if ( cur-1 != _gLastSuppresedComment )
239 {
240 if ( _gCQSize == MAX_CQ_ENTRIES )
241 {
242 size_t i = MAX_CQ_ENTRIES-1;
cecfc5e7 243
d12e3536
VZ
244 while( i != 0 )
245 {
246 _gCommentsQueue[i-1] = _gCommentsQueue[i];
247 --i;
248 }
cecfc5e7 249
d12e3536
VZ
250 --_gCQSize ;
251 }
cecfc5e7 252
d12e3536
VZ
253 _gCommentsQueue[_gCQSize++] = cur-1;
254 }
cecfc5e7 255
d12e3536
VZ
256 // if signle-line comment, skip it now
257 if ( *cur == '/' )
258 {
259 skip_to_eol( cur );
260 skip_eol( cur );
261 return;
262 }
cecfc5e7 263
d12e3536 264 size_t level = 1;
cecfc5e7 265
d12e3536 266 // check for multiline comment (handle nested multiline comments!)
cecfc5e7 267
d12e3536 268 int line_len = 0;
cecfc5e7 269
d12e3536
VZ
270 ++cur;
271 ++cur;
272 do
273 {
274 // TBD:: check eof cond.
cecfc5e7 275
d12e3536 276 // detect and remove vertical columns of '*''s
cecfc5e7 277
d12e3536
VZ
278 while ( *cur != '/' && cur < _gSrcEnd )
279 {
280 switch (*cur)
281 {
282 case '*' :
283 {
284 if ( *(cur+1) != '/' )
285 {
286 if ( line_len == 1 )
cecfc5e7 287
d12e3536
VZ
288 *cur = ' ';
289 }
cecfc5e7 290
d12e3536
VZ
291 break;
292 }
cecfc5e7 293
d12e3536
VZ
294 case 13 : line_len = 0; break;
295 case 10 : { line_len = 0; ++_gLineNo; } break;
cecfc5e7 296
d12e3536
VZ
297 default : ++line_len;
298 }
cecfc5e7 299
d12e3536
VZ
300 ++cur;
301 }
cecfc5e7 302
d12e3536 303 if ( cur >= _gSrcEnd ) return;
cecfc5e7 304
d12e3536 305 ++cur;
cecfc5e7 306
d12e3536
VZ
307 if ( *(cur-2) == '*' )
308 {
309 --level;
310 if ( level == 0 )
311 break;
312 }
313 else
314 if ( *cur == '*' )
315 {
316 ++cur;
317 ++cur;
cecfc5e7 318
d12e3536
VZ
319 ++level;
320 }
cecfc5e7 321
d12e3536 322 } while(1);
cecfc5e7
VZ
323}
324
325static inline void clear_commets_queue()
326{
d12e3536 327 _gCQSize = 0;
cecfc5e7
VZ
328}
329
330static inline void skip_quoted_string( char*& cur )
331{
d12e3536 332 ++cur; // skip first quote '"'
cecfc5e7 333
d12e3536
VZ
334 // check if quote wasn't prefixed
335 if ( *(cur-2) == '\\' )
336 return;
cecfc5e7 337
d12e3536
VZ
338 do
339 {
340 while ( *cur != '"' && cur < _gSrcEnd )
341 {
342 if ( *cur == 10 ) ++_gLineNo;
343 ++cur;
344 }
cecfc5e7 345
d12e3536 346 if ( cur >= _gSrcEnd ) return;
cecfc5e7 347
d12e3536 348 ++cur; // skip the last quote
cecfc5e7 349
d12e3536 350 // check if it wasn't prefixed
cecfc5e7 351
d12e3536
VZ
352 if ( *(cur-2) != '\\' )
353 break;
cecfc5e7 354
d12e3536 355 } while (1);
cecfc5e7
VZ
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{
d12e3536
VZ
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;
cecfc5e7
VZ
388}
389
390static inline void skip_preprocessor_dir( char*& cur )
391{
d12e3536
VZ
392 do
393 {
394 skip_to_eol(cur);
cecfc5e7 395
d12e3536
VZ
396 if ( *(cur-1) != '\\' )
397 break;
cecfc5e7 398
d12e3536
VZ
399 if ( cur < _gSrcEnd )
400 skip_eol( cur );
401 else
402 break;
cecfc5e7 403
d12e3536 404 } while(1);
cecfc5e7
VZ
405}
406
407static void skip_token( char*& cur )
408{
d12e3536
VZ
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 }
cecfc5e7 424
f71f5a4f
VZ
425 // special case of "!=", "<=", ... 2 character composite tokens
426 if ( *cur == '<' ||
d12e3536
VZ
427 *cur == '>' ||
428 *cur == '=' ||
f71f5a4f
VZ
429 *cur == '!'
430 )
431 {
432 cur++;
433 if ( *cur == '=' )
434 cur++;
435
436 return;
437 }
438
d12e3536
VZ
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 }
cecfc5e7
VZ
475}
476
477static inline size_t get_token_len( char* tok )
478{
d12e3536 479 char* start = tok;
cecfc5e7 480
d12e3536 481 skip_token( tok );
cecfc5e7 482
d12e3536 483 return size_t( tok - start );
cecfc5e7
VZ
484}
485
486// returns true, if given tokens are equel
487
488static inline bool cmp_tokens( char* tok1, char* tok2 )
489{
d12e3536
VZ
490 // NOTE:: the case one token includes
491 // other in it's entirely is not handled
cecfc5e7 492
d12e3536 493 size_t len = get_token_len( tok1 );
cecfc5e7 494
d12e3536 495 // assuming that tokens are non-zero length
cecfc5e7 496
d12e3536
VZ
497 do
498 {
499 if ( *(tok1++) != *(tok2++) )
500 return FALSE;
cecfc5e7 501
d12e3536 502 --len;
cecfc5e7 503
d12e3536 504 } while ( --len );
cecfc5e7 505
d12e3536 506 return TRUE;
cecfc5e7
VZ
507}
508
509static inline bool cmp_tokens_fast( char* tok1, char* tok2, size_t len )
510{
d12e3536
VZ
511 do
512 {
513 if ( *(tok1++) != *(tok2++) )
514 return FALSE;
cecfc5e7 515
d12e3536 516 } while ( --len );
cecfc5e7 517
d12e3536 518 return TRUE;
cecfc5e7
VZ
519}
520
521static inline void skip_tempalate_statement( char*& cur )
522{
d12e3536 523 size_t level = 0;
cecfc5e7 524
d12e3536
VZ
525 // go one level deeper
526 while( *cur != '<' && cur < _gSrcEnd )
527 {
528 if (*cur == 10 ) ++_gLineNo;
529 ++cur;
530 }
cecfc5e7 531
d12e3536
VZ
532 // FIXME:: template should be checked statement for
533 // comments inside of it
cecfc5e7 534
d12e3536
VZ
535 do
536 {
537 if ( *cur == '<' )
538 ++level;
539 else
540 --level;
cecfc5e7 541
d12e3536 542 ++cur; // skip '<' or '>' token
cecfc5e7 543
d12e3536
VZ
544 if ( level == 0 )
545 return;
cecfc5e7 546
d12e3536
VZ
547 while( *cur != '<' && *cur != '>' && cur < _gSrcEnd )
548 {
549 if (*cur == 10 ) ++_gLineNo;
550 ++cur;
551 }
cecfc5e7 552
d12e3536 553 } while (1);
cecfc5e7
VZ
554}
555
556static inline void skip_statement( char*& cur )
557{
d12e3536 558 for( ; cur < _gSrcEnd; ++cur )
cecfc5e7 559
d12e3536
VZ
560 switch (*cur)
561 {
562 case ';' : ++cur; // skip statement-terminator token
563 return;
cecfc5e7 564
d12e3536
VZ
565 case '"' : skip_quoted_string(cur);
566 --cur;
567 continue;
cecfc5e7 568
d12e3536 569 case 10 : ++_gLineNo;
cecfc5e7 570
d12e3536
VZ
571 continue;
572 case '/' : skip_comments( cur );
573 --cur;
574 continue;
575 default : continue;
576 }
cecfc5e7
VZ
577}
578
579// "reversed" versions of skip_token() and get_next_token()
580
581static inline void skip_token_back( char*& cur )
582{
d12e3536
VZ
583 // FIXME:: now, when moving backwards, neither strings nor
584 // comment blocks are checked
cecfc5e7 585
d12e3536 586 --cur; // skip to the trailing character
cecfc5e7 587
d12e3536
VZ
588 if ( *cur == ',' ||
589 *cur == ')' ||
590 *cur == '('
591 )
592 return;
cecfc5e7
VZ
593
594
d12e3536
VZ
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;
cecfc5e7 605
d12e3536
VZ
606 default : continue;
607 };
cecfc5e7 608
d12e3536
VZ
609 break;
610 }
cecfc5e7 611
d12e3536 612 ++cur; // get to the leading character of the token
cecfc5e7
VZ
613}
614
615static inline void skip_next_token_back( char*& cur )
616{
d12e3536
VZ
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
cecfc5e7
VZ
646}
647
648static string get_token_str( char* cur )
649{
d12e3536 650 return string( cur, get_token_len( cur ) );
cecfc5e7
VZ
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{
d12e3536
VZ
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);
cecfc5e7
VZ
736}
737
738// returns 0, if end of source reached
739static inline bool skip_imp_block( char*& cur )
740{
d12e3536
VZ
741 while( *cur != '{' && cur < _gSrcEnd )
742 {
743 skip_token( cur );
744 if ( !get_next_token( cur ) ) return FALSE;
745 }
cecfc5e7 746
d12e3536
VZ
747 while( *cur != '}' && cur < _gSrcEnd )
748 {
749 skip_token( cur );
750 if ( !get_next_token( cur ) ) return FALSE;
751 }
cecfc5e7 752
d12e3536 753 ++cur;
cecfc5e7 754
d12e3536 755 return TRUE;
cecfc5e7
VZ
756}
757
758static bool is_class_token( char*& cur )
759{
d12e3536 760 // FIXME:: the below mess should be cleaned in it's entirely
cecfc5e7 761
d12e3536
VZ
762 if ( *cur == 'i' )
763 if ( *(cur+1) == 'n' )
cecfc5e7 764
d12e3536 765 return cmp_tokens_fast( cur, "interface", 9 );
cecfc5e7 766
d12e3536
VZ
767 if ( *cur == 'c' )
768 if ( *(cur+1) == 'l' )
cecfc5e7 769
d12e3536 770 return cmp_tokens_fast( cur, "class", 5 );
cecfc5e7 771
d12e3536
VZ
772 if ( *cur == 's' )
773 if ( *(cur+1) == 't' )
cecfc5e7 774
d12e3536 775 return cmp_tokens_fast( cur, "struct", 6 );
cecfc5e7 776
d12e3536
VZ
777 if ( *cur == 'u' )
778 if ( *(cur+1) == 'n' )
cecfc5e7 779
d12e3536 780 return cmp_tokens_fast( cur, "union", 5 );
cecfc5e7 781
d12e3536 782 return FALSE;
cecfc5e7
VZ
783}
784
785inline static bool is_forward_decl( char* cur )
786{
d12e3536
VZ
787 do
788 {
789 switch( *cur )
790 {
791 case ':' : return FALSE;
792 case '{' : return FALSE;
793 case '(' : return FALSE;
cecfc5e7 794
d12e3536 795 case ';' : return TRUE;
cecfc5e7 796
d12e3536
VZ
797 default : break;
798 };
cecfc5e7 799
d12e3536 800 ++cur;
cecfc5e7 801
d12e3536 802 } while (cur < _gSrcEnd); // prevent running out of bounds
cecfc5e7 803
d12e3536 804 return FALSE;
cecfc5e7
VZ
805}
806
807inline static bool is_function( char* cur, bool& isAMacro )
808{
d12e3536 809 isAMacro = FALSE;
cecfc5e7 810
d12e3536
VZ
811 int tmpLnNo;
812 store_line_no( tmpLnNo );
cecfc5e7 813
d12e3536 814 // NOTE:: comments and quoted strings are not checked here
cecfc5e7 815
d12e3536
VZ
816 // first,check for "single-line hanginging macros" like:
817 // ___UNICODE
818 //
cecfc5e7 819
d12e3536
VZ
820 char* eol = cur;
821 skip_to_eol( eol );
cecfc5e7 822
d12e3536
VZ
823 skip_token( cur );
824 get_next_token( cur );
cecfc5e7 825
d12e3536
VZ
826 if ( cur > eol )
827 {
828 isAMacro = TRUE;
829 restore_line_no( tmpLnNo );
cecfc5e7 830
d12e3536
VZ
831 return TRUE;
832 }
cecfc5e7 833
d12e3536 834 // it's not a macro, go to the begining of arg. list
cecfc5e7 835
d12e3536
VZ
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 }
cecfc5e7 845
d12e3536
VZ
846 // end of statement found without any brackets in it
847 // - it cannot be a function
cecfc5e7 848
d12e3536
VZ
849 if ( *cur == ';' )
850 {
851 restore_line_no( tmpLnNo );
852 return FALSE;
853 }
cecfc5e7 854
d12e3536 855 ++cur;
cecfc5e7 856
d12e3536 857 } while( cur < _gSrcEnd);
cecfc5e7 858
d12e3536
VZ
859 isAMacro = 1;
860 restore_line_no( tmpLnNo );
861
862 return FALSE;
cecfc5e7
VZ
863}
864
865// upon return the cursor is positioned after the
d12e3536 866// terminating curly brace
cecfc5e7
VZ
867
868static inline void skip_scope_block( char*& cur )
869{
d12e3536 870 size_t level = 0;
cecfc5e7 871
d12e3536 872 for( ; cur < _gSrcEnd ; ++cur )
cecfc5e7 873
d12e3536
VZ
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 };
cecfc5e7
VZ
897}
898
899// moves tokens like '*' '**', '***', '&' from the name
900// to the type
901
902static void arrange_indirection_tokens_between( string& type,
d12e3536 903 string& identifier )
cecfc5e7 904{
d12e3536 905 // TBD:: FIXME:: return value of operators !
cecfc5e7 906
d12e3536
VZ
907 while ( identifier[0] == '*' ||
908 identifier[0] == '&'
909 )
910 {
911 type += identifier[0];
912 identifier.erase(0,1);
cecfc5e7 913
d12e3536
VZ
914 if ( !identifier.length() ) return;
915 }
cecfc5e7
VZ
916}
917
918
919// the only function where multi-lang keyword map is accessed
920
921static bool is_keyword( char* cur )
922{
d12e3536
VZ
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';
cecfc5e7 928
d12e3536 929 KeywordMapT::iterator i;
cecfc5e7 930
d12e3536
VZ
931 i = __gMultiLangMap.find( cur );
932
933 // restore original character suppresed by terminating zero
934 *(cur + len) = tmp;
cecfc5e7 935
59734eb5 936 return i == __gMultiLangMap.end() ? false : true;
cecfc5e7
VZ
937}
938
d12e3536
VZ
939static inline void get_string_between( char* start, char* end,
940 string* pStr )
cecfc5e7 941{
d12e3536 942 char saved = *end;
cecfc5e7 943
d12e3536
VZ
944 *end = '\0';
945 *pStr = start;
946 *end = saved;
cecfc5e7
VZ
947}
948
949static char* set_comment_text( string& text, char* start )
950{
d12e3536 951 char* end = start;
cecfc5e7 952
d12e3536
VZ
953 // to avoid poluting the queue with this comment
954 _gLastSuppresedComment = start;
cecfc5e7 955
d12e3536 956 skip_comments( end );
cecfc5e7 957
d12e3536
VZ
958 if ( *(end-1) == '/' )
959 end -= 2;
cecfc5e7 960
d12e3536 961 start += 2;
cecfc5e7 962
d12e3536
VZ
963 // skip multiple leading '/''s or '*''s
964 while( *start == '/' && start < end ) ++start;
965 while( *start == '*' && start < end ) ++start;
cecfc5e7 966
d12e3536 967 get_string_between( start, end, &text );
cecfc5e7 968
d12e3536 969 return end;
cecfc5e7
VZ
970}
971
972/***** Implementation for class CJSourceParser *****/
973
974CJSourceParser::CJSourceParser( bool collectCommnets, bool collectMacros )
d12e3536
VZ
975 : mpStart(0),
976 mpEnd(0),
977 mpCurCtx( 0 ),
978 mCommentsOn( collectCommnets ),
979 mMacrosOn ( collectMacros )
cecfc5e7 980{
d12e3536 981 check_keyword_map();
cecfc5e7
VZ
982}
983
984spFile* CJSourceParser::Parse( char* start, char* end )
985{
d12e3536
VZ
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 }
cecfc5e7 1059
59734eb5 1060 // 'const' is a part of the return type, not a keyword here
d12e3536
VZ
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
cecfc5e7 1067
d12e3536
VZ
1068 ParseKeyword( cur );
1069 continue;
1070 }
cecfc5e7 1071
d12e3536
VZ
1072 if ( *cur >= '0' && *cur <= '9' )
1073 {
1074 skip_token( cur );
1075 continue;
1076 }
cecfc5e7 1077
d12e3536
VZ
1078 if ( *cur == '}' )
1079 {
1080 if ( mCurCtxType != SP_CTX_CLASS )
1081 {
1082 // FOR NOW:: disable the below assertion
cecfc5e7 1083
d12e3536
VZ
1084 // DBG:: unexpected closing-bracket found
1085 //ASSERT(0);
cecfc5e7 1086
d12e3536
VZ
1087 skip_token( cur ); // just skip it
1088 continue;
1089 }
cecfc5e7 1090
d12e3536
VZ
1091 if ( mpCurCtx->GetType() == SP_CTX_CLASS )
1092 {
1093 int curOfs = ( (cur+1) - _gSrcStart );
cecfc5e7 1094
d12e3536
VZ
1095 mpCurCtx->mContextLength = ( curOfs - mpCurCtx->mSrcOffset );
1096 }
1097
1098 --mNestingLevel;
cecfc5e7 1099
d12e3536
VZ
1100 // terminate operation/class/namespace context
1101 // TBD:: check if it's really this type of context
cecfc5e7 1102
d12e3536
VZ
1103 wxASSERT( mpCurCtx );
1104 mpCurCtx = mpCurCtx->GetOutterContext();
1105 wxASSERT( mpCurCtx );
cecfc5e7 1106
d12e3536
VZ
1107 if ( mNestingLevel == 0 )
1108 {
cecfc5e7 1109
d12e3536 1110 mCurCtxType = SP_CTX_FILE;
cecfc5e7 1111
d12e3536
VZ
1112 // not-nested class delclaration finished,
1113 // rest template flag in any case
1114 mIsTemplate = 0;
1115 }
cecfc5e7 1116
d12e3536
VZ
1117 skip_token( cur );
1118 continue;
1119 }
cecfc5e7 1120
d12e3536 1121 bool isAMacro = 0;
cecfc5e7 1122
d12e3536
VZ
1123 if ( is_function( cur, isAMacro ) )
1124 {
1125 if ( isAMacro )
1126 {
1127 skip_token( cur );
1128 continue;
1129 }
cecfc5e7 1130
d12e3536 1131 char* savedPos = cur;
cecfc5e7 1132
d12e3536
VZ
1133 int tmpLnNo;
1134 store_line_no( tmpLnNo );
cecfc5e7 1135
d12e3536 1136 isAMacro = FALSE;
cecfc5e7 1137
d12e3536
VZ
1138 if ( !ParseNameAndRetVal( cur, isAMacro ) )
1139 {
1140 if ( !isAMacro )
1141 {
1142 cur = savedPos;
1143 SkipFunction( cur );
1144 }
1145 continue;
1146 }
cecfc5e7 1147
d12e3536
VZ
1148 if ( !ParseArguments( cur ) )
1149 {
1150 // failure while parsing arguments,
1151 // remove enclosing operation context
cecfc5e7 1152
d12e3536
VZ
1153 spContext* pFailed = mpCurCtx;
1154 mpCurCtx = mpCurCtx->GetOutterContext();
1155 mpCurCtx->RemoveChild( pFailed );
cecfc5e7 1156
d12e3536
VZ
1157 skip_to_eol( cur );
1158 //cur = savedPos;
1159 }
1160 else
1161 {
1162 // otherwise, successfully close operation context:
cecfc5e7 1163
d12e3536 1164 clear_commets_queue();
cecfc5e7 1165
d12e3536 1166 SkipFunctionBody( cur );
cecfc5e7 1167
d12e3536 1168 mpCurCtx = mpCurCtx->GetOutterContext();
cecfc5e7 1169
d12e3536
VZ
1170 // DBG::
1171 wxASSERT( mpCurCtx );
cecfc5e7 1172
d12e3536
VZ
1173 }
1174 }
1175 else // otherwise it's declaration of a variable;
1176 {
1177 // now, the cursor point to the end of statement (';' token)
cecfc5e7 1178
d12e3536
VZ
1179 if ( mCurCtxType != SP_CTX_CLASS )
1180 {
1181 // non-class members are ignored
cecfc5e7 1182
d12e3536
VZ
1183 skip_token( cur ); // skip the end of statement
1184 continue;
1185 }
cecfc5e7 1186
d12e3536
VZ
1187 ParseMemberVar( cur );
1188 }
cecfc5e7 1189
d12e3536 1190 } while( 1 );
cecfc5e7
VZ
1191}
1192
1193void CJSourceParser::AttachComments( spContext& ctx, char* cur )
1194{
d12e3536 1195 if ( !mCommentsOn ) return;
cecfc5e7 1196
d12e3536 1197 MCommentListT& lst = ctx.GetCommentList();
cecfc5e7 1198
d12e3536 1199 char* prevComEnd = 0;
cecfc5e7 1200
d12e3536
VZ
1201 int tmpLnNo;
1202 store_line_no( tmpLnNo );
cecfc5e7 1203
d12e3536 1204 // attach comments which were found before the given context
cecfc5e7 1205
d12e3536
VZ
1206 for( int i = 0; i != _gCQSize; ++i )
1207 {
1208 spComment* pComment = new spComment();
1209 lst.push_back( pComment );
cecfc5e7 1210
d12e3536
VZ
1211 // find the end of comment
1212 char* start = _gCommentsQueue[i];
cecfc5e7 1213
d12e3536 1214 pComment->mIsMultiline = ( *(start+1) == '*' );
cecfc5e7 1215
d12e3536
VZ
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
cecfc5e7 1219
d12e3536 1220 if ( i == 0 )
cecfc5e7 1221
d12e3536
VZ
1222 pComment->mStartsPar = TRUE;
1223 else
1224 if ( pComment->mIsMultiline )
cecfc5e7 1225
d12e3536
VZ
1226 pComment->mStartsPar = TRUE;
1227 else
1228 {
1229 // find out wheather there is a new-line
1230 // between to adjecent comments
cecfc5e7
VZ
1231
1232
d12e3536
VZ
1233 char* prevLine = start;
1234 skip_to_prev_line(prevLine);
cecfc5e7 1235
d12e3536 1236 if ( prevLine >= prevComEnd )
cecfc5e7 1237
d12e3536
VZ
1238 pComment->mStartsPar = TRUE;
1239 else
1240 pComment->mStartsPar = FALSE;
1241 }
cecfc5e7 1242
d12e3536
VZ
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)
cecfc5e7 1249
d12e3536
VZ
1250 if ( skip_to_next_comment_in_the_line( cur ) )
1251 {
1252 spComment* pComment = new spComment();
1253 lst.push_back( pComment );
cecfc5e7 1254
d12e3536 1255 set_comment_text( pComment->mText, cur );
cecfc5e7 1256
d12e3536
VZ
1257 pComment->mStartsPar = 1;
1258 pComment->mIsMultiline = ( *(cur+1) == '*' );
cecfc5e7 1259
d12e3536
VZ
1260 // mark this comment, so that it would not
1261 // get in the comments list of the next context
1262 _gLastSuppresedComment = cur;
1263 }
cecfc5e7 1264
d12e3536 1265 restore_line_no( tmpLnNo );
cecfc5e7 1266
d12e3536 1267 clear_commets_queue();
cecfc5e7
VZ
1268}
1269
1270void CJSourceParser::AddMacroNode( char*& cur )
1271{
d12e3536
VZ
1272 char* start = cur;
1273
1274 int lineNo = get_line_no();
cecfc5e7 1275
d12e3536 1276 skip_preprocessor_dir( cur );
cecfc5e7 1277
d12e3536
VZ
1278 int tmpLnNo;
1279 store_line_no( tmpLnNo );
cecfc5e7 1280
d12e3536 1281 if ( !mMacrosOn ) return;
cecfc5e7 1282
d12e3536
VZ
1283 spPreprocessorLine* pPL = new spPreprocessorLine();
1284 pPL->mSrcLineNo = lineNo;
cecfc5e7 1285
d12e3536 1286 AttachComments( *pPL, cur );
cecfc5e7 1287
d12e3536
VZ
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;
cecfc5e7 1304
d12e3536 1305 get_next_token( tok );
cecfc5e7 1306
d12e3536 1307 pPL->mName = get_token_str( tok );
cecfc5e7 1308
d12e3536
VZ
1309 skip_token( tok );
1310 get_next_token( tok);
cecfc5e7 1311
cecfc5e7 1312
d12e3536
VZ
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 );
cecfc5e7 1331
d12e3536 1332 string condition = get_token_str( cur );
cecfc5e7 1333
d12e3536
VZ
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 );
cecfc5e7 1340
d12e3536
VZ
1341 get_next_token( cur );
1342 if ( *cur++ == '#' && *cur == 'e' )
1343 break;
1344 }
1345 }
cecfc5e7 1346
d12e3536
VZ
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 }
cecfc5e7 1362
d12e3536 1363 mpCurCtx->AddMember( pPL );
cecfc5e7 1364
d12e3536
VZ
1365 skip_to_eol( cur );
1366 skip_eol( cur );
cecfc5e7 1367
d12e3536 1368 restore_line_no( tmpLnNo );
cecfc5e7 1369
d12e3536 1370 clear_commets_queue();
cecfc5e7
VZ
1371}
1372
1373void CJSourceParser::ParseKeyword( char*& cur )
1374{
d12e3536
VZ
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 );
cecfc5e7
VZ
1520}
1521
1522bool CJSourceParser::ParseNameAndRetVal( char*& cur, bool& isAMacro )
1523{
d12e3536 1524 isAMacro = FALSE;
cecfc5e7 1525
d12e3536
VZ
1526 // FOR NOW:: all functions in the global
1527 // scope are ignored
cecfc5e7 1528
d12e3536 1529 int lineNo = get_line_no();
cecfc5e7 1530
d12e3536 1531 char* start = cur;
cecfc5e7 1532
59734eb5 1533 bool isVirtual = false;
d12e3536
VZ
1534 while( *cur != '(' )
1535 {
59734eb5
VZ
1536 if ( get_token_str( cur ) == "virtual" )
1537 isVirtual = true;
1538
d12e3536
VZ
1539 skip_token( cur );
1540 if ( !get_next_token( cur ) ) return FALSE;
1541 }
cecfc5e7 1542
d12e3536
VZ
1543 char* bracketPos = cur;
1544 char* savedPos = cur + 1;
cecfc5e7 1545
d12e3536
VZ
1546 int tmpLnNo;
1547 store_line_no( tmpLnNo );
cecfc5e7 1548
d12e3536
VZ
1549 // skip gap between function name and start of paramters list
1550 while ( *(cur-1) == ' ' )
1551 --cur;
cecfc5e7 1552
d12e3536 1553 // check if it's not a macro, and let plugin handle it, if so
cecfc5e7 1554
d12e3536
VZ
1555 if ( mpPlugin )
1556 {
1557 skip_token_back( cur );
cecfc5e7 1558
d12e3536 1559 char* tmp = cur;
cecfc5e7 1560
d12e3536
VZ
1561 if ( mpPlugin->CanUnderstandContext( tmp, _gSrcEnd, mpCurCtx ) )
1562 {
1563 cur = tmp;
cecfc5e7 1564
d12e3536 1565 mpPlugin->ParseContext( _gSrcStart, cur, _gSrcEnd, mpCurCtx );
cecfc5e7 1566
d12e3536 1567 isAMacro = TRUE;
cecfc5e7 1568
d12e3536
VZ
1569 return FALSE;
1570 }
1571 }
cecfc5e7 1572
d12e3536 1573 spOperation* pOp = new spOperation();
cecfc5e7 1574
d12e3536
VZ
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;
cecfc5e7 1580
d12e3536
VZ
1581 mpCurCtx->AddMember( pOp );
1582 pOp->mVisibility = mCurVis;
59734eb5 1583 pOp->mIsVirtual = isVirtual;
cecfc5e7 1584
d12e3536
VZ
1585 // add comments about operation
1586 AttachComments( *pOp, cur );
cecfc5e7 1587
d12e3536
VZ
1588 // go backwards to method name
1589 skip_token_back( cur );
cecfc5e7 1590
d12e3536 1591 pOp->mName = get_token_str( cur );
cecfc5e7 1592
f71f5a4f
VZ
1593 // checker whether it's not an operator
1594 char chFirst = *pOp->mName.c_str();
d12e3536 1595 if ( !isalpha(chFirst) && chFirst != '_' && chFirst != '~' ) {
f71f5a4f 1596 // skip 'operator'
d12e3536 1597 skip_next_token_back( cur );
f71f5a4f
VZ
1598 skip_token_back( cur );
1599
1600 string lastToken = get_token_str( cur );
d12e3536 1601 if ( lastToken == "operator" ) {
f71f5a4f
VZ
1602 lastToken += pOp->mName;
1603 pOp->mName = lastToken;
1604 }
d12e3536 1605 else {
f71f5a4f
VZ
1606 // ok, it wasn't an operator after all
1607 skip_token( cur );
1608 }
1609 }
d12e3536
VZ
1610 else if ( pOp->mName == "operator" ) {
1611 skip_token( cur );
1612 get_next_token( cur );
1613 string oper = get_token_str( cur );
f71f5a4f 1614
d12e3536
VZ
1615 pOp->mName += oper;
1616 }
cecfc5e7 1617
d12e3536
VZ
1618 // go backwards to method return type
1619 skip_next_token_back( cur );
cecfc5e7 1620
d12e3536
VZ
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 }
cecfc5e7 1627
d12e3536 1628 arrange_indirection_tokens_between( pOp->mRetType, pOp->mName );
cecfc5e7 1629
d12e3536
VZ
1630 cur = savedPos;
1631 restore_line_no( tmpLnNo );
cecfc5e7 1632
d12e3536
VZ
1633 // now, enter operation context
1634 mpCurCtx = pOp;
cecfc5e7 1635
d12e3536 1636 return TRUE;
cecfc5e7
VZ
1637}
1638
1639bool CJSourceParser::ParseArguments( char*& cur )
1640{
d12e3536 1641 // DANGER-MACROS::
cecfc5e7 1642
d12e3536
VZ
1643 // now cursor position is right after the first opening bracket
1644 // of the function declaration
cecfc5e7 1645
d12e3536
VZ
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];
cecfc5e7 1651
d12e3536
VZ
1652 do
1653 {
1654 size_t blocksSkipped = 0;
cecfc5e7 1655
d12e3536 1656 get_next_token( cur );
cecfc5e7 1657
d12e3536 1658 bool first_blk = 1;
cecfc5e7 1659
d12e3536
VZ
1660 while( *cur != ')' && *cur != ',' )
1661 {
1662 blocks[blocksSkipped] = cur;
cecfc5e7 1663
d12e3536
VZ
1664 if ( first_blk )
1665 {
1666 char* prev = cur;
1667 skip_token( cur );
cecfc5e7 1668
d12e3536 1669 blockSizes[blocksSkipped] = size_t(cur-prev);
cecfc5e7 1670
d12e3536
VZ
1671 first_blk = 0;
1672 }
1673 else
1674 blockSizes[blocksSkipped] = skip_block( cur );
cecfc5e7 1675
d12e3536
VZ
1676 get_next_token( cur );
1677 ++blocksSkipped;
1678 }
cecfc5e7
VZ
1679
1680
d12e3536
VZ
1681 if ( blocksSkipped == 1 )
1682 {
1683 // check if the empty arg. list stressed with "void" inside
f71f5a4f
VZ
1684 if ( cmp_tokens_fast( blocks[0] , "void", 4 ) )
1685 {
1686 cur++; // skip ')'
1687
d12e3536 1688 break;
f71f5a4f 1689 }
cecfc5e7 1690
d12e3536
VZ
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 }
cecfc5e7 1698
d12e3536
VZ
1699 if ( blocksSkipped == 0 )
1700 {
1701 if ( *cur == 10 ) ++_gLineNo;
1702 ++cur; // skip ')'
cecfc5e7 1703
d12e3536
VZ
1704 break; // function without paramters
1705 }
59734eb5 1706
d12e3536
VZ
1707 // we should be in the operation context now
1708 spOperation* pOp = (spOperation*)mpCurCtx;
cecfc5e7 1709
d12e3536 1710 spParameter* pPar = new spParameter();
cecfc5e7 1711
d12e3536
VZ
1712 pOp->AddMember( pPar );
1713 // FOR NOW:: line number is not exact if argument list is mutiline
1714 pPar->mSrcLineNo = get_line_no();
cecfc5e7 1715
d12e3536
VZ
1716 size_t nameBlock = blocksSkipped - 1;
1717 size_t typeBlock = nameBlock - 1;
cecfc5e7 1718
d12e3536
VZ
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 }
cecfc5e7 1734
d12e3536 1735 pPar->mInitVal = string( blocks[nameBlock], blockSizes[nameBlock] );
cecfc5e7 1736
d12e3536
VZ
1737 nameBlock = nameBlock - 2; // skip '=' token and default value block
1738 typeBlock = nameBlock - 1;
1739 }
cecfc5e7 1740
d12e3536
VZ
1741 // attach comments about the parameter
1742 AttachComments( *pPar, blocks[nameBlock] );
cecfc5e7 1743
d12e3536
VZ
1744 // retrieve argument name
1745 pPar->mName = string( blocks[nameBlock], blockSizes[nameBlock] );
cecfc5e7 1746
d12e3536 1747 // retreive argument type
cecfc5e7 1748
d12e3536
VZ
1749 size_t len = blockSizes[ typeBlock ];
1750 len = size_t ( (blocks[ typeBlock ] + len) - blocks[ 0 ] );
cecfc5e7 1751
d12e3536 1752 pPar->mType = string( blocks[0], len );
cecfc5e7 1753
d12e3536 1754 arrange_indirection_tokens_between( pPar->mType, pPar->mName );
cecfc5e7 1755
d12e3536
VZ
1756 if ( *cur == ')' )
1757 {
1758 ++cur;
1759 break;
1760 }
cecfc5e7 1761
d12e3536
VZ
1762 ++cur; // skip comma
1763 get_next_token(cur);
cecfc5e7 1764
d12e3536 1765 } while(1);
cecfc5e7 1766
59734eb5
VZ
1767 // skip possible whitespace between ')' and following "const"
1768 while ( isspace(*cur) )
1769 cur++;
1770
d12e3536
VZ
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 {
59734eb5
VZ
1807 ((spOperation*)mpCurCtx)->mIsConstant = true;
1808
d12e3536
VZ
1809 skip_token(tok);
1810 if ( !get_next_token(tok) ) return FALSE;
1811 continue;
1812 }
1813
1814 if ( CheckVisibilty( tok ) ) return FALSE;
cecfc5e7 1815
d12e3536
VZ
1816 // if next context found
1817 if ( is_keyword( tok ) ) return FALSE;
cecfc5e7 1818
d12e3536
VZ
1819 skip_token(tok);
1820 if ( !get_next_token(tok) ) return FALSE;
cecfc5e7 1821
d12e3536 1822 } while(1);
cecfc5e7 1823
d12e3536 1824 return TRUE;
cecfc5e7
VZ
1825}
1826
1827void CJSourceParser::ParseMemberVar( char*& cur )
1828{
d12e3536 1829 MMemberListT& members = mpCurCtx->GetMembers();
cecfc5e7 1830
d12e3536 1831 bool firstMember = 1;
cecfc5e7 1832
d12e3536 1833 size_t first = 0;
cecfc5e7 1834
d12e3536 1835 string type;
cecfc5e7 1836
d12e3536
VZ
1837 // jump to the end of statement
1838 // and start collecting same-type varibles
1839 // back-to-front towards the type identifier
cecfc5e7 1840
d12e3536
VZ
1841 skip_statement( cur );
1842 char* savedPos = cur;
cecfc5e7 1843
d12e3536
VZ
1844 int tmpLnNo;
1845 store_line_no( tmpLnNo );
cecfc5e7
VZ
1846
1847 --cur; // rewind back to ';'
1848
d12e3536
VZ
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();
cecfc5e7 1854
d12e3536
VZ
1855 mpCurCtx->AddMember( pAttr );
1856 pAttr->mVisibility = mCurVis;
cecfc5e7 1857
d12e3536 1858 pAttr->mIsConstant = 0;
cecfc5e7 1859
d12e3536
VZ
1860 if ( firstMember )
1861 {
1862 firstMember = 0;
1863 first = members.size() - 1;;
1864 }
cecfc5e7 1865
d12e3536 1866 skip_token_back( cur );
cecfc5e7 1867
d12e3536
VZ
1868 // attach comments about the attribute
1869 AttachComments( *pAttr, cur );
cecfc5e7 1870
d12e3536 1871 pAttr->mName = get_token_str( cur );
cecfc5e7 1872
d12e3536
VZ
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 );
cecfc5e7 1878
d12e3536
VZ
1879 // if comma, than variable list continues
1880 // otherwise the variable type reached - stop
cecfc5e7 1881
d12e3536
VZ
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;
cecfc5e7 1888
d12e3536
VZ
1889 // skip default value and '=' symbol
1890 skip_next_token_back( cur );
1891 skip_token_back( cur );
cecfc5e7 1892
d12e3536 1893 pAttr->mName = get_token_str( cur );
cecfc5e7 1894
d12e3536
VZ
1895 skip_next_token_back( cur );
1896 skip_token_back( cur );
1897 }
cecfc5e7 1898
d12e3536
VZ
1899 if ( *cur != ',' )
1900 {
1901 type = get_token_str( cur );
1902 break;
1903 }
cecfc5e7 1904
d12e3536 1905 } while(1);
cecfc5e7 1906
d12e3536 1907 first = 0;
cecfc5e7 1908
d12e3536
VZ
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;
cecfc5e7 1915
d12e3536
VZ
1916 if ( !pAttr->mType )
1917 pAttr->mType = type;
1918 pAttr->mVisibility = mCurVis;
cecfc5e7 1919
d12e3536
VZ
1920 if ( !!pAttr->mName )
1921 arrange_indirection_tokens_between( pAttr->mType, pAttr->mName );
1922 }
cecfc5e7 1923
d12e3536
VZ
1924 cur = savedPos;
1925 restore_line_no( tmpLnNo );
cecfc5e7 1926
d12e3536 1927 clear_commets_queue();
cecfc5e7
VZ
1928
1929
1930}
1931
1932void CJSourceParser::SkipFunction( char*& cur )
1933{
d12e3536
VZ
1934 while ( *cur != '(' && cur < _gSrcEnd )
1935 {
1936 if (*cur == 10 ) ++_gLineNo;
1937 ++cur;
1938 }
cecfc5e7 1939
d12e3536
VZ
1940 skip_next_token_back( cur ); // go back and skip function identifier
1941 skip_token_back( cur ); // go back and skip return type
cecfc5e7 1942
d12e3536 1943 skip_block( cur ); // now, go ahead and skip whole declaration
cecfc5e7 1944
d12e3536 1945 SkipFunctionBody( cur );
cecfc5e7
VZ
1946
1947}
1948
1949void CJSourceParser::SkipFunctionBody( char*& cur )
1950{
d12e3536 1951 // FIXME:: check for comments and quoted stirngs here
cecfc5e7 1952
d12e3536 1953 bool hasDefinition = FALSE;
cecfc5e7 1954
d12e3536
VZ
1955 while( *cur != '{' && *cur != ';' )
1956 {
1957 if (*cur == 10 ) ++_gLineNo;
1958 ++cur;
1959 }
cecfc5e7 1960
d12e3536
VZ
1961 if ( *cur == ';' )
1962 {
1963 ++cur;
1964 }
1965 else
1966 {
1967 hasDefinition = TRUE;
cecfc5e7 1968
d12e3536
VZ
1969 skip_scope_block( cur ); // skip the whole imp.
1970 }
cecfc5e7 1971
d12e3536
VZ
1972 if ( mpCurCtx->GetType() == SP_CTX_OPERATION )
1973 {
1974 spOperation& op = *((spOperation*)mpCurCtx);
cecfc5e7 1975
d12e3536 1976 int curOfs = int ( cur - _gSrcStart );
cecfc5e7 1977
d12e3536 1978 op.mContextLength = curOfs - mpCurCtx->mSrcOffset;
cecfc5e7 1979
d12e3536 1980 op.mHasDefinition = hasDefinition;
cecfc5e7 1981
d12e3536 1982 // separate scope resolution token from the name of operation
cecfc5e7 1983
d12e3536
VZ
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 ) );
cecfc5e7 1989
d12e3536 1990 op.mScope = string( op.mName, 0, i );
cecfc5e7 1991
d12e3536 1992 op.mName = unscoped;
cecfc5e7 1993
d12e3536
VZ
1994 break;
1995 }
1996 }
1997 }
cecfc5e7
VZ
1998}
1999
2000bool CJSourceParser::CheckVisibilty( char*& cur )
2001{
d12e3536
VZ
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;
cecfc5e7
VZ
2023}
2024
2025void CJSourceParser::AddClassNode( char*& cur )
2026{
d12e3536
VZ
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 }
cecfc5e7 2040
d12e3536
VZ
2041 // by default all class members are private
2042 mCurVis = SP_VIS_PRIVATE;
cecfc5e7 2043
d12e3536
VZ
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;
cecfc5e7 2049
d12e3536
VZ
2050 mCurVis = SP_VIS_PUBLIC;
2051 }
2052 else if ( classkeyword == "union" ) {
2053 pClass->mClassSubType = SP_CLTYPE_UNION;
cecfc5e7 2054
d12e3536
VZ
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;
cecfc5e7 2061
d12e3536
VZ
2062 wxFAIL_MSG("unknown class keyword");
2063 }
cecfc5e7 2064
d12e3536 2065 mpCurCtx->AddMember( pClass );
cecfc5e7 2066
d12e3536
VZ
2067 // attach comments about the class
2068 AttachComments( *pClass, cur );
cecfc5e7 2069
d12e3536 2070 pClass->mSrcLineNo = get_line_no();
cecfc5e7 2071
d12e3536 2072 pClass->mSrcOffset = int( ctxStart - _gSrcStart );
cecfc5e7 2073
d12e3536
VZ
2074 char* nameTok = cur;
2075 pClass->mName = get_token_str( cur );
cecfc5e7 2076
d12e3536 2077 bool isDerived = 0;
cecfc5e7 2078
d12e3536 2079 // DANGER-MACROS::
cecfc5e7 2080
d12e3536
VZ
2081 do
2082 {
2083 skip_token( cur );
2084 if ( !get_next_token( cur ) ) return;
cecfc5e7 2085
d12e3536
VZ
2086 if ( *cur == ':' )
2087 {
2088 isDerived = 1;
cecfc5e7 2089
d12e3536 2090 char* tok = cur;
cecfc5e7 2091
d12e3536
VZ
2092 int tmpLn;
2093 store_line_no( tmpLn );
cecfc5e7 2094
d12e3536
VZ
2095 skip_next_token_back( tok );
2096 skip_token_back( tok );
cecfc5e7 2097
d12e3536 2098 restore_line_no( tmpLn );
cecfc5e7 2099
d12e3536
VZ
2100 // class name should precend ':' colon, thus
2101 // the one which was captured before was
2102 // proablty something else (like __dllexport MyClass : ... )
cecfc5e7 2103
d12e3536
VZ
2104 if ( nameTok != tok )
2105 {
2106 pClass->mName = get_token_str( tok );
2107 }
cecfc5e7 2108
d12e3536 2109 }
cecfc5e7 2110
d12e3536
VZ
2111 if ( *cur == '{' )
2112 break;
cecfc5e7 2113
d12e3536
VZ
2114 if ( *cur == ',' )
2115 continue;
cecfc5e7 2116
d12e3536 2117 size_t len = get_token_len( cur );
cecfc5e7 2118
d12e3536
VZ
2119 // skip neglectable C++ modifieres
2120 if ( cmp_tokens_fast( cur, "public", len ) )
2121 continue;
cecfc5e7 2122
d12e3536
VZ
2123 if ( cmp_tokens_fast( cur, "protected", len ) )
2124 continue;
cecfc5e7 2125
d12e3536
VZ
2126 if ( cmp_tokens_fast( cur, "private", len ) )
2127 continue;
cecfc5e7 2128
d12e3536
VZ
2129 if ( cmp_tokens_fast( cur, "virtual", len ) )
2130 continue;
cecfc5e7 2131
d12e3536 2132 // skip neglectable JAVA modifieres
cecfc5e7 2133
d12e3536
VZ
2134 if ( cmp_tokens_fast( cur, "extends", len ) )
2135 {
2136 isDerived = 1;
2137 continue;
2138 }
cecfc5e7 2139
d12e3536
VZ
2140 if ( cmp_tokens_fast( cur, "implements", len ) )
2141 {
2142 isDerived = 1;
2143 continue;
2144 }
cecfc5e7 2145
d12e3536 2146 // all we need to know is superclass or interface
cecfc5e7 2147
d12e3536
VZ
2148 char* tok = cur;
2149 int tmpLn;
2150 store_line_no( tmpLn );
cecfc5e7 2151
d12e3536
VZ
2152 skip_token(tok);
2153 get_next_token(tok);
cecfc5e7 2154
d12e3536 2155 restore_line_no( tmpLn );
cecfc5e7 2156
d12e3536 2157 if ( *tok != ':' && *cur != ':' )
cecfc5e7 2158
d12e3536 2159 pClass->mSuperClassNames.push_back( string( cur, len ) );
cecfc5e7 2160
d12e3536 2161 } while(1);
cecfc5e7 2162
d12e3536
VZ
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] );
cecfc5e7 2171
d12e3536 2172 char* tok = cur;
cecfc5e7 2173
d12e3536
VZ
2174 // some non-obviouse token was following "class" keyword -
2175 // we've confused it with class name - thus now we're reverting this mistake
cecfc5e7 2176
d12e3536
VZ
2177 skip_next_token_back( tok );
2178 skip_token_back( tok );
cecfc5e7 2179
d12e3536 2180 pClass->mName = get_token_str( tok );
cecfc5e7 2181
d12e3536
VZ
2182 restore_line_no( tmpLn );
2183 }
cecfc5e7
VZ
2184
2185
d12e3536 2186 ++cur; // skip opening curly brace
cecfc5e7 2187
d12e3536 2188 pClass->mHeaderLength = ( cur - ctxStart );
cecfc5e7 2189
d12e3536
VZ
2190 // now, enter the class context
2191 mpCurCtx = pClass;
cecfc5e7 2192
d12e3536 2193 clear_commets_queue();
cecfc5e7
VZ
2194}
2195
2196void CJSourceParser::AddEnumNode( char*& cur )
2197{
d12e3536
VZ
2198 // now the cursor is at "enum" keyword
2199 char* start = cur;
2200
2201 spEnumeration* pEnum = new spEnumeration();
2202 mpCurCtx->AddMember( pEnum );
cecfc5e7 2203
d12e3536 2204 pEnum->mSrcLineNo = get_line_no();
cecfc5e7 2205
cecfc5e7 2206
d12e3536 2207 AttachComments( *pEnum, cur );
cecfc5e7 2208
d12e3536
VZ
2209 skip_token( cur );
2210 if ( !get_next_token( cur ) ) return;
cecfc5e7 2211
d12e3536
VZ
2212 // check if enumeration has got it's identifier
2213 if ( *cur != '{' )
2214 {
2215 pEnum->mName = get_token_str( cur );
2216 }
cecfc5e7 2217
d12e3536 2218 if ( !skip_imp_block( cur ) ) return;
cecfc5e7 2219
d12e3536 2220 get_string_between( start, cur, &pEnum->mEnumContent );
cecfc5e7 2221
d12e3536
VZ
2222 if ( get_next_token(cur) )
2223 {
2224 // check if the identifier if after the {...} block
2225 if ( *cur != ';' )
cecfc5e7 2226
d12e3536
VZ
2227 pEnum->mName = get_token_str( cur );
2228 }
cecfc5e7 2229
d12e3536 2230 clear_commets_queue();
cecfc5e7
VZ
2231}
2232
2233void CJSourceParser::AddTypeDefNode( char*& cur )
2234{
d12e3536 2235 // now the cursor at the token next to "typedef" keyword
cecfc5e7 2236
d12e3536 2237 if ( !get_next_token(cur) ) return;
cecfc5e7 2238
d12e3536 2239 char* start = cur;
cecfc5e7 2240
d12e3536
VZ
2241 spTypeDef* pTDef = new spTypeDef();
2242 mpCurCtx->AddMember( pTDef );
cecfc5e7 2243
d12e3536 2244 pTDef->mSrcLineNo = get_line_no();
cecfc5e7 2245
d12e3536 2246 AttachComments( *pTDef, cur );
cecfc5e7 2247
d12e3536 2248 skip_statement( cur );
cecfc5e7 2249
d12e3536
VZ
2250 int tmpLnNo;
2251 store_line_no( tmpLnNo );
cecfc5e7 2252
d12e3536
VZ
2253 char* tok = cur-1;
2254 skip_next_token_back( tok );
cecfc5e7 2255
d12e3536 2256 char* nameEnd = tok;
cecfc5e7 2257
d12e3536 2258 skip_token_back( tok );
cecfc5e7 2259
d12e3536 2260 char* nameStart = tok;
cecfc5e7 2261
d12e3536 2262 skip_next_token_back( tok );
cecfc5e7 2263
d12e3536 2264 char* typeEnd = tok;
cecfc5e7 2265
d12e3536
VZ
2266 // check if it's function prototype
2267 if ( *nameStart == ')' )
2268 {
2269 typeEnd = nameStart+1;
2270
2271 // skip argument list
2272 while ( *nameStart != '(' ) --nameStart;
cecfc5e7 2273
d12e3536
VZ
2274 // skip to function type definition
2275 while ( *nameStart != ')' ) --nameStart;
cecfc5e7 2276
d12e3536 2277 skip_next_token_back( nameStart );
cecfc5e7 2278
d12e3536 2279 nameEnd = nameStart;
cecfc5e7 2280
d12e3536 2281 skip_token_back( nameStart );
cecfc5e7 2282
d12e3536
VZ
2283 if ( *nameStart == '*' ) ++nameStart;
2284 }
cecfc5e7 2285
d12e3536 2286 get_string_between( start, typeEnd, &pTDef->mOriginalType );
cecfc5e7 2287
d12e3536 2288 get_string_between( nameStart, nameEnd, &pTDef->mName );
cecfc5e7 2289
d12e3536 2290 clear_commets_queue();
cecfc5e7 2291
d12e3536 2292 restore_line_no( tmpLnNo );
cecfc5e7 2293}